summaryrefslogtreecommitdiffstats
path: root/media/java
diff options
context:
space:
mode:
Diffstat (limited to 'media/java')
-rw-r--r--media/java/android/media/AudioFormat.java4
-rw-r--r--media/java/android/media/AudioManager.java242
-rw-r--r--media/java/android/media/AudioRecord.java134
-rw-r--r--media/java/android/media/AudioService.java414
-rw-r--r--media/java/android/media/AudioSystem.java20
-rw-r--r--media/java/android/media/AudioTrack.java476
-rw-r--r--media/java/android/media/JetPlayer.java134
-rw-r--r--media/java/android/media/MediaFile.java6
-rw-r--r--media/java/android/media/MediaPlayer.java6
-rw-r--r--media/java/android/media/MediaRecorder.java6
-rw-r--r--media/java/android/media/MediaScanner.java10
11 files changed, 869 insertions, 583 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
}