summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/java/android/media/AudioService.java207
-rw-r--r--media/java/android/media/MediaFormat.java8
-rw-r--r--media/java/android/media/MediaPlayer.java4
-rw-r--r--media/java/android/media/MediaRouter.java18
4 files changed, 151 insertions, 86 deletions
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index f0fdfc1..9ec5be3 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -163,6 +163,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 25;
private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 26;
private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 27;
+ private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 28;
// flags for MSG_PERSIST_VOLUME indicating if current and/or last audible volume should be
// persisted
@@ -442,6 +443,8 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
private boolean mDockAudioMediaEnabled = true;
+ private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+
///////////////////////////////////////////////////////////////////////////
// Construction
///////////////////////////////////////////////////////////////////////////
@@ -485,6 +488,14 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
null,
0);
+ mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
+ Settings.Global.AUDIO_SAFE_VOLUME_STATE,
+ SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
+ // The default safe volume index read here will be replaced by the actual value when
+ // the mcc is read by onConfigureSafeVolume()
+ mSafeMediaVolumeIndex = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_safe_media_volume_index) * 10;
+
readPersistedSettings();
mSettingsObserver = new SettingsObserver();
updateStreamVolumeAlias(false /*updateVolumes*/);
@@ -492,8 +503,6 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
mMediaServerOk = true;
- mSafeMediaVolumeState = new Integer(SAFE_MEDIA_VOLUME_NOT_CONFIGURED);
-
// Call setRingerModeInt() to apply correct mute
// state on streams affected by ringer mode.
mRingerModeMutedStreams = 0;
@@ -826,70 +835,72 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
// convert one UI step (+/-1) into a number of internal units on the stream alias
int step = rescaleIndex(10, streamType, streamTypeAlias);
- if ((direction == AudioManager.ADJUST_RAISE) &&
- !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
- return;
- }
-
int index;
int oldIndex;
- flags &= ~AudioManager.FLAG_FIXED_VOLUME;
- if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
- ((device & mFixedVolumeDevices) != 0)) {
- flags |= AudioManager.FLAG_FIXED_VOLUME;
- index = mStreamStates[streamType].getMaxIndex();
+ if ((direction == AudioManager.ADJUST_RAISE) &&
+ !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
+ index = mStreamStates[streamType].getIndex(device,
+ (streamState.muteCount() != 0) /* lastAudible */);
oldIndex = index;
} else {
- // 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) ||
- (streamTypeAlias == getMasterStreamType())) {
- int ringerMode = getRingerMode();
- // do not vibrate if already in vibrate mode
- if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
- flags &= ~AudioManager.FLAG_VIBRATE;
- }
- // Check if the ringer mode changes with this volume adjustment. If
- // it does, it will handle adjusting the volume, so we won't below
- adjustVolume = checkForRingerModeChange(aliasIndex, direction, step);
- if ((streamTypeAlias == getMasterStreamType()) &&
- (mRingerMode == AudioManager.RINGER_MODE_SILENT)) {
- streamState.setLastAudibleIndex(0, device);
- }
- }
-
- // If stream is muted, adjust last audible index only
- oldIndex = mStreamStates[streamType].getIndex(device,
- (mStreamStates[streamType].muteCount() != 0) /* lastAudible */);
-
- if (streamState.muteCount() != 0) {
- if (adjustVolume) {
- // Post a persist volume msg
- // no need to persist volume on all streams sharing the same alias
- streamState.adjustLastAudibleIndex(direction * step, device);
- sendMsg(mAudioHandler,
- MSG_PERSIST_VOLUME,
- SENDMSG_QUEUE,
- PERSIST_LAST_AUDIBLE,
- device,
- streamState,
- PERSIST_DELAY);
- }
- index = mStreamStates[streamType].getIndex(device, true /* lastAudible */);
+ flags &= ~AudioManager.FLAG_FIXED_VOLUME;
+ if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
+ ((device & mFixedVolumeDevices) != 0)) {
+ flags |= AudioManager.FLAG_FIXED_VOLUME;
+ index = mStreamStates[streamType].getMaxIndex();
+ oldIndex = index;
} else {
- if (adjustVolume && streamState.adjustIndex(direction * step, device)) {
- // Post message to set system volume (it in turn will post a message
- // to persist). Do not change volume if stream is muted.
- sendMsg(mAudioHandler,
- MSG_SET_DEVICE_VOLUME,
- SENDMSG_QUEUE,
- device,
- 0,
- streamState,
- 0);
+ // 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) ||
+ (streamTypeAlias == getMasterStreamType())) {
+ int ringerMode = getRingerMode();
+ // do not vibrate if already in vibrate mode
+ if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
+ flags &= ~AudioManager.FLAG_VIBRATE;
+ }
+ // Check if the ringer mode changes with this volume adjustment. If
+ // it does, it will handle adjusting the volume, so we won't below
+ adjustVolume = checkForRingerModeChange(aliasIndex, direction, step);
+ if ((streamTypeAlias == getMasterStreamType()) &&
+ (mRingerMode == AudioManager.RINGER_MODE_SILENT)) {
+ streamState.setLastAudibleIndex(0, device);
+ }
+ }
+
+ // If stream is muted, adjust last audible index only
+ oldIndex = mStreamStates[streamType].getIndex(device,
+ (mStreamStates[streamType].muteCount() != 0) /* lastAudible */);
+
+ if (streamState.muteCount() != 0) {
+ if (adjustVolume) {
+ // Post a persist volume msg
+ // no need to persist volume on all streams sharing the same alias
+ streamState.adjustLastAudibleIndex(direction * step, device);
+ sendMsg(mAudioHandler,
+ MSG_PERSIST_VOLUME,
+ SENDMSG_QUEUE,
+ PERSIST_LAST_AUDIBLE,
+ device,
+ streamState,
+ PERSIST_DELAY);
+ }
+ index = mStreamStates[streamType].getIndex(device, true /* lastAudible */);
+ } else {
+ if (adjustVolume && streamState.adjustIndex(direction * step, device)) {
+ // Post message to set system volume (it in turn will post a message
+ // to persist). Do not change volume if stream is muted.
+ sendMsg(mAudioHandler,
+ MSG_SET_DEVICE_VOLUME,
+ SENDMSG_QUEUE,
+ device,
+ 0,
+ streamState,
+ 0);
+ }
+ index = mStreamStates[streamType].getIndex(device, false /* lastAudible */);
}
- index = mStreamStates[streamType].getIndex(device, false /* lastAudible */);
}
}
sendVolumeUpdate(streamType, oldIndex, index, flags);
@@ -2310,13 +2321,31 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
com.android.internal.R.integer.config_safe_media_volume_index) * 10;
boolean safeMediaVolumeEnabled = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_safe_media_volume_enabled);
+
+ // The persisted state is either "disabled" or "active": this is the state applied
+ // next time we boot and cannot be "inactive"
+ int persistedState;
if (safeMediaVolumeEnabled) {
- mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
- enforceSafeMediaVolume();
+ persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
+ // The state can already be "inactive" here if the user has forced it before
+ // the 30 seconds timeout for forced configuration. In this case we don't reset
+ // it to "active".
+ if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
+ mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
+ enforceSafeMediaVolume();
+ }
} else {
+ persistedState = SAFE_MEDIA_VOLUME_DISABLED;
mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
}
mMcc = mcc;
+ sendMsg(mAudioHandler,
+ MSG_PERSIST_SAFE_VOLUME_STATE,
+ SENDMSG_QUEUE,
+ persistedState,
+ 0,
+ null,
+ 0);
}
}
}
@@ -3228,6 +3257,12 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
AudioSystem.setForceUse(usage, config);
}
+ private void onPersistSafeVolumeState(int state) {
+ Settings.Global.putInt(mContentResolver,
+ Settings.Global.AUDIO_SAFE_VOLUME_STATE,
+ state);
+ }
+
@Override
public void handleMessage(Message msg) {
@@ -3330,6 +3365,13 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
mBluetoothA2dpEnabled ?
AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
}
+
+ synchronized (mSettingsLock) {
+ AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
+ mDockAudioMediaEnabled ?
+ AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
+ }
+
// indicate the end of reconfiguration phase to audio HAL
AudioSystem.setParameters("restarting=false");
break;
@@ -3430,6 +3472,9 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
break;
+ case MSG_PERSIST_SAFE_VOLUME_STATE:
+ onPersistSafeVolumeState(msg.arg1);
+ break;
}
}
}
@@ -3757,13 +3802,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
config = AudioSystem.FORCE_BT_CAR_DOCK;
break;
case Intent.EXTRA_DOCK_STATE_LE_DESK:
- synchronized (mSettingsLock) {
- if (mDockAudioMediaEnabled) {
- config = AudioSystem.FORCE_ANALOG_DOCK;
- } else {
- config = AudioSystem.FORCE_NONE;
- }
- }
+ config = AudioSystem.FORCE_ANALOG_DOCK;
break;
case Intent.EXTRA_DOCK_STATE_HE_DESK:
config = AudioSystem.FORCE_DIGITAL_DOCK;
@@ -3772,8 +3811,14 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
default:
config = AudioSystem.FORCE_NONE;
}
-
- AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
+ // Low end docks have a menu to enable or disable audio
+ // (see mDockAudioMediaEnabled)
+ if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
+ ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
+ (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
+ AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
+ }
+ mDockState = dockState;
} else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
BluetoothProfile.STATE_DISCONNECTED);
@@ -5085,18 +5130,23 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
// top of the stack for the media button event receivers : simply using the top of the
// stack would make the entry disappear from the RemoteControlDisplay in conditions such as
// notifications playing during music playback.
- // crawl the AudioFocus stack until an entry is found with the following characteristics:
+ // Crawl the AudioFocus stack from the top until an entry is found with the following
+ // characteristics:
// - focus gain on STREAM_MUSIC stream
// - non-transient focus gain on a stream other than music
FocusStackEntry af = null;
- Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
- while(stackIterator.hasNext()) {
- FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
- if ((fse.mStreamType == AudioManager.STREAM_MUSIC)
- || (fse.mFocusChangeType == AudioManager.AUDIOFOCUS_GAIN)) {
- af = fse;
- break;
+ try {
+ for (int index = mFocusStack.size()-1; index >= 0; index--) {
+ FocusStackEntry fse = mFocusStack.elementAt(index);
+ if ((fse.mStreamType == AudioManager.STREAM_MUSIC)
+ || (fse.mFocusChangeType == AudioManager.AUDIOFOCUS_GAIN)) {
+ af = fse;
+ break;
+ }
}
+ } catch (ArrayIndexOutOfBoundsException e) {
+ Log.e(TAG, "Wrong index accessing audio focus stack when updating RCD: " + e);
+ af = null;
}
if (af == null) {
clearRemoteControlDisplay_syncAfRcs();
@@ -5117,6 +5167,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
clearRemoteControlDisplay_syncAfRcs();
return;
}
+
// refresh conditions were verified: update the remote controls
// ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty
updateRemoteControlDisplay_syncAfRcs(infoChangedFlags);
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 4414191..a2eb8d9 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -26,7 +26,7 @@ import java.util.Map;
*
* The format of the media data is specified as string/value pairs.
*
- * Keys common to all formats:
+ * Keys common to all formats, <b>all keys not marked optional are mandatory</b>:
*
* <table>
* <tr><th>Name</th><th>Value Type</th><th>Description</th></tr>
@@ -50,9 +50,9 @@ import java.util.Map;
* <tr><th>Name</th><th>Value Type</th><th>Description</th></tr>
* <tr><td>{@link #KEY_CHANNEL_COUNT}</td><td>Integer</td><td></td></tr>
* <tr><td>{@link #KEY_SAMPLE_RATE}</td><td>Integer</td><td></td></tr>
- * <tr><td>{@link #KEY_IS_ADTS}</td><td>Integer</td><td>optional, if content is AAC audio, setting this key to 1 indicates that each audio frame is prefixed by the ADTS header.</td></tr>
+ * <tr><td>{@link #KEY_IS_ADTS}</td><td>Integer</td><td>optional, if <em>decoding</em> AAC audio content, setting this key to 1 indicates that each audio frame is prefixed by the ADTS header.</td></tr>
* <tr><td>{@link #KEY_AAC_PROFILE}</td><td>Integer</td><td><b>encoder-only</b>, optional, if content is AAC audio, specifies the desired profile.</td></tr>
- * <tr><td>{@link #KEY_CHANNEL_MASK}</td><td>Integer</td><td>A mask of audio channel assignments</td></tr>
+ * <tr><td>{@link #KEY_CHANNEL_MASK}</td><td>Integer</td><td>optional, a mask of audio channel assignments</td></tr>
* <tr><td>{@link #KEY_FLAC_COMPRESSION_LEVEL}</td><td>Integer</td><td><b>encoder-only</b>, optional, if content is FLAC audio, specifies the desired compression level.</td></tr>
* </table>
*
@@ -140,6 +140,8 @@ public final class MediaFormat {
* A key mapping to a value of 1 if the content is AAC audio and
* audio frames are prefixed with an ADTS header.
* The associated value is an integer (0 or 1).
+ * This key is only supported when _decoding_ content, it cannot
+ * be used to configure an encoder to emit ADTS output.
*/
public static final String KEY_IS_ADTS = "is-adts";
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index ef0da3a..7c547ec 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -328,8 +328,8 @@ import java.lang.ref.WeakReference;
* the state. Calling this method in an invalid state transfers the
* object to the <em>Error</em> state. </p></td></tr>
* <tr><td>pause </p></td>
- * <td>{Started, Paused}</p></td>
- * <td>{Idle, Initialized, Prepared, Stopped, PlaybackCompleted, Error}</p></td>
+ * <td>{Started, Paused, PlaybackCompleted}</p></td>
+ * <td>{Idle, Initialized, Prepared, Stopped, Error}</p></td>
* <td>Successful invoke of this method in a valid state transfers the
* object to the <em>Paused</em> state. Calling this method in an
* invalid state transfers the object to the <em>Error</em> state.</p></td></tr>
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 2a5a16e..8b489b1 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -313,13 +313,25 @@ public class MediaRouter {
}
/**
- * Return the currently selected route for the given types
+ * Return the currently selected route for any of the given types
*
* @param type route types
* @return the selected route
*/
public RouteInfo getSelectedRoute(int type) {
- return sStatic.mSelectedRoute;
+ if (sStatic.mSelectedRoute != null &&
+ (sStatic.mSelectedRoute.mSupportedTypes & type) != 0) {
+ // If the selected route supports any of the types supplied, it's still considered
+ // 'selected' for that type.
+ return sStatic.mSelectedRoute;
+ } else if (type == ROUTE_TYPE_USER) {
+ // The caller specifically asked for a user route and the currently selected route
+ // doesn't qualify.
+ return null;
+ }
+ // If the above didn't match and we're not specifically asking for a user route,
+ // consider the default selected.
+ return sStatic.mDefaultAudioVideo;
}
/**
@@ -862,7 +874,7 @@ public class MediaRouter {
private static WifiDisplay findMatchingDisplay(WifiDisplay d, WifiDisplay[] displays) {
for (int i = 0; i < displays.length; i++) {
final WifiDisplay other = displays[i];
- if (d.getDeviceAddress().equals(other.getDeviceAddress())) {
+ if (d.hasSameAddress(other)) {
return other;
}
}