diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-02-10 15:44:00 -0800 | 
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-02-10 15:44:00 -0800 | 
| commit | d24b8183b93e781080b2c16c487e60d51c12da31 (patch) | |
| tree | fbb89154858984eb8e41556da7e9433040d55cd4 /media/java | |
| parent | f1e484acb594a726fb57ad0ae4cfe902c7f35858 (diff) | |
| download | frameworks_base-d24b8183b93e781080b2c16c487e60d51c12da31.zip frameworks_base-d24b8183b93e781080b2c16c487e60d51c12da31.tar.gz frameworks_base-d24b8183b93e781080b2c16c487e60d51c12da31.tar.bz2 | |
auto import from //branches/cupcake/...@130745
Diffstat (limited to 'media/java')
| -rw-r--r-- | media/java/android/media/AudioFormat.java | 4 | ||||
| -rw-r--r-- | media/java/android/media/AudioManager.java | 242 | ||||
| -rw-r--r-- | media/java/android/media/AudioRecord.java | 134 | ||||
| -rw-r--r-- | media/java/android/media/AudioService.java | 414 | ||||
| -rw-r--r-- | media/java/android/media/AudioSystem.java | 20 | ||||
| -rw-r--r-- | media/java/android/media/AudioTrack.java | 476 | ||||
| -rw-r--r-- | media/java/android/media/JetPlayer.java | 134 | ||||
| -rw-r--r-- | media/java/android/media/MediaFile.java | 6 | ||||
| -rw-r--r-- | media/java/android/media/MediaPlayer.java | 6 | ||||
| -rw-r--r-- | media/java/android/media/MediaRecorder.java | 6 | ||||
| -rw-r--r-- | media/java/android/media/MediaScanner.java | 10 | 
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              } | 
