Loading core/java/android/bluetooth/BluetoothA2dp.java +60 −0 Original line number Diff line number Diff line Loading @@ -387,6 +387,66 @@ public final class BluetoothA2dp implements BluetoothProfile { 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. * Loading core/java/android/bluetooth/IBluetoothA2dp.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -32,5 +32,8 @@ interface IBluetoothA2dp { int getConnectionState(in BluetoothDevice device); boolean setPriority(in BluetoothDevice device, int priority); int getPriority(in BluetoothDevice device); boolean isAvrcpAbsoluteVolumeSupported(); oneway void adjustAvrcpAbsoluteVolume(int direction); oneway void setAvrcpAbsoluteVolume(int volume); boolean isA2dpPlaying(in BluetoothDevice device); } media/java/android/media/AudioManager.java +29 −0 Original line number Diff line number Diff line Loading @@ -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} */ Loading media/java/android/media/AudioService.java +88 −19 Original line number Diff line number Diff line Loading @@ -460,6 +460,12 @@ public class AudioService extends IAudioService.Stub { 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 /////////////////////////////////////////////////////////////////////////// Loading Loading @@ -901,6 +907,15 @@ public class AudioService extends IAudioService.Stub { int oldIndex = mStreamStates[streamType].getIndex(device); 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) && !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) { Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex); Loading Loading @@ -998,6 +1013,15 @@ public class AudioService extends IAudioService.Stub { 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; if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) && ((device & mFixedVolumeDevices) != 0)) { Loading Loading @@ -2268,12 +2292,13 @@ public class AudioService extends IAudioService.Stub { List<BluetoothDevice> deviceList; switch(profile) { case BluetoothProfile.A2DP: BluetoothA2dp a2dp = (BluetoothA2dp) proxy; deviceList = a2dp.getConnectedDevices(); synchronized (mA2dpAvrcpLock) { mA2dp = (BluetoothA2dp) proxy; deviceList = mA2dp.getConnectedDevices(); if (deviceList.size() > 0) { btDevice = deviceList.get(0); synchronized (mConnectedDevices) { int state = a2dp.getConnectionState(btDevice); int state = mA2dp.getConnectionState(btDevice); int delay = checkSendBecomingNoisyIntent( AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0); Loading @@ -2285,6 +2310,7 @@ public class AudioService extends IAudioService.Stub { delay); } } } break; case BluetoothProfile.HEADSET: Loading Loading @@ -2344,12 +2370,15 @@ public class AudioService extends IAudioService.Stub { public void onServiceDisconnected(int profile) { switch(profile) { case BluetoothProfile.A2DP: synchronized (mA2dpAvrcpLock) { mA2dp = null; synchronized (mConnectedDevices) { if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) { makeA2dpDeviceUnavailableNow( mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)); } } } break; case BluetoothProfile.HEADSET: Loading Loading @@ -3697,6 +3726,7 @@ public class AudioService extends IAudioService.Stub { private void onSetA2dpConnectionState(BluetoothDevice btDevice, int state) { if (DEBUG_VOL) Log.d(TAG, "onSetA2dpConnectionState btDevice="+btDevice+" state="+state); if (btDevice == null) { return; } Loading @@ -3704,6 +3734,20 @@ public class AudioService extends IAudioService.Stub { if (!BluetoothAdapter.checkBluetoothAddress(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) { boolean isConnected = (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) && Loading Loading @@ -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) { synchronized (mConnectedDevices) { boolean isConnected = (mConnectedDevices.containsKey(device) && Loading media/java/android/media/IAudioService.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -98,6 +98,10 @@ interface IAudioService { oneway void reloadAudioSettings(); oneway void avrcpSupportsAbsoluteVolume(String address, boolean support); oneway void avrcpUpdateVolume(int oldVolume, int volume); void setSpeakerphoneOn(boolean on); boolean isSpeakerphoneOn(); Loading Loading
core/java/android/bluetooth/BluetoothA2dp.java +60 −0 Original line number Diff line number Diff line Loading @@ -387,6 +387,66 @@ public final class BluetoothA2dp implements BluetoothProfile { 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. * Loading
core/java/android/bluetooth/IBluetoothA2dp.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -32,5 +32,8 @@ interface IBluetoothA2dp { int getConnectionState(in BluetoothDevice device); boolean setPriority(in BluetoothDevice device, int priority); int getPriority(in BluetoothDevice device); boolean isAvrcpAbsoluteVolumeSupported(); oneway void adjustAvrcpAbsoluteVolume(int direction); oneway void setAvrcpAbsoluteVolume(int volume); boolean isA2dpPlaying(in BluetoothDevice device); }
media/java/android/media/AudioManager.java +29 −0 Original line number Diff line number Diff line Loading @@ -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} */ Loading
media/java/android/media/AudioService.java +88 −19 Original line number Diff line number Diff line Loading @@ -460,6 +460,12 @@ public class AudioService extends IAudioService.Stub { 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 /////////////////////////////////////////////////////////////////////////// Loading Loading @@ -901,6 +907,15 @@ public class AudioService extends IAudioService.Stub { int oldIndex = mStreamStates[streamType].getIndex(device); 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) && !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) { Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex); Loading Loading @@ -998,6 +1013,15 @@ public class AudioService extends IAudioService.Stub { 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; if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) && ((device & mFixedVolumeDevices) != 0)) { Loading Loading @@ -2268,12 +2292,13 @@ public class AudioService extends IAudioService.Stub { List<BluetoothDevice> deviceList; switch(profile) { case BluetoothProfile.A2DP: BluetoothA2dp a2dp = (BluetoothA2dp) proxy; deviceList = a2dp.getConnectedDevices(); synchronized (mA2dpAvrcpLock) { mA2dp = (BluetoothA2dp) proxy; deviceList = mA2dp.getConnectedDevices(); if (deviceList.size() > 0) { btDevice = deviceList.get(0); synchronized (mConnectedDevices) { int state = a2dp.getConnectionState(btDevice); int state = mA2dp.getConnectionState(btDevice); int delay = checkSendBecomingNoisyIntent( AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0); Loading @@ -2285,6 +2310,7 @@ public class AudioService extends IAudioService.Stub { delay); } } } break; case BluetoothProfile.HEADSET: Loading Loading @@ -2344,12 +2370,15 @@ public class AudioService extends IAudioService.Stub { public void onServiceDisconnected(int profile) { switch(profile) { case BluetoothProfile.A2DP: synchronized (mA2dpAvrcpLock) { mA2dp = null; synchronized (mConnectedDevices) { if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) { makeA2dpDeviceUnavailableNow( mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)); } } } break; case BluetoothProfile.HEADSET: Loading Loading @@ -3697,6 +3726,7 @@ public class AudioService extends IAudioService.Stub { private void onSetA2dpConnectionState(BluetoothDevice btDevice, int state) { if (DEBUG_VOL) Log.d(TAG, "onSetA2dpConnectionState btDevice="+btDevice+" state="+state); if (btDevice == null) { return; } Loading @@ -3704,6 +3734,20 @@ public class AudioService extends IAudioService.Stub { if (!BluetoothAdapter.checkBluetoothAddress(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) { boolean isConnected = (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) && Loading Loading @@ -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) { synchronized (mConnectedDevices) { boolean isConnected = (mConnectedDevices.containsKey(device) && Loading
media/java/android/media/IAudioService.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -98,6 +98,10 @@ interface IAudioService { oneway void reloadAudioSettings(); oneway void avrcpSupportsAbsoluteVolume(String address, boolean support); oneway void avrcpUpdateVolume(int oldVolume, int volume); void setSpeakerphoneOn(boolean on); boolean isSpeakerphoneOn(); Loading