diff options
Diffstat (limited to 'media')
44 files changed, 1901 insertions, 1101 deletions
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index c857e17..0732b61 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -18,9 +18,9 @@ package android.media; /** * The AudioFormat class is used to access a number of audio format and - * channel configuration constants. + * channel configuration constants. They are for instance used + * in __link AudioTrack} and __link AudioRecord}. * - * {@hide Pending API council review} */ public class AudioFormat { diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 52cf69f..2978774 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -49,37 +49,60 @@ public class AudioManager { private static boolean localLOGV = DEBUG || android.util.Config.LOGV; /** + * Broadcast intent, a hint for applications that audio is about to become + * 'noisy' due to a change in audio outputs. For example, this intent may + * be sent when a wired headset is unplugged, or when an A2DP audio + * sink is disconnected, and the audio system is about to automatically + * switch audio route to the speaker. Applications that are controlling + * audio streams may consider pausing, reducing volume or some other action + * on receipt of this intent so as not to surprise the user with audio + * from the speaker. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY"; + + /** * Sticky broadcast intent action indicating that the ringer mode has * changed. Includes the new ringer mode. - * + * * @see #EXTRA_RINGER_MODE */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED"; - + /** * The new ringer mode. - * + * * @see #RINGER_MODE_CHANGED_ACTION * @see #RINGER_MODE_NORMAL * @see #RINGER_MODE_SILENT * @see #RINGER_MODE_VIBRATE */ public static final String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE"; - + /** * Broadcast intent action indicating that the vibrate setting has * changed. Includes the vibrate type and its new setting. - * + * * @see #EXTRA_VIBRATE_TYPE * @see #EXTRA_VIBRATE_SETTING */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String VIBRATE_SETTING_CHANGED_ACTION = "android.media.VIBRATE_SETTING_CHANGED"; - + + /** + * @hide Broadcast intent when the volume for a particular stream type changes. + * Includes the stream and the new volume + * + * @see #EXTRA_VOLUME_STREAM_TYPE + * @see #EXTRA_VOLUME_STREAM_VALUE + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION"; + /** * The new vibrate setting for a particular type. - * + * * @see #VIBRATE_SETTING_CHANGED_ACTION * @see #EXTRA_VIBRATE_TYPE * @see #VIBRATE_SETTING_ON @@ -87,16 +110,27 @@ public class AudioManager { * @see #VIBRATE_SETTING_ONLY_SILENT */ public static final String EXTRA_VIBRATE_SETTING = "android.media.EXTRA_VIBRATE_SETTING"; - + /** * The vibrate type whose setting has changed. - * + * * @see #VIBRATE_SETTING_CHANGED_ACTION * @see #VIBRATE_TYPE_NOTIFICATION * @see #VIBRATE_TYPE_RINGER */ public static final String EXTRA_VIBRATE_TYPE = "android.media.EXTRA_VIBRATE_TYPE"; - + + /** + * @hide The stream type for the volume changed intent. + */ + public static final String EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE"; + + /** + * @hide The volume associated with the stream for the volume changed intent. + */ + public static final String EXTRA_VOLUME_STREAM_VALUE = + "android.media.EXTRA_VOLUME_STREAM_VALUE"; + /** The audio stream for phone calls */ public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL; /** The audio stream for system sounds */ @@ -109,6 +143,8 @@ public class AudioManager { public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM; /** The audio stream for notifications */ public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION; + /** @hide The audio stream for phone calls when connected to bluetooth */ + public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO; /** Number of audio streams */ /** * @deprecated Use AudioSystem.getNumStreamTypes() instead @@ -123,9 +159,10 @@ public class AudioManager { 8, // STREAM_RING 16, // STREAM_MUSIC 8, // STREAM_ALARM - 8 // STREAM_NOTIFICATION - }; - + 8, // STREAM_NOTIFICATION + 15, // STREAM_BLUETOOTH_SCO + }; + /** @hide Default volume index values for audio streams */ public static final int[] DEFAULT_STREAM_VOLUME = new int[] { 4, // STREAM_VOICE_CALL @@ -133,12 +170,13 @@ public class AudioManager { 5, // STREAM_RING 11, // STREAM_MUSIC 6, // STREAM_ALARM - 5 // STREAM_NOTIFICATION - }; - + 5, // STREAM_NOTIFICATION + 7 // STREAM_BLUETOOTH_SCO + }; + /** * Increase the ringer volume. - * + * * @see #adjustVolume(int, int) * @see #adjustStreamVolume(int, int, int) */ @@ -146,7 +184,7 @@ public class AudioManager { /** * Decrease the ringer volume. - * + * * @see #adjustVolume(int, int) * @see #adjustStreamVolume(int, int, int) */ @@ -155,17 +193,17 @@ public class AudioManager { /** * Maintain the previous ringer volume. This may be useful when needing to * show the volume toast without actually modifying the volume. - * + * * @see #adjustVolume(int, int) * @see #adjustStreamVolume(int, int, int) */ public static final int ADJUST_SAME = 0; // Flags should be powers of 2! - + /** * Show a toast containing the current volume. - * + * * @see #adjustStreamVolume(int, int, int) * @see #adjustVolume(int, int) * @see #setStreamVolume(int, int, int) @@ -183,12 +221,12 @@ public class AudioManager { * mode (for example, the ring stream type). If this flag is included, this * behavior will be present regardless of the stream type being affected by * the ringer mode. - * + * * @see #adjustVolume(int, int) * @see #adjustStreamVolume(int, int, int) */ public static final int FLAG_ALLOW_RINGER_MODES = 1 << 1; - + /** * Whether to play a sound when changing the volume. * <p> @@ -197,28 +235,28 @@ public class AudioManager { * in some cases (for example, the decided stream type is not * {@link AudioManager#STREAM_RING}, or the volume is being adjusted * downward). - * + * * @see #adjustStreamVolume(int, int, int) * @see #adjustVolume(int, int) * @see #setStreamVolume(int, int, int) */ public static final int FLAG_PLAY_SOUND = 1 << 2; - + /** * Removes any sounds/vibrate that may be in the queue, or are playing (related to * changing volume). */ public static final int FLAG_REMOVE_SOUND_AND_VIBRATE = 1 << 3; - + /** * Whether to vibrate if going into the vibrate ringer mode. */ public static final int FLAG_VIBRATE = 1 << 4; - + /** * Ringer mode that will be silent and will not vibrate. (This overrides the * vibrate setting.) - * + * * @see #setRingerMode(int) * @see #getRingerMode() */ @@ -228,7 +266,7 @@ public class AudioManager { * Ringer mode that will be silent and will vibrate. (This will cause the * phone ringer to always vibrate, but the notification vibrate to only * vibrate if set.) - * + * * @see #setRingerMode(int) * @see #getRingerMode() */ @@ -238,7 +276,7 @@ public class AudioManager { * Ringer mode that may be audible and may vibrate. It will be audible if * the volume before changing out of this mode was audible. It will vibrate * if the vibrate setting is on. - * + * * @see #setRingerMode(int) * @see #getRingerMode() */ @@ -246,53 +284,53 @@ public class AudioManager { /** * Vibrate type that corresponds to the ringer. - * + * * @see #setVibrateSetting(int, int) * @see #getVibrateSetting(int) * @see #shouldVibrate(int) */ public static final int VIBRATE_TYPE_RINGER = 0; - + /** * Vibrate type that corresponds to notifications. - * + * * @see #setVibrateSetting(int, int) * @see #getVibrateSetting(int) * @see #shouldVibrate(int) */ public static final int VIBRATE_TYPE_NOTIFICATION = 1; - + /** * Vibrate setting that suggests to never vibrate. - * + * * @see #setVibrateSetting(int, int) * @see #getVibrateSetting(int) */ public static final int VIBRATE_SETTING_OFF = 0; - + /** * Vibrate setting that suggests to vibrate when possible. - * + * * @see #setVibrateSetting(int, int) * @see #getVibrateSetting(int) */ public static final int VIBRATE_SETTING_ON = 1; - + /** * Vibrate setting that suggests to only vibrate when in the vibrate ringer * mode. - * + * * @see #setVibrateSetting(int, int) * @see #getVibrateSetting(int) */ public static final int VIBRATE_SETTING_ONLY_SILENT = 2; - + /** * Suggests using the default stream type. This may not be used in all * places a stream type is needed. */ public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE; - + private static IAudioService sService; /** @@ -315,8 +353,8 @@ public class AudioManager { /** * Adjusts the volume of a particular stream by one step in a direction. - * - * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL}, + * + * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL}, * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC} or * {@link #STREAM_ALARM} * @param direction The direction to adjust the volume. One of @@ -340,7 +378,7 @@ public class AudioManager { * active, it will have the highest priority regardless of if the in-call * screen is showing. Another example, if music is playing in the background * and a call is not active, the music stream will be adjusted. - * + * * @param direction The direction to adjust the volume. One of * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or * {@link #ADJUST_SAME}. @@ -361,7 +399,7 @@ public class AudioManager { /** * Adjusts the volume of the most relevant stream, or the given fallback * stream. - * + * * @param direction The direction to adjust the volume. One of * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or * {@link #ADJUST_SAME}. @@ -380,10 +418,10 @@ public class AudioManager { Log.e(TAG, "Dead object in adjustVolume", e); } } - + /** * Returns the current ringtone mode. - * + * * @return The current ringtone mode, one of {@link #RINGER_MODE_NORMAL}, * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}. * @see #setRingerMode(int) @@ -400,7 +438,7 @@ public class AudioManager { /** * Returns the maximum volume index for a particular stream. - * + * * @param streamType The stream type whose maximum volume index is returned. * @return The maximum valid volume index for the stream. * @see #getStreamVolume(int) @@ -417,7 +455,7 @@ public class AudioManager { /** * Returns the current volume index for a particular stream. - * + * * @param streamType The stream type whose volume index is returned. * @return The current volume index for the stream. * @see #getStreamMaxVolume(int) @@ -439,7 +477,7 @@ public class AudioManager { * Silent mode will mute the volume and will not vibrate. Vibrate mode will * mute the volume and vibrate. Normal mode will be audible and may vibrate * according to user settings. - * + * * @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL}, * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}. * @see #getRingerMode() @@ -455,7 +493,7 @@ public class AudioManager { /** * Sets the volume index for a particular stream. - * + * * @param streamType The stream whose volume index should be set. * @param index The volume index to set. See * {@link #getStreamMaxVolume(int)} for the largest valid value. @@ -471,7 +509,7 @@ public class AudioManager { Log.e(TAG, "Dead object in setStreamVolume", e); } } - + /** * Solo or unsolo a particular stream. All other streams are muted. * <p> @@ -479,13 +517,13 @@ public class AudioManager { * with an active solo request on a stream dies, all streams that were muted * because of this request will be unmuted automatically. * <p> - * The solo requests for a given stream are cumulative: the AudioManager + * The solo requests for a given stream are cumulative: the AudioManager * can receive several solo requests from one or more clients and the stream * will be unsoloed only when the same number of unsolo requests are received. * <p> - * For a better user experience, applications MUST unsolo a soloed stream + * For a better user experience, applications MUST unsolo a soloed stream * in onPause() and solo is again in onResume() if appropriate. - * + * * @param streamType The stream to be soloed/unsoloed. * @param state The required solo state: true for solo ON, false for solo OFF */ @@ -497,7 +535,7 @@ public class AudioManager { Log.e(TAG, "Dead object in setStreamSolo", e); } } - + /** * Mute or unmute an audio stream. * <p> @@ -505,13 +543,13 @@ public class AudioManager { * with an active mute request on a stream dies, this stream will be unmuted * automatically. * <p> - * The mute requests for a given stream are cumulative: the AudioManager + * The mute requests for a given stream are cumulative: the AudioManager * can receive several mute requests from one or more clients and the stream * will be unmuted only when the same number of unmute requests are received. * <p> - * For a better user experience, applications MUST unmute a muted stream + * For a better user experience, applications MUST unmute a muted stream * in onPause() and mute is again in onResume() if appropriate. - * + * * @param streamType The stream to be muted/unmuted. * @param state The required mute state: true for mute ON, false for mute OFF */ @@ -532,7 +570,7 @@ public class AudioManager { * vibrate. The notification manager will not vibrate if the policy doesn't * allow it, so the client should always set a vibrate pattern and let the * notification manager control whether or not to actually vibrate. - * + * * @param vibrateType The type of vibrate. One of * {@link #VIBRATE_TYPE_NOTIFICATION} or * {@link #VIBRATE_TYPE_RINGER}. @@ -550,13 +588,13 @@ public class AudioManager { return false; } } - + /** * Returns whether the user's vibrate setting for a vibrate type. * <p> * This shouldn't be needed by most clients that want to vibrate, instead * see {@link #shouldVibrate(int)}. - * + * * @param vibrateType The type of vibrate. One of * {@link #VIBRATE_TYPE_NOTIFICATION} or * {@link #VIBRATE_TYPE_RINGER}. @@ -578,7 +616,7 @@ public class AudioManager { /** * Sets the setting for when the vibrate type should vibrate. - * + * * @param vibrateType The type of vibrate. One of * {@link #VIBRATE_TYPE_NOTIFICATION} or * {@link #VIBRATE_TYPE_RINGER}. @@ -597,11 +635,11 @@ public class AudioManager { Log.e(TAG, "Dead object in setVibrateSetting", e); } } - + /** * Sets the speakerphone on or off. * - * @param on set <var>true</var> to turn on speakerphone; + * @param on set <var>true</var> to turn on speakerphone; * <var>false</var> to turn it off */ public void setSpeakerphoneOn(boolean on){ @@ -620,17 +658,17 @@ public class AudioManager { /** * Sets audio routing to the Bluetooth headset on or off. * - * @param on set <var>true</var> to route SCO (voice) audio to/from Bluetooth + * @param on set <var>true</var> to route SCO (voice) audio to/from Bluetooth * headset; <var>false</var> to route audio to/from phone earpiece */ public void setBluetoothScoOn(boolean on){ // Don't disable A2DP when turning off SCO. // A2DP does not affect in-call routing. - setRouting(MODE_RINGTONE, + setRouting(MODE_RINGTONE, on ? ROUTE_BLUETOOTH_SCO: ROUTE_SPEAKER, ROUTE_ALL & ~ROUTE_BLUETOOTH_A2DP); - setRouting(MODE_NORMAL, + setRouting(MODE_NORMAL, on ? ROUTE_BLUETOOTH_SCO: ROUTE_SPEAKER, ROUTE_ALL & ~ROUTE_BLUETOOTH_A2DP); - setRouting(MODE_IN_CALL, + setRouting(MODE_IN_CALL, on ? ROUTE_BLUETOOTH_SCO: ROUTE_EARPIECE, ROUTE_ALL); } @@ -647,15 +685,15 @@ public class AudioManager { /** * Sets A2DP audio routing to the Bluetooth headset on or off. * - * @param on set <var>true</var> to route A2DP audio to/from Bluetooth + * @param on set <var>true</var> to route A2DP audio to/from Bluetooth * headset; <var>false</var> disable A2DP audio */ public void setBluetoothA2dpOn(boolean on){ // the audio flinger chooses A2DP as a higher priority, // so there is no need to disable other routes. - setRouting(MODE_RINGTONE, + setRouting(MODE_RINGTONE, on ? ROUTE_BLUETOOTH_A2DP: 0, ROUTE_BLUETOOTH_A2DP); - setRouting(MODE_NORMAL, + setRouting(MODE_NORMAL, on ? ROUTE_BLUETOOTH_A2DP: 0, ROUTE_BLUETOOTH_A2DP); } @@ -672,7 +710,7 @@ public class AudioManager { /** * Sets audio routing to the wired headset on or off. * - * @param on set <var>true</var> to route audio to/from wired + * @param on set <var>true</var> to route audio to/from wired * headset; <var>false</var> disable wired headset audio * @hide */ @@ -701,7 +739,7 @@ public class AudioManager { /** * Sets the microphone mute on or off. * - * @param on set <var>true</var> to mute the microphone; + * @param on set <var>true</var> to mute the microphone; * <var>false</var> to turn mute off */ public void setMicrophoneMute(boolean on){ @@ -762,57 +800,57 @@ public class AudioManager { /* modes for setMode/getMode/setRoute/getRoute */ /** - * Audio harware modes. - */ + * Audio harware modes. + */ /** - * Invalid audio mode. - */ + * Invalid audio mode. + */ public static final int MODE_INVALID = AudioSystem.MODE_INVALID; /** * Current audio mode. Used to apply audio routing to current mode. - */ + */ public static final int MODE_CURRENT = AudioSystem.MODE_CURRENT; /** * Normal audio mode: not ringing and no call established. - */ + */ public static final int MODE_NORMAL = AudioSystem.MODE_NORMAL; /** * Ringing audio mode. An incoming is being signaled. - */ + */ public static final int MODE_RINGTONE = AudioSystem.MODE_RINGTONE; /** * In call audio mode. A call is established. - */ + */ public static final int MODE_IN_CALL = AudioSystem.MODE_IN_CALL; /* Routing bits for setRouting/getRouting API */ /** * Routing audio output to earpiece - */ + */ public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE; /** * Routing audio output to spaker - */ + */ public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER; /** * @deprecated use {@link #ROUTE_BLUETOOTH_SCO} - */ + */ @Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO; /** * Routing audio output to bluetooth SCO - */ + */ public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO; /** * Routing audio output to headset - */ + */ public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET; /** * Routing audio output to bluetooth A2DP - */ + */ public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP; /** * Used for mask parameter of {@link #setRouting(int,int,int)}. - */ + */ public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL; /** @@ -892,33 +930,33 @@ public class AudioManager { /** * Keyboard and direction pad click sound * @see #playSoundEffect(int) - */ + */ public static final int FX_KEY_CLICK = 0; /** * Focuse has moved up * @see #playSoundEffect(int) - */ + */ public static final int FX_FOCUS_NAVIGATION_UP = 1; /** * Focuse has moved down * @see #playSoundEffect(int) - */ + */ public static final int FX_FOCUS_NAVIGATION_DOWN = 2; /** * Focuse has moved left * @see #playSoundEffect(int) - */ + */ public static final int FX_FOCUS_NAVIGATION_LEFT = 3; /** * Focuse has moved right * @see #playSoundEffect(int) - */ + */ public static final int FX_FOCUS_NAVIGATION_RIGHT = 4; /** - * @hide Number of sound effects - */ + * @hide Number of sound effects + */ public static final int NUM_SOUND_EFFECTS = 5; - + /** * Plays a sound effect (Key clicks, lid open/close...) * @param effectType The type of sound effect. One of @@ -951,10 +989,10 @@ public class AudioManager { private boolean querySoundEffectsEnabled() { return Settings.System.getInt(mContext.getContentResolver(), Settings.System.SOUND_EFFECTS_ENABLED, 0) != 0; } - - + + /** - * Load Sound effects. + * Load Sound effects. * This method must be called when sound effects are enabled. */ public void loadSoundEffects() { @@ -965,9 +1003,9 @@ public class AudioManager { Log.e(TAG, "Dead object in loadSoundEffects"+e); } } - + /** - * Unload Sound effects. + * Unload Sound effects. * This method can be called to free some memory when * sound effects are disabled. */ diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index 7912003b..1314ba1 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -34,11 +34,14 @@ import android.util.Log; * to record audio from the audio input hardware of the platform. This is * achieved by "pulling" (reading) the data from the AudioRecord object. The * application is responsible for polling the AudioRecord object in time using one of - * the following three methods: {@link #read(byte[], int)}, {@link #read(short[], int)} + * the following three methods: {@link #read(byte[],int, int)}, {@link #read(short[], int, int)} * or {@link #read(ByteBuffer, int)}. The choice of which method to use will be based * on the audio data storage format that is the most convenient for the user of AudioRecord. - * - * {@hide Pending API council review} + * <p>Upon creation, an AudioRecord object initializes its associated audio buffer that it will + * fill with the new audio data. The size of this buffer, specified during the construction, + * determines how long an AudioRecord can record before "over-running" data that has not + * been read yet. Data should be from the audio hardware in chunks of sizes inferior to + * the total recording buffer size. */ public class AudioRecord { @@ -82,22 +85,22 @@ public class AudioRecord */ public static final int ERROR_INVALID_OPERATION = -3; - private static final int AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT = -4; - private static final int AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT = -5; - private static final int AUDIORECORD_ERROR_SETUP_INVALIDFORMAT = -6; - private static final int AUDIORECORD_ERROR_SETUP_INVALIDSTREAMTYPE = -7; - private static final int AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED = -8; + private static final int AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT = -16; + private static final int AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT = -17; + private static final int AUDIORECORD_ERROR_SETUP_INVALIDFORMAT = -18; + private static final int AUDIORECORD_ERROR_SETUP_INVALIDSTREAMTYPE = -19; + private static final int AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED = -20; // Events: // to keep in sync with frameworks/base/include/media/AudioRecord.h /** * Event id for when the recording head has reached a previously set marker. */ - protected static final int EVENT_MARKER = 2; + private static final int NATIVE_EVENT_MARKER = 2; /** * Event id for when the previously set update period has passed during recording. */ - protected static final int EVENT_NEW_POS = 3; + private static final int NATIVE_EVENT_NEW_POS = 3; private final static String TAG = "AudioRecord-Java"; @@ -130,63 +133,63 @@ public class AudioRecord /** * The audio data sampling rate in Hz. */ - protected int mSampleRate = 22050; + private int mSampleRate = 22050; /** * The number of input audio channels (1 is mono, 2 is stereo) */ - protected int mChannelCount = 1; + private int mChannelCount = 1; /** * The current audio channel configuration */ - protected int mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO; + private int mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO; /** * The encoding of the audio samples. - * @see #AudioFormat.ENCODING_PCM_8BIT - * @see #AudioFormat.ENCODING_PCM_16BIT + * @see AudioFormat#ENCODING_PCM_8BIT + * @see AudioFormat#ENCODING_PCM_16BIT */ - protected int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; + private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; /** * Where the audio data is recorded from. */ - protected int mRecordSource = MediaRecorder.AudioSource.DEFAULT; + private int mRecordSource = MediaRecorder.AudioSource.DEFAULT; /** * Indicates the state of the AudioRecord instance. */ - protected int mState = STATE_UNINITIALIZED; + private int mState = STATE_UNINITIALIZED; /** * Indicates the recording state of the AudioRecord instance. */ - protected int mRecordingState = RECORDSTATE_STOPPED; + private int mRecordingState = RECORDSTATE_STOPPED; /** * Lock to make sure mRecordingState updates are reflecting the actual state of the object. */ - protected Object mRecordingStateLock = new Object(); + private Object mRecordingStateLock = new Object(); /** * The listener the AudioRecord notifies when a previously set marker is reached. * @see #setMarkerReachedListener(OnMarkerReachedListener) */ - protected OnMarkerReachedListener mMarkerListener = null; + private OnMarkerReachedListener mMarkerListener = null; /** * Lock to protect marker listener updates against event notifications */ - protected final Object mMarkerListenerLock = new Object(); + private final Object mMarkerListenerLock = new Object(); /** * The listener the AudioRecord notifies periodically during recording. * @see #setPeriodicNotificationListener(OnPeriodicNotificationListener) */ - protected OnPeriodicNotificationListener mPeriodicListener = null; + private OnPeriodicNotificationListener mPeriodicListener = null; /** * Lock to protect periodic listener updates against event notifications */ - protected final Object mPeriodicListenerLock = new Object(); + private final Object mPeriodicListenerLock = new Object(); /** * Handler for events coming from the native code */ - protected NativeEventHandler mNativeEventHandler = null; + private NativeEventHandler mNativeEventHandler = null; /** * Size of the native audio buffer. */ - protected int mNativeBufferSizeInBytes = 0; + private int mNativeBufferSizeInBytes = 0; //--------------------------------------------------------- @@ -194,30 +197,30 @@ public class AudioRecord //-------------------- /** * Class constructor. - * @param audioSource the recording source. See {@link MediaRecorder.AudioSource.DEFAULT} - * and {@link MediaRecorder.AudioSource.MIC}. + * @param audioSource the recording source. See {@link MediaRecorder.AudioSource} for + * recording source definitions. * @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but * not limited to) 44100, 22050 and 11025. * @param channelConfig describes the configuration of the audio channels. - * See {@link AudioFormat.CHANNEL_CONFIGURATION_MONO} and - * {@link AudioFormat.CHANNEL_CONFIGURATION_STEREO} + * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and + * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO} * @param audioFormat the format in which the audio data is represented. - * See {@link AudioFormat.ENCODING_PCM_16BIT} and - * {@link AudioFormat.ENCODING_PCM_8BIT} + * See {@link AudioFormat#ENCODING_PCM_16BIT} and + * {@link AudioFormat#ENCODING_PCM_8BIT} * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written * to during the recording. New audio data can be read from this buffer in smaller chunks * than this size. * @throws java.lang.IllegalArgumentException */ public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, - int blockSizeInBytes) + int bufferSizeInBytes) throws IllegalArgumentException { mState = STATE_UNINITIALIZED; mRecordingState = RECORDSTATE_STOPPED; audioParamCheck(audioSource, sampleRateInHz, channelConfig, audioFormat); - audioBuffSizeCheck(blockSizeInBytes); + audioBuffSizeCheck(bufferSizeInBytes); // native initialization //TODO: update native initialization when information about hardware init failure @@ -367,8 +370,8 @@ public class AudioRecord } /** - * Returns the configured audio data format. See {@link #AudioFormat.ENCODING_PCM_16BIT} - * and {@link #AudioFormat.ENCODING_PCM_8BIT}. + * Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_16BIT} + * and {@link AudioFormat#ENCODING_PCM_8BIT}. */ public int getAudioFormat() { return mAudioFormat; @@ -376,8 +379,8 @@ public class AudioRecord /** * Returns the configured channel configuration. - * See {@link #AudioFormat.CHANNEL_CONFIGURATION_MONO} - * and {@link #AudioFormat.CHANNEL_CONFIGURATION_STEREO}. + * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} + * and {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}. */ public int getChannelConfiguration() { return mChannelConfiguration; @@ -395,8 +398,8 @@ public class AudioRecord * AudioRecord instance has been created to check if it was initialized * properly. This ensures that the appropriate hardware resources have been * acquired. - * @see AudioRecord.STATE_INITIALIZED - * @see AudioRecord.STATE_UNINITIALIZED + * @see AudioRecord#STATE_INITIALIZED + * @see AudioRecord#STATE_UNINITIALIZED */ public int getState() { return mState; @@ -404,8 +407,8 @@ public class AudioRecord /** * Returns the recording state of the AudioRecord instance. - * @see AudioRecord.RECORDSTATE_STOPPED - * @see AudioRecord.RECORDSTATE_RECORDING + * @see AudioRecord#RECORDSTATE_STOPPED + * @see AudioRecord#RECORDSTATE_RECORDING */ public int getRecordingState() { return mRecordingState; @@ -472,16 +475,15 @@ public class AudioRecord //-------------------- /** * Reads audio data from the audio hardware for recording into a buffer. - * @throws IllegalStateException * @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. This will not exceed sizeInBytes + * @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. */ - public int read(byte[] audioData, int offsetInBytes, int sizeInBytes) - throws IllegalStateException { + public int read(byte[] audioData, int offsetInBytes, int sizeInBytes) { if (mState != STATE_INITIALIZED) { - throw(new IllegalStateException("read() called on uninitialized AudioRecord.")); + return -1; } return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes); @@ -490,16 +492,15 @@ public class AudioRecord /** * Reads audio data from the audio hardware for recording into a buffer. - * @throws IllegalStateException * @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. This will not exceed sizeInShorts + * @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 */ - public int read(short[] audioData, int offsetInShorts, int sizeInShorts) - throws IllegalStateException { + public int read(short[] audioData, int offsetInShorts, int sizeInShorts) { if (mState != STATE_INITIALIZED) { - throw(new IllegalStateException("read() called on uninitialized AudioRecord.")); + return -1; } return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts); @@ -509,15 +510,14 @@ public class AudioRecord /** * Reads audio data from the audio hardware for recording into a direct buffer. If this buffer * is not a direct buffer, this method will always return 0. - * @throws IllegalStateException * @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. This will not exceed sizeInBytes. + * @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. */ - public int read(ByteBuffer audioBuffer, int sizeInBytes) - throws IllegalStateException { + public int read(ByteBuffer audioBuffer, int sizeInBytes) { if (mState != STATE_INITIALIZED) { - throw(new IllegalStateException("read() called on uninitialized AudioRecord.")); + return -1; } return native_read_in_direct_buffer(audioBuffer, sizeInBytes); @@ -590,7 +590,7 @@ public class AudioRecord * Called on the listener to notify it that the previously set marker has been reached * by the recording head. */ - void onMarkerReached(AudioRecord track); + void onMarkerReached(AudioRecord recorder); } @@ -603,7 +603,7 @@ public class AudioRecord * Called on the listener to periodically notify it that the recording head has reached * a multiple of the notification period. */ - void onPeriodicNotification(AudioRecord track); + void onPeriodicNotification(AudioRecord recorder); } @@ -628,14 +628,14 @@ public class AudioRecord return; } switch(msg.what) { - case EVENT_MARKER: + case NATIVE_EVENT_MARKER: synchronized (mMarkerListenerLock) { if (mAudioRecord.mMarkerListener != null) { mAudioRecord.mMarkerListener.onMarkerReached(mAudioRecord); } } break; - case EVENT_NEW_POS: + case NATIVE_EVENT_NEW_POS: synchronized (mPeriodicListenerLock) { if (mAudioRecord.mPeriodicListener != null) { mAudioRecord.mPeriodicListener.onPeriodicNotification(mAudioRecord); @@ -643,7 +643,7 @@ public class AudioRecord } break; default: - Log.e(TAG, "[ android.media.AudioTrack.NativeEventHandler ] " + + Log.e(TAG, "[ android.media.AudioRecord.NativeEventHandler ] " + "Unknown event type: " + msg.what); break; } @@ -658,14 +658,14 @@ public class AudioRecord private static void postEventFromNative(Object audiorecord_ref, int what, int arg1, int arg2, Object obj) { //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2); - AudioRecord track = (AudioRecord)((WeakReference)audiorecord_ref).get(); - if (track == null) { + AudioRecord recorder = (AudioRecord)((WeakReference)audiorecord_ref).get(); + if (recorder == null) { return; } - if (track.mNativeEventHandler != null) { - Message m = track.mNativeEventHandler.obtainMessage(what, arg1, arg2, obj); - track.mNativeEventHandler.sendMessage(m); + if (recorder.mNativeEventHandler != null) { + Message m = recorder.mNativeEventHandler.obtainMessage(what, arg1, arg2, obj); + recorder.mNativeEventHandler.sendMessage(m); } } diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index b39e7bb..f3d8957 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -16,8 +16,7 @@ package android.media; -import com.android.internal.telephony.ITelephony; - +import android.app.ActivityManagerNative; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -32,11 +31,13 @@ import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; -import android.provider.Settings.System; import android.provider.Settings; +import android.provider.Settings.System; import android.util.Log; import android.view.VolumePanel; +import com.android.internal.telephony.ITelephony; + import java.io.IOException; import java.util.ArrayList; @@ -50,19 +51,19 @@ import java.util.ArrayList; * volume and later persist to the database. Similarly, setting the ringer mode * will update the state and broadcast a change and in a separate thread later * persist the ringer mode. - * + * * @hide */ public class AudioService extends IAudioService.Stub { - + private static final String TAG = "AudioService"; /** How long to delay before persisting a change in volume/ringer mode. */ private static final int PERSIST_DELAY = 3000; - + private Context mContext; private ContentResolver mContentResolver; - + /** The UI */ private VolumePanel mVolumePanel; @@ -75,7 +76,7 @@ public class AudioService extends IAudioService.Stub { private static final int SENDMSG_NOOP = 1; /** If the msg is already queued, queue this one and leave the old. */ private static final int SENDMSG_QUEUE = 2; - + // AudioHandler message.whats private static final int MSG_SET_SYSTEM_VOLUME = 0; private static final int MSG_PERSIST_VOLUME = 1; @@ -91,18 +92,18 @@ public class AudioService extends IAudioService.Stub { private AudioHandler mAudioHandler; /** @see VolumeStreamState */ private VolumeStreamState[] mStreamStates; - + private boolean mMicMute; private int mMode; private int[] mRoutes = new int[AudioSystem.NUM_MODES]; private Object mSettingsLock = new Object(); private boolean mMediaServerOk; - + private SoundPool mSoundPool; private Object mSoundEffectsLock = new Object(); private static final int NUM_SOUNDPOOL_CHANNELS = 4; private static final float SOUND_EFFECT_VOLUME = 1.0f; - + /* Sound effect file names */ private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/"; private static final String[] SOUND_EFFECT_FILES = new String[] { @@ -119,7 +120,7 @@ public class AudioService extends IAudioService.Stub { {0, -1}, // FX_FOCUS_NAVIGATION_LEFT {0, -1} // FX_FOCUS_NAVIGATION_RIGHT }; - + private AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() { public void onError(int error) { switch (error) { @@ -145,7 +146,7 @@ public class AudioService extends IAudioService.Stub { * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL}, * {@link AudioManager#RINGER_MODE_SILENT}, or * {@link AudioManager#RINGER_MODE_VIBRATE}. - */ + */ private int mRingerMode; /** @see System#MODE_RINGER_STREAMS_AFFECTED */ @@ -153,7 +154,7 @@ public class AudioService extends IAudioService.Stub { /** @see System#MUTE_STREAMS_AFFECTED */ private int mMuteAffectedStreams; - + /** * Has multiple bits per vibrate type to indicate the type's vibrate * setting. See {@link #setVibrateSetting(int, int)}. @@ -162,23 +163,23 @@ public class AudioService extends IAudioService.Stub { * type since it depends on the ringer mode. See {@link #shouldVibrate(int)}. */ private int mVibrateSetting; - + /////////////////////////////////////////////////////////////////////////// // Construction /////////////////////////////////////////////////////////////////////////// - + /** @hide */ public AudioService(Context context) { mContext = context; mContentResolver = context.getContentResolver(); mVolumePanel = new VolumePanel(context, this); - + createAudioSystemThread(); createStreamStates(); readPersistedSettings(); readAudioSettings(); mMediaServerOk = true; - AudioSystem.setErrorCallback(mAudioSystemCallback); + AudioSystem.setErrorCallback(mAudioSystemCallback); if (Settings.System.getInt(mContentResolver, Settings.System.SOUND_EFFECTS_ENABLED, 0) == 1) { loadSoundEffects(); } @@ -189,8 +190,8 @@ public class AudioService extends IAudioService.Stub { mAudioSystemThread.start(); waitForAudioHandlerCreation(); } - - /** Waits for the volume handler to be created by the other thread. */ + + /** Waits for the volume handler to be created by the other thread. */ private void waitForAudioHandlerCreation() { synchronized(this) { while (mAudioHandler == null) { @@ -203,37 +204,51 @@ public class AudioService extends IAudioService.Stub { } } } - + private void createStreamStates() { - final int[] volumeLevelsPhone = createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_VOICE_CALL]); - final int[] volumeLevelsCoarse = createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_SYSTEM]); - final int[] volumeLevelsFine = createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC]); - + final int[] volumeLevelsPhone = + createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_VOICE_CALL]); + final int[] volumeLevelsCoarse = + createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_SYSTEM]); + final int[] volumeLevelsFine = + createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC]); + final int[] volumeLevelsBtPhone = + createVolumeLevels(0, + AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_BLUETOOTH_SCO]); + int numStreamTypes = AudioSystem.getNumStreamTypes(); VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; - + for (int i = 0; i < numStreamTypes; i++) { final int[] levels; - + switch (i) { - + case AudioSystem.STREAM_MUSIC: levels = volumeLevelsFine; break; - + case AudioSystem.STREAM_VOICE_CALL: levels = volumeLevelsPhone; break; - + + case AudioSystem.STREAM_BLUETOOTH_SCO: + levels = volumeLevelsBtPhone; + break; + default: levels = volumeLevelsCoarse; break; } - - streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[i], i, levels); + + if (i == AudioSystem.STREAM_BLUETOOTH_SCO) { + streams[i] = new VolumeStreamState(AudioManager.DEFAULT_STREAM_VOLUME[i], i,levels); + } else { + streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[i], i, levels); + } } } - + private static int[] createVolumeLevels(int offset, int numlevels) { double curve = 1.0f; // 1.4f int [] volumes = new int[numlevels + offset]; @@ -249,7 +264,7 @@ public class AudioService extends IAudioService.Stub { } return volumes; } - + private void readPersistedSettings() { final ContentResolver cr = mContentResolver; @@ -260,19 +275,19 @@ public class AudioService extends IAudioService.Stub { mVibrateSetting = System.getInt(cr, System.VIBRATE_ON, 0); mMuteAffectedStreams = System.getInt(cr, - System.MUTE_STREAMS_AFFECTED, + System.MUTE_STREAMS_AFFECTED, ((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM))); - + // Each stream will read its own persisted settings - + // Broadcast the sticky intent broadcastRingerMode(); - + // Broadcast vibrate settings broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER); broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION); } - + private void readAudioSettings() { synchronized (mSettingsLock) { mMicMute = AudioSystem.isMicrophoneMuted(); @@ -282,7 +297,7 @@ public class AudioService extends IAudioService.Stub { } } } - + private void applyAudioSettings() { synchronized (mSettingsLock) { AudioSystem.muteMicrophone(mMicMute); @@ -291,46 +306,46 @@ public class AudioService extends IAudioService.Stub { AudioSystem.setRouting(mode, mRoutes[mode], AudioSystem.ROUTE_ALL); } } - } - + } + /////////////////////////////////////////////////////////////////////////// // IPC methods /////////////////////////////////////////////////////////////////////////// - + /** @see AudioManager#adjustVolume(int, int) */ public void adjustVolume(int direction, int flags) { adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags); } - + /** @see AudioManager#adjustVolume(int, int, int) */ public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) { int streamType = getActiveStreamType(suggestedStreamType); - + // Don't play sound on other streams if (streamType != AudioSystem.STREAM_RING && (flags & AudioManager.FLAG_PLAY_SOUND) != 0) { flags &= ~AudioManager.FLAG_PLAY_SOUND; } - + adjustStreamVolume(streamType, direction, flags); } - + /** @see AudioManager#adjustStreamVolume(int, int, int) */ public void adjustStreamVolume(int streamType, int direction, int flags) { ensureValidDirection(direction); ensureValidStreamType(streamType); - + boolean notificationsUseRingVolume = Settings.System.getInt(mContentResolver, Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1) == 1; if (notificationsUseRingVolume && streamType == AudioManager.STREAM_NOTIFICATION) { // Redirect the volume change to the ring stream streamType = AudioManager.STREAM_RING; } - + VolumeStreamState streamState = mStreamStates[streamType]; - final int oldIndex = streamState.mIndex; + final int oldIndex = streamState.mIndex; boolean adjustVolume = true; - + // If either the client forces allowing ringer modes for this adjustment, // or the stream type is one that is affected by ringer modes if ((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0 @@ -339,21 +354,21 @@ public class AudioService extends IAudioService.Stub { // it does, it will handle adjusting the volome, so we won't below adjustVolume = checkForRingerModeChange(oldIndex, direction); } - + if (adjustVolume && streamState.adjustIndex(direction)) { - + boolean alsoUpdateNotificationVolume = notificationsUseRingVolume && streamType == AudioManager.STREAM_RING; if (alsoUpdateNotificationVolume) { mStreamStates[AudioManager.STREAM_NOTIFICATION].adjustIndex(direction); } - + // Post message to set system volume (it in turn will post a message // to persist). Do not change volume if stream is muted. if (streamState.muteCount() == 0) { sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0, streamState, 0); - + if (alsoUpdateNotificationVolume) { sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, AudioManager.STREAM_NOTIFICATION, SENDMSG_NOOP, 0, 0, mStreamStates[AudioManager.STREAM_NOTIFICATION], 0); @@ -363,12 +378,44 @@ public class AudioService extends IAudioService.Stub { // UI mVolumePanel.postVolumeChanged(streamType, flags); + // Broadcast Intent + sendVolumeUpdate(streamType); } /** @see AudioManager#setStreamVolume(int, int, int) */ public void setStreamVolume(int streamType, int index, int flags) { ensureValidStreamType(streamType); - + syncRingerAndNotificationStreamVolume(streamType, index, false); + + setStreamVolumeInt(streamType, index, false); + + // UI, etc. + mVolumePanel.postVolumeChanged(streamType, flags); + // Broadcast Intent + sendVolumeUpdate(streamType); + } + + private void sendVolumeUpdate(int streamType) { + Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION); + intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType); + intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, getStreamVolume(streamType)); + + // Currently, sending the intent only when the stream is BLUETOOTH_SCO + if (streamType == AudioManager.STREAM_BLUETOOTH_SCO) { + mContext.sendBroadcast(intent); + } + } + + /** + * Sync the STREAM_RING and STREAM_NOTIFICATION volumes if mandated by the + * value in Settings. + * + * @param streamType Type of the stream + * @param index Volume index for the stream + * @param force If true, set the volume even if the current and desired + * volume as same + */ + private void syncRingerAndNotificationStreamVolume(int streamType, int index, boolean force) { boolean notificationsUseRingVolume = Settings.System.getInt(mContentResolver, Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1) == 1; if (notificationsUseRingVolume) { @@ -378,23 +425,24 @@ public class AudioService extends IAudioService.Stub { } if (streamType == AudioManager.STREAM_RING) { // One-off to sync notification volume to ringer volume - setStreamVolumeInt(AudioManager.STREAM_NOTIFICATION, index); + setStreamVolumeInt(AudioManager.STREAM_NOTIFICATION, index, force); } } - - setStreamVolumeInt(streamType, index); - - // UI, etc. - mVolumePanel.postVolumeChanged(streamType, flags); } + /** * Sets the stream state's index, and posts a message to set system volume. * This will not call out to the UI. Assumes a valid stream type. + * + * @param streamType Type of the stream + * @param index Desired volume index of the stream + * @param force If true, set the volume even if the desired volume is same + * as the current volume. */ - private void setStreamVolumeInt(int streamType, int index) { + private void setStreamVolumeInt(int streamType, int index, boolean force) { VolumeStreamState streamState = mStreamStates[streamType]; - if (streamState.setIndex(index)) { + if (streamState.setIndex(index) || force) { // Post message to set system volume (it in turn will post a message // to persist). Do not change volume if stream is muted. if (streamState.muteCount() == 0) { @@ -403,7 +451,7 @@ public class AudioService extends IAudioService.Stub { } } } - + /** @see AudioManager#setStreamSolo(int, boolean) */ public void setStreamSolo(int streamType, boolean state, IBinder cb) { for (int stream = 0; stream < mStreamStates.length; stream++) { @@ -412,7 +460,7 @@ public class AudioService extends IAudioService.Stub { mStreamStates[stream].mute(cb, state); } } - + /** @see AudioManager#setStreamMute(int, boolean) */ public void setStreamMute(int streamType, boolean state, IBinder cb) { if (isStreamAffectedByMute(streamType)) { @@ -441,32 +489,33 @@ public class AudioService extends IAudioService.Stub { public void setRingerMode(int ringerMode) { if (ringerMode != mRingerMode) { mRingerMode = ringerMode; - + // Adjust volumes via posting message int numStreamTypes = AudioSystem.getNumStreamTypes(); if (mRingerMode == AudioManager.RINGER_MODE_NORMAL) { for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { if (!isStreamAffectedByRingerMode(streamType)) continue; // Bring back last audible volume - setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex); + setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex, + false); } } else { for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { if (!isStreamAffectedByRingerMode(streamType)) continue; // Either silent or vibrate, either way volume is 0 - setStreamVolumeInt(streamType, 0); + setStreamVolumeInt(streamType, 0, false); } } - + // Send sticky broadcast broadcastRingerMode(); - + // Post a persist ringer mode msg sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, SHARED_MSG, SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY); } } - + /** @see AudioManager#shouldVibrate(int) */ public boolean shouldVibrate(int vibrateType) { @@ -474,21 +523,21 @@ public class AudioService extends IAudioService.Stub { case AudioManager.VIBRATE_SETTING_ON: return mRingerMode != AudioManager.RINGER_MODE_SILENT; - + case AudioManager.VIBRATE_SETTING_ONLY_SILENT: return mRingerMode == AudioManager.RINGER_MODE_VIBRATE; - + case AudioManager.VIBRATE_SETTING_OFF: - // Phone ringer should always vibrate in vibrate mode + // Phone ringer should always vibrate in vibrate mode if (vibrateType == AudioManager.VIBRATE_TYPE_RINGER) { return mRingerMode == AudioManager.RINGER_MODE_VIBRATE; } - + default: return false; } } - + /** @see AudioManager#getVibrateSetting(int) */ public int getVibrateSetting(int vibrateType) { return (mVibrateSetting >> (vibrateType * 2)) & 3; @@ -498,10 +547,10 @@ public class AudioService extends IAudioService.Stub { public void setVibrateSetting(int vibrateType, int vibrateSetting) { mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting); - + // Broadcast change broadcastVibrateSetting(vibrateType); - + // Post message to set ringer mode (it in turn will post a message // to persist) sendMsg(mAudioHandler, MSG_PERSIST_VIBRATE_SETTING, SHARED_MSG, SENDMSG_NOOP, 0, 0, @@ -518,13 +567,13 @@ public class AudioService extends IAudioService.Stub { // First clear the existing setting. Each vibrate type has two bits in // the value. Note '3' is '11' in binary. existingValue &= ~(3 << (vibrateType * 2)); - + // Set into the old value existingValue |= (vibrateSetting & 3) << (vibrateType * 2); - + return existingValue; } - + /** @see AudioManager#setMicrophoneMute(boolean) */ public void setMicrophoneMute(boolean on) { if (!checkAudioSettingsPermission("setMicrophoneMute()")) { @@ -534,15 +583,15 @@ public class AudioService extends IAudioService.Stub { if (on != mMicMute) { AudioSystem.muteMicrophone(on); mMicMute = on; - } + } } } - + /** @see AudioManager#isMicrophoneMute() */ public boolean isMicrophoneMute() { return mMicMute; } - + /** @see AudioManager#setMode(int) */ public void setMode(int mode) { if (!checkAudioSettingsPermission("setMode()")) { @@ -552,15 +601,19 @@ public class AudioService extends IAudioService.Stub { if (mode != mMode) { AudioSystem.setMode(mode); mMode = mode; - } + } + int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); + int index = mStreamStates[streamType].mIndex; + syncRingerAndNotificationStreamVolume(streamType, index, true); + setStreamVolumeInt(streamType, index, true); } } - + /** @see AudioManager#getMode() */ public int getMode() { return mMode; } - + /** @see AudioManager#setRouting(int, int, int) */ public void setRouting(int mode, int routes, int mask) { if (!checkAudioSettingsPermission("setRouting()")) { @@ -570,10 +623,14 @@ public class AudioService extends IAudioService.Stub { if ((mRoutes[mode] & mask) != (routes & mask)) { AudioSystem.setRouting(mode, routes, mask); mRoutes[mode] = (mRoutes[mode] & ~mask) | (routes & mask); - } + } + int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); + int index = mStreamStates[streamType].mIndex; + syncRingerAndNotificationStreamVolume(streamType, index, true); + setStreamVolumeInt(streamType, index, true); } } - + /** @see AudioManager#getRouting(int) */ public int getRouting(int mode) { return mRoutes[mode]; @@ -583,7 +640,7 @@ public class AudioService extends IAudioService.Stub { public boolean isMusicActive() { return AudioSystem.isMusicActive(); } - + /** @see AudioManager#setParameter(String, String) */ public void setParameter(String key, String value) { AudioSystem.setParameter(key, value); @@ -596,8 +653,8 @@ public class AudioService extends IAudioService.Stub { } /** - * Loads samples into the soundpool. - * This method must be called at when sound effects are enabled + * Loads samples into the soundpool. + * This method must be called at when sound effects are enabled */ public boolean loadSoundEffects() { synchronized (mSoundEffectsLock) { @@ -605,17 +662,17 @@ public class AudioService extends IAudioService.Stub { if (mSoundPool == null) { return false; } - /* - * poolId table: The value -1 in this table indicates that corresponding - * file (same index in SOUND_EFFECT_FILES[] has not been loaded. - * Once loaded, the value in poolId is the sample ID and the same + /* + * poolId table: The value -1 in this table indicates that corresponding + * file (same index in SOUND_EFFECT_FILES[] has not been loaded. + * Once loaded, the value in poolId is the sample ID and the same * sample can be reused for another effect using the same file. - */ + */ int[] poolId = new int[SOUND_EFFECT_FILES.length]; for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { poolId[fileIdx] = -1; } - /* + /* * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded. * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0: * this indicates we have a valid sample loaded for this effect. @@ -638,12 +695,12 @@ public class AudioService extends IAudioService.Stub { } } } - + return true; } /** - * Unloads samples from the sound pool. + * Unloads samples from the sound pool. * This method can be called to free some memory when * sound effects are disabled. */ @@ -665,12 +722,12 @@ public class AudioService extends IAudioService.Stub { mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]); SOUND_EFFECT_FILES_MAP[effect][1] = -1; poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1; - } + } } mSoundPool = null; } } - + /////////////////////////////////////////////////////////////////////////// // Internal methods /////////////////////////////////////////////////////////////////////////// @@ -683,7 +740,7 @@ public class AudioService extends IAudioService.Stub { private boolean checkForRingerModeChange(int oldIndex, int direction) { boolean adjustVolumeIndex = true; int newRingerMode = mRingerMode; - + if (mRingerMode == AudioManager.RINGER_MODE_NORMAL && oldIndex == 1 && direction == AudioManager.ADJUST_LOWER) { newRingerMode = AudioManager.RINGER_MODE_VIBRATE; @@ -697,7 +754,7 @@ public class AudioService extends IAudioService.Stub { && mRingerMode == AudioManager.RINGER_MODE_SILENT) { newRingerMode = AudioManager.RINGER_MODE_VIBRATE; } - + if (newRingerMode != mRingerMode) { setRingerMode(newRingerMode); @@ -708,18 +765,18 @@ public class AudioService extends IAudioService.Stub { */ adjustVolumeIndex = false; } - + return adjustVolumeIndex; } - + public boolean isStreamAffectedByRingerMode(int streamType) { - return (mRingerModeAffectedStreams & (1 << streamType)) != 0; + return (mRingerModeAffectedStreams & (1 << streamType)) != 0; } - + public boolean isStreamAffectedByMute(int streamType) { return (mMuteAffectedStreams & (1 << streamType)) != 0; } - + private void ensureValidDirection(int direction) { if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) { throw new IllegalArgumentException("Bad direction " + direction); @@ -736,13 +793,15 @@ public class AudioService extends IAudioService.Stub { boolean isOffhook = false; try { ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); - isOffhook = phone.isOffhook(); + if (phone != null) isOffhook = phone.isOffhook(); } catch (RemoteException e) { Log.w(TAG, "Couldn't connect to phone service", e); } - // TODO: applications can influence this - if (isOffhook) { + if ((getRouting(AudioSystem.MODE_IN_CALL) & AudioSystem.ROUTE_BLUETOOTH_SCO) != 0) { + // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); + return AudioSystem.STREAM_BLUETOOTH_SCO; + } else if (isOffhook) { // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL..."); return AudioSystem.STREAM_VOICE_CALL; } else if (AudioSystem.isMusicActive()) { @@ -756,29 +815,33 @@ public class AudioService extends IAudioService.Stub { return suggestedStreamType; } } - + private void broadcastRingerMode() { // Send sticky broadcast - Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION); - broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, mRingerMode); - long origCallerIdentityToken = Binder.clearCallingIdentity(); - mContext.sendStickyBroadcast(broadcast); - Binder.restoreCallingIdentity(origCallerIdentityToken); + if (ActivityManagerNative.isSystemReady()) { + Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION); + broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, mRingerMode); + long origCallerIdentityToken = Binder.clearCallingIdentity(); + mContext.sendStickyBroadcast(broadcast); + Binder.restoreCallingIdentity(origCallerIdentityToken); + } } - + private void broadcastVibrateSetting(int vibrateType) { // Send broadcast - Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); - broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType); - broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType)); - mContext.sendBroadcast(broadcast); + if (ActivityManagerNative.isSystemReady()) { + Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); + broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType); + broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType)); + mContext.sendBroadcast(broadcast); + } } - + // Message helper methods private static int getMsg(int baseMsg, int streamType) { - return (baseMsg & 0xffff) | streamType << 16; + return (baseMsg & 0xffff) | streamType << 16; } - + private static int getMsgBase(int msg) { return msg & 0xffff; } @@ -792,11 +855,11 @@ public class AudioService extends IAudioService.Stub { } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) { return; } - + handler .sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay); } - + boolean checkAudioSettingsPermission(String method) { if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS") == PackageManager.PERMISSION_GRANTED) { @@ -809,29 +872,29 @@ public class AudioService extends IAudioService.Stub { return false; } - + /////////////////////////////////////////////////////////////////////////// // Inner classes /////////////////////////////////////////////////////////////////////////// - + public class VolumeStreamState { private final String mVolumeIndexSettingName; - private final String mLastAudibleVolumeIndexSettingName; + private final String mLastAudibleVolumeIndexSettingName; private final int mStreamType; - + private final int[] mVolumes; private int mIndex; private int mLastAudibleIndex; private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo requests client death - + private VolumeStreamState(String settingName, int streamType, int[] volumes) { - + mVolumeIndexSettingName = settingName; mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; - + mStreamType = streamType; mVolumes = volumes; - + final ContentResolver cr = mContentResolver; mIndex = getValidIndex(Settings.System.getInt(cr, mVolumeIndexSettingName, AudioManager.DEFAULT_STREAM_VOLUME[streamType])); mLastAudibleIndex = getValidIndex(Settings.System.getInt(cr, @@ -841,14 +904,31 @@ public class AudioService extends IAudioService.Stub { mDeathHandlers = new ArrayList<VolumeDeathHandler>(); } + /** + * Constructor to be used when there is no setting associated with the VolumeStreamState. + * + * @param defaultVolume Default volume of the stream to use. + * @param streamType Type of the stream. + * @param volumes Volumes levels associated with this stream. + */ + private VolumeStreamState(int defaultVolume, int streamType, int[] volumes) { + mVolumeIndexSettingName = null; + mLastAudibleVolumeIndexSettingName = null; + mIndex = mLastAudibleIndex = defaultVolume; + mStreamType = streamType; + mVolumes = volumes; + AudioSystem.setVolume(mStreamType, defaultVolume); + mDeathHandlers = new ArrayList<VolumeDeathHandler>(); + } + public boolean adjustIndex(int deltaIndex) { return setIndex(mIndex + deltaIndex); } - + public boolean setIndex(int index) { int oldIndex = mIndex; mIndex = getValidIndex(index); - + if (oldIndex != mIndex) { if (mIndex > 0) { mLastAudibleIndex = mIndex; @@ -858,11 +938,11 @@ public class AudioService extends IAudioService.Stub { return false; } } - + public int getMaxIndex() { return mVolumes.length - 1; } - + public void mute(IBinder cb, boolean state) { VolumeDeathHandler handler = getDeathHandler(cb, state); if (handler == null) { @@ -871,17 +951,17 @@ public class AudioService extends IAudioService.Stub { } handler.mute(state); } - + private int getValidIndex(int index) { if (index < 0) { return 0; } else if (index >= mVolumes.length) { return mVolumes.length - 1; } - + return index; } - + private class VolumeDeathHandler implements IBinder.DeathRecipient { private IBinder mICallback; // To be notified of client's death private int mMuteCount; // Number of active mutes for this client @@ -924,7 +1004,7 @@ public class AudioService extends IAudioService.Stub { mDeathHandlers.remove(this); mICallback.unlinkToDeath(this, 0); if (muteCount() == 0) { - // If the stream is not mut any more, restore it's volume if + // If the stream is not mut any more, restore it's volume if // ringer mode allows it if (!isStreamAffectedByRingerMode(mStreamType) || mRingerMode == AudioManager.RINGER_MODE_NORMAL) { setIndex(mLastAudibleIndex); @@ -980,59 +1060,59 @@ public class AudioService extends IAudioService.Stub { } } } - + /** Thread that handles native AudioSystem control. */ private class AudioSystemThread extends Thread { AudioSystemThread() { super("AudioService"); } - + @Override public void run() { // Set this thread up so the handler will work on it Looper.prepare(); - + synchronized(AudioService.this) { mAudioHandler = new AudioHandler(); // Notify that the handler has been created AudioService.this.notify(); } - + // Listen for volume change requests that are set by VolumePanel Looper.loop(); } } - + /** Handles internal volume messages in separate volume thread. */ private class AudioHandler extends Handler { - + private void setSystemVolume(VolumeStreamState streamState) { - + // Adjust volume AudioSystem .setVolume(streamState.mStreamType, streamState.mVolumes[streamState.mIndex]); - + // Post a persist volume msg sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamState.mStreamType, SENDMSG_REPLACE, 0, 0, streamState, PERSIST_DELAY); } - + private void persistVolume(VolumeStreamState streamState) { System.putInt(mContentResolver, streamState.mVolumeIndexSettingName, streamState.mIndex); System.putInt(mContentResolver, streamState.mLastAudibleVolumeIndexSettingName, streamState.mLastAudibleIndex); } - + private void persistRingerMode() { System.putInt(mContentResolver, System.MODE_RINGER, mRingerMode); } - + private void persistVibrateSetting() { System.putInt(mContentResolver, System.VIBRATE_ON, mVibrateSetting); } - + private void playSoundEffect(int effectType) { synchronized (mSoundEffectsLock) { if (mSoundPool == null) { @@ -1084,36 +1164,36 @@ public class AudioService extends IAudioService.Stub { } } } - + @Override public void handleMessage(Message msg) { int baseMsgWhat = getMsgBase(msg.what); - + switch (baseMsgWhat) { - + case MSG_SET_SYSTEM_VOLUME: setSystemVolume((VolumeStreamState) msg.obj); break; - + case MSG_PERSIST_VOLUME: persistVolume((VolumeStreamState) msg.obj); break; - + case MSG_PERSIST_RINGER_MODE: persistRingerMode(); break; - + case MSG_PERSIST_VIBRATE_SETTING: persistVibrateSetting(); break; - + case MSG_MEDIA_SERVER_DIED: Log.e(TAG, "Media server died."); - // Force creation of new IAudioflinger interface + // Force creation of new IAudioflinger interface mMediaServerOk = false; AudioSystem.getMode(); break; - + case MSG_MEDIA_SERVER_STARTED: Log.e(TAG, "Media server started."); // Restore audio routing and stream volumes @@ -1139,5 +1219,5 @@ public class AudioService extends IAudioService.Stub { } } } - + } diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 37100677..d0fa795 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -43,15 +43,17 @@ public class AudioSystem public static final int STREAM_ALARM = 4; /* The audio stream for notifications */ public static final int STREAM_NOTIFICATION = 5; + /* @hide The audio stream for phone calls when connected on bluetooth */ + public static final int STREAM_BLUETOOTH_SCO = 6; /** * @deprecated Use {@link #numStreamTypes() instead} */ public static final int NUM_STREAMS = 5; // Expose only the getter method publicly so we can change it in the future - private static final int NUM_STREAM_TYPES = 6; + private static final int NUM_STREAM_TYPES = 7; public static final int getNumStreamTypes() { return NUM_STREAM_TYPES; } - + /* max and min volume levels */ /* Maximum volume setting, for use with setVolume(int,int) */ public static final int MAX_VOLUME = 100; @@ -78,7 +80,7 @@ public class AudioSystem /* * Sets the microphone mute on or off. * - * param on set <var>true</var> to mute the microphone; + * param on set <var>true</var> to mute the microphone; * <var>false</var> to turn mute off * return command completion status see AUDIO_STATUS_OK, see AUDIO_STATUS_ERROR */ @@ -116,18 +118,18 @@ public class AudioSystem public static final int MODE_RINGTONE = 1; public static final int MODE_IN_CALL = 2; public static final int NUM_MODES = 3; - + /* Routing bits for setRouting/getRouting API */ public static final int ROUTE_EARPIECE = (1 << 0); public static final int ROUTE_SPEAKER = (1 << 1); - - /** @deprecated use {@link #ROUTE_BLUETOOTH_SCO} */ + + /** @deprecated use {@link #ROUTE_BLUETOOTH_SCO} */ @Deprecated public static final int ROUTE_BLUETOOTH = (1 << 2); public static final int ROUTE_BLUETOOTH_SCO = (1 << 2); public static final int ROUTE_HEADSET = (1 << 3); public static final int ROUTE_BLUETOOTH_A2DP = (1 << 4); - public static final int ROUTE_ALL = 0xFFFFFFFF; + public static final int ROUTE_ALL = 0xFFFFFFFF; /* * Sets the audio routing for a specified mode @@ -185,7 +187,7 @@ public class AudioSystem public static final int AUDIO_STATUS_ERROR = 1; /* Media server died. see ErrorCallback */ public static final int AUDIO_STATUS_SERVER_DIED = 100; - + private static ErrorCallback mErrorCallback; /* @@ -211,7 +213,7 @@ public class AudioSystem { mErrorCallback = cb; } - + private static void errorCallbackFromNative(int error) { if (mErrorCallback != null) { diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 2b7656f..9bb1df9 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -30,12 +30,31 @@ import android.util.Log; /** * The AudioTrack class manages and plays a single audio resource for Java applications. * It allows to stream PCM audio buffers to the audio hardware for playback. This is - * be achieved by "pushing" the data to the AudioTrack object using the - * {@link #write(byte[], int, int)} or {@link #write(short[], int, int)} method. - * During construction, an AudioTrack object can be initialized with a given buffer. - * This size determines how long an AudioTrack can play before running out of data. - * - * {@hide Pending API council review} + * achieved by "pushing" the data to the AudioTrack object using one of the + * {@link #write(byte[], int, int)} and {@link #write(short[], int, int)} methods. + * <p>An AudioTrack instance can operate under two modes: static of streaming.<br> + * The Streaming mode consists in continuously writing data to the AudioTrack, using one + * of the write() methods. These are blocking and return when the data has been transferred + * from the Java layer to the native layer, and is queued for playback. The streaming mode + * is most useful when playing blocks of audio data that for instance are: + * <ul> + * <li>too big to fit in memory because of the duration of the sound to play,</li> + * <li>too big to fit in memory because of the characteristics of the audio data + * (high sampling rate, bits per sample ...)</li> + * <li>chosen, received or generated as the audio keeps playing.</li> + * </ul> + * The static mode is to be chosen when dealing with short sounds that fit in memory and + * that need to be played with the smallest latency possible. Static mode AudioTrack instances can + * play the sound without the need to transfer the audio data from Java to the audio hardware + * each time the sound is to be played. The static mode will therefore be preferred for UI and + * game sounds that are played often, and with the smallest overhead possible. + * <p>Upon creation, an AudioTrack object initializes its associated audio buffer. + * The size of this buffer, specified during the construction, determines how long an AudioTrack + * can play before running out of data.<br> + * For an AudioTrack using the static mode, this size is the maximum size of the sound that can + * be played from it.<br> + * For the streaming mode, data will be written to the hardware in chunks of + * sizes inferior to the total buffer size. */ public class AudioTrack { @@ -46,42 +65,41 @@ public class AudioTrack private static final float VOLUME_MIN = 0.0f; /** Maximum value for a channel volume */ private static final float VOLUME_MAX = 1.0f; - + /** state of an AudioTrack this is stopped */ public static final int PLAYSTATE_STOPPED = 1; // matches SL_PLAYSTATE_STOPPED /** state of an AudioTrack this is paused */ public static final int PLAYSTATE_PAUSED = 2; // matches SL_PLAYSTATE_PAUSED /** state of an AudioTrack this is playing */ public static final int PLAYSTATE_PLAYING = 3; // matches SL_PLAYSTATE_PLAYING - - /** - * Creation mode where audio data is transferred from Java to the native layer + + /** + * Creation mode where audio data is transferred from Java to the native layer * only once before the audio starts playing. */ public static final int MODE_STATIC = 0; - /** - * Creation mode where audio data is streamed from Java to the native layer + /** + * Creation mode where audio data is streamed from Java to the native layer * as the audio is playing. */ public static final int MODE_STREAM = 1; - - /** - * State of an AudioTrack that was not successfully initialized upon creation + + /** + * State of an AudioTrack that was not successfully initialized upon creation */ public static final int STATE_UNINITIALIZED = 0; - /** + /** * State of an AudioTrack that is ready to be used. */ public static final int STATE_INITIALIZED = 1; /** - * State of a successfully initialized AudioTrack that uses static data, + * State of a successfully initialized AudioTrack that uses static data, * but that hasn't received that data yet. */ public static final int STATE_NO_STATIC_DATA = 2; - - // to keep in sync with libs/android_runtime/android_media_AudioTrack.cpp - // error codes + // Error codes: + // to keep in sync with frameworks/base/core/jni/android_media_AudioTrack.cpp /** * Denotes a successful operation. */ @@ -90,139 +108,145 @@ public class AudioTrack * Denotes a generic operation failure. */ public static final int ERROR = -1; - private static final int ERROR_NATIVESETUP_AUDIOSYSTEM = -2; - private static final int ERROR_NATIVESETUP_INVALIDCHANNELCOUNT = -3; - private static final int ERROR_NATIVESETUP_INVALIDFORMAT = -4; - private static final int ERROR_NATIVESETUP_INVALIDSTREAMTYPE = -5; - private static final int ERROR_NATIVESETUP_NATIVEINITFAILED = -6; /** * Denotes a failure due to the use of an invalid value. */ - public static final int ERROR_BAD_VALUE = -7; + public static final int ERROR_BAD_VALUE = -2; /** * Denotes a failure due to the improper use of a method. */ - public static final int ERROR_INVALID_OPERATION = -8; - // events + public static final int ERROR_INVALID_OPERATION = -3; + + private static final int ERROR_NATIVESETUP_AUDIOSYSTEM = -16; + private static final int ERROR_NATIVESETUP_INVALIDCHANNELCOUNT = -17; + private static final int ERROR_NATIVESETUP_INVALIDFORMAT = -18; + private static final int ERROR_NATIVESETUP_INVALIDSTREAMTYPE = -19; + private static final int ERROR_NATIVESETUP_NATIVEINITFAILED = -20; + + // Events: + // to keep in sync with frameworks/base/include/media/AudioTrack.h /** * Event id for when the playback head has reached a previously set marker. */ - protected static final int NATIVE_EVENT_MARKER = 3; + private static final int NATIVE_EVENT_MARKER = 3; /** * Event id for when the previously set update period has passed during playback. */ - protected static final int NATIVE_EVENT_NEW_POS = 4; - + private static final int NATIVE_EVENT_NEW_POS = 4; + private final static String TAG = "AudioTrack-Java"; - + //-------------------------------------------------------------------------- // Member variables //-------------------- /** * Indicates the state of the AudioTrack instance */ - protected int mState = STATE_UNINITIALIZED; + private int mState = STATE_UNINITIALIZED; /** * Indicates the play state of the AudioTrack instance */ - protected int mPlayState = PLAYSTATE_STOPPED; + private int mPlayState = PLAYSTATE_STOPPED; /** * Lock to make sure mPlayState updates are reflecting the actual state of the object. */ - protected final Object mPlayStateLock = new Object(); + private final Object mPlayStateLock = new Object(); /** * The listener the AudioTrack notifies previously set marker is reached. * @see #setMarkerReachedListener(OnMarkerReachedListener) */ - protected OnMarkerReachedListener mMarkerListener = null; + private OnMarkerReachedListener mMarkerListener = null; /** * Lock to protect marker listener updates against event notifications */ - protected final Object mMarkerListenerLock = new Object(); + private final Object mMarkerListenerLock = new Object(); /** * The listener the AudioTrack notifies periodically during playback. * @see #setPeriodicNotificationListener(OnPeriodicNotificationListener) */ - protected OnPeriodicNotificationListener mPeriodicListener = null; + private OnPeriodicNotificationListener mPeriodicListener = null; /** * Lock to protect periodic listener updates against event notifications */ - protected final Object mPeriodicListenerLock = new Object(); + private final Object mPeriodicListenerLock = new Object(); /** * Size of the native audio buffer. */ - protected int mNativeBufferSizeInBytes = 0; + private int mNativeBufferSizeInBytes = 0; /** * Handler for events coming from the native code */ - protected NativeEventHandler mNativeEventHandler = null; + private NativeEventHandler mNativeEventHandler = null; /** * The audio data sampling rate in Hz. */ - protected int mSampleRate = 22050; + private int mSampleRate = 22050; /** * The number of input audio channels (1 is mono, 2 is stereo) */ - protected int mChannelCount = 1; + private int mChannelCount = 1; /** * The type of the audio stream to play. See - * {@link AudioManager.STREAM_VOICE_CALL}, {@link AudioManager.STREAM_SYSTEM}, - * {@link AudioManager.STREAM_RING}, {@link AudioManager.STREAM_MUSIC} and - * {@link AudioManager.STREAM_ALARM} + * {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM}, + * {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and + * {@link AudioManager#STREAM_ALARM} */ - protected int mStreamType = AudioManager.STREAM_MUSIC; + private int mStreamType = AudioManager.STREAM_MUSIC; /** * The way audio is consumed by the hardware, streaming or static. */ - protected int mDataLoadMode = MODE_STREAM; + private int mDataLoadMode = MODE_STREAM; /** * The current audio channel configuration */ - protected int mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO; + private int mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO; /** * The encoding of the audio samples. - * @see #AudioFormat.ENCODING_PCM_8BIT - * @see #AudioFormat.ENCODING_PCM_16BIT + * @see AudioFormat#ENCODING_PCM_8BIT + * @see AudioFormat#ENCODING_PCM_16BIT */ - protected int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; + private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; //-------------------------------- // Used exclusively by native code //-------------------- - /** - * Accessed by native methods: provides access to C++ AudioTrack object + /** + * Accessed by native methods: provides access to C++ AudioTrack object */ @SuppressWarnings("unused") private int mNativeTrackInJavaObj; - /** + /** * Accessed by native methods: provides access to the JNI data (i.e. resources used by * the native AudioTrack object, but not stored in it). */ @SuppressWarnings("unused") private int mJniData; - - + + //-------------------------------------------------------------------------- // Constructor, Finalize //-------------------- /** * Class constructor. - * @param streamType the type of the audio stream. See - * {@link AudioSystem.STREAM_VOICE_CALL}, {@link AudioSystem.STREAM_SYSTEM}, - * {@link AudioSystem.STREAM_RING}, {@link AudioSystem.STREAM_MUSIC} and - * {@link AudioSystem.STREAM_ALARM} + * @param streamType the type of the audio stream. See + + * {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM}, + * {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and + * {@link AudioManager#STREAM_ALARM} * @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but * not limited to) 44100, 22050 and 11025. - * @param channelConfig describes the configuration of the audio channels. - * See {@link AudioFormat.CHANNEL_CONFIGURATION_MONO} and - * {@link AudioFormat.CHANNEL_CONFIGURATION_STEREO} - * @param audioFormat the format in which the audio data is represented. - * See {@link AudioFormat.ENCODING_PCM_16BIT} and - * {@link AudioFormat.ENCODING_PCM_8BIT} + * @param channelConfig describes the configuration of the audio channels. + + * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and + * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO} + + * @param audioFormat the format in which the audio data is represented. + * See {@link AudioFormat#ENCODING_PCM_16BIT} and + * {@link AudioFormat#ENCODING_PCM_8BIT} * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is read - * from for playback. If using the AudioTrack in streaming mode, you can write data into + * from for playback. If using the AudioTrack in streaming mode, you can write data into * this buffer in smaller chunks than this size. If using the AudioTrack in static mode, * this is the maximum size of the sound that will be played for this instance. * @param mode streaming or static buffer. See {@link #MODE_STATIC} and {@link #MODE_STREAM} @@ -230,7 +254,7 @@ public class AudioTrack */ public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode) - throws IllegalArgumentException { + throws IllegalArgumentException { mState = STATE_UNINITIALIZED; audioParamCheck(streamType, sampleRateInHz, channelConfig, audioFormat, mode); @@ -238,8 +262,8 @@ public class AudioTrack audioBuffSizeCheck(bufferSizeInBytes); // native initialization - int initResult = native_setup(new WeakReference<AudioTrack>(this), - mStreamType, mSampleRate, mChannelCount, mAudioFormat, + int initResult = native_setup(new WeakReference<AudioTrack>(this), + mStreamType, mSampleRate, mChannelCount, mAudioFormat, mNativeBufferSizeInBytes, mDataLoadMode); if (initResult != SUCCESS) { loge("Error code "+initResult+" when initializing AudioTrack."); @@ -252,8 +276,8 @@ public class AudioTrack mState = STATE_INITIALIZED; } } - - + + // Convenience method for the constructor's parameter checks. // This is where constructor IllegalArgumentException-s are thrown // postconditions: @@ -262,25 +286,27 @@ public class AudioTrack // mAudioFormat is valid // mSampleRate is valid // mDataLoadMode is valid - private void audioParamCheck(int streamType, int sampleRateInHz, + private void audioParamCheck(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int mode) { - + //-------------- // stream type if( (streamType != AudioManager.STREAM_ALARM) && (streamType != AudioManager.STREAM_MUSIC) && (streamType != AudioManager.STREAM_RING) && (streamType != AudioManager.STREAM_SYSTEM) - && (streamType != AudioManager.STREAM_VOICE_CALL) && (streamType != AudioManager.STREAM_NOTIFICATION) ) { + && (streamType != AudioManager.STREAM_VOICE_CALL) + && (streamType != AudioManager.STREAM_NOTIFICATION) + && (streamType != AudioManager.STREAM_BLUETOOTH_SCO)) { throw (new IllegalArgumentException("Invalid stream type.")); } else { mStreamType = streamType; } - + //-------------- // sample rate if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) { throw (new IllegalArgumentException(sampleRateInHz + "Hz is not a supported sample rate.")); - } else { + } else { mSampleRate = sampleRateInHz; } @@ -314,10 +340,10 @@ public class AudioTrack break; default: mAudioFormat = AudioFormat.ENCODING_INVALID; - throw(new IllegalArgumentException("Unsupported sample encoding." + throw(new IllegalArgumentException("Unsupported sample encoding." + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT.")); } - + //-------------- // audio load mode if ( (mode != MODE_STREAM) && (mode != MODE_STATIC) ) { @@ -326,8 +352,8 @@ public class AudioTrack mDataLoadMode = mode; } } - - + + // Convenience method for the contructor's audio buffer size check. // preconditions: // mChannelCount is valid @@ -335,18 +361,18 @@ public class AudioTrack // postcondition: // mNativeBufferSizeInBytes is valid (multiple of frame size, positive) private void audioBuffSizeCheck(int audioBufferSize) { - // NB: this section is only valid with PCM data. + // NB: this section is only valid with PCM data. // To update when supporting compressed formats - int frameSizeInBytes = mChannelCount + int frameSizeInBytes = mChannelCount * (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2); if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) { throw (new IllegalArgumentException("Invalid audio buffer size.")); } - + mNativeBufferSizeInBytes = audioBufferSize; } - - + + // Convenience method for the creation of the native event handler // It is called only when a non-null event listener is set. // precondition: @@ -361,8 +387,8 @@ public class AudioTrack mNativeEventHandler = null; } } - - + + /** * Releases the native AudioTrack resources. */ @@ -377,7 +403,7 @@ public class AudioTrack @Override protected void finalize() { native_finalize(); - } + } //-------------------------------------------------------------------------- // Getters @@ -390,7 +416,7 @@ public class AudioTrack static public float getMinVolume() { return AudioTrack.VOLUME_MIN; } - + /** * Returns the maximum valid volume value. Volume values set above this one will * be clamped at this value. @@ -398,8 +424,8 @@ public class AudioTrack */ static public float getMaxVolume() { return AudioTrack.VOLUME_MAX; - } - + } + /** * Returns the configured audio data sample rate in Hz */ @@ -408,27 +434,28 @@ public class AudioTrack } /** - * Returns the configured audio data format. See {@link #AudioFormat.ENCODING_PCM_16BIT} - * and {@link #AudioFormat.ENCODING_PCM_8BIT}. + * Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_16BIT} + * and {@link AudioFormat#ENCODING_PCM_8BIT}. */ public int getAudioFormat() { return mAudioFormat; } - + /** * Returns the type of audio stream this AudioTrack is configured for. - * Compare the result against {@link AudioManager.STREAM_VOICE_CALL}, - * {@link AudioManager.STREAM_SYSTEM}, {@link AudioManager.STREAM_RING}, - * {@link AudioManager.STREAM_MUSIC} or {@link AudioManager.STREAM_ALARM} + * Compare the result against {@link AudioManager#STREAM_VOICE_CALL}, + * {@link AudioManager#STREAM_SYSTEM}, {@link AudioManager#STREAM_RING}, + * {@link AudioManager#STREAM_MUSIC} or {@link AudioManager#STREAM_ALARM} */ public int getStreamType() { return mStreamType; } /** - * Returns the configured channel configuration. - * See {@link #AudioFormat.CHANNEL_CONFIGURATION_MONO} - * and {@link #AudioFormat.CHANNEL_CONFIGURATION_STEREO}. + * Returns the configured channel configuration. + + * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} + * and {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}. */ public int getChannelConfiguration() { return mChannelConfiguration; @@ -443,19 +470,19 @@ public class AudioTrack /** * Returns the state of the AudioTrack instance. This is useful after the - * AudioTrack instance has been created to check if it was initialized + * AudioTrack instance has been created to check if it was initialized * properly. This ensures that the appropriate hardware resources have been * acquired. */ public int getState() { return mState; } - + /** * Returns the playback state of the AudioTrack instance. - * @see AudioTrack.PLAYSTATE_STOPPED - * @see AudioTrack.PLAYSTATE_PAUSED - * @see AudioTrack.PLAYSTATE_PLAYING + * @see #PLAYSTATE_STOPPED + * @see #PLAYSTATE_PAUSED + * @see #PLAYSTATE_PLAYING */ public int getPlayState() { return mPlayState; @@ -495,11 +522,49 @@ public class AudioTrack static public int getNativeOutputSampleRate() { return native_get_output_sample_rate(); } - + /** + * {@hide} + * Returns the minimum buffer size required for the successful creation of an AudioTrack + * object to be created in the {@link #MODE_STREAM} mode. + * @param sampleRateInHz the sample rate expressed in Hertz. + * @param channelConfig describes the configuration of the audio channels. + * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and + * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO} + * @param audioFormat the format in which the audio data is represented. + * See {@link AudioFormat#ENCODING_PCM_16BIT} and + * {@link AudioFormat#ENCODING_PCM_8BIT} + * @return -1 if an invalid parameter was passed or if the implementation was unable to + * query the hardware for its output properties, or the minimum buffer size expressed + * in number of bytes. + */ + static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) { + int channelCount = 0; + switch(channelConfig) { + case AudioFormat.CHANNEL_CONFIGURATION_MONO: + channelCount = 1; + break; + case AudioFormat.CHANNEL_CONFIGURATION_STEREO: + channelCount = 2; + break; + default: + loge("getMinBufferSize(): Invalid channel configuration."); + return -1; + } + + if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT) + && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) { + loge("getMinBufferSize(): Invalid audio format."); + return -1; + } + + return native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat); + } + + //-------------------------------------------------------------------------- // Initialization / configuration - //-------------------- + //-------------------- /** * Sets the listener the AudioTrack notifies when a previously set marker is reached. * @param listener @@ -512,8 +577,8 @@ public class AudioTrack createNativeEventHandler(); } } - - + + /** * Sets the listener the AudioTrack notifies periodically during playback. * @param listener @@ -526,22 +591,20 @@ public class AudioTrack createNativeEventHandler(); } } - - - /** - * Sets the specified left/right output volume values on the AudioTrack. Values are clamped + + + /** + * Sets the specified left/right output volume values on the AudioTrack. Values are clamped * to the ({@link #getMinVolume()}, {@link #getMaxVolume()}) interval if outside this range. - * @param leftVolume output attenuation for the left channel. A value of 0.0f is silence, + * @param leftVolume output attenuation for the left channel. A value of 0.0f is silence, * a value of 1.0f is no attenuation. * @param rightVolume output attenuation for the right channel - * @return {@link #SUCCESS} - * @throws IllegalStateException + * @return error code or success, see {@link #SUCCESS}, + * {@link #ERROR_INVALID_OPERATION} */ - public int setStereoVolume(float leftVolume, float rightVolume) - throws IllegalStateException { + public int setStereoVolume(float leftVolume, float rightVolume) { if (mState != STATE_INITIALIZED) { - throw(new IllegalStateException("setStereoVolume() called on an "+ - "uninitialized AudioTrack.")); + return ERROR_INVALID_OPERATION; } // clamp the volumes @@ -559,11 +622,11 @@ public class AudioTrack } native_setVolume(leftVolume, rightVolume); - + return SUCCESS; } - - + + /** * Sets the playback sample rate for this track. This sets the sampling rate at which * the audio data will be consumed and played back, not the original sampling rate of the @@ -573,70 +636,88 @@ public class AudioTrack * sample rate (see {@link #getNativeOutputSampleRate()}). Use {@link #getSampleRate()} to * check the rate actually used in hardware after potential clamping. * @param sampleRateInHz - * @return {@link #SUCCESS} + * @return error code or success, see {@link #SUCCESS}, + * {@link #ERROR_INVALID_OPERATION} */ public int setPlaybackRate(int sampleRateInHz) { + if (mState != STATE_INITIALIZED) { + return ERROR_INVALID_OPERATION; + } native_set_playback_rate(sampleRateInHz); return SUCCESS; } - - + + /** - * + * * @param markerInFrames marker in frames * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, - * {@link #ERROR_INVALID_OPERATION} + * {@link #ERROR_INVALID_OPERATION} */ public int setNotificationMarkerPosition(int markerInFrames) { + if (mState != STATE_INITIALIZED) { + return ERROR_INVALID_OPERATION; + } return native_set_marker_pos(markerInFrames); } - - + + /** * @param periodInFrames update period in frames * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION} */ public int setPositionNotificationPeriod(int periodInFrames) { + if (mState != STATE_INITIALIZED) { + return ERROR_INVALID_OPERATION; + } return native_set_pos_update_period(periodInFrames); } - - + + /** * Sets the playback head position. The track must be stopped for the position to be changed. * @param positionInFrames playback head position in frames - * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE} - * @throws java.lang.IllegalStateException if the track is not in - * the {@link #PLAYSTATE_STOPPED} state. + * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, + * {@link #ERROR_INVALID_OPERATION} */ - public int setPlaybackHeadPosition(int positionInFrames) - throws IllegalStateException { + public int setPlaybackHeadPosition(int positionInFrames) { synchronized(mPlayStateLock) { if(mPlayState == PLAYSTATE_STOPPED) { return native_set_position(positionInFrames); + } else { + return ERROR_INVALID_OPERATION; } } - throw(new IllegalStateException("setPlaybackHeadPosition() called on a track that is "+ - "not in the PLAYSTATE_STOPPED play state.")); } - + /** * Sets the loop points and the loop count. The loop can be infinite. * @param startInFrames loop start marker in frames * @param endInFrames loop end marker in frames - * @param loopCount the number of times the loop is looped. + * @param loopCount the number of times the loop is looped. * A value of -1 means infinite looping. - * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE} + * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, + * {@link #ERROR_INVALID_OPERATION} */ public int setLoopPoints(int startInFrames, int endInFrames, int loopCount) { return native_set_loop(startInFrames, endInFrames, loopCount); } + /** + * Sets the initialization state of the instance. To be used in an AudioTrack subclass + * constructor to set a subclass-specific post-initialization state. + * @param state the state of the AudioTrack instance + */ + protected void setState(int state) { + mState = state; + } + //--------------------------------------------------------- // Transport control methods //-------------------- /** - * Starts playing an AudioTrack. + * Starts playing an AudioTrack. * @throws IllegalStateException */ public void play() @@ -644,7 +725,7 @@ public class AudioTrack if (mState != STATE_INITIALIZED) { throw(new IllegalStateException("play() called on uninitialized AudioTrack.")); } - + synchronized(mPlayStateLock) { native_start(); mPlayState = PLAYSTATE_PLAYING; @@ -671,7 +752,7 @@ public class AudioTrack /** * Pauses the playback of the audio data. * @throws IllegalStateException - */ + */ public void pause() throws IllegalStateException { if (mState != STATE_INITIALIZED) { @@ -685,25 +766,21 @@ public class AudioTrack mPlayState = PLAYSTATE_PAUSED; } } - - + + //--------------------------------------------------------- // Audio data supply //-------------------- /** * Flushes the audio data currently queued for playback. - * @throws IllegalStateException - */ - public void flush() - throws IllegalStateException { - if (mState != STATE_INITIALIZED) { - throw(new IllegalStateException("flush() called on uninitialized AudioTrack.")); - } - //logd("flush()"); + */ - // flush the data in native layer - native_flush(); + public void flush() { + if (mState == STATE_INITIALIZED) { + // flush the data in native layer + native_flush(); + } } @@ -712,12 +789,12 @@ 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. - * @throws IllegalStateException - */ - public int write(byte[] audioData,int offsetInBytes, int sizeInBytes) - throws IllegalStateException { - if ((mDataLoadMode == MODE_STATIC) + * @return the number of bytes that were written or -1 if the object wasn't properly + * initialized. + */ + + public int write(byte[] audioData,int offsetInBytes, int sizeInBytes) { + if ((mDataLoadMode == MODE_STATIC) && (mState == STATE_NO_STATIC_DATA) && (sizeInBytes > 0)) { mState = STATE_INITIALIZED; @@ -726,24 +803,24 @@ public class AudioTrack // or: how to update data for static tracks? if (mState != STATE_INITIALIZED) { - throw(new IllegalStateException("write() called on uninitialized AudioTrack.")); + return -1; } return native_write_byte(audioData, offsetInBytes, sizeInBytes); } - - + + /** * Writes the audio data to the audio hardware for playback. * @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. - * @throws IllegalStateException - */ - public int write(short[] audioData, int offsetInShorts, int sizeInShorts) - throws IllegalStateException { - if ((mDataLoadMode == MODE_STATIC) + * @return the number of shorts that were written or -1 if the object wasn't properly + * initialized. + */ + + public int write(short[] audioData, int offsetInShorts, int sizeInShorts) { + if ((mDataLoadMode == MODE_STATIC) && (mState == STATE_NO_STATIC_DATA) && (sizeInShorts > 0)) { mState = STATE_INITIALIZED; @@ -752,13 +829,13 @@ public class AudioTrack // or: how to update data for static tracks? if (mState != STATE_INITIALIZED) { - throw(new IllegalStateException("write() called on uninitialized AudioTrack.")); + return -1; } return native_write_short(audioData, offsetInShorts, sizeInShorts); } - - + + /** * Notifies the native resource to reuse the audio data already loaded in the native * layer. This call is only valid with AudioTrack instances that don't use the streaming @@ -791,7 +868,7 @@ public class AudioTrack /** - * Interface definition for a callback to be invoked for each periodic AudioTrack + * Interface definition for a callback to be invoked for each periodic AudioTrack * update during playback. The update interval is set by setPositionNotificationPeriod(). */ public interface OnPeriodicNotificationListener { @@ -858,28 +935,28 @@ public class AudioTrack if (track == null) { return; } - + if (track.mNativeEventHandler != null) { Message m = track.mNativeEventHandler.obtainMessage(what, arg1, arg2, obj); track.mNativeEventHandler.sendMessage(m); } } - - + + //--------------------------------------------------------- // Native methods called from the Java side //-------------------- - private native final int native_setup(Object audiotrack_this, - int streamType, int sampleRate, int nbChannels, int audioFormat, + private native final int native_setup(Object audiotrack_this, + int streamType, int sampleRate, int nbChannels, int audioFormat, int buffSizeInBytes, int mode); private native final void native_finalize(); - + private native final void native_release(); - private native final void native_start(); + private native final void native_start(); private native final void native_stop(); @@ -887,34 +964,36 @@ public class AudioTrack private native final void native_flush(); - private native final int native_write_byte(byte[] audioData, + private native final int native_write_byte(byte[] audioData, int offsetInBytes, int sizeInBytes); - - private native final int native_write_short(short[] audioData, + + private native final int native_write_short(short[] audioData, int offsetInShorts, int sizeInShorts); - + private native final int native_reload_static(); private native final int native_get_native_frame_count(); private native final void native_setVolume(float leftVolume, float rightVolume); - + private native final void native_set_playback_rate(int sampleRateInHz); private native final int native_get_playback_rate(); - + private native final int native_set_marker_pos(int marker); private native final int native_get_marker_pos(); - + private native final int native_set_pos_update_period(int updatePeriod); private native final int native_get_pos_update_period(); - + private native final int native_set_position(int position); private native final int native_get_position(); - + 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_min_buff_size( + int sampleRateInHz, int channelConfig, int audioFormat); + //--------------------------------------------------------- // Utility methods @@ -928,7 +1007,4 @@ public class AudioTrack Log.e(TAG, "[ android.media.AudioTrack ] " + msg); } -} - - - +}
\ No newline at end of file diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java index b9268d5..bfa2f80 100644 --- a/media/java/android/media/JetPlayer.java +++ b/media/java/android/media/JetPlayer.java @@ -17,9 +17,11 @@ package android.media; +import java.io.FileDescriptor; import java.lang.ref.WeakReference; import java.lang.CloneNotSupportedException; +import android.content.res.AssetFileDescriptor; import android.os.Looper; import android.os.Handler; import android.os.Message; @@ -29,9 +31,7 @@ import android.util.Log; * JetPlayer provides access to JET content playback and control. * <p> * Use <code>JetPlayer.getJetPlayer()</code> to get an instance of this class. - * There can only be one instance of this class at any one time. * - * @hide */ public class JetPlayer { @@ -39,15 +39,29 @@ public class JetPlayer // Constants //------------------------ /** - * The maximum number of simultaneous tracks. Use {@link #getMaxTracks()} to + * The maximum number of simultaneous tracks. Use __link #getMaxTracks()} to * access this value. */ - protected static int MAXTRACKS = 32; + private static int MAXTRACKS = 32; - // These constants are to be kept in sync with the ones in include/media/JetPlayer.h - protected static final int JET_USERID_UPDATE = 1; - protected static final int JET_NUMQUEUEDSEGMENT_UPDATE = 2; - protected static final int JET_PAUSE_UPDATE = 3; + // to keep in sync with the JetPlayer class constants + // defined in frameworks/base/include/media/JetPlayer.h + private static final int JET_EVENT = 1; + private static final int JET_USERID_UPDATE = 2; + private static final int JET_NUMQUEUEDSEGMENT_UPDATE = 3; + private static final int JET_PAUSE_UPDATE = 4; + + // to keep in sync with external/sonivox/arm-wt-22k/lib_src/jet_data.h + // Encoding of event information on 32 bits + private static final int JET_EVENT_VAL_MASK = 0x0000007f; // mask for value + private static final int JET_EVENT_CTRL_MASK = 0x00003f80; // mask for controller + private static final int JET_EVENT_CHAN_MASK = 0x0003c000; // mask for channel + private static final int JET_EVENT_TRACK_MASK = 0x00fc0000; // mask for track number + private static final int JET_EVENT_SEG_MASK = 0xff000000; // mask for segment ID + private static final int JET_EVENT_CTRL_SHIFT = 7; // shift to get controller number to bit 0 + private static final int JET_EVENT_CHAN_SHIFT = 14; // shift to get MIDI channel to bit 0 + private static final int JET_EVENT_TRACK_SHIFT = 18; // shift to get track ID to bit 0 + private static final int JET_EVENT_SEG_SHIFT = 24; // shift to get segment ID to bit 0 //-------------------------------------------- @@ -56,13 +70,20 @@ public class JetPlayer private EventHandler mNativeEventHandler = null; /** - * Lock to protect event listener updates against event notifications + * Lock to protect status listener updates against status change notifications */ - protected final Object mStatusListenerLock = new Object(); + private final Object mStatusListenerLock = new Object(); - protected JetStatusUpdateListener mJetStatusUpdateListener = null; + /** + * Lock to protect the event listener updates against event notifications + */ + private final Object mEventListenerLock = new Object(); + + private JetStatusUpdateListener mJetStatusUpdateListener = null; - protected static JetPlayer singletonRef; + private JetEventListener mJetEventListener = null; + + private static JetPlayer singletonRef; //-------------------------------- @@ -136,8 +157,14 @@ public class JetPlayer //-------------------------------------------- // Jet functionality //------------------------ - public boolean openJetFile(String path) { - return native_openJetFile(path); + public boolean loadJetFile(String path) { + return native_loadJetFromFile(path); + } + + + public boolean loadJetFile(AssetFileDescriptor afd) { + return native_loadJetFromFileD( + afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); } @@ -195,6 +222,10 @@ public class JetPlayer } + public boolean clearQueue() { + return native_clearQueue(); + } + //--------------------------------------------------------- // Internal class to handle events posted from native code @@ -211,28 +242,42 @@ public class JetPlayer @Override public void handleMessage(Message msg) { switch(msg.what) { + case JET_EVENT: + synchronized (mEventListenerLock) { + if (mJetEventListener != null) { + // call the appropriate listener after decoding the event parameters + // encoded in msg.arg1 + mJetEventListener.onJetEvent( + 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), + (byte) ((msg.arg1 & JET_EVENT_CTRL_MASK) >> JET_EVENT_CTRL_SHIFT), + (byte) (msg.arg1 & JET_EVENT_VAL_MASK) ); + } + } + return; case JET_USERID_UPDATE: synchronized (mStatusListenerLock) { if (mJetStatusUpdateListener != null) { - mJetStatusUpdateListener.onJetUserIdUpdate(msg.arg1, msg.arg2); + mJetStatusUpdateListener.onJetUserIdUpdate(mJet, msg.arg1, msg.arg2); } } return; case JET_NUMQUEUEDSEGMENT_UPDATE: synchronized (mStatusListenerLock) { if (mJetStatusUpdateListener != null) { - mJetStatusUpdateListener.onJetNumQueuedSegmentUpdate(msg.arg1); + mJetStatusUpdateListener.onJetNumQueuedSegmentUpdate(mJet, msg.arg1); } } return; case JET_PAUSE_UPDATE: synchronized (mStatusListenerLock) { if (mJetStatusUpdateListener != null) - mJetStatusUpdateListener.onJetPauseUpdate(msg.arg1); + mJetStatusUpdateListener.onJetPauseUpdate(mJet, msg.arg1); } return; - default: loge("Unknown message type " + msg.what); return; @@ -242,7 +287,7 @@ public class JetPlayer //-------------------------------------------- - // Jet event listener + // Jet status update listener //------------------------ public void setStatusUpdateListener(JetStatusUpdateListener listener) { synchronized(mStatusListenerLock) { @@ -255,31 +300,66 @@ public class JetPlayer } /** - * Handles the notification when the JET segment userID is updated. + * Handles the notification when the JET status is updated. */ public interface JetStatusUpdateListener { /** * Callback for when JET's currently playing segment userID is updated. * + * @param player the JET player the status update is coming from * @param userId the ID of the currently playing segment * @param repeatCount the repetition count for the segment (0 means it plays once) */ - void onJetUserIdUpdate(int userId, int repeatCount); + void onJetUserIdUpdate(JetPlayer player, int userId, int repeatCount); /** * Callback for when JET's number of queued segments is updated. * + * @param player the JET player the status update is coming from * @param nbSegments the number of segments in the JET queue */ - void onJetNumQueuedSegmentUpdate(int nbSegments); + void onJetNumQueuedSegmentUpdate(JetPlayer player, int nbSegments); /** * Callback for when JET pause state is updated. * + * @param player the JET player the status update is coming from * @param paused indicates whether JET is paused or not */ - void onJetPauseUpdate(int paused); - }; + void onJetPauseUpdate(JetPlayer player, int paused); + } + + + //-------------------------------------------- + // Jet event listener + //------------------------ + public void setEventListener(JetEventListener listener) { + synchronized(mEventListenerLock) { + mJetEventListener = listener; + } + + if ((listener != null) && (mNativeEventHandler == null)) { + createNativeEventHandler(); + } + } + + /** + * Handles the notification when the JET engine generates an event. + */ + public interface JetEventListener { + /** + * Callback for when the JET engine generates a new event. + * + * @param player the JET player the event is coming from + * @param segment 8 bit unsigned value + * @param track 6 bit unsigned value + * @param channel 4 bit unsigned value + * @param controller 7 bit unsigned value + * @param value 7 bit unsigned value + */ + void onJetEvent(JetPlayer player, + short segment, byte track, byte channel, byte controller, byte value); + } //-------------------------------------------- @@ -289,7 +369,8 @@ public class JetPlayer int maxTracks, int trackBufferSize); private native final void native_finalize(); private native final void native_release(); - private native final boolean native_openJetFile(String pathToJetFile); + private native final boolean native_loadJetFromFile(String pathToJetFile); + private native final boolean native_loadJetFromFileD(FileDescriptor fd, long offset, long len); private native final boolean native_closeJetFile(); private native final boolean native_playJet(); private native final boolean native_pauseJet(); @@ -300,7 +381,8 @@ public class JetPlayer private native final boolean native_setMuteFlags(int muteFlags, boolean sync); private native final boolean native_setMuteArray(boolean[]muteArray, boolean sync); private native final boolean native_setMuteFlag(int trackId, boolean muteFlag, boolean sync); - private native final boolean native_triggerClip(int clipId); + private native final boolean native_triggerClip(int clipId); + private native final boolean native_clearQueue(); //--------------------------------------------------------- // Called exclusively by native code diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java index 22361aa..f05842d 100644 --- a/media/java/android/media/MediaFile.java +++ b/media/java/android/media/MediaFile.java @@ -102,13 +102,17 @@ public class MediaFile { addFileType("AMR", FILE_TYPE_AMR, "audio/amr"); addFileType("AWB", FILE_TYPE_AWB, "audio/amr-wb"); addFileType("WMA", FILE_TYPE_WMA, "audio/x-ms-wma"); - addFileType("OGG", FILE_TYPE_OGG, "application/ogg"); + addFileType("OGG", FILE_TYPE_OGG, "application/ogg"); + addFileType("OGA", FILE_TYPE_OGG, "application/ogg"); addFileType("MID", FILE_TYPE_MID, "audio/midi"); + addFileType("MIDI", FILE_TYPE_MID, "audio/midi"); addFileType("XMF", FILE_TYPE_MID, "audio/midi"); addFileType("RTTTL", FILE_TYPE_MID, "audio/midi"); addFileType("SMF", FILE_TYPE_SMF, "audio/sp-midi"); addFileType("IMY", FILE_TYPE_IMY, "audio/imelody"); + addFileType("RTX", FILE_TYPE_MID, "audio/midi"); + addFileType("OTA", FILE_TYPE_MID, "audio/midi"); addFileType("MP4", FILE_TYPE_MP4, "video/mp4"); addFileType("M4V", FILE_TYPE_M4V, "video/mp4"); diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 1a82654..601557d 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -39,11 +39,11 @@ import java.lang.ref.WeakReference; /** * MediaPlayer class can be used to control playback * of audio/video files and streams. An example on how to use the methods in - * this class can be found in <a href="../widget/VideoView.html">VideoView</a>. - * Please see <a href="../../../toolbox/apis/media.html">Android Media APIs</a> + * this class can be found in {@link android.widget.VideoView}. + * Please see <a href="{@docRoot}guide/topics/media/index.html">Audio and Video</a> * for additional help using MediaPlayer. * - * <p>Topics covered are: + * <p>Topics covered here are: * <ol> * <li><a href="#StateDiagram">State Diagram</a> * <li><a href="#Valid_and_Invalid_States">Valid and Invalid States</a> diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 651cc41..4a30114 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -24,7 +24,7 @@ import java.io.IOException; * Used to record audio and video. The recording control is based on a * simple state machine (see below). * - * <p><img src="../../../images/mediarecorder_state_diagram.gif" border="0" /> + * <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: @@ -42,8 +42,8 @@ import java.io.IOException; * recorder.release(); // Now the object cannot be reused * </pre> * - * <p>See the <a href="../../../toolbox/apis/media.html">Android Media APIs</a> - * page for additional help with using MediaRecorder. + * <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 { diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java index 38203b6..fc8476d 100644 --- a/media/java/android/media/MediaScanner.java +++ b/media/java/android/media/MediaScanner.java @@ -118,6 +118,7 @@ public class MediaScanner private static final String NOTIFICATIONS_DIR = "/notifications/"; private static final String ALARMS_DIR = "/alarms/"; private static final String MUSIC_DIR = "/music/"; + private static final String PODCAST_DIR = "/podcasts/"; private static final String[] ID3_GENRES = { // ID3v1 Genres @@ -455,8 +456,9 @@ public class MediaScanner boolean ringtones = (path.indexOf(RINGTONES_DIR) > 0); boolean notifications = (path.indexOf(NOTIFICATIONS_DIR) > 0); boolean alarms = (path.indexOf(ALARMS_DIR) > 0); + boolean podcasts = (path.indexOf(PODCAST_DIR) > 0); boolean music = (path.indexOf(MUSIC_DIR) > 0) || - (!ringtones && !notifications && !alarms); + (!ringtones && !notifications && !alarms && !podcasts); if (mFileType == MediaFile.FILE_TYPE_MP3 || mFileType == MediaFile.FILE_TYPE_MP4 || @@ -473,7 +475,7 @@ public class MediaScanner // we used to compute the width and height but it's not worth it } - result = endFile(entry, ringtones, notifications, alarms, music); + result = endFile(entry, ringtones, notifications, alarms, music, podcasts); } } catch (RemoteException e) { Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e); @@ -586,7 +588,8 @@ public class MediaScanner return map; } - public Uri endFile(FileCacheEntry entry, boolean ringtones, boolean notifications, boolean alarms, boolean music) + private Uri endFile(FileCacheEntry entry, boolean ringtones, boolean notifications, + boolean alarms, boolean music, boolean podcasts) throws RemoteException { // update database Uri tableUri; @@ -634,6 +637,7 @@ public class MediaScanner values.put(Audio.Media.IS_NOTIFICATION, notifications); values.put(Audio.Media.IS_ALARM, alarms); values.put(Audio.Media.IS_MUSIC, music); + values.put(Audio.Media.IS_PODCAST, podcasts); } else if (isImage) { // nothing right now } diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp index 2810a9c..8eb638e 100644 --- a/media/jni/android_media_MediaRecorder.cpp +++ b/media/jni/android_media_MediaRecorder.cpp @@ -60,15 +60,18 @@ static sp<Surface> get_surface(JNIEnv* env, jobject clazz) return sp<Surface>(p); } -static void process_media_recorder_call(JNIEnv *env, status_t opStatus, const char* exception, const char* message) +// Returns true if it throws an exception. +static bool process_media_recorder_call(JNIEnv *env, status_t opStatus, const char* exception, const char* message) { LOGV("process_media_recorder_call"); if (opStatus == (status_t)INVALID_OPERATION) { jniThrowException(env, "java/lang/IllegalStateException", NULL); + return true; } else if (opStatus != (status_t)OK) { jniThrowException(env, exception, message); + return true; } - return; + return false; } static void android_media_MediaRecorder_setCamera(JNIEnv* env, jobject thiz, jobject camera) @@ -196,7 +199,9 @@ android_media_MediaRecorder_prepare(JNIEnv *env, jobject thiz) if (surface != NULL) { const sp<Surface>& native_surface = get_surface(env, surface); LOGI("prepare: surface=%p (id=%d)", native_surface.get(), native_surface->ID()); - process_media_recorder_call(env, mr->setPreviewSurface(native_surface), "java/lang/RuntimeException", "setPreviewSurface failed."); + if (process_media_recorder_call(env, mr->setPreviewSurface(native_surface), "java/lang/RuntimeException", "setPreviewSurface failed.")) { + return; + } } process_media_recorder_call(env, mr->prepare(), "java/io/IOException", "prepare failed."); } diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp index 7872a8d..559f9d5 100644 --- a/media/jni/soundpool/SoundPool.cpp +++ b/media/jni/soundpool/SoundPool.cpp @@ -64,13 +64,6 @@ SoundPool::SoundPool(jobject soundPoolRef, int maxChannels, int streamType, int mChannels.push_back(&mChannelPool[i]); } - if (AudioSystem::getOutputFrameCount(&mFrameCount) != NO_ERROR) { - mFrameCount = kDefaultFrameCount; - } - if (AudioSystem::getOutputSamplingRate(&mSampleRate) != NO_ERROR) { - mSampleRate = kDefaultSampleRate; - } - // start decode thread startThreads(); } @@ -481,8 +474,8 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV { AudioTrack* oldTrack; - LOGV("play: sampleID=%d, channelID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f", - sample->sampleID(), nextChannelID, leftVolume, rightVolume, priority, loop, rate); + LOGV("play %p: sampleID=%d, channelID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f", + this, sample->sampleID(), nextChannelID, leftVolume, rightVolume, priority, loop, rate); // if not idle, this voice is being stolen if (mState != IDLE) { @@ -496,9 +489,17 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV } // initialize track + int afFrameCount; + int afSampleRate; + if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) { + afFrameCount = kDefaultFrameCount; + } + if (AudioSystem::getOutputSamplingRate(&afSampleRate) != NO_ERROR) { + afSampleRate = kDefaultSampleRate; + } int numChannels = sample->numChannels(); uint32_t sampleRate = uint32_t(float(sample->sampleRate()) * rate + 0.5); - uint32_t bufferFrames = (mSoundPool->mFrameCount * sampleRate) / mSoundPool->mSampleRate; + uint32_t bufferFrames = (afFrameCount * sampleRate) / afSampleRate; uint32_t frameCount = 0; if (loop) { @@ -511,12 +512,21 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV } AudioTrack* newTrack; + + // mToggle toggles each time a track is started on a given channel. + // The toggle is concatenated with the SoundChannel address and passed to AudioTrack + // as callback user data. This enables the detection of callbacks received from the old + // audio track while the new one is being started and avoids processing them with + // wrong audio audio buffer size (mAudioBufferSize) + unsigned long toggle = mToggle ^ 1; + void *userData = (void *)((unsigned long)this | toggle); + #ifdef USE_SHARED_MEM_BUFFER newTrack = new AudioTrack(mSoundPool->streamType(), sampleRate, sample->format(), - numChannels, sample->getIMemory(), 0, callback, this); + numChannels, sample->getIMemory(), 0, callback, userData); #else newTrack = new AudioTrack(mSoundPool->streamType(), sampleRate, sample->format(), - numChannels, frameCount, 0, callback, this, bufferFrames); + numChannels, frameCount, 0, callback, userData, bufferFrames); #endif if (newTrack->initCheck() != NO_ERROR) { LOGE("Error creating AudioTrack"); @@ -529,6 +539,8 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV { Mutex::Autolock lock(&mLock); + // From now on, AudioTrack callbacks recevieved with previous toggle value will be ignored. + mToggle = toggle; oldTrack = mAudioTrack; mAudioTrack = newTrack; mPos = 0; @@ -583,7 +595,13 @@ void SoundChannel::nextEvent() void SoundChannel::callback(int event, void* user, void *info) { - SoundChannel* channel = static_cast<SoundChannel*>(user); + unsigned long toggle = (unsigned long)user & 1; + SoundChannel* channel = static_cast<SoundChannel*>((void *)((unsigned long)user & ~1)); + + if (channel->mToggle != toggle) { + LOGV("callback with wrong toggle"); + return; + } channel->process(event, info); } @@ -592,7 +610,7 @@ void SoundChannel::process(int event, void *info) //LOGV("process(%d)", mChannelID); sp<Sample> sample = mSample; - LOGV("SoundChannel::process event %d", event); +// LOGV("SoundChannel::process event %d", event); if (event == AudioTrack::EVENT_MORE_DATA) { AudioTrack::Buffer* b = static_cast<AudioTrack::Buffer *>(info); diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h index d02ae8b..7802781 100644 --- a/media/jni/soundpool/SoundPool.h +++ b/media/jni/soundpool/SoundPool.h @@ -118,7 +118,7 @@ protected: class SoundChannel : public SoundEvent { public: enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING }; - SoundChannel() : mAudioTrack(0), mState(IDLE), mNumChannels(1), mPos(0) {} + SoundChannel() : mAudioTrack(0), mState(IDLE), mNumChannels(1), mPos(0), mToggle(0) {} ~SoundChannel(); void init(SoundPool* soundPool); void play(const sp<Sample>& sample, int channelID, float leftVolume, float rightVolume, @@ -151,6 +151,7 @@ private: int mNumChannels; int mPos; int mAudioBufferSize; + unsigned long mToggle; }; // application object for managing a pool of sounds @@ -215,8 +216,6 @@ private: int mAllocated; int mNextSampleID; int mNextChannelID; - int mFrameCount; - int mSampleRate; bool mQuit; }; diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index 2a697b9..8020da2 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ AudioTrack.cpp \ IAudioFlinger.cpp \ + IAudioFlingerClient.cpp \ IAudioTrack.cpp \ IAudioRecord.cpp \ AudioRecord.cpp \ diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 3d39181..a987b92 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -128,8 +128,22 @@ status_t AudioRecord::set( return BAD_VALUE; } - // TODO: Get input frame count from hardware. - int minFrameCount = 1024*2; + size_t inputBuffSizeInBytes = -1; + if (AudioSystem::getInputBufferSize(sampleRate, format, channelCount, &inputBuffSizeInBytes) + != NO_ERROR) { + LOGE("AudioSystem could not query the input buffer size."); + return NO_INIT; + } + if (inputBuffSizeInBytes == 0) { + LOGE("Recording parameters are not supported: sampleRate %d, channelCount %d, format %d", + sampleRate, channelCount, format); + return BAD_VALUE; + } + int frameSizeInBytes = channelCount * (format == AudioSystem::PCM_16_BIT ? 2 : 1); + + // We use 2* size of input buffer for ping pong use of record buffer. + int minFrameCount = 2 * inputBuffSizeInBytes / frameSizeInBytes; + LOGV("AudioRecord::set() minFrameCount = %d", minFrameCount); if (frameCount == 0) { frameCount = minFrameCount; diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index a375b55..cf91105 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -15,6 +15,8 @@ */ #define LOG_TAG "AudioSystem" +//#define LOG_NDEBUG 0 + #include <utils/Log.h> #include <utils/IServiceManager.h> #include <media/AudioSystem.h> @@ -26,12 +28,17 @@ namespace android { // client singleton for AudioFlinger binder interface Mutex AudioSystem::gLock; sp<IAudioFlinger> AudioSystem::gAudioFlinger; -sp<AudioSystem::DeathNotifier> AudioSystem::gDeathNotifier; +sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient; audio_error_callback AudioSystem::gAudioErrorCallback = NULL; // Cached values int AudioSystem::gOutSamplingRate = 0; int AudioSystem::gOutFrameCount = 0; uint32_t AudioSystem::gOutLatency = 0; +// Cached values for recording queries +uint32_t AudioSystem::gPrevInSamplingRate = 16000; +int AudioSystem::gPrevInFormat = AudioSystem::PCM_16_BIT; +int AudioSystem::gPrevInChannelCount = 1; +size_t AudioSystem::gInBuffSize = 0; // establish binder interface to AudioFlinger service @@ -48,15 +55,16 @@ const sp<IAudioFlinger>& AudioSystem::get_audio_flinger() LOGW("AudioFlinger not published, waiting..."); usleep(500000); // 0.5 s } while(true); - if (gDeathNotifier == NULL) { - gDeathNotifier = new DeathNotifier(); + if (gAudioFlingerClient == NULL) { + gAudioFlingerClient = new AudioFlingerClient(); } else { if (gAudioErrorCallback) { gAudioErrorCallback(NO_ERROR); } } - binder->linkToDeath(gDeathNotifier); + binder->linkToDeath(gAudioFlingerClient); gAudioFlinger = interface_cast<IAudioFlinger>(binder); + gAudioFlinger->registerClient(gAudioFlingerClient); // Cache frequently accessed parameters gOutFrameCount = (int)gAudioFlinger->frameCount(); gOutSamplingRate = (int)gAudioFlinger->sampleRate(); @@ -250,7 +258,7 @@ status_t AudioSystem::getOutputSamplingRate(int* samplingRate) const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; // gOutSamplingRate is updated by get_audio_flinger() - } + } *samplingRate = gOutSamplingRate; return NO_ERROR; @@ -261,7 +269,7 @@ status_t AudioSystem::getOutputFrameCount(int* frameCount) if (gOutFrameCount == 0) { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; - // gOutSamplingRate is updated by get_audio_flinger() + // gOutFrameCount is updated by get_audio_flinger() } *frameCount = gOutFrameCount; return NO_ERROR; @@ -279,14 +287,38 @@ status_t AudioSystem::getOutputLatency(uint32_t* latency) return NO_ERROR; } +status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, int format, int channelCount, + size_t* buffSize) +{ + // Do we have a stale gInBufferSize or are we requesting the input buffer size for new values + if ((gInBuffSize == 0) || (sampleRate != gPrevInSamplingRate) || (format != gPrevInFormat) + || (channelCount != gPrevInChannelCount)) { + // save the request params + gPrevInSamplingRate = sampleRate; + gPrevInFormat = format; + gPrevInChannelCount = channelCount; + + gInBuffSize = 0; + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) { + return PERMISSION_DENIED; + } + gInBuffSize = af->getInputBufferSize(sampleRate, format, channelCount); + } + *buffSize = gInBuffSize; + + return NO_ERROR; +} + // --------------------------------------------------------------------------- -void AudioSystem::DeathNotifier::binderDied(const wp<IBinder>& who) { +void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) { Mutex::Autolock _l(AudioSystem::gLock); AudioSystem::gAudioFlinger.clear(); AudioSystem::gOutSamplingRate = 0; AudioSystem::gOutFrameCount = 0; AudioSystem::gOutLatency = 0; + AudioSystem::gInBuffSize = 0; if (gAudioErrorCallback) { gAudioErrorCallback(DEAD_OBJECT); @@ -294,6 +326,15 @@ void AudioSystem::DeathNotifier::binderDied(const wp<IBinder>& who) { LOGW("AudioFlinger server died!"); } +void AudioSystem::AudioFlingerClient::audioOutputChanged(uint32_t frameCount, uint32_t samplingRate, uint32_t latency) { + + AudioSystem::gOutFrameCount = frameCount; + AudioSystem::gOutSamplingRate = samplingRate; + AudioSystem::gOutLatency = latency; + + LOGV("AudioFlinger output changed!"); +} + void AudioSystem::setErrorCallback(audio_error_callback cb) { Mutex::Autolock _l(AudioSystem::gLock); gAudioErrorCallback = cb; diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index f9f8568..63b2012 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -603,13 +603,17 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) if (__builtin_expect(result!=NO_ERROR, false)) { cblk->waitTimeMs += WAIT_PERIOD_MS; if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) { - LOGW( "obtainBuffer timed out (is the CPU pegged?) " - "user=%08x, server=%08x", cblk->user, cblk->server); - mAudioTrack->start(); // FIXME: Wake up audioflinger - timeout = 1; + // timing out when a loop has been set and we have already written upto loop end + // is a normal condition: no need to wake AudioFlinger up. + if (cblk->user < cblk->loopEnd) { + LOGW( "obtainBuffer timed out (is the CPU pegged?) " + "user=%08x, server=%08x", cblk->user, cblk->server); + mAudioFlinger->wakeUp(); + timeout = 1; + } cblk->waitTimeMs = 0; } - ; + if (--waitCount == 0) { return TIMED_OUT; } diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 018ea6c..4215820 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -51,6 +51,9 @@ enum { GET_MIC_MUTE, IS_MUSIC_ACTIVE, SET_PARAMETER, + REGISTER_CLIENT, + GET_INPUTBUFFERSIZE, + WAKE_UP }; class BpAudioFlinger : public BpInterface<IAudioFlinger> @@ -303,6 +306,33 @@ public: remote()->transact(SET_PARAMETER, data, &reply); return reply.readInt32(); } + + virtual void registerClient(const sp<IAudioFlingerClient>& client) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeStrongBinder(client->asBinder()); + remote()->transact(REGISTER_CLIENT, data, &reply); + } + + virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(sampleRate); + data.writeInt32(format); + data.writeInt32(channelCount); + remote()->transact(GET_INPUTBUFFERSIZE, data, &reply); + return reply.readInt32(); + } + + virtual void wakeUp() + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + remote()->transact(WAKE_UP, data, &reply); + return; + } }; IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger"); @@ -470,6 +500,26 @@ status_t BnAudioFlinger::onTransact( reply->writeInt32( setParameter(key, value) ); return NO_ERROR; } break; + case REGISTER_CLIENT: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient>(data.readStrongBinder()); + registerClient(client); + return NO_ERROR; + } break; + case GET_INPUTBUFFERSIZE: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + uint32_t sampleRate = data.readInt32(); + int format = data.readInt32(); + int channelCount = data.readInt32(); + reply->writeInt32( getInputBufferSize(sampleRate, format, channelCount) ); + return NO_ERROR; + } break; + case WAKE_UP: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + wakeUp(); + return NO_ERROR; + } break; + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp new file mode 100644 index 0000000..d956266 --- /dev/null +++ b/media/libmedia/IAudioFlingerClient.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "IAudioFlingerClient" +#include <utils/Log.h> + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Parcel.h> + +#include <media/IAudioFlingerClient.h> + +namespace android { + +enum { + AUDIO_OUTPUT_CHANGED = IBinder::FIRST_CALL_TRANSACTION +}; + +class BpAudioFlingerClient : public BpInterface<IAudioFlingerClient> +{ +public: + BpAudioFlingerClient(const sp<IBinder>& impl) + : BpInterface<IAudioFlingerClient>(impl) + { + } + + void audioOutputChanged(uint32_t frameCount, uint32_t samplingRate, uint32_t latency) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlingerClient::getInterfaceDescriptor()); + data.writeInt32(frameCount); + data.writeInt32(samplingRate); + data.writeInt32(latency); + remote()->transact(AUDIO_OUTPUT_CHANGED, data, &reply); + } +}; + +IMPLEMENT_META_INTERFACE(AudioFlingerClient, "android.media.IAudioFlingerClient"); + +// ---------------------------------------------------------------------- + +#define CHECK_INTERFACE(interface, data, reply) \ + do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ + LOGW("Call incorrectly routed to " #interface); \ + return PERMISSION_DENIED; \ + } } while (0) + +status_t BnAudioFlingerClient::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case AUDIO_OUTPUT_CHANGED: { + CHECK_INTERFACE(IAudioFlingerClient, data, reply); + uint32_t frameCount = data.readInt32(); + uint32_t samplingRate = data.readInt32(); + uint32_t latency = data.readInt32(); + audioOutputChanged(frameCount, samplingRate, latency); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp index f0edf88..ead24d4 100644 --- a/media/libmedia/JetPlayer.cpp +++ b/media/libmedia/JetPlayer.cpp @@ -214,12 +214,15 @@ int JetPlayer::render() { } p += count * pLibConfig->numChannels; num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM); + + // send events that were generated (if any) to the event callback + fireEventsFromJetQueue(); } // update playback state //LOGV("JetPlayer::render(): updating state"); JET_Status(mEasData, &mJetStatus); - fireEventOnStatusChange(); + fireUpdateOnStatusChange(); mPaused = mJetStatus.paused; mMutex.unlock(); // UNLOCK ]]]]]]]] ----------------------------------- @@ -261,9 +264,9 @@ threadExit: //------------------------------------------------------------------------------------------------- -// fire up an event if any of the status fields has changed +// fire up an update if any of the status fields has changed // precondition: mMutex locked -void JetPlayer::fireEventOnStatusChange() +void JetPlayer::fireUpdateOnStatusChange() { if( (mJetStatus.currentUserID != mPreviousJetStatus.currentUserID) ||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) { @@ -303,9 +306,31 @@ void JetPlayer::fireEventOnStatusChange() //------------------------------------------------------------------------------------------------- -int JetPlayer::openFile(const char* path) +// fire up all the JET events in the JET engine queue (until the queue is empty) +// precondition: mMutex locked +void JetPlayer::fireEventsFromJetQueue() +{ + if(!mEventCallback) { + // no callback, just empty the event queue + while (JET_GetEvent(mEasData, NULL, NULL)) { } + return; + } + + EAS_U32 rawEvent; + while (JET_GetEvent(mEasData, &rawEvent, NULL)) { + mEventCallback( + JetPlayer::JET_EVENT, + rawEvent, + -1, + mJavaJetPlayerRef); + } +} + + +//------------------------------------------------------------------------------------------------- +int JetPlayer::loadFromFile(const char* path) { - LOGV("JetPlayer::openFile(): path=%s", path); + LOGV("JetPlayer::loadFromFile(): path=%s", path); Mutex::Autolock lock(mMutex); @@ -326,6 +351,29 @@ int JetPlayer::openFile(const char* path) return( result ); } + +//------------------------------------------------------------------------------------------------- +int JetPlayer::loadFromFD(const int fd, const long long offset, const long long length) +{ + LOGV("JetPlayer::loadFromFD(): fd=%d offset=%lld length=%lld", fd, offset, length); + + Mutex::Autolock lock(mMutex); + + mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE)); + mEasJetFileLoc->fd = fd; + mEasJetFileLoc->offset = offset; + mEasJetFileLoc->length = length; + mEasJetFileLoc->path = NULL; + + EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc); + if(result != EAS_SUCCESS) + mState = EAS_STATE_ERROR; + else + mState = EAS_STATE_OPEN; + return( result ); +} + + //------------------------------------------------------------------------------------------------- int JetPlayer::closeFile() { @@ -348,7 +396,7 @@ int JetPlayer::play() JET_Status(mEasData, &mJetStatus); this->dumpJetStatus(&mJetStatus); - fireEventOnStatusChange(); + fireUpdateOnStatusChange(); // wake up render thread LOGV("JetPlayer::play(): wakeup render thread"); @@ -368,7 +416,7 @@ int JetPlayer::pause() JET_Status(mEasData, &mJetStatus); this->dumpJetStatus(&mJetStatus); - fireEventOnStatusChange(); + fireUpdateOnStatusChange(); return result; @@ -408,6 +456,14 @@ int JetPlayer::triggerClip(int clipId) } //------------------------------------------------------------------------------------------------- +int JetPlayer::clearQueue() +{ + LOGV("JetPlayer::clearQueue"); + Mutex::Autolock lock(mMutex); + return JET_Clear_Queue(mEasData); +} + +//------------------------------------------------------------------------------------------------- void JetPlayer::dump() { LOGE("JetPlayer dump: JET file=%s", mEasJetFileLoc->path); diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp index 584d135..fa36460 100644 --- a/media/libmedia/ToneGenerator.cpp +++ b/media/libmedia/ToneGenerator.cpp @@ -97,10 +97,6 @@ ToneGenerator::ToneGenerator(int streamType, float volume) { LOGE("Unable to marshal AudioFlinger"); return; } - if (AudioSystem::getOutputFrameCount(&mBufferSize) != NO_ERROR) { - LOGE("Unable to marshal AudioFlinger"); - return; - } mStreamType = streamType; mVolume = volume; mpAudioTrack = 0; @@ -275,9 +271,9 @@ bool ToneGenerator::initAudioTrack() { mpAudioTrack = 0; } - // Open audio track in mono, PCM 16bit, default sampling rate, 2 buffers of + // Open audio track in mono, PCM 16bit, default sampling rate, default buffer size mpAudioTrack - = new AudioTrack(mStreamType, 0, AudioSystem::PCM_16_BIT, 1, NUM_PCM_BUFFERS*mBufferSize, 0, audioCallback, this, mBufferSize); + = new AudioTrack(mStreamType, 0, AudioSystem::PCM_16_BIT, 1, 0, 0, audioCallback, this, 0); if (mpAudioTrack == 0) { LOGE("AudioTrack allocation failed"); diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index ebdbda8..31ff507 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -172,7 +172,7 @@ status_t MediaPlayer::setDataSource(const sp<IMediaPlayer>& player) status_t MediaPlayer::setDataSource(const char *url) { LOGV("setDataSource(%s)", url); - status_t err = UNKNOWN_ERROR; + status_t err = BAD_VALUE; if (url != NULL) { const sp<IMediaPlayerService>& service(getMediaPlayerService()); if (service != 0) { @@ -199,7 +199,7 @@ status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface) { LOGV("setVideoSurface"); Mutex::Autolock _l(mLock); - if (mPlayer == 0) return UNKNOWN_ERROR; + if (mPlayer == 0) return NO_INIT; return mPlayer->setVideoSurface(surface->getISurface()); } @@ -219,7 +219,7 @@ status_t MediaPlayer::prepare() { LOGV("prepare"); Mutex::Autolock _l(mLock); - if (mPrepareSync) return UNKNOWN_ERROR; + if (mPrepareSync) return -EALREADY; mPrepareSync = true; status_t ret = prepareAsync_l(); if (ret != NO_ERROR) return ret; @@ -253,7 +253,6 @@ status_t MediaPlayer::start() status_t ret = mPlayer->start(); if (ret != NO_ERROR) { mCurrentState = MEDIA_PLAYER_STATE_ERROR; - ret = UNKNOWN_ERROR; } else { if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) { LOGV("playback completed immediately following start()"); @@ -275,7 +274,6 @@ status_t MediaPlayer::stop() status_t ret = mPlayer->stop(); if (ret != NO_ERROR) { mCurrentState = MEDIA_PLAYER_STATE_ERROR; - ret = UNKNOWN_ERROR; } else { mCurrentState = MEDIA_PLAYER_STOPPED; } @@ -295,7 +293,6 @@ status_t MediaPlayer::pause() status_t ret = mPlayer->pause(); if (ret != NO_ERROR) { mCurrentState = MEDIA_PLAYER_STATE_ERROR; - ret = UNKNOWN_ERROR; } else { mCurrentState = MEDIA_PLAYER_PAUSED; } @@ -422,7 +419,6 @@ status_t MediaPlayer::reset() if (ret != NO_ERROR) { LOGE("reset() failed with return code (%d)", ret); mCurrentState = MEDIA_PLAYER_STATE_ERROR; - ret = UNKNOWN_ERROR; } else { mCurrentState = MEDIA_PLAYER_IDLE; } diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 53831717..9e366e2 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -61,113 +61,32 @@ pid_t gettid() { return syscall(__NR_gettid);} #undef __KERNEL__ #endif -/* - When USE_SIGBUS_HANDLER is set to 1, a handler for SIGBUS will be - installed, which allows us to recover when there is a read error - when accessing an mmap'ed file. However, since the kernel folks - don't seem to like it when non kernel folks install signal handlers - in their own process, this is currently disabled. - Without the handler, the process hosting this service will die and - then be restarted. This is mostly OK right now because the process is - not being shared with any other services, and clients of the service - will be notified of its death in their MediaPlayer.onErrorListener - callback, assuming they have installed one, and can then attempt to - do their own recovery. - It does open us up to a DOS attack against the media server, where - a malicious application can trivially force the media server to - restart continuously. -*/ -#define USE_SIGBUS_HANDLER 0 + +namespace android { // TODO: Temp hack until we can register players -static const char* MIDI_FILE_EXTS[] = -{ - ".mid", - ".smf", - ".xmf", - ".imy", - ".rtttl", - ".rtx", - ".ota" +typedef struct { + const char *extension; + const player_type playertype; +} extmap; +extmap FILE_EXTS [] = { + {".mid", SONIVOX_PLAYER}, + {".midi", SONIVOX_PLAYER}, + {".smf", SONIVOX_PLAYER}, + {".xmf", SONIVOX_PLAYER}, + {".imy", SONIVOX_PLAYER}, + {".rtttl", SONIVOX_PLAYER}, + {".rtx", SONIVOX_PLAYER}, + {".ota", SONIVOX_PLAYER}, + {".ogg", VORBIS_PLAYER}, + {".oga", VORBIS_PLAYER}, }; -namespace android { - // TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround /* static */ const uint32_t MediaPlayerService::AudioOutput::kAudioVideoDelayMs = 96; /* static */ int MediaPlayerService::AudioOutput::mMinBufferCount = 4; /* static */ bool MediaPlayerService::AudioOutput::mIsOnEmulator = false; -static struct sigaction oldact; -static pthread_key_t sigbuskey; - -static void sigbushandler(int signal, siginfo_t *info, void *context) -{ - char *faultaddr = (char*) info->si_addr; - LOGE("SIGBUS at %p\n", faultaddr); - - struct mediasigbushandler* h = (struct mediasigbushandler*) pthread_getspecific(sigbuskey); - - if (h) { - if (h->len) { - if (faultaddr < h->base || faultaddr >= h->base + h->len) { - // outside specified range, call old handler - if (oldact.sa_flags & SA_SIGINFO) { - oldact.sa_sigaction(signal, info, context); - } else { - oldact.sa_handler(signal); - } - return; - } - } - - // no range specified or address was in range - - if (h->handlesigbus) { - if (h->handlesigbus(info, h)) { - // thread's handler didn't handle the signal - if (oldact.sa_flags & SA_SIGINFO) { - oldact.sa_sigaction(signal, info, context); - } else { - oldact.sa_handler(signal); - } - } - return; - } - - if (h->sigbusvar) { - // map in a zeroed out page so the operation can succeed - long pagesize = sysconf(_SC_PAGE_SIZE); - long pagemask = ~(pagesize - 1); - void * pageaddr = (void*) (((long)(faultaddr)) & pagemask); - - void * bar = mmap( pageaddr, pagesize, PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0); - if (bar == MAP_FAILED) { - LOGE("couldn't map zero page at %p: %s", pageaddr, strerror(errno)); - if (oldact.sa_flags & SA_SIGINFO) { - oldact.sa_sigaction(signal, info, context); - } else { - oldact.sa_handler(signal); - } - return; - } - - LOGE("setting sigbusvar at %p", h->sigbusvar); - *(h->sigbusvar) = 1; - return; - } - } - - LOGE("SIGBUS: no handler, or improperly configured handler (%p)", h); - - if (oldact.sa_flags & SA_SIGINFO) { - oldact.sa_sigaction(signal, info, context); - } else { - oldact.sa_handler(signal); - } - return; -} - void MediaPlayerService::instantiate() { defaultServiceManager()->addService( String16("media.player"), new MediaPlayerService()); @@ -177,25 +96,10 @@ MediaPlayerService::MediaPlayerService() { LOGV("MediaPlayerService created"); mNextConnId = 1; - - pthread_key_create(&sigbuskey, NULL); - - -#if USE_SIGBUS_HANDLER - struct sigaction act; - memset(&act,0, sizeof act); - act.sa_sigaction = sigbushandler; - act.sa_flags = SA_SIGINFO; - sigaction(SIGBUS, &act, &oldact); -#endif } MediaPlayerService::~MediaPlayerService() { -#if USE_SIGBUS_HANDLER - sigaction(SIGBUS, &oldact, NULL); -#endif - pthread_key_delete(sigbuskey); LOGV("MediaPlayerService destroyed"); } @@ -481,7 +385,7 @@ static player_type getPlayerType(int fd, int64_t offset, int64_t length) locator.offset = offset; locator.length = length; EAS_HANDLE eashandle; - if (EAS_OpenFile(easdata, &locator, &eashandle, NULL) == EAS_SUCCESS) { + if (EAS_OpenFile(easdata, &locator, &eashandle) == EAS_SUCCESS) { EAS_CloseFile(easdata, eashandle); EAS_Shutdown(easdata); return SONIVOX_PLAYER; @@ -498,22 +402,16 @@ static player_type getPlayerType(const char* url) // use MidiFile for MIDI extensions int lenURL = strlen(url); - for (int i = 0; i < NELEM(MIDI_FILE_EXTS); ++i) { - int len = strlen(MIDI_FILE_EXTS[i]); + for (int i = 0; i < NELEM(FILE_EXTS); ++i) { + int len = strlen(FILE_EXTS[i].extension); int start = lenURL - len; if (start > 0) { - if (!strncmp(url + start, MIDI_FILE_EXTS[i], len)) { - LOGV("Type is MIDI"); - return SONIVOX_PLAYER; + if (!strncmp(url + start, FILE_EXTS[i].extension, len)) { + return FILE_EXTS[i].playertype; } } } - if (strcmp(url + strlen(url) - 4, ".ogg") == 0) { - LOGV("Type is Vorbis"); - return VORBIS_PLAYER; - } - // Fall through to PV return PV_PLAYER; } @@ -539,7 +437,6 @@ static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie, if (p != NULL) { if (p->initCheck() == NO_ERROR) { p->setNotifyCallback(cookie, notifyFunc); - p->setSigBusHandlerStructTLSKey(sigbuskey); } else { p.clear(); } diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp index cfad66c..7ce2fab 100644 --- a/media/libmediaplayerservice/MidiFile.cpp +++ b/media/libmediaplayerservice/MidiFile.cpp @@ -40,8 +40,6 @@ static pid_t myTid() { return getpid(); } // ---------------------------------------------------------------------------- -extern pthread_key_t EAS_sigbuskey; - namespace android { // ---------------------------------------------------------------------------- @@ -132,7 +130,7 @@ status_t MidiFile::setDataSource(const char* path) mFileLocator.fd = -1; mFileLocator.offset = 0; mFileLocator.length = 0; - EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle, &mMemFailedVar); + EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle); if (result == EAS_SUCCESS) { updateState(); } @@ -148,12 +146,6 @@ status_t MidiFile::setDataSource(const char* path) return NO_ERROR; } -status_t MidiFile::setSigBusHandlerStructTLSKey(pthread_key_t key) -{ - EAS_sigbuskey = key; - return 0; -} - status_t MidiFile::setDataSource(int fd, int64_t offset, int64_t length) { LOGV("MidiFile::setDataSource fd=%d", fd); @@ -168,7 +160,7 @@ status_t MidiFile::setDataSource(int fd, int64_t offset, int64_t length) mFileLocator.fd = dup(fd); mFileLocator.offset = offset; mFileLocator.length = length; - EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle, &mMemFailedVar); + EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle); updateState(); if (result != EAS_SUCCESS) { @@ -332,7 +324,7 @@ status_t MidiFile::getDuration(int* duration) EAS_HANDLE easHandle = NULL; EAS_RESULT result = EAS_Init(&easData); if (result == EAS_SUCCESS) { - result = EAS_OpenFile(easData, &mFileLocator, &easHandle, NULL); + result = EAS_OpenFile(easData, &mFileLocator, &easHandle); } if (result == EAS_SUCCESS) { result = EAS_Prepare(easData, easHandle); @@ -451,8 +443,6 @@ int MidiFile::render() { LOGV("MidiFile::render"); - struct mediasigbushandler sigbushandler; - // allocate render buffer mAudioBuffer = new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * NUM_BUFFERS]; if (!mAudioBuffer) { @@ -468,10 +458,6 @@ int MidiFile::render() { mCondition.signal(); } - sigbushandler.handlesigbus = NULL; - sigbushandler.sigbusvar = mMemFailedVar; - pthread_setspecific(EAS_sigbuskey, &sigbushandler); - while (1) { mMutex.lock(); diff --git a/media/libmediaplayerservice/MidiFile.h b/media/libmediaplayerservice/MidiFile.h index 9d2dfdd..302f1cf 100644 --- a/media/libmediaplayerservice/MidiFile.h +++ b/media/libmediaplayerservice/MidiFile.h @@ -30,7 +30,6 @@ public: ~MidiFile(); virtual status_t initCheck(); - virtual status_t setSigBusHandlerStructTLSKey(pthread_key_t key); virtual status_t setDataSource(const char* path); virtual status_t setDataSource(int fd, int64_t offset, int64_t length); virtual status_t setVideoSurface(const sp<ISurface>& surface) { return UNKNOWN_ERROR; } @@ -57,7 +56,6 @@ private: Mutex mMutex; Condition mCondition; - int* mMemFailedVar; EAS_DATA_HANDLE mEasData; EAS_HANDLE mEasHandle; EAS_PCM* mAudioBuffer; diff --git a/media/libmediaplayerservice/VorbisPlayer.cpp b/media/libmediaplayerservice/VorbisPlayer.cpp index 9a64403..009d628 100644 --- a/media/libmediaplayerservice/VorbisPlayer.cpp +++ b/media/libmediaplayerservice/VorbisPlayer.cpp @@ -455,13 +455,15 @@ int VorbisPlayer::render() { current_section = 0; numread = ov_read(&mVorbisFile, mAudioBuffer, AUDIOBUFFER_SIZE, ¤t_section); } else { - sendEvent(MEDIA_PLAYBACK_COMPLETE); mAudioSink->stop(); audioStarted = false; mRender = false; mPaused = true; int endpos = ov_time_tell(&mVorbisFile); + LOGV("send MEDIA_PLAYBACK_COMPLETE"); + sendEvent(MEDIA_PLAYBACK_COMPLETE); + // wait until we're started again LOGV("playback complete - wait for signal"); mCondition.wait(mMutex); diff --git a/media/sdutils/sdutil.cpp b/media/sdutils/sdutil.cpp index 0daa523..a9aabf0 100644 --- a/media/sdutils/sdutil.cpp +++ b/media/sdutils/sdutil.cpp @@ -114,6 +114,16 @@ static int unmount(const char* path) { return -1; } +static int format(const char* path) { + String16 string(path); + + if (isMounted(path)) + return -EBUSY; + gMountService->formatMedia(string); + + return 0; +} + static int umsEnable(bool enable) { gMountService->setMassStorageEnabled(enable); return 0; @@ -129,6 +139,9 @@ int main(int argc, char **argv) if (strcmp(command, "mount") == 0) { android::init(); return android::mount(argument); + } else if (strcmp(command, "format") == 0) { + android::init(); + return android::format(argument); } else if (strcmp(command, "unmount") == 0) { android::init(); return android::unmount(argument); @@ -145,6 +158,7 @@ int main(int argc, char **argv) fprintf(stderr, "usage:\n" " sdutil mount <mount path> - mounts the SD card at the given mount point\n" " sdutil unmount <mount path> - unmounts the SD card at the given mount point\n" + " sdutil format <mount path> - formats the SD card at the given mount point\n" " sdutil ums enable - enables USB mass storage\n" " sdutil ums disable - disnables USB mass storage\n" ); diff --git a/media/tests/MediaFrameworkTest/AndroidManifest.xml b/media/tests/MediaFrameworkTest/AndroidManifest.xml index 16e658a..a32f590 100644 --- a/media/tests/MediaFrameworkTest/AndroidManifest.xml +++ b/media/tests/MediaFrameworkTest/AndroidManifest.xml @@ -42,5 +42,10 @@ android:targetPackage="com.android.mediaframeworktest" android:label="MediaFramework unit tests InstrumentationRunner"> </instrumentation> + + <instrumentation android:name=".MediaRecorderStressTestRunner" + android:targetPackage="com.android.mediaframeworktest" + android:label="MediaRecorder stress tests InstrumentationRunner"> + </instrumentation> </manifest> diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java index 3d3878e..1731940 100755 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java @@ -21,6 +21,7 @@ import com.android.mediaframeworktest.functional.SimTonesTest; import com.android.mediaframeworktest.functional.MediaMetadataTest; import com.android.mediaframeworktest.functional.CameraTest; import com.android.mediaframeworktest.functional.MediaRecorderTest; +import com.android.mediaframeworktest.functional.MediaAudioTrackTest; import junit.framework.TestSuite; @@ -48,6 +49,7 @@ public class MediaFrameworkTestRunner extends InstrumentationTestRunner { suite.addTestSuite(MediaMetadataTest.class); suite.addTestSuite(CameraTest.class); suite.addTestSuite(MediaRecorderTest.class); + suite.addTestSuite(MediaAudioTrackTest.class); return suite; } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java index 5843007..5e9c488 100755 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java @@ -25,16 +25,16 @@ package com.android.mediaframeworktest; public class MediaNames { //Audio files - public static final String MP3CBR = "/sdcard/music/MP3CBR.mp3"; - public static final String MP3VBR = "/sdcard/music/MP3VBR.mp3"; - public static final String SHORTMP3 = "/sdcard/music/SHORTMP3.mp3"; - public static final String MIDI = "/sdcard/music/MIDI.mid"; - public static final String WMA9 = "/sdcard/music/WMA9.wma"; - public static final String WMA10 = "/sdcard/music/WMA10.wma"; - public static final String WAV = "/sdcard/music/complicated_wav.wav"; - public static final String AMR = "/sdcard/music/AMRNB.amr"; - public static final String OGG = "/sdcard/music/Mists_of_Time-4T.ogg"; - public static final String OGGSHORT = "/sdcard/music/Skippy.ogg"; + public static final String MP3CBR = "/sdcard/media_api/music/MP3CBR.mp3"; + public static final String MP3VBR = "/sdcard/media_api/music/MP3VBR.mp3"; + public static final String SHORTMP3 = "/sdcard/media_api/music/SHORTMP3.mp3"; + public static final String MIDI = "/sdcard/media_api/music/MIDI.mid"; + public static final String WMA9 = "/sdcard/media_api/music/WMA9.wma"; + public static final String WMA10 = "/sdcard/media_api/music/WMA10.wma"; + public static final String WAV = "/sdcard/media_api/music/complicated_wav.wav"; + public static final String AMR = "/sdcard/media_api/music/AMRNB.amr"; + public static final String OGG = "/sdcard/media_api/music/Mists_of_Time-4T.ogg"; + public static final String OGGSHORT = "/sdcard/media_api/music/Skippy.ogg"; public static final int MP3CBR_LENGTH = 231116; public static final int MP3VBR_LENGTH = 126407; @@ -60,20 +60,20 @@ public class MediaNames { //public static final String VIDEO_RTSP3GP = "rtsp://193.159.241.21/sp/alizee05.3gp"; //local video - public static final String VIDEO_MP4 = "/sdcard/video/gingerkids.MP4"; - public static final String VIDEO_LONG_3GP = "/sdcard/video/radiohead.3gp"; - public static final String VIDEO_SHORT_3GP = "/sdcard/video/short.3gp"; - public static final String VIDEO_LARGE_SIZE_3GP = "/sdcard/video/border_large.3gp"; - public static final String VIDEO_H263_AAC = "/sdcard/video/H263_AAC.3gp"; - public static final String VIDEO_H263_AMR = "/sdcard/video/H263_AMR.3gp"; - public static final String VIDEO_H264_AAC = "/sdcard/video/H264_AAC.3gp"; - public static final String VIDEO_H264_AMR = "/sdcard/video/H264_AMR.3gp"; - public static final String VIDEO_WMV = "/sdcard/video/bugs.wmv"; - public static final String VIDEO_HIGHRES_H263 = "/sdcard/video/h263_qcif_30fps.3gp"; - public static final String VIDEO_HIGHRES_MP4 = "/sdcard/video/mpeg4_qvga_24fps.3gp"; + public static final String VIDEO_MP4 = "/sdcard/media_api/video/gingerkids.MP4"; + public static final String VIDEO_LONG_3GP = "/sdcard/media_api/video/radiohead.3gp"; + public static final String VIDEO_SHORT_3GP = "/sdcard/media_api/video/short.3gp"; + public static final String VIDEO_LARGE_SIZE_3GP = "/sdcard/media_api/video/border_large.3gp"; + public static final String VIDEO_H263_AAC = "/sdcard/media_api/video/H263_AAC.3gp"; + public static final String VIDEO_H263_AMR = "/sdcard/media_api/video/H263_AMR.3gp"; + public static final String VIDEO_H264_AAC = "/sdcard/media_api/video/H264_AAC.3gp"; + public static final String VIDEO_H264_AMR = "/sdcard/media_api/video/H264_AMR.3gp"; + public static final String VIDEO_WMV = "/sdcard/media_api/video/bugs.wmv"; + public static final String VIDEO_HIGHRES_H263 = "/sdcard/media_api/video/h263_qcif_30fps.3gp"; + public static final String VIDEO_HIGHRES_MP4 = "/sdcard/media_api/video/mpeg4_qvga_24fps.3gp"; //ringtone - public static final String ringtone = "/sdcard/ringtones/F1_NewVoicemail.mp3"; + public static final String ringtone = "/sdcard/media_api/ringtones/F1_NewVoicemail.mp3"; //streaming mp3 public static final String STREAM_LARGE_MP3 = @@ -110,264 +110,266 @@ public class MediaNames { "http://wms.pv.com:7070/MediaDownloadContent/UserUploads/beefcake.mp3"; //Sonivox - public static String MIDIFILES[] = { "/sdcard/music/Leadsol.mxmf", - "/sdcard/music/abba.imy", "/sdcard/music/ants.mid", - "/sdcard/music/greensleeves.rtttl", "/sdcard/music/test.ota"}; + public static String MIDIFILES[] = { + "/sdcard/media_api/music/Leadsol.mxmf", + "/sdcard/media_api/music/abba.imy", "/sdcard/media_api/music/ants.mid", + "/sdcard/media_api/music/greensleeves.rtttl", "/sdcard/media_api/music/test.ota"}; //Performance measurement - public static String[] WAVFILES = { "/sdcard/music_perf/WAV/M1F1-AlawWE-AFsp.wav", - "/sdcard/music_perf/WAV/M1F1-float64-AFsp.wav", - "/sdcard/music_perf/WAV/song.wav", - "/sdcard/music_perf/WAV/WAVEtest.wav", - "/sdcard/music_perf/WAV/WAVEtest_out.wav", - "/sdcard/music_perf/WAV/test_out.wav"}; - + public static String[] WAVFILES = { + "/sdcard/media_api/music_perf/WAV/M1F1-AlawWE-AFsp.wav", + "/sdcard/media_api/music_perf/WAV/M1F1-float64-AFsp.wav", + "/sdcard/media_api/music_perf/WAV/song.wav", + "/sdcard/media_api/music_perf/WAV/WAVEtest.wav", + "/sdcard/media_api/music_perf/WAV/WAVEtest_out.wav", + "/sdcard/media_api/music_perf/WAV/test_out.wav"}; + public static String[] AMRNBFILES = { - "/sdcard/music_perf/AMR/AI_AMR-NB_5.9kbps_6.24kbps_8khz_mono_NMC.amr", - "/sdcard/music_perf/AMR/AI_AMR-NB_5.15kbps_5.46kbps_8khz_mono_NMC.amr", - "/sdcard/music_perf/AMR/AI_AMR-NB_7.4kbps_7.80kbps_8khz_mono_NMC.amr", - "/sdcard/music_perf/AMR/AI_AMR-NB_7.95kbps_9.6kbps_8khz_mono_NMC.amr", - "/sdcard/music_perf/AMR/AI_AMR-NB_10.2kbps_10.48kbps_8khz_mono_NMC.amr"}; + "/sdcard/media_api/music_perf/AMR/AI_AMR-NB_5.9kbps_6.24kbps_8khz_mono_NMC.amr", + "/sdcard/media_api/music_perf/AMR/AI_AMR-NB_5.15kbps_5.46kbps_8khz_mono_NMC.amr", + "/sdcard/media_api/music_perf/AMR/AI_AMR-NB_7.4kbps_7.80kbps_8khz_mono_NMC.amr", + "/sdcard/media_api/music_perf/AMR/AI_AMR-NB_7.95kbps_9.6kbps_8khz_mono_NMC.amr", + "/sdcard/media_api/music_perf/AMR/AI_AMR-NB_10.2kbps_10.48kbps_8khz_mono_NMC.amr"}; public static String[] AMRWBFILES = { - "/sdcard/music_perf/AMRWB/NIN_AMR-WB_15.85kbps_16kbps.amr", - "/sdcard/music_perf/AMRWB/NIN_AMR-WB_18.25kbps_18kbps.amr", - "/sdcard/music_perf/AMRWB/NIN_AMR-WB_19.85kbps_20kbps.amr", - "/sdcard/music_perf/AMRWB/NIN_AMR-WB_23.05kbps_23kbps.amr", - "/sdcard/music_perf/AMRWB/NIN_AMR-WB_23.85kbps_24kbps.amr", - "/sdcard/music_perf/AMRWB/PD_AMR-WB_19.85kbps_20kbps.amr", - "/sdcard/music_perf/AMRWB/PD_AMR-WB_23.05kbps_23kbps.amr", - "/sdcard/music_perf/AMRWB/PD_AMR-WB_23.85kbps_24kbps.amr", - "/sdcard/music_perf/AMRWB/WC_AMR-WB_23.05kbps_23kbps.amr", - "/sdcard/music_perf/AMRWB/WC_AMR-WB_23.85kbps_24kbps.amr", }; + "/sdcard/media_api/music_perf/AMRWB/NIN_AMR-WB_15.85kbps_16kbps.amr", + "/sdcard/media_api/music_perf/AMRWB/NIN_AMR-WB_18.25kbps_18kbps.amr", + "/sdcard/media_api/music_perf/AMRWB/NIN_AMR-WB_19.85kbps_20kbps.amr", + "/sdcard/media_api/music_perf/AMRWB/NIN_AMR-WB_23.05kbps_23kbps.amr", + "/sdcard/media_api/music_perf/AMRWB/NIN_AMR-WB_23.85kbps_24kbps.amr", + "/sdcard/media_api/music_perf/AMRWB/PD_AMR-WB_19.85kbps_20kbps.amr", + "/sdcard/media_api/music_perf/AMRWB/PD_AMR-WB_23.05kbps_23kbps.amr", + "/sdcard/media_api/music_perf/AMRWB/PD_AMR-WB_23.85kbps_24kbps.amr", + "/sdcard/media_api/music_perf/AMRWB/WC_AMR-WB_23.05kbps_23kbps.amr", + "/sdcard/media_api/music_perf/AMRWB/WC_AMR-WB_23.85kbps_24kbps.amr", }; public static String[] MP3FILES = { - "/sdcard/music_perf/MP3/NIN_56kbps_32khz_stereo_VBR_MCA.MP3", - "/sdcard/music_perf/MP3/NIN_80kbps_32khz_stereo_VBR_MCA.mp3", - "/sdcard/music_perf/MP3/NIN_80kbps_44.1khz_stereo_VBR_MCA.mp3", - "/sdcard/music_perf/MP3/NIN_80kbps_48khz_stereo_VBR_MCA.mp3", - "/sdcard/music_perf/MP3/NIN_112kbps_32khz_stereo_VBR_MCA.mp3", - "/sdcard/music_perf/MP3/NIN_112kbps_44.1khz_stereo_VBR_MCA.mp3", - "/sdcard/music_perf/MP3/NIN_112kbps_48khz_stereo_VBR_MCA.mp3", - "/sdcard/music_perf/MP3/NIN_192kbps_32khz_mono_CBR_MCA.mp3", - "/sdcard/music_perf/MP3/NIN_192kbps_44.1khz_mono_CBR_MCA.mp3", - "/sdcard/music_perf/MP3/NIN_192kbps_48khz_mono_CBR_MCA.mp3", - "/sdcard/music_perf/MP3/NIN_256kbps_44.1khz_mono_CBR_MCA.mp3", - "/sdcard/music_perf/MP3/NIN_256kbps_48khz_mono_CBR_MCA.mp3", - "/sdcard/music_perf/MP3/PD_112kbps_32khz_stereo_VBR_MCA.mp3", - "/sdcard/music_perf/MP3/PD_112kbps_44.1khz_stereo_VBR_MCA.mp3", - "/sdcard/music_perf/MP3/PD_112kbps_48khz_stereo_VBR_MCA.mp3", - "/sdcard/music_perf/MP3/PD_192kbps_32khz_mono_CBR_DPA.mp3", - "/sdcard/music_perf/MP3/PD_256kbps_44.1khz_mono_CBR_DPA.mp3", - "/sdcard/music_perf/MP3/PD_256kbps_48khz_mono_CBR_MCA.mp3", - "/sdcard/music_perf/MP3/WC_256kbps_44.1khz_mono_CBR_DPA.mp3", - "/sdcard/music_perf/MP3/WC_256kbps_48khz_mono_CBR_DPA.mp3", - "/sdcard/music_perf/regular_album_photo/Apologize.mp3", - "/sdcard/music_perf/regular_album_photo/Because_Of_You.mp3", - "/sdcard/music_perf/regular_album_photo/Complicated.mp3", - "/sdcard/music_perf/regular_album_photo/Glamorous.mp3", - "/sdcard/music_perf/regular_album_photo/Im_With_You.mp3", - "/sdcard/music_perf/regular_album_photo/Smile.mp3", - "/sdcard/music_perf/regular_album_photo/Suddenly_I_See.mp3", - "/sdcard/music_perf/regular_album_photo/When You Say Nothing At All.mp3", - "/sdcard/music_perf/regular_album_photo/my_happy_ending.mp3"}; + "/sdcard/media_api/music_perf/MP3/NIN_56kbps_32khz_stereo_VBR_MCA.MP3", + "/sdcard/media_api/music_perf/MP3/NIN_80kbps_32khz_stereo_VBR_MCA.mp3", + "/sdcard/media_api/music_perf/MP3/NIN_80kbps_44.1khz_stereo_VBR_MCA.mp3", + "/sdcard/media_api/music_perf/MP3/NIN_80kbps_48khz_stereo_VBR_MCA.mp3", + "/sdcard/media_api/music_perf/MP3/NIN_112kbps_32khz_stereo_VBR_MCA.mp3", + "/sdcard/media_api/music_perf/MP3/NIN_112kbps_44.1khz_stereo_VBR_MCA.mp3", + "/sdcard/media_api/music_perf/MP3/NIN_112kbps_48khz_stereo_VBR_MCA.mp3", + "/sdcard/media_api/music_perf/MP3/NIN_192kbps_32khz_mono_CBR_MCA.mp3", + "/sdcard/media_api/music_perf/MP3/NIN_192kbps_44.1khz_mono_CBR_MCA.mp3", + "/sdcard/media_api/music_perf/MP3/NIN_192kbps_48khz_mono_CBR_MCA.mp3", + "/sdcard/media_api/music_perf/MP3/NIN_256kbps_44.1khz_mono_CBR_MCA.mp3", + "/sdcard/media_api/music_perf/MP3/NIN_256kbps_48khz_mono_CBR_MCA.mp3", + "/sdcard/media_api/music_perf/MP3/PD_112kbps_32khz_stereo_VBR_MCA.mp3", + "/sdcard/media_api/music_perf/MP3/PD_112kbps_44.1khz_stereo_VBR_MCA.mp3", + "/sdcard/media_api/music_perf/MP3/PD_112kbps_48khz_stereo_VBR_MCA.mp3", + "/sdcard/media_api/music_perf/MP3/PD_192kbps_32khz_mono_CBR_DPA.mp3", + "/sdcard/media_api/music_perf/MP3/PD_256kbps_44.1khz_mono_CBR_DPA.mp3", + "/sdcard/media_api/music_perf/MP3/PD_256kbps_48khz_mono_CBR_MCA.mp3", + "/sdcard/media_api/music_perf/MP3/WC_256kbps_44.1khz_mono_CBR_DPA.mp3", + "/sdcard/media_api/music_perf/MP3/WC_256kbps_48khz_mono_CBR_DPA.mp3", + "/sdcard/media_api/music_perf/regular_album_photo/Apologize.mp3", + "/sdcard/media_api/music_perf/regular_album_photo/Because_Of_You.mp3", + "/sdcard/media_api/music_perf/regular_album_photo/Complicated.mp3", + "/sdcard/media_api/music_perf/regular_album_photo/Glamorous.mp3", + "/sdcard/media_api/music_perf/regular_album_photo/Im_With_You.mp3", + "/sdcard/media_api/music_perf/regular_album_photo/Smile.mp3", + "/sdcard/media_api/music_perf/regular_album_photo/Suddenly_I_See.mp3", + "/sdcard/media_api/music_perf/regular_album_photo/When You Say Nothing At All.mp3", + "/sdcard/media_api/music_perf/regular_album_photo/my_happy_ending.mp3"}; public static String[] AACFILES = { - "/sdcard/music_perf/AAC/AI_AAC_24kbps_12khz_Mono_1pCBR_SSE.mp4", - "/sdcard/music_perf/AAC/AI_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4", - "/sdcard/music_perf/AAC/AI_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4", - "/sdcard/music_perf/AAC/AI_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4", - "/sdcard/music_perf/AAC/AI_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4", - "/sdcard/music_perf/AAC/AI_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4", - "/sdcard/music_perf/AAC/NIN_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4", - "/sdcard/music_perf/AAC/NIN_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4", - "/sdcard/music_perf/AAC/NIN_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4", - "/sdcard/music_perf/AAC/NIN_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4", - "/sdcard/music_perf/AAC/NIN_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4", - "/sdcard/music_perf/AAC/PD_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4", - "/sdcard/music_perf/AAC/PD_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4", - "/sdcard/music_perf/AAC/PD_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4", - "/sdcard/music_perf/AAC/PD_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4", - "/sdcard/music_perf/AAC/PD_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4", - "/sdcard/music_perf/AAC/PV_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4", - "/sdcard/music_perf/AAC/PV_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4", - "/sdcard/music_perf/AAC/PV_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4", - "/sdcard/music_perf/AAC/PV_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4", - "/sdcard/music_perf/AAC/PV_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4", - "/sdcard/music_perf/AAC/WC_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4", - "/sdcard/music_perf/AAC/WC_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4", - "/sdcard/music_perf/AAC/WC_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4", - "/sdcard/music_perf/AAC/WC_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4", - "/sdcard/music_perf/AAC/WC_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/AI_AAC_24kbps_12khz_Mono_1pCBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/AI_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/AI_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/AI_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/AI_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/AI_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/NIN_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/NIN_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/NIN_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/NIN_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/NIN_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/PD_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/PD_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/PD_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/PD_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/PD_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/PV_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/PV_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/PV_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/PV_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/PV_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/WC_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/WC_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/WC_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/WC_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4", + "/sdcard/media_api/music_perf/AAC/WC_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4", }; - public static String[] VIDEOFILES = { "/sdcard/video_perf/AI_CTO_Mpeg4_32kbps_10fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4", - "/sdcard/video_perf/AI_CTO_Mpeg4_32kbps_12fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4", - "/sdcard/video_perf/AI_CTO_Mpeg4_32kbps_15fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4", - "/sdcard/video_perf/AI_CTO_Mpeg4_32kbps_5fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4", - "/sdcard/video_perf/AI_CTO_Mpeg4_32kbps_5fps_SQCIF_128x96+AAC_8kbps_8khz_mono_SSE.mp4", - "/sdcard/video_perf/AI_CTO_Mpeg4_32kbps_7.5fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4", - "/sdcard/video_perf/AI_WMV_1024kbps_20fps_QCIF_176x144_noaudio_SSE.wmv", - "/sdcard/video_perf/AI_WMV_1024kbps_25fps_QCIF_176x144_noaudio_SSE.wmv", - "/sdcard/video_perf/Chicken.wmv", - "/sdcard/video_perf/MP_qcif_15fps_100kbps_48kHz_192kbps_30secs.wmv", - "/sdcard/video_perf/NIN_CTO_H264_123kbps_5fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp", - "/sdcard/video_perf/NIN_CTO_H264_96kbps_10.2fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp", - "/sdcard/video_perf/NIN_CTO_H264_96kbps_12fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp", - "/sdcard/video_perf/NIN_CTO_H264_96kbps_15fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp", - "/sdcard/video_perf/NIN_CTO_Mpeg4_123kbps_15fps_QCIF_176x144+AAC_32kbps_22khz_mono_SSE.3gp", - "/sdcard/video_perf/NIN_CTO_Mpeg4_123kbps_7.5fps_QCIF_176x144+AAC_32kbps_22khz_stereo_SSE.3gp", - "/sdcard/video_perf/NIN_CTO_Mpeg4_128kbps_10fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp", - "/sdcard/video_perf/NIN_CTO_Mpeg4_128kbps_12fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp", - "/sdcard/video_perf/NIN_CTO_Mpeg4_128kbps_15fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp", - "/sdcard/video_perf/NIN_CTO_Mpeg4_128kbps_5fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp", - "/sdcard/video_perf/NIN_CTO_Mpeg4_128kbps_7.5fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp", - "/sdcard/video_perf/NIN_H263_128kbps_10fps_QCIF_174x144_noaudio_SSE.mp4", - "/sdcard/video_perf/NIN_H263_128kbps_15fps_QCIF_174x144_noaudio_SSE.mp4", - "/sdcard/video_perf/NIN_H263_48kbps_10fps_QCIF_174x144_noaudio_SSE.3gp", - "/sdcard/video_perf/NIN_H263_48kbps_12fps_QCIF_174x144_noaudio_SSE.3gp", - "/sdcard/video_perf/NIN_H264_123kbps_15fps_QCIF_176x144+AAC_32kbps_22khz_stereo_SSE.3gp", - "/sdcard/video_perf/NIN_H264_123kbps_7.5fps_QCIF_176x144+AAC_32kbps_22khz_stereo_SSE.3gp", - "/sdcard/video_perf/PV_H264_2000kbps_20fps_CIF_352x288+AAC_96kbps_48khz_stereo_SSE.mp4", - "/sdcard/video_perf/PV_H264_2000kbps_25fps_CIF_352x288+AAC_96kbps_48khz_stereo_SSE.mp4", - "/sdcard/video_perf/PV_H264_2000kbps_30fps_CIF_352x288+AAC_128kbps_48khz_stereo_SSE.mp4", - "/sdcard/video_perf/Stevie-1.wmv", - "/sdcard/video_perf/WC_H264_1600kbps_20fps_QCIF_176x144+AAC_96kbps_48khz_mono_SSE.mp4", - "/sdcard/video_perf/WC_H264_1600kbps_25fps_QCIF_176x144+AAC_96kbps_48khz_mono_SSE.mp4", - "/sdcard/video_perf/WC_H264_1600kbps_30fps_QCIF_176x144+AAC_96kbps_48khz_mono_SSE.mp4", - "/sdcard/video_perf/bugs.wmv", - "/sdcard/video_perf/niceday.wmv", - "/sdcard/video_perf/eaglesatopnflpe.wmv", + public static String[] VIDEOFILES = { "/sdcard/media_api/video_perf/AI_CTO_Mpeg4_32kbps_10fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4", + "/sdcard/media_api/video_perf/AI_CTO_Mpeg4_32kbps_12fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4", + "/sdcard/media_api/video_perf/AI_CTO_Mpeg4_32kbps_15fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4", + "/sdcard/media_api/video_perf/AI_CTO_Mpeg4_32kbps_5fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4", + "/sdcard/media_api/video_perf/AI_CTO_Mpeg4_32kbps_5fps_SQCIF_128x96+AAC_8kbps_8khz_mono_SSE.mp4", + "/sdcard/media_api/video_perf/AI_CTO_Mpeg4_32kbps_7.5fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4", + "/sdcard/media_api/video_perf/AI_WMV_1024kbps_20fps_QCIF_176x144_noaudio_SSE.wmv", + "/sdcard/media_api/video_perf/AI_WMV_1024kbps_25fps_QCIF_176x144_noaudio_SSE.wmv", + "/sdcard/media_api/video_perf/Chicken.wmv", + "/sdcard/media_api/video_perf/MP_qcif_15fps_100kbps_48kHz_192kbps_30secs.wmv", + "/sdcard/media_api/video_perf/NIN_CTO_H264_123kbps_5fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp", + "/sdcard/media_api/video_perf/NIN_CTO_H264_96kbps_10.2fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp", + "/sdcard/media_api/video_perf/NIN_CTO_H264_96kbps_12fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp", + "/sdcard/media_api/video_perf/NIN_CTO_H264_96kbps_15fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp", + "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_123kbps_15fps_QCIF_176x144+AAC_32kbps_22khz_mono_SSE.3gp", + "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_123kbps_7.5fps_QCIF_176x144+AAC_32kbps_22khz_stereo_SSE.3gp", + "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_128kbps_10fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp", + "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_128kbps_12fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp", + "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_128kbps_15fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp", + "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_128kbps_5fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp", + "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_128kbps_7.5fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp", + "/sdcard/media_api/video_perf/NIN_H263_128kbps_10fps_QCIF_174x144_noaudio_SSE.mp4", + "/sdcard/media_api/video_perf/NIN_H263_128kbps_15fps_QCIF_174x144_noaudio_SSE.mp4", + "/sdcard/media_api/video_perf/NIN_H263_48kbps_10fps_QCIF_174x144_noaudio_SSE.3gp", + "/sdcard/media_api/video_perf/NIN_H263_48kbps_12fps_QCIF_174x144_noaudio_SSE.3gp", + "/sdcard/media_api/video_perf/NIN_H264_123kbps_15fps_QCIF_176x144+AAC_32kbps_22khz_stereo_SSE.3gp", + "/sdcard/media_api/video_perf/NIN_H264_123kbps_7.5fps_QCIF_176x144+AAC_32kbps_22khz_stereo_SSE.3gp", + "/sdcard/media_api/video_perf/PV_H264_2000kbps_20fps_CIF_352x288+AAC_96kbps_48khz_stereo_SSE.mp4", + "/sdcard/media_api/video_perf/PV_H264_2000kbps_25fps_CIF_352x288+AAC_96kbps_48khz_stereo_SSE.mp4", + "/sdcard/media_api/video_perf/PV_H264_2000kbps_30fps_CIF_352x288+AAC_128kbps_48khz_stereo_SSE.mp4", + "/sdcard/media_api/video_perf/Stevie-1.wmv", + "/sdcard/media_api/video_perf/WC_H264_1600kbps_20fps_QCIF_176x144+AAC_96kbps_48khz_mono_SSE.mp4", + "/sdcard/media_api/video_perf/WC_H264_1600kbps_25fps_QCIF_176x144+AAC_96kbps_48khz_mono_SSE.mp4", + "/sdcard/media_api/video_perf/WC_H264_1600kbps_30fps_QCIF_176x144+AAC_96kbps_48khz_mono_SSE.mp4", + "/sdcard/media_api/video_perf/bugs.wmv", + "/sdcard/media_api/video_perf/niceday.wmv", + "/sdcard/media_api/video_perf/eaglesatopnflpe.wmv", }; //wma - only support up to wma 9 public static String[] WMASUPPORTED = { - "/sdcard/music_perf/WMASUPPORTED/AI_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma", - "/sdcard/music_perf/WMASUPPORTED/AI_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma", - "/sdcard/music_perf/WMASUPPORTED/NIN_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma", - "/sdcard/music_perf/WMASUPPORTED/NIN_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma", - "/sdcard/music_perf/WMASUPPORTED/PD_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma", - "/sdcard/music_perf/WMASUPPORTED/PD_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma", - "/sdcard/music_perf/WMASUPPORTED/PV_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma", - "/sdcard/music_perf/WMASUPPORTED/PV_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma", - "/sdcard/music_perf/WMASUPPORTED/WC_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma", - "/sdcard/music_perf/WMASUPPORTED/WC_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma" + "/sdcard/media_api/music_perf/WMASUPPORTED/AI_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma", + "/sdcard/media_api/music_perf/WMASUPPORTED/AI_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma", + "/sdcard/media_api/music_perf/WMASUPPORTED/NIN_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma", + "/sdcard/media_api/music_perf/WMASUPPORTED/NIN_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma", + "/sdcard/media_api/music_perf/WMASUPPORTED/PD_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma", + "/sdcard/media_api/music_perf/WMASUPPORTED/PD_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma", + "/sdcard/media_api/music_perf/WMASUPPORTED/PV_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma", + "/sdcard/media_api/music_perf/WMASUPPORTED/PV_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma", + "/sdcard/media_api/music_perf/WMASUPPORTED/WC_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma", + "/sdcard/media_api/music_perf/WMASUPPORTED/WC_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma" }; public static String[] WMAUNSUPPORTED = { - "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_127kbps_48khz_stereo_CBR_DPA.wma", - "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_44.1khz_stereo_2pVBR_DPA.wma", - "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_48khz_stereo_2pVBR_DPA.wma", - "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_88khz_stereo_CBR_DPA.wma", - "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_96khz_stereo_CBR_DPA.wma", - "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_192kbps_44.1khz_stereo_2pVBR_DPA.wma", - "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_192kbps_88khz_stereo_CBR_DPA.wma", - "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_192kbps_96khz_stereo_CBR_DPA.wma", - "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_44khz_stereo_CBR_DPA.wma", - "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_48khz_stereo_CBR_DPA.wma", - "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_88khz_stereo_CBR_DPA.wma", - "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_96khz_stereo_CBR_DPA.wma", - "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_384kbps_44khz_stereo_CBR_DPA.wma", - "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_384kbps_48khz_stereo_CBR_DPA.wma", - "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_384kbps_88khz_stereo_CBR_DPA.wma" + "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_127kbps_48khz_stereo_CBR_DPA.wma", + "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_44.1khz_stereo_2pVBR_DPA.wma", + "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_48khz_stereo_2pVBR_DPA.wma", + "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_88khz_stereo_CBR_DPA.wma", + "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_96khz_stereo_CBR_DPA.wma", + "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_192kbps_44.1khz_stereo_2pVBR_DPA.wma", + "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_192kbps_88khz_stereo_CBR_DPA.wma", + "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_192kbps_96khz_stereo_CBR_DPA.wma", + "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_44khz_stereo_CBR_DPA.wma", + "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_48khz_stereo_CBR_DPA.wma", + "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_88khz_stereo_CBR_DPA.wma", + "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_96khz_stereo_CBR_DPA.wma", + "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_384kbps_44khz_stereo_CBR_DPA.wma", + "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_384kbps_48khz_stereo_CBR_DPA.wma", + "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_384kbps_88khz_stereo_CBR_DPA.wma" }; //Media Recorder - public static final String RECORDER_OUTPUT = "/sdcard/recorderOutput.amr"; + public static final String RECORDER_OUTPUT = "/sdcard/media_api/recorderOutput.amr"; //video thumbnail - public static final String THUMBNAIL_OUTPUT = "/sdcard/videoThumbnail.png"; - public static final String GOLDEN_THUMBNAIL_OUTPUT = "/sdcard/goldenThumbnail.png"; + public static final String THUMBNAIL_OUTPUT = "/sdcard/media_api/videoThumbnail.png"; + public static final String GOLDEN_THUMBNAIL_OUTPUT = "/sdcard/media_api/goldenThumbnail.png"; //Metadata Utility public static final String[] THUMBNAIL_CAPTURE_TEST_FILES = { - "/sdcard/metadata/test.mp4", - "/sdcard/metadata/test1.3gp", - "/sdcard/metadata/test2.3gp", - "/sdcard/metadata/test3.3gp", - "/sdcard/metadata/test4.3gp", - "/sdcard/metadata/test5.3gp", - "/sdcard/metadata/test6.3gp", - "/sdcard/metadata/test7.3gp", - "/sdcard/metadata/test8.3gp", - "/sdcard/metadata/test9.3gp", - "/sdcard/metadata/test10.3gp", - "/sdcard/metadata/test11.3gp", - "/sdcard/metadata/test12.3gp", - "/sdcard/metadata/test13.3gp", - "/sdcard/metadata/test14.3gp", - "/sdcard/metadata/test15.3gp", - "/sdcard/metadata/test16.3gp", - "/sdcard/metadata/test17.3gp", - "/sdcard/metadata/test18.3gp", - "/sdcard/metadata/test19.3gp", - "/sdcard/metadata/test20.3gp", - "/sdcard/metadata/test21.3gp", - "/sdcard/metadata/test22.3gp", - "/sdcard/metadata/test23.3gp", - "/sdcard/metadata/test24.3gp", - "/sdcard/metadata/test25.3gp", - "/sdcard/metadata/test26.3gp", - "/sdcard/metadata/test27.3gp", - "/sdcard/metadata/test28.3gp", - "/sdcard/metadata/test29.3gp", - "/sdcard/metadata/test30.3gp", - "/sdcard/metadata/test31.3gp", - "/sdcard/metadata/test32.3gp", - "/sdcard/metadata/test33.3gp", - "/sdcard/metadata/test35.mp4", - "/sdcard/metadata/test36.m4v", - "/sdcard/metadata/test34.wmv", - "/sdcard/metadata/test_metadata.mp4", + "/sdcard/media_api/metadata/test.mp4", + "/sdcard/media_api/metadata/test1.3gp", + "/sdcard/media_api/metadata/test2.3gp", + "/sdcard/media_api/metadata/test3.3gp", + "/sdcard/media_api/metadata/test4.3gp", + "/sdcard/media_api/metadata/test5.3gp", + "/sdcard/media_api/metadata/test6.3gp", + "/sdcard/media_api/metadata/test7.3gp", + "/sdcard/media_api/metadata/test8.3gp", + "/sdcard/media_api/metadata/test9.3gp", + "/sdcard/media_api/metadata/test10.3gp", + "/sdcard/media_api/metadata/test11.3gp", + "/sdcard/media_api/metadata/test12.3gp", + "/sdcard/media_api/metadata/test13.3gp", + "/sdcard/media_api/metadata/test14.3gp", + "/sdcard/media_api/metadata/test15.3gp", + "/sdcard/media_api/metadata/test16.3gp", + "/sdcard/media_api/metadata/test17.3gp", + "/sdcard/media_api/metadata/test18.3gp", + "/sdcard/media_api/metadata/test19.3gp", + "/sdcard/media_api/metadata/test20.3gp", + "/sdcard/media_api/metadata/test21.3gp", + "/sdcard/media_api/metadata/test22.3gp", + "/sdcard/media_api/metadata/test23.3gp", + "/sdcard/media_api/metadata/test24.3gp", + "/sdcard/media_api/metadata/test25.3gp", + "/sdcard/media_api/metadata/test26.3gp", + "/sdcard/media_api/metadata/test27.3gp", + "/sdcard/media_api/metadata/test28.3gp", + "/sdcard/media_api/metadata/test29.3gp", + "/sdcard/media_api/metadata/test30.3gp", + "/sdcard/media_api/metadata/test31.3gp", + "/sdcard/media_api/metadata/test32.3gp", + "/sdcard/media_api/metadata/test33.3gp", + "/sdcard/media_api/metadata/test35.mp4", + "/sdcard/media_api/metadata/test36.m4v", + "/sdcard/media_api/metadata/test34.wmv", + "/sdcard/media_api/metadata/test_metadata.mp4", }; public static final String[] METADATA_RETRIEVAL_TEST_FILES = { // Raw AAC is not supported - // "/sdcard/test_raw.aac", - // "/sdcard/test_adts.aac", - // "/sdcard/test_adif.aac", - "/sdcard/metadata/test_metadata.mp4", - "/sdcard/metadata/WMA10.wma", - "/sdcard/metadata/Leadsol_out.wav", - "/sdcard/metadata/test_aac.mp4", - "/sdcard/metadata/test_amr.mp4", - "/sdcard/metadata/test_avc_amr.mp4", - "/sdcard/metadata/test_metadata.mp4", - "/sdcard/metadata/test_vbr.mp3", - "/sdcard/metadata/test_cbr.mp3", - "/sdcard/metadata/metadata_test1.mp3", - "/sdcard/metadata/test33.3gp", - "/sdcard/metadata/test35.mp4", - "/sdcard/metadata/test36.m4v", - "/sdcard/metadata/test_m4v_amr.mp4", - "/sdcard/metadata/test_h263_amr.mp4", - "/sdcard/metadata/test34.wmv", + // "/sdcard/media_api/test_raw.aac", + // "/sdcard/media_api/test_adts.aac", + // "/sdcard/media_api/test_adif.aac", + "/sdcard/media_api/metadata/test_metadata.mp4", + "/sdcard/media_api/metadata/WMA10.wma", + "/sdcard/media_api/metadata/Leadsol_out.wav", + "/sdcard/media_api/metadata/test_aac.mp4", + "/sdcard/media_api/metadata/test_amr.mp4", + "/sdcard/media_api/metadata/test_avc_amr.mp4", + "/sdcard/media_api/metadata/test_metadata.mp4", + "/sdcard/media_api/metadata/test_vbr.mp3", + "/sdcard/media_api/metadata/test_cbr.mp3", + "/sdcard/media_api/metadata/metadata_test1.mp3", + "/sdcard/media_api/metadata/test33.3gp", + "/sdcard/media_api/metadata/test35.mp4", + "/sdcard/media_api/metadata/test36.m4v", + "/sdcard/media_api/metadata/test_m4v_amr.mp4", + "/sdcard/media_api/metadata/test_h263_amr.mp4", + "/sdcard/media_api/metadata/test34.wmv", }; public static final String[] ALBUMART_TEST_FILES = { - "/sdcard/album_photo/test_22_16_mp3.mp3", - "/sdcard/album_photo/PD_256kbps_48khz_mono_CBR_MCA.mp3", - "/sdcard/album_photo/PD_256kbps_44.1khz_mono_CBR_DPA.mp3", - "/sdcard/album_photo/PD_192kbps_32khz_mono_CBR_DPA.mp3", - "/sdcard/album_photo/NIN_256kbps_48khz_mono_CBR_MCA.mp3", - "/sdcard/album_photo/NIN_256kbps_44.1khz_mono_CBR_MCA.mp3", - "/sdcard/album_photo/NIN_112kbps(96kbps)_48khz_stereo_VBR_MCA.mp3", - "/sdcard/album_photo/NIN_112kbps(96kbps)_44.1khz_stereo_VBR_MCA.mp3", - "/sdcard/album_photo/lightGreen1.mp3", - "/sdcard/album_photo/babyBlue2 1.mp3", - "/sdcard/album_photo/2-01 01 NIN_56kbps(64kbps)_32khz_stereo_VBR_MCA.mp3", - "/sdcard/album_photo/02_NIN_112kbps(80kbps)_32khz_stereo_VBR_MCA.mp3", - "/sdcard/album_photo/No_Woman_No_Cry_128K.wma", - "/sdcard/album_photo/Beethoven_2.wma", + "/sdcard/media_api/album_photo/test_22_16_mp3.mp3", + "/sdcard/media_api/album_photo/PD_256kbps_48khz_mono_CBR_MCA.mp3", + "/sdcard/media_api/album_photo/PD_256kbps_44.1khz_mono_CBR_DPA.mp3", + "/sdcard/media_api/album_photo/PD_192kbps_32khz_mono_CBR_DPA.mp3", + "/sdcard/media_api/album_photo/NIN_256kbps_48khz_mono_CBR_MCA.mp3", + "/sdcard/media_api/album_photo/NIN_256kbps_44.1khz_mono_CBR_MCA.mp3", + "/sdcard/media_api/album_photo/NIN_112kbps(96kbps)_48khz_stereo_VBR_MCA.mp3", + "/sdcard/media_api/album_photo/NIN_112kbps(96kbps)_44.1khz_stereo_VBR_MCA.mp3", + "/sdcard/media_api/album_photo/lightGreen1.mp3", + "/sdcard/media_api/album_photo/babyBlue2 1.mp3", + "/sdcard/media_api/album_photo/2-01 01 NIN_56kbps(64kbps)_32khz_stereo_VBR_MCA.mp3", + "/sdcard/media_api/album_photo/02_NIN_112kbps(80kbps)_32khz_stereo_VBR_MCA.mp3", + "/sdcard/media_api/album_photo/No_Woman_No_Cry_128K.wma", + "/sdcard/media_api/album_photo/Beethoven_2.wma", }; //TEST_PATH_1: is a video and contains metadata for key "num-tracks" // TEST_PATH_2: any valid media file. // TEST_PATH_3: invalid media file - public static final String TEST_PATH_1 = "/sdcard/metadata/test.mp4"; - public static final String TEST_PATH_3 = "/sdcard/data.txt"; + public static final String TEST_PATH_1 = "/sdcard/media_api/metadata/test.mp4"; + public static final String TEST_PATH_3 = "/sdcard/media_api/data.txt"; public static final String TEST_PATH_4 = "somenonexistingpathname"; public static final String TEST_PATH_5 = "mem://012345"; @@ -376,81 +378,81 @@ public class MediaNames { //cd_track_number, album, artist, author, composer, date, genre //title, years, duration public static final String META_DATA_MP3 [][] = { - {"/sdcard/metaDataTestMedias/MP3/ID3V1_ID3V2.mp3", "1/10", "ID3V2.3 Album", "ID3V2.3 Artist", + {"/sdcard/media_api/metaDataTestMedias/MP3/ID3V1_ID3V2.mp3", "1/10", "ID3V2.3 Album", "ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null, "Blues", "ID3V2.3 Title", "1234", "321", "1"}, - {"/sdcard/metaDataTestMedias/MP3/ID3V2.mp3", "1/10", "ID3V2.3 Album", "ID3V2.3 Artist", + {"/sdcard/media_api/metaDataTestMedias/MP3/ID3V2.mp3", "1/10", "ID3V2.3 Album", "ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null, "Blues", "ID3V2.3 Title", "1234", "313", "1"}, - {"/sdcard/metaDataTestMedias/MP3/ID3V1.mp3", null, "test ID3V1 Album", "test ID3V1 Artist", + {"/sdcard/media_api/metaDataTestMedias/MP3/ID3V1.mp3", null, "test ID3V1 Album", "test ID3V1 Artist", null, null, null, null, "test ID3V1 Title", "1234", "231332", "1"}, - {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V1.mp3" , null, null, null, + {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V1.mp3" , null, null, null, null, null, null, null, null, null, "231330", "1"}, //The corrupted TALB field in id3v2 would not switch to id3v1 tag automatically - {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TALB.mp3", "01", null, "ID3V2.3 Artist", + {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TALB.mp3", "01", null, "ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null, "Blues", "ID3V2.3 Title", "1234", "321", "1"}, - {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TCOM.mp3", "01", "ID3V2.3 Album", + {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TCOM.mp3", "01", "ID3V2.3 Album", "ID3V2.3 Artist", "ID3V2.3 Lyricist", null, null, "Blues", "ID3V2.3 Title", "1234", "321", "1"}, - {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TCOM_2.mp3", "01", "ID3V2.3 Album", + {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TCOM_2.mp3", "01", "ID3V2.3 Album", "ID3V2.3 Artist", null, null, null, "Blues", "ID3V2.3 Title", "1234", "321", "1"}, - {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TRCK.mp3", "dd", "ID3V2.3 Album", + {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TRCK.mp3", "dd", "ID3V2.3 Album", "ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null, "Blues", "ID3V2.3 Title", "1234", "321", "1"}, - {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TRCK_2.mp3", "01", "ID3V2.3 Album", + {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TRCK_2.mp3", "01", "ID3V2.3 Album", "ID3V2.3 Artist", null, null, null, null, "ID3V2.3 Title", null, "321", "1"}, - {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER.mp3", "01", "ID3V2.3 Album", + {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER.mp3", "01", "ID3V2.3 Album", "ID3V2.3 Artist", null, null, null, null, "ID3V2.3 Title", "9999", "321", "1"}, - {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER_2.mp3", "01", "ID3V2.3 Album", + {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER_2.mp3", "01", "ID3V2.3 Album", "ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null, "Blues", "ID3V2.3 Title", null, "321", "1"}, - {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TIT.mp3", null, null, null, + {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TIT.mp3", null, null, null, null, null, null, null, null, null, "577", "1"} }; public static final String META_DATA_OTHERS [][] = { - {"/sdcard/metaDataTestMedias/3GP/cat.3gp", null, null, null, + {"/sdcard/media_api/metaDataTestMedias/3GP/cat.3gp", null, null, null, null, null, "20080309T002415.000Z", null, null, null, "1404928", "2"}, - {"/sdcard/metaDataTestMedias/AMR/AMR_NB.amr", null, null, null, + {"/sdcard/media_api/metaDataTestMedias/AMR/AMR_NB.amr", null, null, null, null, null, null, null, null, null, "126540", "1"}, - {"/sdcard/metaDataTestMedias/AMRWB/AMR_WB.amr", null, null, null, + {"/sdcard/media_api/metaDataTestMedias/AMRWB/AMR_WB.amr", null, null, null, null, null, null, null, null, null, "231180", "1"}, - {"/sdcard/metaDataTestMedias/M4A/Jaws Of Life_ver1.m4a", null, "Suspended Animation", + {"/sdcard/media_api/metaDataTestMedias/M4A/Jaws Of Life_ver1.m4a", null, "Suspended Animation", "John Petrucci", null, null, "20070510T125223.000Z", null, null, "2005", "231180", "1"}, - {"/sdcard/metaDataTestMedias/M4V/sample_iPod.m4v", null, null, + {"/sdcard/media_api/metaDataTestMedias/M4V/sample_iPod.m4v", null, null, null, null, null, "20051220T202015.000Z", null, null, null, "3771392", "2"}, - {"/sdcard/metaDataTestMedias/MIDI/MIDI.mid", null, "Suspended Animation", + {"/sdcard/media_api/metaDataTestMedias/MIDI/MIDI.mid", null, "Suspended Animation", "John Petrucci", null, null, "20070510T125223.000Z", null, null, "2005", "231180", "1"}, - {"/sdcard/metaDataTestMedias/MP4/kung_fu_panda_h264.mp4", null, "mp4 album Kung Fu Panda", + {"/sdcard/media_api/metaDataTestMedias/MP4/kung_fu_panda_h264.mp4", null, "mp4 album Kung Fu Panda", "mp4 artist Kung Fu Panda", null, null, "20080517T091451.000Z", "Kung Fu Panda", "Kung Fu Panda", "2008", "5667840", "2"}, - {"/sdcard/metaDataTestMedias/OGG/Ring_Classic_02.ogg", null, "Suspended Animation", + {"/sdcard/media_api/metaDataTestMedias/OGG/Ring_Classic_02.ogg", null, "Suspended Animation", "John Petrucci", null, null, "20070510T125223.000Z", null, null, "2005", "231180", "1"}, - {"/sdcard/metaDataTestMedias/OGG/When You Say Nothing At All.ogg", + {"/sdcard/media_api/metaDataTestMedias/OGG/When You Say Nothing At All.ogg", null, "Suspended Animation", "John Petrucci", null, null, "20070510T125223.000Z", null, null, "2005", "231180", "1"}, - {"/sdcard/metaDataTestMedias/WAV/Im With You.wav", null, null, + {"/sdcard/media_api/metaDataTestMedias/WAV/Im With You.wav", null, null, null, null, null, null, null, null, null, "224000", "1"}, - {"/sdcard/metaDataTestMedias/WMA/WMA9.wma", "6", "Ten Songs in the Key of Betrayal", + {"/sdcard/media_api/metaDataTestMedias/WMA/WMA9.wma", "6", "Ten Songs in the Key of Betrayal", "Alien Crime Syndicate", "Alien Crime Syndicate", "wma 9 Composer", "20040521T175729.483Z", "Rock", "Run for the Money", "2004", "134479", "1"}, - {"/sdcard/metaDataTestMedias/WMA/WMA10.wma", "09", "wma 10 Album", + {"/sdcard/media_api/metaDataTestMedias/WMA/WMA10.wma", "09", "wma 10 Album", "wma 10 Album Artist", "wma 10 Artist", "wma 10 Composer", "20070705T063625.097Z", "Acid Jazz", "wma 10 Title", "2010", "126574", "1"}, - {"/sdcard/metaDataTestMedias/WMV/bugs.wmv", "8", "wmv 9 Album", + {"/sdcard/media_api/metaDataTestMedias/WMV/bugs.wmv", "8", "wmv 9 Album", null, "wmv 9 Artist ", null, "20051122T155247.540Z", null, "Looney Tunes - Hare-Breadth Hurry", "2005", "193482", "2"}, - {"/sdcard/metaDataTestMedias/WMV/clips_ver7.wmv", "50", "wmv 7 Album", + {"/sdcard/media_api/metaDataTestMedias/WMV/clips_ver7.wmv", "50", "wmv 7 Album", null, "Hallau Shoots & Company", null, "20020226T170045.891Z", null, "CODEC Shootout", "1986", "43709", "2"} }; @@ -471,9 +473,25 @@ public class MediaNames { public static final String RECORDED_VIDEO_3GP = "/sdcard/temp.3gp"; + public static final String INVALD_VIDEO_PATH = "/sdcard/media_api/filepathdoesnotexist" + + "/filepathdoesnotexist/temp.3gp"; + - public static final long RECORDED_TIME = 3000; + public static final long RECORDED_TIME = 5000; public static final long VALID_VIDEO_DURATION = 2000; - + //Videos for the mediaplayer stress test + public static String[] H263_STRESS = { + "/sdcard/media_api/video_stress/h263/H263_CIF.3gp", + "/sdcard/media_api/video_stress/h263/H263_QCIF.3gp", + "/sdcard/media_api/video_stress/h263/H263_QVGA.3gp", + "/sdcard/media_api/video_stress/h263/H263_SQVGA.3gp" + }; + + public static String[] MPEG4_STRESS = { + "/sdcard/media_api/video_stress/h263/mpeg4_CIF.mp4", + "/sdcard/media_api/video_stress/h263/mpeg4_QCIF.3gp", + "/sdcard/media_api/video_stress/h263/mpeg4_QVGA.3gp", + "/sdcard/media_api/video_stress/h263/mpeg4_SQVGA.mp4" + }; } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaRecorderStressTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaRecorderStressTestRunner.java new file mode 100755 index 0000000..12eacd3 --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaRecorderStressTestRunner.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.mediaframeworktest; + +import android.test.InstrumentationTestRunner; +import android.test.InstrumentationTestSuite; +import com.android.mediaframeworktest.stress.MediaRecorderStressTest; + +import junit.framework.TestSuite; + +public class MediaRecorderStressTestRunner extends InstrumentationTestRunner { + + @Override + public TestSuite getAllTests() { + TestSuite suite = new InstrumentationTestSuite(this); + suite.addTestSuite(MediaRecorderStressTest.class); + return suite; + } + + @Override + public ClassLoader getLoader() { + return MediaRecorderStressTestRunner.class.getClassLoader(); + } +} diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java new file mode 100644 index 0000000..ae6a834 --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.mediaframeworktest.functional; + +import com.android.mediaframeworktest.MediaFrameworkTest; +import com.android.mediaframeworktest.MediaNames; + +import android.media.AudioTrack; +import android.content.Context; +import android.test.ActivityInstrumentationTestCase2; +import android.util.Log; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.Suppress; + +/** + * Junit / Instrumentation test case for the media AudioTrack api + + */ +public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> { + private String TAG = "MediaAudioTrack"; + + public MediaAudioTrackTest() { + super("com.android.mediaframeworktest", MediaFrameworkTest.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + //Test case 1: Set the invalid volume + @MediumTest + public void testGetMinVolume() throws Exception { + //To Do: Create the test case for GetMinVolume + assertTrue("testGetMinVolume", true); + } + +} + diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java index 20f213e..dd94164 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java @@ -385,9 +385,6 @@ public class MediaPlayerApiTest extends ActivityInstrumentationTestCase<MediaFra assertTrue("WMV SeekTo", isSeek); } - //TODO(elaurent) - //reactivate the test until bug#1495237 fix - @Suppress @LargeTest public void testSoundRecord() throws Exception { boolean isRecordered = CodecTest.mediaRecorderRecord(MediaNames.RECORDER_OUTPUT); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java index d970f5e..65451c5 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java @@ -35,8 +35,7 @@ import android.test.suitebuilder.annotation.Suppress; /** - * Junit / Instrumentation test case for the media recorder api - + * Junit / Instrumentation test case for the media recorder api */ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFrameworkTest> { private String TAG = "MediaRecorderTest"; @@ -60,12 +59,48 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram } private void recordVideo(int frameRate, int width, int height, - int videoFormat, int outFormat, String outFile, boolean videoOnly){ + int videoFormat, int outFormat, String outFile, boolean videoOnly) { Log.v(TAG,"startPreviewAndPrepareRecording"); - try{ - if (!videoOnly){ + try { + if (!videoOnly) { + Log.v(TAG, "setAudioSource"); + mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); + } + mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); + mRecorder.setOutputFormat(outFormat); + Log.v(TAG, "output format " + outFormat); + mRecorder.setOutputFile(outFile); + mRecorder.setVideoFrameRate(frameRate); + mRecorder.setVideoSize(width, height); + Log.v(TAG, "setEncoder"); + mRecorder.setVideoEncoder(videoFormat); + if (!videoOnly) { + mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); + } + mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); + Log.v(TAG, "setPreview"); + mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); + Log.v(TAG, "prepare"); + mRecorder.prepare(); + Log.v(TAG, "start"); + mRecorder.start(); + Thread.sleep(MediaNames.RECORDED_TIME); + Log.v(TAG, "stop"); + mRecorder.stop(); + mRecorder.release(); + } catch (Exception e) { + Log.v("record video failed ", e.toString()); + mRecorder.release(); + } + } + + + private boolean invalidRecordSetting(int frameRate, int width, int height, + int videoFormat, int outFormat, String outFile, boolean videoOnly) { + try { + if (!videoOnly) { Log.v(TAG, "setAudioSource"); - //mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); + mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); } mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); mRecorder.setOutputFormat(outFormat); @@ -75,8 +110,8 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram mRecorder.setVideoSize(width, height); Log.v(TAG, "setEncoder"); mRecorder.setVideoEncoder(videoFormat); - if (!videoOnly){ - // mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); + if (!videoOnly) { + mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); } mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); Log.v(TAG, "setPreview"); @@ -88,16 +123,21 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram Thread.sleep(MediaNames.RECORDED_TIME); Log.v(TAG, "stop"); mRecorder.stop(); - mRecorder.reset(); mRecorder.release(); - } catch (Exception e){ + } catch (Exception e) { Log.v("record video failed ", e.toString()); + mRecorder.release(); + Log.v(TAG, "reset and release"); + return true; } + return false; } - private void getOutputVideoProperty(String outputFilePath){ + + + private void getOutputVideoProperty(String outputFilePath) { MediaPlayer mediaPlayer = new MediaPlayer(); - try{ + try { mediaPlayer.setDataSource(outputFilePath); Log.v(TAG, "file Path = " + outputFilePath); mediaPlayer.setDisplay(MediaFrameworkTest.mSurfaceView.getHolder()); @@ -111,19 +151,20 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram mediaPlayer.release(); } catch (Exception e) { Log.v(TAG, e.toString()); + mediaPlayer.release(); } } - private void removeFile(String filePath){ + private void removeFile(String filePath) { File fileRemove = new File(filePath); fileRemove.delete(); } - private boolean validateVideo(String filePath, int width, int height){ + private boolean validateVideo(String filePath, int width, int height) { boolean validVideo = false; getOutputVideoProperty(filePath); if (mOutputVideoWidth == width && mOutputVideoHeight == height && - mOutputDuration > MediaNames.VALID_VIDEO_DURATION ){ + mOutputDuration > MediaNames.VALID_VIDEO_DURATION ) { validVideo = true; } Log.v(TAG, "width = " + mOutputVideoWidth + " height = " + mOutputVideoHeight + " Duration = " + mOutputDuration); @@ -143,7 +184,7 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram } //Format: QVGA h263 - @Suppress + @LargeTest public void testQVGAH263() throws Exception { boolean videoRecordedResult = false; recordVideo(15, 320, 240, MediaRecorder.VideoEncoder.H263, @@ -153,7 +194,7 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram } //Format: SQVGA h263 - @Suppress + @LargeTest public void testSQVGAH263() throws Exception { boolean videoRecordedResult = false; recordVideo(15, 240, 160, MediaRecorder.VideoEncoder.H263, @@ -184,14 +225,12 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram - @Suppress + @LargeTest public void testVideoOnly() throws Exception { boolean videoRecordedResult = false; - for (int i=0; i< 10; i++){ recordVideo(15, 176, 144, MediaRecorder.VideoEncoder.H263, MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true); videoRecordedResult = validateVideo(MediaNames.RECORDED_VIDEO_3GP, 176, 144); - } assertTrue("QCIFH263 Video Only", videoRecordedResult); } @@ -204,7 +243,7 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram assertTrue("PortraitH263", videoRecordedResult); } - @LargeTest + @Suppress public void testHVGAMP4() throws Exception { boolean videoRecordedResult = false; recordVideo(15, 480, 320, MediaRecorder.VideoEncoder.MPEG_4_SP, @@ -242,7 +281,7 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram } - //Format: CIF h263 + //Format: CIF MP4 @LargeTest public void testCIFMP4() throws Exception { boolean videoRecordedResult = false; @@ -253,14 +292,14 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram } - //Format: CIF h263 outputforma 3gpp + //Format: CIF MP4 output format 3gpp @LargeTest public void testCIFMP43GPP() throws Exception { boolean videoRecordedResult = false; recordVideo(15, 352, 288, MediaRecorder.VideoEncoder.MPEG_4_SP, MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_VIDEO_3GP, false); videoRecordedResult = validateVideo(MediaNames.RECORDED_VIDEO_3GP, 352, 288); - assertTrue("CIFH263", videoRecordedResult); + assertTrue("CIFMP4 3GPP", videoRecordedResult); } @LargeTest @@ -272,5 +311,29 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram assertTrue("QCIFH263 3GPP", videoRecordedResult); } + @LargeTest + public void testInvalidVideoPath() throws Exception { + boolean isTestInvalidVideoPathSuccessful = false; + isTestInvalidVideoPathSuccessful = invalidRecordSetting(15, 176, 144, MediaRecorder.VideoEncoder.H263, + MediaRecorder.OutputFormat.THREE_GPP, MediaNames.INVALD_VIDEO_PATH, false); + assertTrue("Invalid outputFile Path", isTestInvalidVideoPathSuccessful); + } + + @Suppress + public void testInvalidVideoSize() throws Exception { + boolean isTestInvalidVideoSizeSuccessful = false; + isTestInvalidVideoSizeSuccessful = invalidRecordSetting(15, 800, 600, MediaRecorder.VideoEncoder.H263, + MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_VIDEO_3GP, false); + assertTrue("Invalid video Size", isTestInvalidVideoSizeSuccessful); + } + + @LargeTest + public void testInvalidFrameRate() throws Exception { + boolean isTestInvalidFrameRateSuccessful = false; + isTestInvalidFrameRateSuccessful = invalidRecordSetting(50, 176, 144, MediaRecorder.VideoEncoder.H263, + MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_VIDEO_3GP, false); + assertTrue("Invalid FrameRate", isTestInvalidFrameRateSuccessful); + } + } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java new file mode 100644 index 0000000..dbf937c --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.mediaframeworktest.stress; + +import com.android.mediaframeworktest.MediaFrameworkTest; + +import android.hardware.Camera; +import android.media.MediaPlayer; +import android.media.MediaRecorder; +import android.test.ActivityInstrumentationTestCase2; +import android.test.suitebuilder.annotation.LargeTest; +import android.util.Log; +import android.view.SurfaceHolder; + +/** + * Junit / Instrumentation test case for the media player api + + */ +public class MediaRecorderStressTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> { + + + private String TAG = "MediaRecorderStressTest"; + private MediaRecorder mRecorder; + private Camera mCamera; + + private static final int NUMBER_OF_CAMERA_STRESS_LOOPS = 100; + private static final int NUMBER_OF_RECORDER_STRESS_LOOPS = 100; + private static final int NUMBER_OF_RECORDERANDPLAY_STRESS_LOOPS = 50; + private static final int NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER = 200; + private static final long WAIT_TIME_CAMERA_TEST = 3000; // 3 second + private static final long WAIT_TIME_RECORDER_TEST = 60000; // 6 second + private static final long WAIT_TIME_RECORD = 100000; // 10 seconds + private static final long WAIT_TIME_PLAYBACK = 60000; // 6 second + private static final String OUTPUT_FILE = "/sdcard/temp"; + private static final String OUTPUT_FILE_EXT = ".3gp"; + + public MediaRecorderStressTest() { + super("com.android.mediaframeworktest", MediaFrameworkTest.class); + } + + protected void setUp() throws Exception { + getActivity(); + super.setUp(); + } + + //Test case for stressing the camera preview. + @LargeTest + public void testStressCamera() throws Exception { + SurfaceHolder mSurfaceHolder; + mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); + try { + Log.v(TAG, "Start preview"); + for (int i = 0; i< NUMBER_OF_CAMERA_STRESS_LOOPS; i++){ + mCamera = Camera.open(); + mCamera.setPreviewDisplay(mSurfaceHolder); + mCamera.startPreview(); + Thread.sleep(WAIT_TIME_CAMERA_TEST); + mCamera.stopPreview(); + mCamera.release(); + } + } catch (Exception e) { + Log.v(TAG, e.toString()); + } + } + + //Test case for stressing the camera preview. + @LargeTest + public void testStressRecorder() throws Exception { + String filename; + SurfaceHolder mSurfaceHolder; + mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); + try { + Log.v(TAG, "Start preview"); + for (int i = 0; i < NUMBER_OF_RECORDER_STRESS_LOOPS; i++){ + Log.v(TAG, "counter = " + i); + filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT; + Log.v(TAG, filename); + mRecorder = new MediaRecorder(); + mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); + mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); + mRecorder.setOutputFile(filename); + mRecorder.setVideoFrameRate(20); + mRecorder.setVideoSize(176,144); + Log.v(TAG, "setEncoder"); + mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263); + mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); + Log.v(TAG, "setPreview"); + mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); + Log.v(TAG, "prepare"); + mRecorder.prepare(); + Log.v(TAG, "before release"); + Thread.sleep(WAIT_TIME_RECORDER_TEST); + mRecorder.reset(); + mRecorder.release(); + } + } catch (Exception e) { + Log.v(TAG, e.toString()); + } + } + + + //Stress test case for switching camera and video recorder preview. + @LargeTest + public void testStressCameraSwitchRecorder() throws Exception { + String filename; + SurfaceHolder mSurfaceHolder; + mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); + try { + Log.v(TAG, "Start preview"); + for (int i = 0; i < NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER; i++){ + mCamera = Camera.open(); + mCamera.setPreviewDisplay(mSurfaceHolder); + mCamera.startPreview(); + Thread.sleep(WAIT_TIME_CAMERA_TEST); + mCamera.stopPreview(); + mCamera.release(); + mCamera = null; + Log.v(TAG, "release camera"); + filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT; + Log.v(TAG, filename); + mRecorder = new MediaRecorder(); + mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); + mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); + mRecorder.setOutputFile(filename); + mRecorder.setVideoFrameRate(20); + mRecorder.setVideoSize(176,144); + Log.v(TAG, "Media recorder setEncoder"); + mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263); + Log.v(TAG, "mediaRecorder setPreview"); + mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); + Log.v(TAG, "prepare"); + mRecorder.prepare(); + Log.v(TAG, "before release"); + Thread.sleep(WAIT_TIME_CAMERA_TEST); + mRecorder.release(); + Log.v(TAG, "release video recorder"); + } + } catch (Exception e) { + Log.v(TAG, e.toString()); + } + } + + //Stress test case for record a video and play right away. + @LargeTest + public void testStressRecordVideoAndPlayback() throws Exception { + String filename; + SurfaceHolder mSurfaceHolder; + mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); + try { + for (int i = 0; i < NUMBER_OF_RECORDERANDPLAY_STRESS_LOOPS; i++){ + filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT; + Log.v(TAG, filename); + mRecorder = new MediaRecorder(); + mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); + mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); + mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); + mRecorder.setOutputFile(filename); + mRecorder.setVideoFrameRate(20); + mRecorder.setVideoSize(352,288); + mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263); + mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); + Log.v(TAG, "mediaRecorder setPreview"); + mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); + mRecorder.prepare(); + mRecorder.start(); + Thread.sleep(WAIT_TIME_RECORD); + Log.v(TAG, "Before stop"); + mRecorder.stop(); + mRecorder.release(); + //start the playback + MediaPlayer mp = new MediaPlayer(); + mp.setDataSource(filename); + mp.setDisplay(MediaFrameworkTest.mSurfaceView.getHolder()); + mp.prepare(); + mp.start(); + Thread.sleep(WAIT_TIME_PLAYBACK); + mp.release(); + } + } catch (Exception e) { + Log.v(TAG, e.toString()); + } + } +} + diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderPrepareStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderPrepareStateUnitTest.java index 366b6ff..dfd544a 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderPrepareStateUnitTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderPrepareStateUnitTest.java @@ -59,9 +59,6 @@ public class MediaRecorderPrepareStateUnitTest extends AndroidTestCase implement } } - //TODO(elaurent) - //reactivate the test until bug#1495237 fix - @Suppress @MediumTest public void testPrepare() { mTestTemplate.runTestOnMethod(this); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderResetStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderResetStateUnitTest.java index a45f7ba..cae9e31 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderResetStateUnitTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderResetStateUnitTest.java @@ -54,9 +54,6 @@ public class MediaRecorderResetStateUnitTest extends AndroidTestCase implements recorder.reset(); } - //TODO(elaurent) - //reactivate the test until bug#1495237 fix - @Suppress @MediumTest public void testReset() { mTestTemplate.runTestOnMethod(this); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioEncoderStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioEncoderStateUnitTest.java index f17d017..4b5a818 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioEncoderStateUnitTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioEncoderStateUnitTest.java @@ -54,9 +54,6 @@ public class MediaRecorderSetAudioEncoderStateUnitTest extends AndroidTestCase i recorder.setAudioEncoder(MediaRecorderStateUnitTestTemplate.AUDIO_ENCODER); } - //TODO(elaurent) - //reactivate the test until bug#1495237 fix - @Suppress @MediumTest public void testSetAudioEncoder() { mTestTemplate.runTestOnMethod(this); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioSourceStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioSourceStateUnitTest.java index a972dae..f8ab48cf 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioSourceStateUnitTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioSourceStateUnitTest.java @@ -54,9 +54,6 @@ public class MediaRecorderSetAudioSourceStateUnitTest extends AndroidTestCase im recorder.setAudioSource(MediaRecorderStateUnitTestTemplate.AUDIO_SOURCE); } - //TODO(elaurent) - //reactivate the test until bug#1495237 fix - @Suppress @MediumTest public void testSetAudioSource() { mTestTemplate.runTestOnMethod(this); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFileStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFileStateUnitTest.java index b5e7bb7..50e235b 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFileStateUnitTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFileStateUnitTest.java @@ -53,9 +53,6 @@ public class MediaRecorderSetOutputFileStateUnitTest extends AndroidTestCase imp recorder.setOutputFile(MediaRecorderStateUnitTestTemplate.RECORD_OUTPUT_PATH); } - //TODO(elaurent) - //reactivate the test until bug#1495237 fix - @Suppress @MediumTest public void testSetOutputFile() { mTestTemplate.runTestOnMethod(this); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFormatStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFormatStateUnitTest.java index 3d6f87f..cacdd87 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFormatStateUnitTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFormatStateUnitTest.java @@ -54,9 +54,6 @@ public class MediaRecorderSetOutputFormatStateUnitTest extends AndroidTestCase i recorder.setOutputFormat(MediaRecorderStateUnitTestTemplate.OUTPUT_FORMAT); } - //TODO(elaurent) - //reactivate the test until bug#1495237 fix - @Suppress @MediumTest public void testSetOutputFormat() { mTestTemplate.runTestOnMethod(this); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStartStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStartStateUnitTest.java index 03180d5..d1232fc 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStartStateUnitTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStartStateUnitTest.java @@ -54,9 +54,6 @@ public class MediaRecorderStartStateUnitTest extends AndroidTestCase implements recorder.start(); } - //TODO(elaurent) - //reactivate the test until bug#1495237 fix - @Suppress @MediumTest public void testStart() { mTestTemplate.runTestOnMethod(this); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStopStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStopStateUnitTest.java index 330e8ab..8737595 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStopStateUnitTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStopStateUnitTest.java @@ -54,9 +54,6 @@ public class MediaRecorderStopStateUnitTest extends AndroidTestCase implements M recorder.stop(); } - //TODO(elaurent) - //reactivate the test until bug#1495237 fix - @Suppress @MediumTest public void testStop() { mTestTemplate.runTestOnMethod(this); |