Merge "Add a mechanism for configuring the A2DP Source codecs" am: 63270f2b96 am: 8b46f87e7e am: da3de76bdb

am: 62c5226e9c

Change-Id: I14d4cc2dc91cb1ab431eda32d5066ac8f471c3a6
This commit is contained in:
Pavlin Radoslavov
2017-01-04 03:54:18 +00:00
committed by android-build-merger
11 changed files with 468 additions and 12 deletions

View File

@@ -632,6 +632,7 @@ android.bluetooth.BluetoothAdapter$LeScanCallback
android.bluetooth.BluetoothAudioConfig
android.bluetooth.BluetoothClass
android.bluetooth.BluetoothClass$1
android.bluetooth.BluetoothCodecConfig
android.bluetooth.BluetoothDevice
android.bluetooth.BluetoothDevice$1
android.bluetooth.BluetoothDevice$2

View File

@@ -102,6 +102,27 @@ public final class BluetoothA2dp implements BluetoothProfile {
public static final String ACTION_AVRCP_CONNECTION_STATE_CHANGED =
"android.bluetooth.a2dp.profile.action.AVRCP_CONNECTION_STATE_CHANGED";
/**
* Intent used to broadcast the change in the Audio Codec state of the
* A2DP Source profile.
*
* <p>This intent will have 3 extras:
* <ul>
* <li> {@link #EXTRA_CODEC_CONFIG} - The current codec configuration. </li>
* <li> {@link #EXTRA_PREVIOUS_CODEC_CONFIG} - The previous codec configuration. </li>
* <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device if the device is currently
* connected, otherwise it is not included.</li>
* </ul>
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
* receive.
*
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_CODEC_CONFIG_CHANGED =
"android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED";
/**
* A2DP sink device is streaming music. This state can be one of
* {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
@@ -543,6 +564,54 @@ public final class BluetoothA2dp implements BluetoothProfile {
return false;
}
/**
* Gets the current codec configuration.
*
* @return the current codec configuration
* @hide
*/
public BluetoothCodecConfig getCodecConfig() {
if (DBG) Log.d(TAG, "getCodecConfig");
try {
mServiceLock.readLock().lock();
if (mService != null && isEnabled()) {
return mService.getCodecConfig();
}
if (mService == null) {
Log.w(TAG, "Proxy not attached to service");
}
return null;
} catch (RemoteException e) {
Log.e(TAG, "Error talking to BT service in getCodecConfig()", e);
return null;
} finally {
mServiceLock.readLock().unlock();
}
}
/**
* Sets the codec configuration preference.
*
* @param codecConfig the codec configuration preference
* @hide
*/
public void setCodecConfigPreference(BluetoothCodecConfig codecConfig) {
if (DBG) Log.d(TAG, "setCodecConfigPreference");
try {
mServiceLock.readLock().lock();
if (mService != null && isEnabled()) {
mService.setCodecConfigPreference(codecConfig);
}
if (mService == null) Log.w(TAG, "Proxy not attached to service");
return;
} catch (RemoteException e) {
Log.e(TAG, "Error talking to BT service in setCodecConfigPreference()", e);
return;
} finally {
mServiceLock.readLock().unlock();
}
}
/**
* Helper for converting a state to a string.
*

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.bluetooth;
parcelable BluetoothCodecConfig;

View File

@@ -0,0 +1,287 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.bluetooth;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Objects;
/**
* Represents the codec configuration for a Bluetooth A2DP source device.
*
* {@see BluetoothA2dp}
*
* {@hide}
*/
public final class BluetoothCodecConfig implements Parcelable {
/**
* Extra for the codec configuration intents of the individual profiles.
*
* This extra represents the current codec configuration of the A2DP
* profile.
*/
public static final String EXTRA_CODEC_CONFIG = "android.bluetooth.codec.extra.CODEC_CONFIG";
/**
* Extra for the codec configuration intents of the individual profiles.
*
* This extra represents the previous codec configuration of the A2DP
* profile.
*/
public static final String EXTRA_PREVIOUS_CODEC_CONFIG =
"android.bluetooth.codec.extra.PREVIOUS_CODEC_CONFIG";
public static final int SOURCE_CODEC_TYPE_SBC = 0;
public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000;
public static final int CODEC_PRIORITY_DEFAULT = 0;
public static final int CODEC_PRIORITY_HIGHEST = 1000 * 1000;
public static final int SAMPLE_RATE_NONE = 0;
public static final int SAMPLE_RATE_44100 = 0x1 << 0;
public static final int SAMPLE_RATE_48000 = 0x1 << 1;
public static final int SAMPLE_RATE_88200 = 0x1 << 2;
public static final int SAMPLE_RATE_96000 = 0x1 << 3;
public static final int SAMPLE_RATE_176400 = 0x1 << 4;
public static final int SAMPLE_RATE_192000 = 0x1 << 5;
public static final int BITS_PER_SAMPLE_NONE = 0;
public static final int BITS_PER_SAMPLE_16 = 0x1 << 0;
public static final int BITS_PER_SAMPLE_24 = 0x1 << 1;
public static final int BITS_PER_SAMPLE_32 = 0x1 << 2;
public static final int CHANNEL_MODE_NONE = 0;
public static final int CHANNEL_MODE_MONO = 0x1 << 0;
public static final int CHANNEL_MODE_STEREO = 0x1 << 1;
private final int mCodecType;
private final int mCodecPriority;
private final int mSampleRate;
private final int mBitsPerSample;
private final int mChannelMode;
private final long mCodecSpecific1;
private final long mCodecSpecific2;
private final long mCodecSpecific3;
private final long mCodecSpecific4;
public BluetoothCodecConfig(int codecType, int codecPriority,
int sampleRate, int bitsPerSample,
int channelMode,long codecSpecific1,
long codecSpecific2, long codecSpecific3,
long codecSpecific4) {
mCodecType = codecType;
mCodecPriority = codecPriority;
mSampleRate = sampleRate;
mBitsPerSample = bitsPerSample;
mChannelMode = channelMode;
mCodecSpecific1 = codecSpecific1;
mCodecSpecific2 = codecSpecific2;
mCodecSpecific3 = codecSpecific3;
mCodecSpecific4 = codecSpecific4;
}
@Override
public boolean equals(Object o) {
if (o instanceof BluetoothCodecConfig) {
BluetoothCodecConfig other = (BluetoothCodecConfig)o;
return (other.mCodecType == mCodecType &&
other.mCodecPriority == mCodecPriority &&
other.mSampleRate == mSampleRate &&
other.mBitsPerSample == mBitsPerSample &&
other.mChannelMode == mChannelMode &&
other.mCodecSpecific1 == mCodecSpecific1 &&
other.mCodecSpecific2 == mCodecSpecific2 &&
other.mCodecSpecific3 == mCodecSpecific3 &&
other.mCodecSpecific4 == mCodecSpecific4);
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(mCodecType, mCodecPriority, mSampleRate,
mBitsPerSample, mChannelMode, mCodecSpecific1,
mCodecSpecific2, mCodecSpecific3, mCodecSpecific4);
}
@Override
public String toString() {
return "{mCodecType:" + mCodecType +
",mCodecPriority:" + mCodecPriority +
",mSampleRate:" + String.format("0x%x", mSampleRate) +
",mBitsPerSample:" + String.format("0x%x", mBitsPerSample) +
",mChannelMode:" + String.format("0x%x", mChannelMode) +
",mCodecSpecific1:" + mCodecSpecific1 +
",mCodecSpecific2:" + mCodecSpecific2 +
",mCodecSpecific3:" + mCodecSpecific3 +
",mCodecSpecific4:" + mCodecSpecific4 + "}";
}
public int describeContents() {
return 0;
}
public static final Parcelable.Creator<BluetoothCodecConfig> CREATOR =
new Parcelable.Creator<BluetoothCodecConfig>() {
public BluetoothCodecConfig createFromParcel(Parcel in) {
final int codecType = in.readInt();
final int codecPriority = in.readInt();
final int sampleRate = in.readInt();
final int bitsPerSample = in.readInt();
final int channelMode = in.readInt();
final long codecSpecific1 = in.readLong();
final long codecSpecific2 = in.readLong();
final long codecSpecific3 = in.readLong();
final long codecSpecific4 = in.readLong();
return new BluetoothCodecConfig(codecType, codecPriority,
sampleRate, bitsPerSample,
channelMode, codecSpecific1,
codecSpecific2, codecSpecific3,
codecSpecific4);
}
public BluetoothCodecConfig[] newArray(int size) {
return new BluetoothCodecConfig[size];
}
};
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mCodecType);
out.writeInt(mCodecPriority);
out.writeInt(mSampleRate);
out.writeInt(mBitsPerSample);
out.writeInt(mChannelMode);
out.writeLong(mCodecSpecific1);
out.writeLong(mCodecSpecific2);
out.writeLong(mCodecSpecific3);
out.writeLong(mCodecSpecific4);
}
/**
* Returns the codec type.
* See {@link android.bluetooth.BluetoothCodecConfig#SOURCE_CODEC_TYPE_SBC}.
*
* @return the codec type
*/
public int getCodecType() {
return mCodecType;
}
/**
* Returns the codec selection priority.
* The codec selection priority is relative to other codecs: larger value
* means higher priority. If 0, reset to default.
*
* @return the codec priority
*/
public int getCodecPriority() {
return mCodecPriority;
}
/**
* Returns the codec sample rate. The value can be a bitmask with all
* supported sample rates:
* {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_NONE} or
* {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_44100} or
* {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_48000} or
* {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_88200} or
* {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_96000} or
* {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_176400} or
* {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_192000}
*
* @return the codec sample rate
*/
public int getSampleRate() {
return mSampleRate;
}
/**
* Returns the codec bits per sample. The value can be a bitmask with all
* bits per sample supported:
* {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_NONE} or
* {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_16} or
* {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_24} or
* {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_32}
*
* @return the codec bits per sample
*/
public int getBitsPerSample() {
return mBitsPerSample;
}
/**
* Returns the codec channel mode. The value can be a bitmask with all
* supported channel modes:
* {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_NONE} or
* {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_MONO} or
* {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_STEREO}
*
* @return the codec channel mode
*/
public int getChannelMode() {
return mChannelMode;
}
/**
* Returns a codec specific value1.
*
* @return a codec specific value1.
*/
public long getCodecSpecific1() {
return mCodecSpecific1;
}
/**
* Returns a codec specific value2.
*
* @return a codec specific value2
*/
public long getCodecSpecific2() {
return mCodecSpecific2;
}
/**
* Returns a codec specific value3.
*
* @return a codec specific value3
*/
public long getCodecSpecific3() {
return mCodecSpecific3;
}
/**
* Returns a codec specific value4.
*
* @return a codec specific value4
*/
public long getCodecSpecific4() {
return mCodecSpecific4;
}
/**
* Checks whether the audio feeding parameters are same.
*
* @param other the codec config to compare against
* @return true if the audio feeding parameters are same, otherwise false
*/
public boolean sameAudioFeedingParameters(BluetoothCodecConfig other) {
return (other != null && other.mSampleRate == mSampleRate &&
other.mBitsPerSample == mBitsPerSample &&
other.mChannelMode == mChannelMode);
}
}

