diff options
Diffstat (limited to 'media')
| -rw-r--r-- | media/java/android/media/AudioManager.java | 85 | ||||
| -rw-r--r-- | media/java/android/media/AudioService.java | 262 | ||||
| -rw-r--r-- | media/libstagefright/AwesomePlayer.cpp | 5 | ||||
| -rw-r--r-- | media/libstagefright/OMXCodec.cpp | 3 | ||||
| -rw-r--r-- | media/libstagefright/WVMExtractor.cpp | 22 | ||||
| -rw-r--r-- | media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp | 27 | ||||
| -rw-r--r-- | media/libstagefright/include/SimpleSoftOMXComponent.h | 2 | ||||
| -rw-r--r-- | media/libstagefright/include/SoftOMXComponent.h | 2 | ||||
| -rw-r--r-- | media/libstagefright/include/WVMExtractor.h | 16 | ||||
| -rw-r--r-- | media/libstagefright/omx/SimpleSoftOMXComponent.cpp | 6 | ||||
| -rw-r--r-- | media/libstagefright/omx/SoftOMXPlugin.cpp | 4 |
11 files changed, 315 insertions, 119 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/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/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, ×tamp, &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; |
