am 56af4f21: Merge "AudioService: SCO audio backward compatibility" into jb-mr2-dev
* commit '56af4f212a21fe08b54de10322e023b09fa125aa': AudioService: SCO audio backward compatibility
This commit is contained in:
@@ -24,6 +24,7 @@ import android.content.ComponentName;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
@@ -1205,6 +1206,11 @@ public class AudioManager {
|
|||||||
* call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection.
|
* 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
|
* <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:
|
* 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>
|
* <ul>
|
||||||
* <li> the stream type must be {@link #STREAM_VOICE_CALL} </li>
|
* <li> the stream type must be {@link #STREAM_VOICE_CALL} </li>
|
||||||
* <li> the format must be mono </li>
|
* <li> the format must be mono </li>
|
||||||
@@ -1226,7 +1232,7 @@ public class AudioManager {
|
|||||||
public void startBluetoothSco(){
|
public void startBluetoothSco(){
|
||||||
IAudioService service = getService();
|
IAudioService service = getService();
|
||||||
try {
|
try {
|
||||||
service.startBluetoothSco(mICallBack);
|
service.startBluetoothSco(mICallBack, mContext.getApplicationInfo().targetSdkVersion);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Dead object in startBluetoothSco", e);
|
Log.e(TAG, "Dead object in startBluetoothSco", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import android.database.ContentObserver;
|
|||||||
import android.media.MediaPlayer.OnCompletionListener;
|
import android.media.MediaPlayer.OnCompletionListener;
|
||||||
import android.media.MediaPlayer.OnErrorListener;
|
import android.media.MediaPlayer.OnErrorListener;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@@ -369,6 +370,14 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
|
|||||||
// waiting for headset service to connect
|
// waiting for headset service to connect
|
||||||
private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
|
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
|
// Current connection state indicated by bluetooth headset
|
||||||
private int mScoConnectionState;
|
private int mScoConnectionState;
|
||||||
|
|
||||||
@@ -1910,7 +1919,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @see AudioManager#startBluetoothSco() */
|
/** @see AudioManager#startBluetoothSco() */
|
||||||
public void startBluetoothSco(IBinder cb){
|
public void startBluetoothSco(IBinder cb, int targetSdkVersion){
|
||||||
if (!checkAudioSettingsPermission("startBluetoothSco()") ||
|
if (!checkAudioSettingsPermission("startBluetoothSco()") ||
|
||||||
!mBootCompleted) {
|
!mBootCompleted) {
|
||||||
return;
|
return;
|
||||||
@@ -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
|
// The caller identity must be cleared after getScoClient() because it is needed if a new
|
||||||
// client is created.
|
// client is created.
|
||||||
final long ident = Binder.clearCallingIdentity();
|
final long ident = Binder.clearCallingIdentity();
|
||||||
client.incCount();
|
client.incCount(targetSdkVersion);
|
||||||
Binder.restoreCallingIdentity(ident);
|
Binder.restoreCallingIdentity(ident);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1968,9 +1977,9 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void incCount() {
|
public void incCount(int targetSdkVersion) {
|
||||||
synchronized(mScoClients) {
|
synchronized(mScoClients) {
|
||||||
requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED);
|
requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, targetSdkVersion);
|
||||||
if (mStartcount == 0) {
|
if (mStartcount == 0) {
|
||||||
try {
|
try {
|
||||||
mCb.linkToDeath(this, 0);
|
mCb.linkToDeath(this, 0);
|
||||||
@@ -1996,7 +2005,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
|
|||||||
Log.w(TAG, "decCount() going to 0 but not registered to binder");
|
Log.w(TAG, "decCount() going to 0 but not registered to binder");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
|
requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2012,7 +2021,7 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
|
|||||||
}
|
}
|
||||||
mStartcount = 0;
|
mStartcount = 0;
|
||||||
if (stopSco) {
|
if (stopSco) {
|
||||||
requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
|
requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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();
|
checkScoAudioState();
|
||||||
if (totalCount() == 0) {
|
if (totalCount() == 0) {
|
||||||
if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
|
if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
|
||||||
@@ -2055,8 +2064,18 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
|
|||||||
(mScoAudioState == SCO_STATE_INACTIVE ||
|
(mScoAudioState == SCO_STATE_INACTIVE ||
|
||||||
mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
|
mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
|
||||||
if (mScoAudioState == SCO_STATE_INACTIVE) {
|
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 != 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;
|
mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
|
||||||
} else {
|
} else {
|
||||||
broadcastScoConnectionState(
|
broadcastScoConnectionState(
|
||||||
@@ -2078,7 +2097,14 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
|
|||||||
mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
|
mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
|
||||||
if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
|
if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
|
||||||
if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
|
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;
|
mScoAudioState = SCO_STATE_INACTIVE;
|
||||||
broadcastScoConnectionState(
|
broadcastScoConnectionState(
|
||||||
AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
|
||||||
@@ -2251,10 +2277,20 @@ public class AudioService extends IAudioService.Stub implements OnFinished {
|
|||||||
switch (mScoAudioState) {
|
switch (mScoAudioState) {
|
||||||
case SCO_STATE_ACTIVATE_REQ:
|
case SCO_STATE_ACTIVATE_REQ:
|
||||||
mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
|
mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
|
||||||
status = mBluetoothHeadset.connectAudio();
|
if (mScoAudioMode == SCO_MODE_RAW) {
|
||||||
|
status = mBluetoothHeadset.connectAudio();
|
||||||
|
} else {
|
||||||
|
status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
|
||||||
|
mBluetoothHeadsetDevice);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case SCO_STATE_DEACTIVATE_REQ:
|
case SCO_STATE_DEACTIVATE_REQ:
|
||||||
status = mBluetoothHeadset.disconnectAudio();
|
if (mScoAudioMode == SCO_MODE_RAW) {
|
||||||
|
status = mBluetoothHeadset.disconnectAudio();
|
||||||
|
} else {
|
||||||
|
status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
|
||||||
|
mBluetoothHeadsetDevice);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case SCO_STATE_DEACTIVATE_EXT_REQ:
|
case SCO_STATE_DEACTIVATE_EXT_REQ:
|
||||||
status = mBluetoothHeadset.stopVoiceRecognition(
|
status = mBluetoothHeadset.stopVoiceRecognition(
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ interface IAudioService {
|
|||||||
int getRemoteStreamVolume();
|
int getRemoteStreamVolume();
|
||||||
oneway void registerRemoteVolumeObserverForRcc(int rccId, in IRemoteVolumeObserver rvo);
|
oneway void registerRemoteVolumeObserverForRcc(int rccId, in IRemoteVolumeObserver rvo);
|
||||||
|
|
||||||
void startBluetoothSco(IBinder cb);
|
void startBluetoothSco(IBinder cb, int targetSdkVersion);
|
||||||
void stopBluetoothSco(IBinder cb);
|
void stopBluetoothSco(IBinder cb);
|
||||||
|
|
||||||
void forceVolumeControlStream(int streamType, IBinder cb);
|
void forceVolumeControlStream(int streamType, IBinder cb);
|
||||||
|
|||||||
Reference in New Issue
Block a user