am f855a2ff: Merge "Adding support for Absolute Volume" into klp-dev

* commit 'f855a2ff01b270c06977f64f4a002f3f1c7769ca':
  Adding support for Absolute Volume
This commit is contained in:
Matthew Xie
2013-08-18 12:51:20 -07:00
committed by Android Git Automerger
5 changed files with 184 additions and 19 deletions

View File

@@ -387,6 +387,66 @@ public final class BluetoothA2dp implements BluetoothProfile {
return BluetoothProfile.PRIORITY_OFF; return BluetoothProfile.PRIORITY_OFF;
} }
/**
* Checks if Avrcp device supports the absolute volume feature.
*
* @return true if device supports absolute volume
* @hide
*/
public boolean isAvrcpAbsoluteVolumeSupported() {
if (DBG) Log.d(TAG, "isAvrcpAbsoluteVolumeSupported");
if (mService != null && isEnabled()) {
try {
return mService.isAvrcpAbsoluteVolumeSupported();
} catch (RemoteException e) {
Log.e(TAG, "Error talking to BT service in isAvrcpAbsoluteVolumeSupported()", e);
return false;
}
}
if (mService == null) Log.w(TAG, "Proxy not attached to service");
return false;
}
/**
* Tells remote device to adjust volume. Only if absolute volume is supported.
*
* @param direction 1 to increase volume, or -1 to decrease volume
* @hide
*/
public void adjustAvrcpAbsoluteVolume(int direction) {
if (DBG) Log.d(TAG, "adjustAvrcpAbsoluteVolume");
if (mService != null && isEnabled()) {
try {
mService.adjustAvrcpAbsoluteVolume(direction);
return;
} catch (RemoteException e) {
Log.e(TAG, "Error talking to BT service in adjustAvrcpAbsoluteVolume()", e);
return;
}
}
if (mService == null) Log.w(TAG, "Proxy not attached to service");
}
/**
* Tells remote device to set an absolute volume. Only if absolute volume is supported
*
* @param volume Absolute volume to be set on AVRCP side
* @hide
*/
public void setAvrcpAbsoluteVolume(int volume) {
if (DBG) Log.d(TAG, "setAvrcpAbsoluteVolume");
if (mService != null && isEnabled()) {
try {
mService.setAvrcpAbsoluteVolume(volume);
return;
} catch (RemoteException e) {
Log.e(TAG, "Error talking to BT service in setAvrcpAbsoluteVolume()", e);
return;
}
}
if (mService == null) Log.w(TAG, "Proxy not attached to service");
}
/** /**
* Check if A2DP profile is streaming music. * Check if A2DP profile is streaming music.
* *

View File

@@ -32,5 +32,8 @@ interface IBluetoothA2dp {
int getConnectionState(in BluetoothDevice device); int getConnectionState(in BluetoothDevice device);
boolean setPriority(in BluetoothDevice device, int priority); boolean setPriority(in BluetoothDevice device, int priority);
int getPriority(in BluetoothDevice device); int getPriority(in BluetoothDevice device);
boolean isAvrcpAbsoluteVolumeSupported();
oneway void adjustAvrcpAbsoluteVolume(int direction);
oneway void setAvrcpAbsoluteVolume(int volume);
boolean isA2dpPlaying(in BluetoothDevice device); boolean isA2dpPlaying(in BluetoothDevice device);
} }

View File

@@ -2387,6 +2387,35 @@ public class AudioManager {
} }
} }
/**
* @hide
* Notifies AudioService that it is connected to an A2DP device that supports absolute volume,
* so that AudioService can send volume change events to the A2DP device, rather than handling
* them.
*/
public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
IAudioService service = getService();
try {
service.avrcpSupportsAbsoluteVolume(address, support);
} catch (RemoteException e) {
Log.e(TAG, "Dead object in avrcpSupportsAbsoluteVolume", e);
}
}
/**
* @hide
* Notifies AudioService of the volume set on the A2DP device as a callback, so AudioService
* is able to update the UI.
*/
public void avrcpUpdateVolume(int oldVolume, int volume) {
IAudioService service = getService();
try {
service.avrcpUpdateVolume(oldVolume, volume);
} catch (RemoteException e) {
Log.e(TAG, "Dead object in avrcpUpdateVolume", e);
}
}
/** /**
* {@hide} * {@hide}
*/ */

View File

