summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/java/android/media/AudioManager.java85
-rw-r--r--media/java/android/media/AudioService.java262
-rw-r--r--media/java/android/media/MediaPlayer.java7
-rw-r--r--media/libstagefright/AwesomePlayer.cpp5
-rw-r--r--media/libstagefright/OMXCodec.cpp3
-rw-r--r--media/libstagefright/WVMExtractor.cpp22
-rw-r--r--media/libstagefright/chromium_http/support.cpp2
-rw-r--r--media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp27
-rw-r--r--media/libstagefright/include/SimpleSoftOMXComponent.h2
-rw-r--r--media/libstagefright/include/SoftOMXComponent.h2
-rw-r--r--media/libstagefright/include/WVMExtractor.h16
-rw-r--r--media/libstagefright/omx/SimpleSoftOMXComponent.cpp6
-rw-r--r--media/libstagefright/omx/SoftOMXPlugin.cpp4
13 files changed, 322 insertions, 121 deletions
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index e1daede..253010c 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -828,29 +828,64 @@ public class AudioManager {
* or {@link #SCO_AUDIO_STATE_CONNECTED}
*
* @see #startBluetoothSco()
+ * @deprecated Use {@link #ACTION_SCO_AUDIO_STATE_UPDATED} instead
*/
+ @Deprecated
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_SCO_AUDIO_STATE_CHANGED =
"android.media.SCO_AUDIO_STATE_CHANGED";
+
+ /**
+ * Sticky broadcast intent action indicating that the bluetoooth SCO audio
+ * connection state has been updated.
+ * <p>This intent has two extras:
+ * <ul>
+ * <li> {@link #EXTRA_SCO_AUDIO_STATE} - The new SCO audio state. </li>
+ * <li> {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}- The previous SCO audio state. </li>
+ * </ul>
+ * <p> EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE can be any of:
+ * <ul>
+ * <li> {@link #SCO_AUDIO_STATE_DISCONNECTED}, </li>
+ * <li> {@link #SCO_AUDIO_STATE_CONNECTING} or </li>
+ * <li> {@link #SCO_AUDIO_STATE_CONNECTED}, </li>
+ * </ul>
+ * @see #startBluetoothSco()
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_SCO_AUDIO_STATE_UPDATED =
+ "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
+
/**
- * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED} containing the new
- * bluetooth SCO connection state.
+ * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED} or
+ * {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the new bluetooth SCO connection state.
*/
public static final String EXTRA_SCO_AUDIO_STATE =
"android.media.extra.SCO_AUDIO_STATE";
/**
- * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} indicating that the
- * SCO audio channel is not established
+ * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the previous
+ * bluetooth SCO connection state.
+ */
+ public static final String EXTRA_SCO_AUDIO_PREVIOUS_STATE =
+ "android.media.extra.SCO_AUDIO_PREVIOUS_STATE";
+
+ /**
+ * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
+ * indicating that the SCO audio channel is not established
*/
public static final int SCO_AUDIO_STATE_DISCONNECTED = 0;
/**
- * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} indicating that the
- * SCO audio channel is established
+ * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} or {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}
+ * indicating that the SCO audio channel is established
*/
public static final int SCO_AUDIO_STATE_CONNECTED = 1;
/**
- * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} indicating that
+ * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
+ * indicating that the SCO audio channel is being established
+ */
+ public static final int SCO_AUDIO_STATE_CONNECTING = 2;
+ /**
+ * Value for extra EXTRA_SCO_AUDIO_STATE indicating that
* there was an error trying to obtain the state
*/
public static final int SCO_AUDIO_STATE_ERROR = -1;
@@ -878,29 +913,37 @@ public class AudioManager {
* to/from a bluetooth SCO headset while the phone is not in call.
* <p>As the SCO connection establishment can take several seconds,
* applications should not rely on the connection to be available when the method
- * returns but instead register to receive the intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED}
+ * returns but instead register to receive the intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED}
* and wait for the state to be {@link #SCO_AUDIO_STATE_CONNECTED}.
- * <p>As the connection is not guaranteed to succeed, applications must wait for this intent with
- * a timeout.
- * <p>When finished with the SCO connection or if the establishment times out,
- * the application must call {@link #stopBluetoothSco()} to clear the request and turn
- * down the bluetooth connection.
+ * <p>As the ACTION_SCO_AUDIO_STATE_UPDATED intent is sticky, the application can check the SCO
+ * audio state before calling startBluetoothSco() by reading the intent returned by the receiver
+ * registration. If the state is already CONNECTED, no state change will be received via the
+ * intent after calling startBluetoothSco(). It is however useful to call startBluetoothSco()
+ * so that the connection stays active in case the current initiator stops the connection.
+ * <p>Unless the connection is already active as described above, the state will always
+ * transition from DISCONNECTED to CONNECTING and then either to CONNECTED if the connection
+ * succeeds or back to DISCONNECTED if the connection fails (e.g no headset is connected).
+ * <p>When finished with the SCO connection or if the establishment fails, the application must
+ * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection.
* <p>Even if a SCO connection is established, the following restrictions apply on audio
* output streams so that they can be routed to SCO headset:
- * - the stream type must be {@link #STREAM_VOICE_CALL}
- * - the format must be mono
- * - the sampling must be 16kHz or 8kHz
+ * <ul>
+ * <li> the stream type must be {@link #STREAM_VOICE_CALL} </li>
+ * <li> the format must be mono </li>
+ * <li> the sampling must be 16kHz or 8kHz </li>
+ * </ul>
* <p>The following restrictions apply on input streams:
- * - the format must be mono
- * - the sampling must be 8kHz
- *
+ * <ul>
+ * <li> the format must be mono </li>
+ * <li> the sampling must be 8kHz </li>
+ * </ul>
* <p>Note that the phone application always has the priority on the usage of the SCO
* connection for telephony. If this method is called while the phone is in call
* it will be ignored. Similarly, if a call is received or sent while an application
* is using the SCO connection, the connection will be lost for the application and NOT
* returned automatically when the call ends.
* @see #stopBluetoothSco()
- * @see #ACTION_SCO_AUDIO_STATE_CHANGED
+ * @see #ACTION_SCO_AUDIO_STATE_UPDATED
*/
public void startBluetoothSco(){
IAudioService service = getService();
@@ -917,7 +960,7 @@ public class AudioManager {
* {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
* <p>This method must be called by applications having requested the use of
* bluetooth SCO audio with {@link #startBluetoothSco()}
- * when finished with the SCO connection or if the establishment times out.
+ * when finished with the SCO connection or if connection fails.
* @see #startBluetoothSco()
*/
public void stopBluetoothSco(){
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 504cfde..4e77fcb 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -112,9 +112,12 @@ public class AudioService extends IAudioService.Stub {
private static final int MSG_LOAD_SOUND_EFFECTS = 9;
private static final int MSG_SET_FORCE_USE = 10;
private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 11;
-
+ private static final int MSG_BT_HEADSET_CNCT_FAILED = 12;
private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
+ // Timeout for connection to bluetooth headset service
+ private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
+
/** @see AudioSystemThread */
private AudioSystemThread mAudioSystemThread;
@@ -273,11 +276,22 @@ public class AudioService extends IAudioService.Stub {
private int mScoAudioState;
// SCO audio state is not active
private static final int SCO_STATE_INACTIVE = 0;
+ // SCO audio activation request waiting for headset service to connect
+ private static final int SCO_STATE_ACTIVATE_REQ = 1;
// SCO audio state is active or starting due to a local request to start a virtual call
- private static final int SCO_STATE_ACTIVE_INTERNAL = 1;
+ private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
+ // SCO audio deactivation request waiting for headset service to connect
+ private static final int SCO_STATE_DEACTIVATE_REQ = 5;
+
// SCO audio state is active due to an action in BT handsfree (either voice recognition or
// in call audio)
private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
+ // Deactivation request for all SCO connections (initiated by audio mode change)
+ // waiting for headset service to connect
+ private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
+
+ // Current connection state indicated by bluetooth headset
+ private int mScoConnectionState;
// true if boot sequence has been completed
private boolean mBootCompleted;
@@ -335,13 +349,6 @@ public class AudioService extends IAudioService.Stub {
AudioSystem.setErrorCallback(mAudioSystemCallback);
- mBluetoothHeadsetDevice = null;
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- if (adapter != null) {
- adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
- BluetoothProfile.HEADSET);
- }
-
// Register for device connection intent broadcasts.
IntentFilter intentFilter =
new IntentFilter(Intent.ACTION_HEADSET_PLUG);
@@ -768,17 +775,7 @@ public class AudioService extends IAudioService.Stub {
if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) {
AudioService.this.mMode = mode;
if (mode != AudioSystem.MODE_NORMAL) {
- synchronized(mScoClients) {
- checkScoAudioState();
- if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL) {
- mBluetoothHeadset.stopVoiceRecognition(
- mBluetoothHeadsetDevice);
- mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
- mBluetoothHeadsetDevice);
- } else {
- clearAllScoClients(mCb, true);
- }
- }
+ disconnectBluetoothSco(mCb);
}
}
}
@@ -856,16 +853,7 @@ public class AudioService extends IAudioService.Stub {
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
// SCO connections not started by the application changing the mode
if (mode != AudioSystem.MODE_NORMAL) {
- synchronized(mScoClients) {
- checkScoAudioState();
- if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL) {
- mBluetoothHeadset.stopVoiceRecognition(mBluetoothHeadsetDevice);
- mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
- mBluetoothHeadsetDevice);
- } else {
- clearAllScoClients(cb, true);
- }
- }
+ disconnectBluetoothSco(cb);
}
}
}
@@ -1213,7 +1201,8 @@ public class AudioService extends IAudioService.Stub {
/** @see AudioManager#startBluetoothSco() */
public void startBluetoothSco(IBinder cb){
- if (!checkAudioSettingsPermission("startBluetoothSco()")) {
+ if (!checkAudioSettingsPermission("startBluetoothSco()") ||
+ !mBootCompleted) {
return;
}
ScoClient client = getScoClient(cb, true);
@@ -1222,7 +1211,8 @@ public class AudioService extends IAudioService.Stub {
/** @see AudioManager#stopBluetoothSco() */
public void stopBluetoothSco(IBinder cb){
- if (!checkAudioSettingsPermission("stopBluetoothSco()")) {
+ if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
+ !mBootCompleted) {
return;
}
ScoClient client = getScoClient(cb, false);
@@ -1322,25 +1312,57 @@ public class AudioService extends IAudioService.Stub {
}
private void requestScoState(int state) {
- if (mBluetoothHeadset == null) {
- return;
- }
-
checkScoAudioState();
-
- if (totalCount() == 0 &&
- mBluetoothHeadsetDevice != null) {
- // Accept SCO audio activation only in NORMAL audio mode or if the mode is
- // currently controlled by the same client.
- if ((AudioService.this.mMode == AudioSystem.MODE_NORMAL ||
- mSetModeDeathHandlers.get(0).getBinder() == mCb) &&
- state == BluetoothHeadset.STATE_AUDIO_CONNECTED &&
- mScoAudioState == SCO_STATE_INACTIVE) {
- mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
- mBluetoothHeadset.startScoUsingVirtualVoiceCall(mBluetoothHeadsetDevice);
+ if (totalCount() == 0) {
+ if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
+ // Make sure that the state transitions to CONNECTING even if we cannot initiate
+ // the connection.
+ broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
+ // Accept SCO audio activation only in NORMAL audio mode or if the mode is
+ // currently controlled by the same client.
+ if ((AudioService.this.mMode == AudioSystem.MODE_NORMAL ||
+ mSetModeDeathHandlers.get(0).getBinder() == mCb) &&
+ mBluetoothHeadsetDevice != null &&
+ (mScoAudioState == SCO_STATE_INACTIVE ||
+ mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
+ if (mScoAudioState == SCO_STATE_INACTIVE) {
+ if (mBluetoothHeadset != null) {
+ if (mBluetoothHeadset.startScoUsingVirtualVoiceCall(
+ mBluetoothHeadsetDevice)) {
+ mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+ } else {
+ broadcastScoConnectionState(
+ AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+ }
+ } else if (getBluetoothHeadset()) {
+ mScoAudioState = SCO_STATE_ACTIVATE_REQ;
+ }
+ } else {
+ mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+ broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
+ }
+ } else {
+ broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+ }
} else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
- mScoAudioState == SCO_STATE_ACTIVE_INTERNAL){
- mBluetoothHeadset.stopScoUsingVirtualVoiceCall(mBluetoothHeadsetDevice);
+ mBluetoothHeadsetDevice != null &&
+ (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
+ mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
+ if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
+ if (mBluetoothHeadset != null) {
+ if (!mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
+ mBluetoothHeadsetDevice)) {
+ mScoAudioState = SCO_STATE_INACTIVE;
+ broadcastScoConnectionState(
+ AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+ }
+ } else if (getBluetoothHeadset()) {
+ mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
+ }
+ } else {
+ mScoAudioState = SCO_STATE_INACTIVE;
+ broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+ }
}
}
}
@@ -1348,7 +1370,7 @@ public class AudioService extends IAudioService.Stub {
private void checkScoAudioState() {
if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
- mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
+ mScoAudioState == SCO_STATE_INACTIVE &&
mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
!= BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
@@ -1391,10 +1413,72 @@ public class AudioService extends IAudioService.Stub {
}
}
+ private boolean getBluetoothHeadset() {
+ boolean result = false;
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter != null) {
+ result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
+ BluetoothProfile.HEADSET);
+ }
+ // If we could not get a bluetooth headset proxy, send a failure message
+ // without delay to reset the SCO audio state and clear SCO clients.
+ // If we could get a proxy, send a delayed failure message that will reset our state
+ // in case we don't receive onServiceConnected().
+ sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 0,
+ SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
+ return result;
+ }
+
+ private void disconnectBluetoothSco(IBinder exceptBinder) {
+ synchronized(mScoClients) {
+ checkScoAudioState();
+ if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
+ mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
+ if (mBluetoothHeadsetDevice != null) {
+ if (mBluetoothHeadset != null) {
+ if (!mBluetoothHeadset.stopVoiceRecognition(
+ mBluetoothHeadsetDevice) ||
+ !mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
+ mBluetoothHeadsetDevice)) {
+ sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 0,
+ SENDMSG_REPLACE, 0, 0, null, 0);
+ }
+ } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
+ getBluetoothHeadset()) {
+ mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
+ }
+ }
+ } else {
+ clearAllScoClients(exceptBinder, true);
+ }
+ }
+ }
+
+ private void resetBluetoothSco() {
+ synchronized(mScoClients) {
+ clearAllScoClients(null, false);
+ mScoAudioState = SCO_STATE_INACTIVE;
+ broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+ }
+ }
+
+ private void broadcastScoConnectionState(int state) {
+ if (state != mScoConnectionState) {
+ Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
+ newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
+ newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
+ mScoConnectionState);
+ mContext.sendStickyBroadcast(newIntent);
+ mScoConnectionState = state;
+ }
+ }
+
private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
synchronized (mScoClients) {
+ // Discard timeout message
+ mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
mBluetoothHeadset = (BluetoothHeadset) proxy;
List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices();
if (deviceList.size() > 0) {
@@ -1402,19 +1486,41 @@ public class AudioService extends IAudioService.Stub {
} else {
mBluetoothHeadsetDevice = null;
}
+ // Refresh SCO audio state
+ checkScoAudioState();
+ // Continue pending action if any
+ if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
+ mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
+ mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
+ boolean status = false;
+ if (mBluetoothHeadsetDevice != null) {
+ switch (mScoAudioState) {
+ case SCO_STATE_ACTIVATE_REQ:
+ mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+ status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
+ mBluetoothHeadsetDevice);
+ break;
+ case SCO_STATE_DEACTIVATE_REQ:
+ status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
+ mBluetoothHeadsetDevice);
+ break;
+ case SCO_STATE_DEACTIVATE_EXT_REQ:
+ status = mBluetoothHeadset.stopVoiceRecognition(
+ mBluetoothHeadsetDevice) &&
+ mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
+ mBluetoothHeadsetDevice);
+ }
+ }
+ if (!status) {
+ sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 0,
+ SENDMSG_REPLACE, 0, 0, null, 0);
+ }
+ }
}
}
public void onServiceDisconnected(int profile) {
synchronized (mScoClients) {
- if (mBluetoothHeadset != null) {
- List<BluetoothDevice> devices = mBluetoothHeadset.getConnectedDevices();
- if (devices.size() == 0) {
- mBluetoothHeadsetDevice = null;
- clearAllScoClients(null, false);
- mScoAudioState = SCO_STATE_INACTIVE;
- }
- mBluetoothHeadset = null;
- }
+ mBluetoothHeadset = null;
}
}
};
@@ -2041,6 +2147,10 @@ public class AudioService extends IAudioService.Stub {
case MSG_PERSIST_MEDIABUTTONRECEIVER:
persistMediaButtonReceiver( (ComponentName) msg.obj );
break;
+
+ case MSG_BT_HEADSET_CNCT_FAILED:
+ resetBluetoothSco();
+ break;
}
}
}
@@ -2241,8 +2351,7 @@ public class AudioService extends IAudioService.Stub {
address);
mConnectedDevices.remove(device);
mBluetoothHeadsetDevice = null;
- clearAllScoClients(null, false);
- mScoAudioState = SCO_STATE_INACTIVE;
+ resetBluetoothSco();
} else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
AudioSystem.setDeviceConnectionState(device,
AudioSystem.DEVICE_STATE_AVAILABLE,
@@ -2332,26 +2441,34 @@ public class AudioService extends IAudioService.Stub {
}
} else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
boolean broadcast = false;
- int audioState = AudioManager.SCO_AUDIO_STATE_ERROR;
+ int state = AudioManager.SCO_AUDIO_STATE_ERROR;
synchronized (mScoClients) {
int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
- if (!mScoClients.isEmpty() && mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
+ // broadcast intent if the connection was initated by AudioService
+ if (!mScoClients.isEmpty() &&
+ (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
+ mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
+ mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
broadcast = true;
}
switch (btState) {
case BluetoothHeadset.STATE_AUDIO_CONNECTED:
- audioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
- if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL) {
+ state = AudioManager.SCO_AUDIO_STATE_CONNECTED;
+ if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
+ mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
+ mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
}
break;
case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
- audioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
+ state = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
mScoAudioState = SCO_STATE_INACTIVE;
clearAllScoClients(null, false);
break;
case BluetoothHeadset.STATE_AUDIO_CONNECTING:
- if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL) {
+ if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
+ mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
+ mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
}
default:
@@ -2361,14 +2478,23 @@ public class AudioService extends IAudioService.Stub {
}
}
if (broadcast) {
+ broadcastScoConnectionState(state);
+ //FIXME: this is to maintain compatibility with deprecated intent
+ // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
- newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, audioState);
+ newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
mContext.sendStickyBroadcast(newIntent);
}
} else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
mBootCompleted = true;
sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SHARED_MSG, SENDMSG_NOOP,
0, 0, null, 0);
+
+ mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
+ resetBluetoothSco();
+ getBluetoothHeadset();
+ //FIXME: this is to maintain compatibility with deprecated intent
+ // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 84f588e..0e161a8 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -628,9 +628,11 @@ public class MediaPlayer
* and cannot be directly compared between different media sources or different
* instances of the same media source, or across multiple runs of the same
* program.
- * @hide
*/
public void setTexture(SurfaceTexture st) {
+ if (mScreenOnWhilePlaying && st != null && mSurfaceTexture == null) {
+ Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective for SurfaceTexture");
+ }
mSurfaceHolder = null;
mSurface = null;
mSurfaceTexture = st;
@@ -960,6 +962,9 @@ public class MediaPlayer
*/
public void setScreenOnWhilePlaying(boolean screenOn) {
if (mScreenOnWhilePlaying != screenOn) {
+ if (screenOn && mSurfaceTexture != null) {
+ Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective for SurfaceTexture");
+ }
mScreenOnWhilePlaying = screenOn;
updateSurfaceScreenOn();
}
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index fb7a871..70053ea 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -400,6 +400,7 @@ status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
}
void AwesomePlayer::reset() {
+ LOGI("reset");
Mutex::Autolock autoLock(mLock);
reset_l();
}
@@ -413,8 +414,10 @@ void AwesomePlayer::reset_l() {
Playback::STOP, 0);
mDecryptHandle = NULL;
mDrmManagerClient = NULL;
+ LOGI("DRM manager client stopped");
}
+
if (mFlags & PLAYING) {
uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
@@ -447,6 +450,7 @@ void AwesomePlayer::reset_l() {
mPreparedCondition.wait(mLock);
}
+ LOGI("cancel player events");
cancelPlayerEvents();
mWVMExtractor.clear();
@@ -1081,6 +1085,7 @@ void AwesomePlayer::shutdownVideoDecoder_l() {
usleep(1000);
}
IPCThreadState::self()->flushCommands();
+ LOGI("video decoder shutdown completed");
}
void AwesomePlayer::setNativeWindow_l(const sp<ANativeWindow> &native) {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 0f0ffd4..ba495cc 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -3443,7 +3443,7 @@ status_t OMXCodec::start(MetaData *meta) {
}
status_t OMXCodec::stop() {
- CODEC_LOGV("stop mState=%d", mState);
+ CODEC_LOGI("stop mState=%d", mState);
Mutex::Autolock autoLock(mLock);
@@ -3505,6 +3505,7 @@ status_t OMXCodec::stop() {
mLeftOverBuffer = NULL;
}
+ CODEC_LOGI("stopping video source");
mSource->stop();
CODEC_LOGI("stopped in state %d", mState);
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
index 83a1eaa..26eda0c 100644
--- a/media/libstagefright/WVMExtractor.cpp
+++ b/media/libstagefright/WVMExtractor.cpp
@@ -45,8 +45,7 @@ namespace android {
static Mutex gWVMutex;
WVMExtractor::WVMExtractor(const sp<DataSource> &source)
- : mDataSource(source),
- mUseAdaptiveStreaming(false) {
+ : mDataSource(source) {
{
Mutex::Autolock autoLock(gWVMutex);
if (gVendorLibHandle == NULL) {
@@ -59,13 +58,12 @@ WVMExtractor::WVMExtractor(const sp<DataSource> &source)
}
}
- typedef MediaExtractor *(*GetInstanceFunc)(sp<DataSource>);
+ typedef WVMLoadableExtractor *(*GetInstanceFunc)(sp<DataSource>);
GetInstanceFunc getInstanceFunc =
(GetInstanceFunc) dlsym(gVendorLibHandle,
"_ZN7android11GetInstanceENS_2spINS_10DataSourceEEE");
if (getInstanceFunc) {
- LOGD("Calling GetInstanceFunc");
mImpl = (*getInstanceFunc)(source);
CHECK(mImpl != NULL);
} else {
@@ -102,19 +100,17 @@ sp<MetaData> WVMExtractor::getMetaData() {
}
int64_t WVMExtractor::getCachedDurationUs(status_t *finalStatus) {
- // TODO: Fill this with life.
-
- *finalStatus = OK;
+ if (mImpl == NULL) {
+ return 0;
+ }
- return 0;
+ return mImpl->getCachedDurationUs(finalStatus);
}
void WVMExtractor::setAdaptiveStreamingMode(bool adaptive) {
- mUseAdaptiveStreaming = adaptive;
-}
-
-bool WVMExtractor::getAdaptiveStreamingMode() const {
- return mUseAdaptiveStreaming;
+ if (mImpl != NULL) {
+ mImpl->setAdaptiveStreamingMode(adaptive);
+ }
}
} //namespace android
diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp
index 3e4e493..805bd48 100644
--- a/media/libstagefright/chromium_http/support.cpp
+++ b/media/libstagefright/chromium_http/support.cpp
@@ -23,7 +23,7 @@
#include "support.h"
#include "android/net/android_network_library_impl.h"
-#include "base/thread.h"
+#include "base/threading/thread.h"
#include "net/base/cert_verifier.h"
#include "net/base/host_resolver.h"
#include "net/base/ssl_config_service.h"
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
index 13e1662..cffbfb5 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
@@ -360,10 +360,14 @@ void SoftMPEG4::onQueueFilled(OMX_U32 portIndex) {
mFramesConfigured = true;
}
- uint32_t timestamp = 0xFFFFFFFF;
+ uint32_t useExtTimestamp = (inHeader->nOffset == 0);
+
+ // decoder deals in ms, OMX in us.
+ uint32_t timestamp =
+ useExtTimestamp ? (inHeader->nTimeStamp + 500) / 1000 : 0xFFFFFFFF;
+
int32_t bufferSize = inHeader->nFilledLen;
- uint32_t useExtTimestamp = 0;
if (PVDecodeVideoFrame(
mHandle, &bitstream, &timestamp, &bufferSize,
&useExtTimestamp,
@@ -379,13 +383,20 @@ void SoftMPEG4::onQueueFilled(OMX_U32 portIndex) {
return;
}
- outHeader->nTimeStamp = inHeader->nTimeStamp;
+ // decoder deals in ms, OMX in us.
+ outHeader->nTimeStamp = timestamp * 1000;
- inInfo->mOwnedByUs = false;
- inQueue.erase(inQueue.begin());
- inInfo = NULL;
- notifyEmptyBufferDone(inHeader);
- inHeader = NULL;
+ CHECK_LE(bufferSize, inHeader->nFilledLen);
+ inHeader->nOffset += inHeader->nFilledLen - bufferSize;
+ inHeader->nFilledLen = bufferSize;
+
+ if (inHeader->nFilledLen == 0) {
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ inInfo = NULL;
+ notifyEmptyBufferDone(inHeader);
+ inHeader = NULL;
+ }
++mInputBufferCount;
diff --git a/media/libstagefright/include/SimpleSoftOMXComponent.h b/media/libstagefright/include/SimpleSoftOMXComponent.h
index 2a29a7d..50cd275 100644
--- a/media/libstagefright/include/SimpleSoftOMXComponent.h
+++ b/media/libstagefright/include/SimpleSoftOMXComponent.h
@@ -36,7 +36,7 @@ struct SimpleSoftOMXComponent : public SoftOMXComponent {
OMX_PTR appData,
OMX_COMPONENTTYPE **component);
- virtual ~SimpleSoftOMXComponent();
+ virtual void prepareForDestruction();
void onMessageReceived(const sp<AMessage> &msg);
diff --git a/media/libstagefright/include/SoftOMXComponent.h b/media/libstagefright/include/SoftOMXComponent.h
index 053bc22..a808611 100644
--- a/media/libstagefright/include/SoftOMXComponent.h
+++ b/media/libstagefright/include/SoftOMXComponent.h
@@ -38,6 +38,8 @@ struct SoftOMXComponent : public RefBase {
void setLibHandle(void *libHandle);
void *libHandle() const;
+ virtual void prepareForDestruction() {}
+
protected:
virtual ~SoftOMXComponent();
diff --git a/media/libstagefright/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h
index 62e5aa5..deecd25 100644
--- a/media/libstagefright/include/WVMExtractor.h
+++ b/media/libstagefright/include/WVMExtractor.h
@@ -25,6 +25,15 @@ namespace android {
class DataSource;
+class WVMLoadableExtractor : public MediaExtractor {
+public:
+ WVMLoadableExtractor() {}
+ virtual ~WVMLoadableExtractor() {}
+
+ virtual int64_t getCachedDurationUs(status_t *finalStatus) = 0;
+ virtual void setAdaptiveStreamingMode(bool adaptive) = 0;
+};
+
class WVMExtractor : public MediaExtractor {
public:
WVMExtractor(const sp<DataSource> &source);
@@ -49,20 +58,15 @@ public:
// is used.
void setAdaptiveStreamingMode(bool adaptive);
- // Retrieve the adaptive streaming mode used by the WV component.
- bool getAdaptiveStreamingMode() const;
-
protected:
virtual ~WVMExtractor();
private:
sp<DataSource> mDataSource;
- sp<MediaExtractor> mImpl;
- bool mUseAdaptiveStreaming;
+ sp<WVMLoadableExtractor> mImpl;
WVMExtractor(const WVMExtractor &);
WVMExtractor &operator=(const WVMExtractor &);
-
};
} // namespace android
diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
index 179b2a0..f7330f3 100644
--- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
+++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
@@ -45,7 +45,11 @@ SimpleSoftOMXComponent::SimpleSoftOMXComponent(
PRIORITY_AUDIO);
}
-SimpleSoftOMXComponent::~SimpleSoftOMXComponent() {
+void SimpleSoftOMXComponent::prepareForDestruction() {
+ // The looper's queue may still contain messages referencing this
+ // object. Make sure those are flushed before returning so that
+ // a subsequent dlunload() does not pull out the rug from under us.
+
mLooper->unregisterHandler(mHandler->id());
mLooper->stop();
}
diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp
index 6bd6624..04ca39e 100644
--- a/media/libstagefright/omx/SoftOMXPlugin.cpp
+++ b/media/libstagefright/omx/SoftOMXPlugin.cpp
@@ -21,6 +21,7 @@
#include "SoftOMXPlugin.h"
#include "include/SoftOMXComponent.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AString.h>
#include <dlfcn.h>
@@ -126,8 +127,11 @@ OMX_ERRORTYPE SoftOMXPlugin::destroyComponentInstance(
(SoftOMXComponent *)
((OMX_COMPONENTTYPE *)component)->pComponentPrivate;
+ me->prepareForDestruction();
+
void *libHandle = me->libHandle();
+ CHECK_EQ(me->getStrongCount(), 1);
me->decStrong(this);
me = NULL;