summaryrefslogtreecommitdiffstats
path: root/media/java
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-02 22:54:33 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-02 22:54:33 -0800
commit3dec7d563a2f3e1eb967ce2054a00b6620e3558c (patch)
treeaa3b0365c47cb3c1607c0dc76c8d32b4046fc287 /media/java
parent15ab3eae2ec3d73b3e8aa60b33ae41445bf83f4b (diff)
downloadframeworks_base-3dec7d563a2f3e1eb967ce2054a00b6620e3558c.zip
frameworks_base-3dec7d563a2f3e1eb967ce2054a00b6620e3558c.tar.gz
frameworks_base-3dec7d563a2f3e1eb967ce2054a00b6620e3558c.tar.bz2
auto import from //depot/cupcake/@137055
Diffstat (limited to 'media/java')
-rw-r--r--media/java/android/media/AudioRecord.java38
-rw-r--r--media/java/android/media/AudioTrack.java57
-rw-r--r--media/java/android/media/JetPlayer.java11
-rw-r--r--media/java/android/media/MediaMetadataRetriever.java14
-rw-r--r--media/java/android/media/MediaPlayer.java13
-rw-r--r--media/java/android/media/MediaRecorder.java238
-rw-r--r--media/java/android/media/Ringtone.java13
-rw-r--r--media/java/android/media/SoundPool.java7
8 files changed, 295 insertions, 96 deletions
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index fd990fe..0ef7760 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -532,12 +532,19 @@ public class AudioRecord
* @param audioData the array to which the recorded audio data is written.
* @param offsetInBytes index in audioData from which the data is written.
* @param sizeInBytes the number of requested bytes.
- * @return the number of bytes that were read or -1 if the object wasn't properly
- * initialized. The number of bytes will not exceed sizeInBytes.
+ * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION}
+ * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+ * the parameters don't resolve to valid data and indexes.
+ * The number of bytes will not exceed sizeInBytes.
*/
public int read(byte[] audioData, int offsetInBytes, int sizeInBytes) {
if (mState != STATE_INITIALIZED) {
- return -1;
+ return ERROR_INVALID_OPERATION;
+ }
+
+ if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
+ || (offsetInBytes + sizeInBytes > audioData.length)) {
+ return ERROR_BAD_VALUE;
}
return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes);
@@ -549,12 +556,19 @@ public class AudioRecord
* @param audioData the array to which the recorded audio data is written.
* @param offsetInShorts index in audioData from which the data is written.
* @param sizeInShorts the number of requested shorts.
- * @return the number of shorts that were read. or -1 if the object wasn't properly
- * initialized. The number of shorts will not exceed sizeInShorts
+ * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION}
+ * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+ * the parameters don't resolve to valid data and indexes.
+ * The number of shorts will not exceed sizeInShorts.
*/
public int read(short[] audioData, int offsetInShorts, int sizeInShorts) {
if (mState != STATE_INITIALIZED) {
- return -1;
+ return ERROR_INVALID_OPERATION;
+ }
+
+ if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
+ || (offsetInShorts + sizeInShorts > audioData.length)) {
+ return ERROR_BAD_VALUE;
}
return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts);
@@ -566,12 +580,18 @@ public class AudioRecord
* is not a direct buffer, this method will always return 0.
* @param audioBuffer the direct buffer to which the recorded audio data is written.
* @param sizeInBytes the number of requested bytes.
- * @return the number of bytes that were read or -1 if the object wasn't properly
- * initialized. The number of bytes will not exceed sizeInBytes.
+ * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION}
+ * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+ * the parameters don't resolve to valid data and indexes.
+ * The number of bytes will not exceed sizeInBytes.
*/
public int read(ByteBuffer audioBuffer, int sizeInBytes) {
if (mState != STATE_INITIALIZED) {
- return -1;
+ return ERROR_INVALID_OPERATION;
+ }
+
+ if ( (audioBuffer == null) || (sizeInBytes < 0) ) {
+ return ERROR_BAD_VALUE;
}
return native_read_in_direct_buffer(audioBuffer, sizeInBytes);
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index e32835c..997cd44 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -436,6 +436,15 @@ public class AudioTrack
public int getSampleRate() {
return mSampleRate;
}
+
+ /**
+ * @hide
+ * Returns the current playback rate in Hz. Note that this rate may differ from one set using
+ * {@link #setPlaybackRate(int)} as the value effectively set is implementation-dependent.
+ */
+ public int getPlaybackRate() {
+ return native_get_playback_rate();
+ }
/**
* Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_16BIT}
@@ -523,8 +532,8 @@ public class AudioTrack
/**
* Returns the hardware output sample rate
*/
- static public int getNativeOutputSampleRate() {
- return native_get_output_sample_rate();
+ static public int getNativeOutputSampleRate(int streamType) {
+ return native_get_output_sample_rate(streamType);
}
/**
@@ -650,16 +659,19 @@ public class AudioTrack
* content. Setting it to half the sample rate of the content will cause the playback to
* last twice as long, but will also result result in a negative pitch shift.
* The current implementation supports a maximum sample rate of twice the hardware output
- * sample rate (see {@link #getNativeOutputSampleRate()}). Use {@link #getSampleRate()} to
+ * sample rate (see {@link #getNativeOutputSampleRate(int)}). Use {@link #getSampleRate()} to
* check the rate actually used in hardware after potential clamping.
* @param sampleRateInHz
- * @return error code or success, see {@link #SUCCESS},
+ * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
* {@link #ERROR_INVALID_OPERATION}
*/
public int setPlaybackRate(int sampleRateInHz) {
if (mState != STATE_INITIALIZED) {
return ERROR_INVALID_OPERATION;
}
+ if (sampleRateInHz <= 0) {
+ return ERROR_BAD_VALUE;
+ }
native_set_playback_rate(sampleRateInHz);
return SUCCESS;
}
@@ -699,7 +711,7 @@ public class AudioTrack
*/
public int setPlaybackHeadPosition(int positionInFrames) {
synchronized(mPlayStateLock) {
- if(mPlayState == PLAYSTATE_STOPPED) {
+ if ((mPlayState == PLAYSTATE_STOPPED) || (mPlayState == PLAYSTATE_PAUSED)) {
return native_set_position(positionInFrames);
} else {
return ERROR_INVALID_OPERATION;
@@ -717,6 +729,9 @@ public class AudioTrack
* {@link #ERROR_INVALID_OPERATION}
*/
public int setLoopPoints(int startInFrames, int endInFrames, int loopCount) {
+ if (mDataLoadMode == MODE_STREAM) {
+ return ERROR_INVALID_OPERATION;
+ }
return native_set_loop(startInFrames, endInFrames, loopCount);
}
@@ -806,8 +821,9 @@ public class AudioTrack
* @param audioData the array that holds the data to play.
* @param offsetInBytes the offset in audioData where the data to play starts.
* @param sizeInBytes the number of bytes to read in audioData after the offset.
- * @return the number of bytes that were written or -1 if the object wasn't properly
- * initialized.
+ * @return the number of bytes that were written or {@link #ERROR_INVALID_OPERATION}
+ * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+ * the parameters don't resolve to valid data and indexes.
*/
public int write(byte[] audioData,int offsetInBytes, int sizeInBytes) {
@@ -816,11 +832,14 @@ public class AudioTrack
&& (sizeInBytes > 0)) {
mState = STATE_INITIALIZED;
}
- //TODO check if future writes should be forbidden for static tracks
- // or: how to update data for static tracks?
if (mState != STATE_INITIALIZED) {
- return -1;
+ return ERROR_INVALID_OPERATION;
+ }
+
+ if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
+ || (offsetInBytes + sizeInBytes > audioData.length)) {
+ return ERROR_BAD_VALUE;
}
return native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat);
@@ -832,8 +851,9 @@ public class AudioTrack
* @param audioData the array that holds the data to play.
* @param offsetInShorts the offset in audioData where the data to play starts.
* @param sizeInShorts the number of bytes to read in audioData after the offset.
- * @return the number of shorts that were written or -1 if the object wasn't properly
- * initialized.
+ * @return the number of shorts that were written or {@link #ERROR_INVALID_OPERATION}
+ * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+ * the parameters don't resolve to valid data and indexes.
*/
public int write(short[] audioData, int offsetInShorts, int sizeInShorts) {
@@ -842,11 +862,14 @@ public class AudioTrack
&& (sizeInShorts > 0)) {
mState = STATE_INITIALIZED;
}
- //TODO check if future writes should be forbidden for static tracks
- // or: how to update data for static tracks?
-
+
if (mState != STATE_INITIALIZED) {
- return -1;
+ return ERROR_INVALID_OPERATION;
+ }
+
+ if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
+ || (offsetInShorts + sizeInShorts > audioData.length)) {
+ return ERROR_BAD_VALUE;
}
return native_write_short(audioData, offsetInShorts, sizeInShorts, mAudioFormat);
@@ -1007,7 +1030,7 @@ public class AudioTrack
private native final int native_set_loop(int start, int end, int loopCount);
- static private native final int native_get_output_sample_rate();
+ static private native final int native_get_output_sample_rate(int streamType);
static private native final int native_get_min_buff_size(
int sampleRateInHz, int channelConfig, int audioFormat);
diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java
index bfa2f80..9de0eec 100644
--- a/media/java/android/media/JetPlayer.java
+++ b/media/java/android/media/JetPlayer.java
@@ -25,6 +25,7 @@ import android.content.res.AssetFileDescriptor;
import android.os.Looper;
import android.os.Handler;
import android.os.Message;
+import android.util.AndroidRuntimeException;
import android.util.Log;
/**
@@ -163,8 +164,12 @@ public class JetPlayer
public boolean loadJetFile(AssetFileDescriptor afd) {
+ long len = afd.getLength();
+ if (len < 0) {
+ throw new AndroidRuntimeException("no length for fd");
+ }
return native_loadJetFromFileD(
- afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+ afd.getFileDescriptor(), afd.getStartOffset(), len);
}
@@ -251,7 +256,9 @@ public class JetPlayer
mJet,
(short)((msg.arg1 & JET_EVENT_SEG_MASK) >> JET_EVENT_SEG_SHIFT),
(byte) ((msg.arg1 & JET_EVENT_TRACK_MASK) >> JET_EVENT_TRACK_SHIFT),
- (byte) ((msg.arg1 & JET_EVENT_CHAN_MASK) >> JET_EVENT_CHAN_SHIFT),
+ // JETCreator channel numbers start at 1, but the index starts at 0
+ // in the .jet files
+ (byte)(((msg.arg1 & JET_EVENT_CHAN_MASK) >> JET_EVENT_CHAN_SHIFT) + 1),
(byte) ((msg.arg1 & JET_EVENT_CTRL_MASK) >> JET_EVENT_CTRL_SHIFT),
(byte) (msg.arg1 & JET_EVENT_VAL_MASK) );
}
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index c1a0c21..3a49a5f 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -18,6 +18,7 @@ package android.media;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
@@ -137,11 +138,11 @@ public class MediaMetadataRetriever
return;
}
- ParcelFileDescriptor fd = null;
+ AssetFileDescriptor fd = null;
try {
ContentResolver resolver = context.getContentResolver();
try {
- fd = resolver.openFileDescriptor(uri, "r");
+ fd = resolver.openAssetFileDescriptor(uri, "r");
} catch(FileNotFoundException e) {
throw new IllegalArgumentException();
}
@@ -152,7 +153,14 @@ public class MediaMetadataRetriever
if (!descriptor.valid()) {
throw new IllegalArgumentException();
}
- setDataSource(descriptor);
+ // Note: using getDeclaredLength so that our behavior is the same
+ // as previous versions when the content provider is returning
+ // a full file.
+ if (fd.getDeclaredLength() < 0) {
+ setDataSource(descriptor);
+ } else {
+ setDataSource(descriptor, fd.getStartOffset(), fd.getDeclaredLength());
+ }
return;
} catch (SecurityException ex) {
} finally {
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 601557d..fe1de8e 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -584,14 +584,21 @@ public class MediaPlayer
return;
}
- ParcelFileDescriptor fd = null;
+ AssetFileDescriptor fd = null;
try {
ContentResolver resolver = context.getContentResolver();
- fd = resolver.openFileDescriptor(uri, "r");
+ fd = resolver.openAssetFileDescriptor(uri, "r");
if (fd == null) {
return;
}
- setDataSource(fd.getFileDescriptor());
+ // Note: using getDeclaredLength so that our behavior is the same
+ // as previous versions when the content provider is returning
+ // a full file.
+ if (fd.getDeclaredLength() < 0) {
+ setDataSource(fd.getFileDescriptor());
+ } else {
+ setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getDeclaredLength());
+ }
return;
} catch (SecurityException ex) {
} catch (IOException ex) {
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 3609826..4906cbb 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -16,23 +16,27 @@
package android.media;
-import android.view.Surface;
import android.hardware.Camera;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android.view.Surface;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileDescriptor;
-import android.util.Log;
+import java.lang.ref.WeakReference;
/**
* Used to record audio and video. The recording control is based on a
- * simple state machine (see below).
- *
+ * simple state machine (see below).
+ *
* <p><img src="{@docRoot}images/mediarecorder_state_diagram.gif" border="0" />
* </p>
- *
+ *
* <p>A common case of using MediaRecorder to record audio works as follows:
- *
+ *
* <pre>MediaRecorder recorder = new MediaRecorder();
* recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
* recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
@@ -45,39 +49,54 @@ import android.util.Log;
* recorder.reset(); // You can reuse the object by going back to setAudioSource() step
* recorder.release(); // Now the object cannot be reused
* </pre>
- *
+ *
* <p>See the <a href="{@docRoot}guide/topics/media/index.html">Audio and Video</a>
* documentation for additional help with using MediaRecorder.
*/
public class MediaRecorder
-{
+{
static {
System.loadLibrary("media_jni");
}
private final static String TAG = "MediaRecorder";
-
+
// The two fields below are accessed by native methods
@SuppressWarnings("unused")
private int mNativeContext;
-
+
@SuppressWarnings("unused")
private Surface mSurface;
private String mPath;
private FileDescriptor mFd;
+ private EventHandler mEventHandler;
+ private OnErrorListener mOnErrorListener;
/**
* Default constructor.
*/
public MediaRecorder() {
- native_setup();
+
+ Looper looper;
+ if ((looper = Looper.myLooper()) != null) {
+ mEventHandler = new EventHandler(this, looper);
+ } else if ((looper = Looper.getMainLooper()) != null) {
+ mEventHandler = new EventHandler(this, looper);
+ } else {
+ mEventHandler = null;
+ }
+
+ /* Native setup requires a weak reference to our object.
+ * It's easier to create it here than in C++.
+ */
+ native_setup(new WeakReference<MediaRecorder>(this));
}
-
+
/**
* Sets a Camera to use for recording. Use this function to switch
* quickly between preview and capture mode without a teardown of
* the camera object. Must call before prepare().
- *
+ *
* @param c the Camera to use for recording
*/
public native void setCamera(Camera c);
@@ -86,15 +105,15 @@ public class MediaRecorder
* Sets a Surface to show a preview of recorded media (video). Calls this
* before prepare() to make sure that the desirable preview display is
* set.
- *
+ *
* @param sv the Surface to use for the preview
*/
public void setPreviewDisplay(Surface sv) {
mSurface = sv;
}
-
+
/**
- * Defines the audio source. These constants are used with
+ * Defines the audio source. These constants are used with
* {@link MediaRecorder#setAudioSource(int)}.
*/
public final class AudioSource {
@@ -108,7 +127,7 @@ public class MediaRecorder
}
/**
- * Defines the video source. These constants are used with
+ * Defines the video source. These constants are used with
* {@link MediaRecorder#setVideoSource(int)}.
*/
public final class VideoSource {
@@ -122,7 +141,7 @@ public class MediaRecorder
}
/**
- * Defines the output format. These constants are used with
+ * Defines the output format. These constants are used with
* {@link MediaRecorder#setOutputFormat(int)}.
*/
public final class OutputFormat {
@@ -140,7 +159,7 @@ public class MediaRecorder
};
/**
- * Defines the audio encoding. These constants are used with
+ * Defines the audio encoding. These constants are used with
* {@link MediaRecorder#setAudioEncoder(int)}.
*/
public final class AudioEncoder {
@@ -155,7 +174,7 @@ public class MediaRecorder
}
/**
- * Defines the video encoding. These constants are used with
+ * Defines the video encoding. These constants are used with
* {@link MediaRecorder#setVideoEncoder(int)}.
*/
public final class VideoEncoder {
@@ -172,50 +191,50 @@ public class MediaRecorder
/**
* Sets the audio source to be used for recording. If this method is not
* called, the output file will not contain an audio track. The source needs
- * to be specified before setting recording-parameters or encoders. Call
+ * to be specified before setting recording-parameters or encoders. Call
* this only before setOutputFormat().
- *
+ *
* @param audio_source the audio source to use
* @throws IllegalStateException if it is called after setOutputFormat()
* @see android.media.MediaRecorder.AudioSource
- */
+ */
public native void setAudioSource(int audio_source)
throws IllegalStateException;
/**
* Sets the video source to be used for recording. If this method is not
* called, the output file will not contain an video track. The source needs
- * to be specified before setting recording-parameters or encoders. Call
+ * to be specified before setting recording-parameters or encoders. Call
* this only before setOutputFormat().
- *
+ *
* @param video_source the video source to use
* @throws IllegalStateException if it is called after setOutputFormat()
* @see android.media.MediaRecorder.VideoSource
- */
+ */
public native void setVideoSource(int video_source)
throws IllegalStateException;
/**
* Sets the format of the output file produced during recording. Call this
* after setAudioSource()/setVideoSource() but before prepare().
- *
- * @param output_format the output format to use. The output format
+ *
+ * @param output_format the output format to use. The output format
* needs to be specified before setting recording-parameters or encoders.
* @throws IllegalStateException if it is called after prepare() or before
* setAudioSource()/setVideoSource().
* @see android.media.MediaRecorder.OutputFormat
- */
+ */
public native void setOutputFormat(int output_format)
throws IllegalStateException;
-
+
/**
* Sets the width and height of the video to be captured. Must be called
* after setVideoSource(). Call this after setOutFormat() but before
* prepare().
- *
+ *
* @param width the width of the video to be captured
* @param height the height of the video to be captured
- * @throws IllegalStateException if it is called after
+ * @throws IllegalStateException if it is called after
* prepare() or before setOutputFormat()
*/
public native void setVideoSize(int width, int height)
@@ -227,7 +246,7 @@ public class MediaRecorder
* prepare().
*
* @param rate the number of frames per second of video to capture
- * @throws IllegalStateException if it is called after
+ * @throws IllegalStateException if it is called after
* prepare() or before setOutputFormat().
*
* NOTE: On some devices that have auto-frame rate, this sets the
@@ -240,12 +259,12 @@ public class MediaRecorder
* Sets the audio encoder to be used for recording. If this method is not
* called, the output file will not contain an audio track. Call this after
* setOutputFormat() but before prepare().
- *
+ *
* @param audio_encoder the audio encoder to use.
* @throws IllegalStateException if it is called before
* setOutputFormat() or after prepare().
* @see android.media.MediaRecorder.AudioEncoder
- */
+ */
public native void setAudioEncoder(int audio_encoder)
throws IllegalStateException;
@@ -253,43 +272,43 @@ public class MediaRecorder
* Sets the video encoder to be used for recording. If this method is not
* called, the output file will not contain an video track. Call this after
* setOutputFormat() and before prepare().
- *
+ *
* @param video_encoder the video encoder to use.
* @throws IllegalStateException if it is called before
* setOutputFormat() or after prepare()
* @see android.media.MediaRecorder.VideoEncoder
- */
+ */
public native void setVideoEncoder(int video_encoder)
throws IllegalStateException;
/**
* Pass in the file descriptor of the file to be written. Call this after
* setOutputFormat() but before prepare().
- *
+ *
* @param fd an open file descriptor to be written into.
* @throws IllegalStateException if it is called before
* setOutputFormat() or after prepare()
- */
+ */
public void setOutputFile(FileDescriptor fd) throws IllegalStateException
{
mPath = null;
mFd = fd;
}
-
+
/**
* Sets the path of the output file to be produced. Call this after
* setOutputFormat() but before prepare().
- *
+ *
* @param path The pathname to use.
* @throws IllegalStateException if it is called before
* setOutputFormat() or after prepare()
- */
+ */
public void setOutputFile(String path) throws IllegalStateException
{
mFd = null;
mPath = path;
}
-
+
// native implementation
private native void _setOutputFile(FileDescriptor fd, long offset, long length)
throws IllegalStateException, IOException;
@@ -299,7 +318,7 @@ public class MediaRecorder
* Prepares the recorder to begin capturing and encoding data. This method
* must be called after setting up the desired audio and video sources,
* encoders, file format, etc., but before start().
- *
+ *
* @throws IllegalStateException if it is called after
* start() or before setOutputFormat().
* @throws IOException if prepare fails otherwise.
@@ -307,8 +326,12 @@ public class MediaRecorder
public void prepare() throws IllegalStateException, IOException
{
if (mPath != null) {
- FileOutputStream f = new FileOutputStream(mPath);
- _setOutputFile(f.getFD(), 0, 0);
+ FileOutputStream fos = new FileOutputStream(mPath);
+ try {
+ _setOutputFile(fos.getFD(), 0, 0);
+ } finally {
+ fos.close();
+ }
} else if (mFd != null) {
_setOutputFile(mFd, 0, 0);
} else {
@@ -318,9 +341,9 @@ public class MediaRecorder
}
/**
- * Begins capturing and encoding data to the file specified with
+ * Begins capturing and encoding data to the file specified with
* setOutputFile(). Call this after prepare().
- *
+ *
* @throws IllegalStateException if it is called before
* prepare().
*/
@@ -329,7 +352,7 @@ public class MediaRecorder
/**
* Stops recording. Call this after start(). Once recording is stopped,
* you will have to configure it again as if it has just been constructed.
- *
+ *
* @throws IllegalStateException if it is called before start()
*/
public native void stop() throws IllegalStateException;
@@ -339,19 +362,118 @@ public class MediaRecorder
* this method, you will have to configure it again as if it had just been
* constructed.
*/
- public native void reset();
-
+ public void reset() {
+ native_reset();
+
+ // make sure none of the listeners get called anymore
+ mEventHandler.removeCallbacksAndMessages(null);
+ }
+
+ private native void native_reset();
+
/**
- * Returns the maximum absolute amplitude that was sampled since the last
+ * Returns the maximum absolute amplitude that was sampled since the last
* call to this method. Call this only after the setAudioSource().
- *
- * @return the maximum absolute amplitude measured since the last call, or
+ *
+ * @return the maximum absolute amplitude measured since the last call, or
* 0 when called for the first time
* @throws IllegalStateException if it is called before
* the audio source has been set.
*/
public native int getMaxAmplitude() throws IllegalStateException;
-
+
+ /* Do not change this value without updating its counterpart
+ * in include/media/mediarecorder.h!
+ */
+ /** Unspecified media recorder error.
+ * @see android.media.MediaRecorder.OnErrorListener
+ */
+ public static final int MEDIA_RECORDER_ERROR_UNKNOWN = 1;
+
+ /**
+ * Interface definition for a callback to be invoked when an error
+ * occurs while recording.
+ */
+ public interface OnErrorListener
+ {
+ /**
+ * Called when an error occurs while recording.
+ *
+ * @param mr the MediaRecorder that encountered the error
+ * @param what the type of error that has occurred:
+ * <ul>
+ * <li>{@link #MEDIA_RECORDER_ERROR_UNKNOWN}
+ * </ul>
+ * @param extra an extra code, specific to the error type
+ */
+ void onError(MediaRecorder mr, int what, int extra);
+ }
+
+ /**
+ * Register a callback to be invoked when an error occurs while
+ * recording.
+ *
+ * @param l the callback that will be run
+ */
+ public void setOnErrorListener(OnErrorListener l)
+ {
+ mOnErrorListener = l;
+ }
+
+ private class EventHandler extends Handler
+ {
+ private MediaRecorder mMediaRecorder;
+
+ public EventHandler(MediaRecorder mr, Looper looper) {
+ super(looper);
+ mMediaRecorder = mr;
+ }
+
+ /* Do not change this value without updating its counterpart
+ * in include/media/mediarecorder.h!
+ */
+ private static final int MEDIA_RECORDER_EVENT_ERROR = 1;
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (mMediaRecorder.mNativeContext == 0) {
+ Log.w(TAG, "mediarecorder went away with unhandled events");
+ return;
+ }
+ switch(msg.what) {
+ case MEDIA_RECORDER_EVENT_ERROR:
+ if (mOnErrorListener != null)
+ mOnErrorListener.onError(mMediaRecorder, msg.arg1, msg.arg2);
+
+ return;
+
+ default:
+ Log.e(TAG, "Unknown message type " + msg.what);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Called from native code when an interesting event happens. This method
+ * just uses the EventHandler system to post the event back to the main app thread.
+ * We use a weak reference to the original MediaRecorder object so that the native
+ * code is safe from the object disappearing from underneath it. (This is
+ * the cookie passed to native_setup().)
+ */
+ private static void postEventFromNative(Object mediarecorder_ref,
+ int what, int arg1, int arg2, Object obj)
+ {
+ MediaRecorder mr = (MediaRecorder)((WeakReference)mediarecorder_ref).get();
+ if (mr == null) {
+ return;
+ }
+
+ if (mr.mEventHandler != null) {
+ Message m = mr.mEventHandler.obtainMessage(what, arg1, arg2, obj);
+ mr.mEventHandler.sendMessage(m);
+ }
+ }
/**
* Releases resources associated with this MediaRecorder object.
@@ -360,10 +482,10 @@ public class MediaRecorder
*/
public native void release();
- private native final void native_setup() throws IllegalStateException;
-
+ private native final void native_setup(Object mediarecorder_this) throws IllegalStateException;
+
private native final void native_finalize();
-
+
@Override
protected void finalize() { native_finalize(); }
}
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index cfcb5eb..e80d8aa 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -164,9 +164,16 @@ public class Ringtone {
} else if (mFileDescriptor != null) {
mAudio.setDataSource(mFileDescriptor);
} else if (mAssetFileDescriptor != null) {
- mAudio.setDataSource(mAssetFileDescriptor.getFileDescriptor(),
- mAssetFileDescriptor.getStartOffset(),
- mAssetFileDescriptor.getLength());
+ // Note: using getDeclaredLength so that our behavior is the same
+ // as previous versions when the content provider is returning
+ // a full file.
+ if (mAssetFileDescriptor.getDeclaredLength() < 0) {
+ mAudio.setDataSource(mAssetFileDescriptor.getFileDescriptor());
+ } else {
+ mAudio.setDataSource(mAssetFileDescriptor.getFileDescriptor(),
+ mAssetFileDescriptor.getStartOffset(),
+ mAssetFileDescriptor.getDeclaredLength());
+ }
} else {
throw new IOException("No data source set.");
}
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 427f173..000430f 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -16,6 +16,7 @@
package android.media;
+import android.util.AndroidRuntimeException;
import android.util.Log;
import java.io.File;
import java.io.FileDescriptor;
@@ -79,7 +80,11 @@ public class SoundPool
public int load(AssetFileDescriptor afd, int priority) {
if (afd != null) {
- return _load(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength(), priority);
+ long len = afd.getLength();
+ if (len < 0) {
+ throw new AndroidRuntimeException("no length for fd");
+ }
+ return _load(afd.getFileDescriptor(), afd.getStartOffset(), len, priority);
} else {
return 0;
}