View File

@@ -16,6 +16,7 @@
package android.bluetooth;
import android.bluetooth.BluetoothCodecConfig;
import android.bluetooth.BluetoothDevice;
/**
@@ -36,4 +37,6 @@ interface IBluetoothA2dp {
oneway void adjustAvrcpAbsoluteVolume(int direction);
oneway void setAvrcpAbsoluteVolume(int volume);
boolean isA2dpPlaying(in BluetoothDevice device);
BluetoothCodecConfig getCodecConfig();
oneway void setCodecConfigPreference(in BluetoothCodecConfig codecConfig);
}

View File

@@ -462,6 +462,18 @@ android_media_AudioSystem_getDeviceConnectionState(JNIEnv *env, jobject thiz, ji
return (jint) state;
}
static jint
android_media_AudioSystem_handleDeviceConfigChange(JNIEnv *env, jobject thiz, jint device, jstring device_address, jstring device_name)
{
const char *c_address = env->GetStringUTFChars(device_address, NULL);
const char *c_name = env->GetStringUTFChars(device_name, NULL);
int status = check_AudioSystem_Command(AudioSystem::handleDeviceConfigChange(static_cast <audio_devices_t>(device),
c_address, c_name));
env->ReleaseStringUTFChars(device_address, c_address);
env->ReleaseStringUTFChars(device_name, c_name);
return (jint) status;
}
static jint
android_media_AudioSystem_setPhoneState(JNIEnv *env, jobject thiz, jint state)
{
@@ -1764,6 +1776,7 @@ static const JNINativeMethod gMethods[] = {
{"newAudioPlayerId", "()I", (void *)android_media_AudioSystem_newAudioPlayerId},
{"setDeviceConnectionState", "(IILjava/lang/String;Ljava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
{"getDeviceConnectionState", "(ILjava/lang/String;)I", (void *)android_media_AudioSystem_getDeviceConnectionState},
{"handleDeviceConfigChange", "(ILjava/lang/String;Ljava/lang/String;)I", (void *)android_media_AudioSystem_handleDeviceConfigChange},
{"setPhoneState", "(I)I", (void *)android_media_AudioSystem_setPhoneState},
{"setForceUse", "(II)I", (void *)android_media_AudioSystem_setForceUse},
{"getForceUse", "(I)I", (void *)android_media_AudioSystem_getForceUse},

View File

@@ -167,6 +167,8 @@
android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast

View File

@@ -3482,6 +3482,20 @@ public class AudioManager {
return delay;
}
/**
* Indicate A2DP device configuration has changed.
* @param device Bluetooth device whose configuration has changed.
* {@hide}
*/
public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device) {
IAudioService service = getService();
try {
service.handleBluetoothA2dpDeviceConfigChange(device);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/** {@hide} */
public IRingtonePlayer getRingtonePlayer() {
try {

View File

@@ -689,6 +689,9 @@ public class AudioSystem
public static native int setDeviceConnectionState(int device, int state,
String device_address, String device_name);
public static native int getDeviceConnectionState(int device, String device_address);
public static native int handleDeviceConfigChange(int device,
String device_address,
String device_name);
public static native int setPhoneState(int state);
public static native int setForceUse(int usage, int config);
public static native int getForceUse(int usage);

View File

@@ -143,6 +143,8 @@ interface IAudioService {
int setBluetoothA2dpDeviceConnectionState(in BluetoothDevice device, int state, int profile);
void handleBluetoothA2dpDeviceConfigChange(in BluetoothDevice device);
AudioRoutesInfo startWatchingRoutes(in IAudioRoutesObserver observer);
boolean isCameraSoundForced();

View File

@@ -232,6 +232,7 @@ public class AudioService extends IAudioService.Stub
private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
private static final int MSG_A2DP_DEVICE_CONFIG_CHANGE = 103;
// end of messages handled under wakelock
private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
@@ -3183,7 +3184,7 @@ public class AudioService extends IAudioService.Stub
queueMsgUnderWakeLock(mAudioHandler,
MSG_SET_A2DP_SINK_CONNECTION_STATE,
state,
0,
0 /* arg2 unused */,
btDevice,
delay);
}
@@ -3200,7 +3201,7 @@ public class AudioService extends IAudioService.Stub
queueMsgUnderWakeLock(mAudioHandler,
MSG_SET_A2DP_SRC_CONNECTION_STATE,
state,
0,
0 /* arg2 unused */,
btDevice,
0 /* delay */);
}
@@ -3848,8 +3849,8 @@ public class AudioService extends IAudioService.Stub
int delay = checkSendBecomingNoisyIntent(type, state);
queueMsgUnderWakeLock(mAudioHandler,
MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
0,
0,
0 /* arg1 unused */,
0 /* arg2 unused */,
new WiredDeviceConnectionState(type, state, address, name, caller),
delay);
}
@@ -3872,13 +3873,25 @@ public class AudioService extends IAudioService.Stub
(profile == BluetoothProfile.A2DP ?
MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
state,
0,
0 /* arg2 unused */,
device,
delay);
}
return delay;
}
public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device)
{
synchronized (mConnectedDevices) {
queueMsgUnderWakeLock(mAudioHandler,
MSG_A2DP_DEVICE_CONFIG_CHANGE,
0 /* arg1 unused */,
0 /* arg1 unused */,
device,
0 /* delay */);
}
}
///////////////////////////////////////////////////////////////////////////
// Inner classes
///////////////////////////////////////////////////////////////////////////
@@ -4691,6 +4704,11 @@ public class AudioService extends IAudioService.Stub
mAudioEventWakeLock.release();
break;
case MSG_A2DP_DEVICE_CONFIG_CHANGE:
onBluetoothA2dpDeviceConfigChange((BluetoothDevice)msg.obj);
mAudioEventWakeLock.release();
break;
case MSG_REPORT_NEW_ROUTES: {
int N = mRoutesObservers.beginBroadcast();
if (N > 0) {
@@ -4913,7 +4931,7 @@ public class AudioService extends IAudioService.Stub
private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
{
if (DEBUG_VOL) {
Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice+"state=" + state);
}
if (btDevice == null) {
return;
@@ -4924,9 +4942,9 @@ public class AudioService extends IAudioService.Stub
}
synchronized (mConnectedDevices) {
String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
btDevice.getAddress());
DeviceListSpec deviceSpec = mConnectedDevices.get(key);
final String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
btDevice.getAddress());
final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
boolean isConnected = deviceSpec != null;
if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
@@ -4977,7 +4995,7 @@ public class AudioService extends IAudioService.Stub
private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
{
if (DEBUG_VOL) {
Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
Log.d(TAG, "onSetA2dpSourceConnectionState btDevice=" + btDevice + " state=" + state);
}
if (btDevice == null) {
return;
@@ -4988,8 +5006,8 @@ public class AudioService extends IAudioService.Stub
}
synchronized (mConnectedDevices) {
String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
DeviceListSpec deviceSpec = mConnectedDevices.get(key);
final String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
boolean isConnected = deviceSpec != null;
if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
@@ -5000,6 +5018,31 @@ public class AudioService extends IAudioService.Stub
}
}
private void onBluetoothA2dpDeviceConfigChange(BluetoothDevice btDevice)
{
if (DEBUG_VOL) {
Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice);
}
if (btDevice == null) {
return;
}
String address = btDevice.getAddress();
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
address = "";
}
int device = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
synchronized (mConnectedDevices) {
final String key = makeDeviceListKey(device, address);
final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
if (deviceSpec != null) {
// Device is connected
AudioSystem.handleDeviceConfigChange(device, address,
btDevice.getName());
}
}
}
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) {