Loading media/java/android/media/AudioManager.java +7 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; Loading Loading @@ -1205,6 +1206,11 @@ public class AudioManager { * 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: * <p>NOTE: up to and including API version * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual * voice call to the bluetooth headset. * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio * connection is established. * <ul> * <li> the stream type must be {@link #STREAM_VOICE_CALL} </li> * <li> the format must be mono </li> Loading @@ -1226,7 +1232,7 @@ public class AudioManager { public void startBluetoothSco(){ IAudioService service = getService(); try { service.startBluetoothSco(mICallBack); service.startBluetoothSco(mICallBack, mContext.getApplicationInfo().targetSdkVersion); } catch (RemoteException e) { Log.e(TAG, "Dead object in startBluetoothSco", e); } Loading media/java/android/media/AudioService.java +47 −11 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ import android.database.ContentObserver; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnErrorListener; import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; Loading Loading @@ -369,6 +370,14 @@ public class AudioService extends IAudioService.Stub implements OnFinished { // waiting for headset service to connect private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4; // Indicates the mode used for SCO audio connection. The mode is virtual call if the request // originated from an app targeting an API version before JB MR2 and raw audio after that. private int mScoAudioMode; // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall()) private static final int SCO_MODE_VIRTUAL_CALL = 0; // SCO audio mode is raw audio (BluetoothHeadset.connectAudio()) private static final int SCO_MODE_RAW = 1; // Current connection state indicated by bluetooth headset private int mScoConnectionState; Loading Loading @@ -1910,7 +1919,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } /** @see AudioManager#startBluetoothSco() */ public void startBluetoothSco(IBinder cb){ public void startBluetoothSco(IBinder cb, int targetSdkVersion){ if (!checkAudioSettingsPermission("startBluetoothSco()") || !mBootCompleted) { return; Loading @@ -1922,7 +1931,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { // The caller identity must be cleared after getScoClient() because it is needed if a new // client is created. final long ident = Binder.clearCallingIdentity(); client.incCount(); client.incCount(targetSdkVersion); Binder.restoreCallingIdentity(ident); } Loading Loading @@ -1968,9 +1977,9 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } } public void incCount() { public void incCount(int targetSdkVersion) { synchronized(mScoClients) { requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED); requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, targetSdkVersion); if (mStartcount == 0) { try { mCb.linkToDeath(this, 0); Loading @@ -1996,7 +2005,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { Log.w(TAG, "decCount() going to 0 but not registered to binder"); } } requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED); requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0); } } } Loading @@ -2012,7 +2021,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } mStartcount = 0; if (stopSco) { requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED); requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0); } } } Loading Loading @@ -2040,7 +2049,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } } private void requestScoState(int state) { private void requestScoState(int state, int targetSdkVersion) { checkScoAudioState(); if (totalCount() == 0) { if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) { Loading @@ -2055,8 +2064,18 @@ public class AudioService extends IAudioService.Stub implements OnFinished { (mScoAudioState == SCO_STATE_INACTIVE || mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) { if (mScoAudioState == SCO_STATE_INACTIVE) { mScoAudioMode = (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ? SCO_MODE_VIRTUAL_CALL : SCO_MODE_RAW; if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) { if (mBluetoothHeadset.connectAudio()) { boolean status; if (mScoAudioMode == SCO_MODE_RAW) { status = mBluetoothHeadset.connectAudio(); } else { status = mBluetoothHeadset.startScoUsingVirtualVoiceCall( mBluetoothHeadsetDevice); } if (status) { mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; } else { broadcastScoConnectionState( Loading @@ -2078,7 +2097,14 @@ public class AudioService extends IAudioService.Stub implements OnFinished { mScoAudioState == SCO_STATE_ACTIVATE_REQ)) { if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) { if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) { if (!mBluetoothHeadset.disconnectAudio()) { boolean status; if (mScoAudioMode == SCO_MODE_RAW) { status = mBluetoothHeadset.disconnectAudio(); } else { status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall( mBluetoothHeadsetDevice); } if (!status) { mScoAudioState = SCO_STATE_INACTIVE; broadcastScoConnectionState( AudioManager.SCO_AUDIO_STATE_DISCONNECTED); Loading Loading @@ -2251,10 +2277,20 @@ public class AudioService extends IAudioService.Stub implements OnFinished { switch (mScoAudioState) { case SCO_STATE_ACTIVATE_REQ: mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; if (mScoAudioMode == SCO_MODE_RAW) { status = mBluetoothHeadset.connectAudio(); } else { status = mBluetoothHeadset.startScoUsingVirtualVoiceCall( mBluetoothHeadsetDevice); } break; case SCO_STATE_DEACTIVATE_REQ: if (mScoAudioMode == SCO_MODE_RAW) { status = mBluetoothHeadset.disconnectAudio(); } else { status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall( mBluetoothHeadsetDevice); } break; case SCO_STATE_DEACTIVATE_EXT_REQ: status = mBluetoothHeadset.stopVoiceRecognition( Loading media/java/android/media/IAudioService.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -179,7 +179,7 @@ interface IAudioService { int getRemoteStreamVolume(); oneway void registerRemoteVolumeObserverForRcc(int rccId, in IRemoteVolumeObserver rvo); void startBluetoothSco(IBinder cb); void startBluetoothSco(IBinder cb, int targetSdkVersion); void stopBluetoothSco(IBinder cb); void forceVolumeControlStream(int streamType, IBinder cb); Loading Loading
media/java/android/media/AudioManager.java +7 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; Loading Loading @@ -1205,6 +1206,11 @@ public class AudioManager { * 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: * <p>NOTE: up to and including API version * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual * voice call to the bluetooth headset. * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio * connection is established. * <ul> * <li> the stream type must be {@link #STREAM_VOICE_CALL} </li> * <li> the format must be mono </li> Loading @@ -1226,7 +1232,7 @@ public class AudioManager { public void startBluetoothSco(){ IAudioService service = getService(); try { service.startBluetoothSco(mICallBack); service.startBluetoothSco(mICallBack, mContext.getApplicationInfo().targetSdkVersion); } catch (RemoteException e) { Log.e(TAG, "Dead object in startBluetoothSco", e); } Loading
media/java/android/media/AudioService.java +47 −11 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ import android.database.ContentObserver; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnErrorListener; import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; Loading Loading @@ -369,6 +370,14 @@ public class AudioService extends IAudioService.Stub implements OnFinished { // waiting for headset service to connect private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4; // Indicates the mode used for SCO audio connection. The mode is virtual call if the request // originated from an app targeting an API version before JB MR2 and raw audio after that. private int mScoAudioMode; // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall()) private static final int SCO_MODE_VIRTUAL_CALL = 0; // SCO audio mode is raw audio (BluetoothHeadset.connectAudio()) private static final int SCO_MODE_RAW = 1; // Current connection state indicated by bluetooth headset private int mScoConnectionState; Loading Loading @@ -1910,7 +1919,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } /** @see AudioManager#startBluetoothSco() */ public void startBluetoothSco(IBinder cb){ public void startBluetoothSco(IBinder cb, int targetSdkVersion){ if (!checkAudioSettingsPermission("startBluetoothSco()") || !mBootCompleted) { return; Loading @@ -1922,7 +1931,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { // The caller identity must be cleared after getScoClient() because it is needed if a new // client is created. final long ident = Binder.clearCallingIdentity(); client.incCount(); client.incCount(targetSdkVersion); Binder.restoreCallingIdentity(ident); } Loading Loading @@ -1968,9 +1977,9 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } } public void incCount() { public void incCount(int targetSdkVersion) { synchronized(mScoClients) { requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED); requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, targetSdkVersion); if (mStartcount == 0) { try { mCb.linkToDeath(this, 0); Loading @@ -1996,7 +2005,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { Log.w(TAG, "decCount() going to 0 but not registered to binder"); } } requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED); requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0); } } } Loading @@ -2012,7 +2021,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } mStartcount = 0; if (stopSco) { requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED); requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0); } } } Loading Loading @@ -2040,7 +2049,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished { } } private void requestScoState(int state) { private void requestScoState(int state, int targetSdkVersion) { checkScoAudioState(); if (totalCount() == 0) { if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) { Loading @@ -2055,8 +2064,18 @@ public class AudioService extends IAudioService.Stub implements OnFinished { (mScoAudioState == SCO_STATE_INACTIVE || mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) { if (mScoAudioState == SCO_STATE_INACTIVE) { mScoAudioMode = (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ? SCO_MODE_VIRTUAL_CALL : SCO_MODE_RAW; if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) { if (mBluetoothHeadset.connectAudio()) { boolean status; if (mScoAudioMode == SCO_MODE_RAW) { status = mBluetoothHeadset.connectAudio(); } else { status = mBluetoothHeadset.startScoUsingVirtualVoiceCall( mBluetoothHeadsetDevice); } if (status) { mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; } else { broadcastScoConnectionState( Loading @@ -2078,7 +2097,14 @@ public class AudioService extends IAudioService.Stub implements OnFinished { mScoAudioState == SCO_STATE_ACTIVATE_REQ)) { if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) { if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) { if (!mBluetoothHeadset.disconnectAudio()) { boolean status; if (mScoAudioMode == SCO_MODE_RAW) { status = mBluetoothHeadset.disconnectAudio(); } else { status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall( mBluetoothHeadsetDevice); } if (!status) { mScoAudioState = SCO_STATE_INACTIVE; broadcastScoConnectionState( AudioManager.SCO_AUDIO_STATE_DISCONNECTED); Loading Loading @@ -2251,10 +2277,20 @@ public class AudioService extends IAudioService.Stub implements OnFinished { switch (mScoAudioState) { case SCO_STATE_ACTIVATE_REQ: mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; if (mScoAudioMode == SCO_MODE_RAW) { status = mBluetoothHeadset.connectAudio(); } else { status = mBluetoothHeadset.startScoUsingVirtualVoiceCall( mBluetoothHeadsetDevice); } break; case SCO_STATE_DEACTIVATE_REQ: if (mScoAudioMode == SCO_MODE_RAW) { status = mBluetoothHeadset.disconnectAudio(); } else { status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall( mBluetoothHeadsetDevice); } break; case SCO_STATE_DEACTIVATE_EXT_REQ: status = mBluetoothHeadset.stopVoiceRecognition( Loading
media/java/android/media/IAudioService.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -179,7 +179,7 @@ interface IAudioService { int getRemoteStreamVolume(); oneway void registerRemoteVolumeObserverForRcc(int rccId, in IRemoteVolumeObserver rvo); void startBluetoothSco(IBinder cb); void startBluetoothSco(IBinder cb, int targetSdkVersion); void stopBluetoothSco(IBinder cb); void forceVolumeControlStream(int streamType, IBinder cb); Loading