@@ -460,6 +460,12 @@ public class AudioService extends IAudioService.Stub {
private final MediaFocusControl mMediaFocusControl; private final MediaFocusControl mMediaFocusControl;
// Reference to BluetoothA2dp to query for AbsoluteVolume.
private BluetoothA2dp mA2dp;
private final Object mA2dpAvrcpLock = new Object();
// If absolute volume is supported in AVRCP device
private boolean mAvrcpAbsVolSupported = false;
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Construction // Construction
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@@ -901,6 +907,15 @@ public class AudioService extends IAudioService.Stub {
int oldIndex = mStreamStates[streamType].getIndex(device); int oldIndex = mStreamStates[streamType].getIndex(device);
if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) { if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
// Check if volume update should be send to AVRCP
synchronized (mA2dpAvrcpLock) {
if (mA2dp != null && mAvrcpAbsVolSupported) {
mA2dp.adjustAvrcpAbsoluteVolume(direction);
return;
// No need to send volume update, because we will update the volume with a
// callback from Avrcp.
}
}
if ((direction == AudioManager.ADJUST_RAISE) && if ((direction == AudioManager.ADJUST_RAISE) &&
!checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) { !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex); Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
@@ -998,6 +1013,15 @@ public class AudioService extends IAudioService.Stub {
index = rescaleIndex(index * 10, streamType, streamTypeAlias); index = rescaleIndex(index * 10, streamType, streamTypeAlias);
synchronized (mA2dpAvrcpLock) {
if (mA2dp != null && mAvrcpAbsVolSupported) {
mA2dp.setAvrcpAbsoluteVolume(index);
return;
// No need to send volume update, because we will update the volume with a
// callback from Avrcp.
}
}
flags &= ~AudioManager.FLAG_FIXED_VOLUME; flags &= ~AudioManager.FLAG_FIXED_VOLUME;
if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) && if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
((device & mFixedVolumeDevices) != 0)) { ((device & mFixedVolumeDevices) != 0)) {
@@ -2268,21 +2292,23 @@ public class AudioService extends IAudioService.Stub {
List<BluetoothDevice> deviceList; List<BluetoothDevice> deviceList;
switch(profile) { switch(profile) {
case BluetoothProfile.A2DP: case BluetoothProfile.A2DP:
BluetoothA2dp a2dp = (BluetoothA2dp) proxy; synchronized (mA2dpAvrcpLock) {
deviceList = a2dp.getConnectedDevices(); mA2dp = (BluetoothA2dp) proxy;
if (deviceList.size() > 0) { deviceList = mA2dp.getConnectedDevices();
btDevice = deviceList.get(0); if (deviceList.size() > 0) {
synchronized (mConnectedDevices) { btDevice = deviceList.get(0);
int state = a2dp.getConnectionState(btDevice); synchronized (mConnectedDevices) {
int delay = checkSendBecomingNoisyIntent( int state = mA2dp.getConnectionState(btDevice);
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, int delay = checkSendBecomingNoisyIntent(
(state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0); AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
queueMsgUnderWakeLock(mAudioHandler, (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
MSG_SET_A2DP_CONNECTION_STATE, queueMsgUnderWakeLock(mAudioHandler,
state, MSG_SET_A2DP_CONNECTION_STATE,
0, state,
btDevice, 0,
delay); btDevice,
delay);
}
} }
} }
break; break;
@@ -2344,10 +2370,13 @@ public class AudioService extends IAudioService.Stub {
public void onServiceDisconnected(int profile) { public void onServiceDisconnected(int profile) {
switch(profile) { switch(profile) {
case BluetoothProfile.A2DP: case BluetoothProfile.A2DP:
synchronized (mConnectedDevices) { synchronized (mA2dpAvrcpLock) {
if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) { mA2dp = null;
makeA2dpDeviceUnavailableNow( synchronized (mConnectedDevices) {
mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)); if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
makeA2dpDeviceUnavailableNow(
mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
}
} }
} }
break; break;
@@ -3697,6 +3726,7 @@ public class AudioService extends IAudioService.Stub {
private void onSetA2dpConnectionState(BluetoothDevice btDevice, int state) private void onSetA2dpConnectionState(BluetoothDevice btDevice, int state)
{ {
if (DEBUG_VOL) Log.d(TAG, "onSetA2dpConnectionState btDevice="+btDevice+" state="+state);
if (btDevice == null) { if (btDevice == null) {
return; return;
} }
@@ -3704,6 +3734,20 @@ public class AudioService extends IAudioService.Stub {
if (!BluetoothAdapter.checkBluetoothAddress(address)) { if (!BluetoothAdapter.checkBluetoothAddress(address)) {
address = ""; address = "";
} }
// Disable absolute volume, if device is disconnected
synchronized (mA2dpAvrcpLock) {
if (state == BluetoothProfile.STATE_DISCONNECTED && mAvrcpAbsVolSupported) {
mAvrcpAbsVolSupported = false;
sendMsg(mAudioHandler,
MSG_SET_DEVICE_VOLUME,
SENDMSG_QUEUE,
getDeviceForStream(AudioSystem.STREAM_MUSIC),
0,
mStreamStates[AudioSystem.STREAM_MUSIC],
0);
}
}
synchronized (mConnectedDevices) { synchronized (mConnectedDevices) {
boolean isConnected = boolean isConnected =
(mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) && (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
@@ -3754,6 +3798,31 @@ public class AudioService extends IAudioService.Stub {
} }
} }
public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
// address is not used for now, but may be used when multiple a2dp devices are supported
synchronized (mA2dpAvrcpLock) {
mAvrcpAbsVolSupported = support;
if (support) {
VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
streamState.setIndex(streamState.getMaxIndex(), device);
sendMsg(mAudioHandler,
MSG_SET_DEVICE_VOLUME,
SENDMSG_QUEUE,
device,
0,
streamState,
0);
}
}
}
public void avrcpUpdateVolume(int oldVolume, int volume) {
mStreamStates[AudioSystem.STREAM_MUSIC].
setIndex(volume, getDeviceForStream(AudioSystem.STREAM_MUSIC));
sendVolumeUpdate(AudioSystem.STREAM_MUSIC, oldVolume, volume, AudioManager.FLAG_SHOW_UI);
}
private boolean handleDeviceConnection(boolean connected, int device, String params) { private boolean handleDeviceConnection(boolean connected, int device, String params) {
synchronized (mConnectedDevices) { synchronized (mConnectedDevices) {
boolean isConnected = (mConnectedDevices.containsKey(device) && boolean isConnected = (mConnectedDevices.containsKey(device) &&

View File

@@ -98,6 +98,10 @@ interface IAudioService {
oneway void reloadAudioSettings(); oneway void reloadAudioSettings();
oneway void avrcpSupportsAbsoluteVolume(String address, boolean support);
oneway void avrcpUpdateVolume(int oldVolume, int volume);
void setSpeakerphoneOn(boolean on); void setSpeakerphoneOn(boolean on);
boolean isSpeakerphoneOn(); boolean isSpeakerphoneOn();