Merge changes from topics "AudioDeviceAttributes_update", "ShortAudioDescriptors"

* changes:
  Inform AudioManager about ARC SADs
  Add AudioDeviceAttributes as argument to AudioManager API
  Add fields to AudioDeviceAttributes class
This commit is contained in:
Nathalie Le Clair
2022-02-04 14:11:19 +00:00
committed by Android (Google) Code Review
23 changed files with 1007 additions and 170 deletions

View File

@@ -19679,10 +19679,13 @@ package android.media {
method public android.media.AudioAttributes.Builder setUsage(int);
}
public class AudioDescriptor {
public class AudioDescriptor implements android.os.Parcelable {
method public int describeContents();
method @NonNull public byte[] getDescriptor();
method public int getEncapsulationType();
method public int getStandard();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioDescriptor> CREATOR;
field public static final int STANDARD_EDID = 1; // 0x1
field public static final int STANDARD_NONE = 0; // 0x0
}
@@ -20198,14 +20201,17 @@ package android.media {
method @NonNull public android.media.AudioPresentation.Builder setProgramId(int);
}
public class AudioProfile {
public class AudioProfile implements android.os.Parcelable {
method public int describeContents();
method @NonNull public int[] getChannelIndexMasks();
method @NonNull public int[] getChannelMasks();
method public int getEncapsulationType();
method public int getFormat();
method @NonNull public int[] getSampleRates();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final int AUDIO_ENCAPSULATION_TYPE_IEC61937 = 1; // 0x1
field public static final int AUDIO_ENCAPSULATION_TYPE_NONE = 0; // 0x0
field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioProfile> CREATOR;
}
public class AudioRecord implements android.media.AudioRecordingMonitor android.media.AudioRouting android.media.MicrophoneDirection {

View File

@@ -5933,11 +5933,20 @@ package android.media {
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioAttributes.Builder setSystemUsage(int);
}
public class AudioDescriptor implements android.os.Parcelable {
ctor public AudioDescriptor(int, int, @NonNull byte[]);
}
public final class AudioDeviceAttributes implements android.os.Parcelable {
ctor public AudioDeviceAttributes(@NonNull android.media.AudioDeviceInfo);
ctor public AudioDeviceAttributes(int, int, @NonNull String);
ctor public AudioDeviceAttributes(int, int, @NonNull String, @NonNull String, @NonNull java.util.List<android.media.AudioProfile>, @NonNull java.util.List<android.media.AudioDescriptor>);
method public int describeContents();
method public boolean equalTypeAddress(@Nullable Object);
method @NonNull public String getAddress();
method @NonNull public java.util.List<android.media.AudioDescriptor> getAudioDescriptors();
method @NonNull public java.util.List<android.media.AudioProfile> getAudioProfiles();
method @NonNull public String getName();
method public int getRole();
method public int getType();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -6094,6 +6103,10 @@ package android.media {
field public static final int PLAYER_TYPE_UNKNOWN = -1; // 0xffffffff
}
public class AudioProfile implements android.os.Parcelable {
ctor public AudioProfile(int, @NonNull int[], @NonNull int[], @NonNull int[], int);
}
public class AudioRecord implements android.media.AudioRecordingMonitor android.media.AudioRouting android.media.MicrophoneDirection {
ctor @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public AudioRecord(android.media.AudioAttributes, android.media.AudioFormat, int, int) throws java.lang.IllegalArgumentException;
method public static long getMaxSharedAudioHistoryMillis();

View File

@@ -18,25 +18,25 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "AudioSystem-JNI"
#include <utils/Log.h>
#include <sstream>
#include <vector>
#include <jni.h>
#include <nativehelper/JNIHelp.h>
#include "core_jni_helpers.h"
#include <android/media/AudioVibratorInfo.h>
#include <android/media/INativeSpatializerCallback.h>
#include <android/media/ISpatializer.h>
#include <android_os_Parcel.h>
#include <audiomanager/AudioManager.h>
#include <jni.h>
#include <media/AudioContainers.h>
#include <media/AudioPolicy.h>
#include <media/AudioSystem.h>
#include <media/MicrophoneInfo.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalRef.h>
#include <system/audio.h>
#include <system/audio_policy.h>
#include <utils/Log.h>
#include <sstream>
#include <vector>
#include "android_media_AudioAttributes.h"
#include "android_media_AudioDescriptor.h"
#include "android_media_AudioDeviceAttributes.h"
@@ -46,6 +46,7 @@
#include "android_media_AudioProfile.h"
#include "android_media_MicrophoneInfo.h"
#include "android_util_Binder.h"
#include "core_jni_helpers.h"
// ----------------------------------------------------------------------------
@@ -584,18 +585,26 @@ android_media_AudioSystem_routing_callback()
env->DeleteLocalRef(clazz);
}
static jint
android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name,
jint codec)
{
const char *c_address = env->GetStringUTFChars(device_address, NULL);
const char *c_name = env->GetStringUTFChars(device_name, NULL);
int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <audio_devices_t>(device),
static_cast <audio_policy_dev_state_t>(state),
c_address, c_name,
static_cast <audio_format_t>(codec)));
env->ReleaseStringUTFChars(device_address, c_address);
env->ReleaseStringUTFChars(device_name, c_name);
static jint android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz,
jint state, jobject jParcel,
jint codec) {
int status;
if (Parcel *parcel = parcelForJavaObject(env, jParcel); parcel != nullptr) {
android::media::audio::common::AudioPort port{};
if (status_t statusOfParcel = port.readFromParcel(parcel); statusOfParcel == OK) {
status = check_AudioSystem_Command(
AudioSystem::setDeviceConnectionState(static_cast<audio_policy_dev_state_t>(
state),
port,
static_cast<audio_format_t>(codec)));
} else {
ALOGE("Failed to read from parcel: %s", statusToString(statusOfParcel).c_str());
status = kAudioStatusError;
}
} else {
ALOGE("Failed to retrieve the native parcel from Java parcel");
status = kAudioStatusError;
}
return (jint) status;
}
@@ -2912,7 +2921,7 @@ static const JNINativeMethod gMethods[] =
{"newAudioSessionId", "()I", (void *)android_media_AudioSystem_newAudioSessionId},
{"newAudioPlayerId", "()I", (void *)android_media_AudioSystem_newAudioPlayerId},
{"newAudioRecorderId", "()I", (void *)android_media_AudioSystem_newAudioRecorderId},
{"setDeviceConnectionState", "(IILjava/lang/String;Ljava/lang/String;I)I",
{"setDeviceConnectionState", "(ILandroid/os/Parcel;I)I",
(void *)android_media_AudioSystem_setDeviceConnectionState},
{"getDeviceConnectionState", "(ILjava/lang/String;)I",
(void *)android_media_AudioSystem_getDeviceConnectionState},

View File

@@ -18,16 +18,21 @@ package android.media;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.Objects;
/**
* The AudioDescriptor contains the information to describe the audio playback/capture
* capabilities. The capabilities are described by a byte array, which is defined by a
* particular standard. This is used when the format is unrecognized to the platform.
*/
public class AudioDescriptor {
public class AudioDescriptor implements Parcelable {
/**
* The audio standard is not specified.
*/
@@ -49,7 +54,15 @@ public class AudioDescriptor {
private final byte[] mDescriptor;
private final int mEncapsulationType;
AudioDescriptor(int standard, int encapsulationType, @NonNull byte[] descriptor) {
/**
* @hide
* Constructor from standard, encapsulation type and descriptor
* @param standard the standard of the audio descriptor
* @param encapsulationType the encapsulation type of the audio descriptor
* @param descriptor the audio descriptor
*/
@SystemApi
public AudioDescriptor(int standard, int encapsulationType, @NonNull byte[] descriptor) {
mStandard = standard;
mEncapsulationType = encapsulationType;
mDescriptor = descriptor;
@@ -87,4 +100,66 @@ public class AudioDescriptor {
public @AudioProfile.EncapsulationType int getEncapsulationType() {
return mEncapsulationType;
}
@Override
public int hashCode() {
return Objects.hash(mStandard, mEncapsulationType, Arrays.hashCode(mDescriptor));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AudioDescriptor that = (AudioDescriptor) o;
return ((mStandard == that.mStandard)
&& (mEncapsulationType == that.mEncapsulationType)
&& (Arrays.equals(mDescriptor, that.mDescriptor)));
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("{");
sb.append("standard=" + mStandard);
sb.append(", encapsulation type=" + mEncapsulationType);
if (mDescriptor != null && mDescriptor.length > 0) {
sb.append(", descriptor=").append(Arrays.toString(mDescriptor));
}
sb.append("}");
return sb.toString();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mStandard);
dest.writeInt(mEncapsulationType);
dest.writeByteArray(mDescriptor);
}
private AudioDescriptor(@NonNull Parcel in) {
mStandard = in.readInt();
mEncapsulationType = in.readInt();
mDescriptor = in.createByteArray();
}
public static final @NonNull Parcelable.Creator<AudioDescriptor> CREATOR =
new Parcelable.Creator<AudioDescriptor>() {
/**
* Rebuilds an AudioDescriptor previously stored with writeToParcel().
* @param p Parcel object to read the AudioDescriptor from
* @return a new AudioDescriptor created from the data in the parcel
*/
public AudioDescriptor createFromParcel(Parcel p) {
return new AudioDescriptor(p);
}
public AudioDescriptor[] newArray(int size) {
return new AudioDescriptor[size];
}
};
}

View File

@@ -18,12 +18,16 @@ package android.media;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
@@ -65,16 +69,27 @@ public final class AudioDeviceAttributes implements Parcelable {
* The unique address of the device. Some devices don't have addresses, only an empty string.
*/
private final @NonNull String mAddress;
/**
* The non-unique name of the device. Some devices don't have names, only an empty string.
* Should not be used as a unique identifier for a device.
*/
private final @NonNull String mName;
/**
* Is input or output device
*/
private final @Role int mRole;
/**
* The internal audio device type
*/
private final int mNativeType;
/**
* List of AudioProfiles supported by the device
*/
private final @NonNull List<AudioProfile> mAudioProfiles;
/**
* List of AudioDescriptors supported by the device
*/
private final @NonNull List<AudioDescriptor> mAudioDescriptors;
/**
* @hide
@@ -88,7 +103,10 @@ public final class AudioDeviceAttributes implements Parcelable {
mRole = deviceInfo.isSink() ? ROLE_OUTPUT : ROLE_INPUT;
mType = deviceInfo.getType();
mAddress = deviceInfo.getAddress();
mName = String.valueOf(deviceInfo.getProductName());
mNativeType = deviceInfo.getInternalType();
mAudioProfiles = deviceInfo.getAudioProfiles();
mAudioDescriptors = deviceInfo.getAudioDescriptors();
}
/**
@@ -100,7 +118,24 @@ public final class AudioDeviceAttributes implements Parcelable {
*/
@SystemApi
public AudioDeviceAttributes(@Role int role, @AudioDeviceInfo.AudioDeviceType int type,
@NonNull String address) {
@NonNull String address) {
this(role, type, address, "", new ArrayList<>(), new ArrayList<>());
}
/**
* @hide
* Constructor with specification of all attributes
* @param role indicates input or output role
* @param type the device type, as defined in {@link AudioDeviceInfo}
* @param address the address of the device, or an empty string for devices without one
* @param name the name of the device, or an empty string for devices without one
* @param profiles the list of AudioProfiles supported by the device
* @param descriptors the list of AudioDescriptors supported by the device
*/
@SystemApi
public AudioDeviceAttributes(@Role int role, @AudioDeviceInfo.AudioDeviceType int type,
@NonNull String address, @NonNull String name, @NonNull List<AudioProfile> profiles,
@NonNull List<AudioDescriptor> descriptors) {
Objects.requireNonNull(address);
if (role != ROLE_OUTPUT && role != ROLE_INPUT) {
throw new IllegalArgumentException("Invalid role " + role);
@@ -118,19 +153,37 @@ public final class AudioDeviceAttributes implements Parcelable {
mRole = role;
mType = type;
mAddress = address;
mName = name;
mAudioProfiles = profiles;
mAudioDescriptors = descriptors;
}
/**
* @hide
* Constructor from internal device type and address
* @param type the internal device type, as defined in {@link AudioSystem}
* Constructor called from AudioSystem JNI when creating an AudioDeviceAttributes from a native
* AudioDeviceTypeAddr instance.
* @param nativeType the internal device type, as defined in {@link AudioSystem}
* @param address the address of the device, or an empty string for devices without one
*/
public AudioDeviceAttributes(int nativeType, @NonNull String address) {
this(nativeType, address, "");
}
/**
* @hide
* Constructor called from BtHelper to connect or disconnect a Bluetooth device.
* @param nativeType the internal device type, as defined in {@link AudioSystem}
* @param address the address of the device, or an empty string for devices without one
* @param name the name of the device, or an empty string for devices without one
*/
public AudioDeviceAttributes(int nativeType, @NonNull String address, @NonNull String name) {
mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT;
mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType);
mAddress = address;
mName = name;
mNativeType = nativeType;
mAudioProfiles = new ArrayList<>();
mAudioDescriptors = new ArrayList<>();
}
/**
@@ -163,6 +216,16 @@ public final class AudioDeviceAttributes implements Parcelable {
return mAddress;
}
/**
* @hide
* Returns the name of the audio device, or an empty string for devices without one
* @return the device name
*/
@SystemApi
public @NonNull String getName() {
return mName;
}
/**
* @hide
* Returns the internal device type of a device
@@ -172,9 +235,29 @@ public final class AudioDeviceAttributes implements Parcelable {
return mNativeType;
}
/**
* @hide
* Returns the list of AudioProfiles supported by the device
* @return the list of AudioProfiles
*/
@SystemApi
public @NonNull List<AudioProfile> getAudioProfiles() {
return mAudioProfiles;
}
/**
* @hide
* Returns the list of AudioDescriptors supported by the device
* @return the list of AudioDescriptors
*/
@SystemApi
public @NonNull List<AudioDescriptor> getAudioDescriptors() {
return mAudioDescriptors;
}
@Override
public int hashCode() {
return Objects.hash(mRole, mType, mAddress);
return Objects.hash(mRole, mType, mAddress, mName, mAudioProfiles, mAudioDescriptors);
}
@Override
@@ -182,6 +265,25 @@ public final class AudioDeviceAttributes implements Parcelable {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AudioDeviceAttributes that = (AudioDeviceAttributes) o;
return ((mRole == that.mRole)
&& (mType == that.mType)
&& mAddress.equals(that.mAddress)
&& mName.equals(that.mName)
&& mAudioProfiles.equals(that.mAudioProfiles)
&& mAudioDescriptors.equals(that.mAudioDescriptors));
}
/**
* Returns true if the role, type and address are equal. Called to compare with an
* AudioDeviceAttributes that was created from a native AudioDeviceTypeAddr instance.
* @param o object to compare with
* @return whether role, type and address are equal
*/
public boolean equalTypeAddress(@Nullable Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AudioDeviceAttributes that = (AudioDeviceAttributes) o;
return ((mRole == that.mRole)
&& (mType == that.mType)
@@ -199,7 +301,10 @@ public final class AudioDeviceAttributes implements Parcelable {
+ " role:" + roleToString(mRole)
+ " type:" + (mRole == ROLE_OUTPUT ? AudioSystem.getOutputDeviceName(mNativeType)
: AudioSystem.getInputDeviceName(mNativeType))
+ " addr:" + mAddress);
+ " addr:" + mAddress
+ " name:" + mName
+ " profiles:" + mAudioProfiles.toString()
+ " descriptors:" + mAudioDescriptors.toString());
}
@Override
@@ -212,14 +317,26 @@ public final class AudioDeviceAttributes implements Parcelable {
dest.writeInt(mRole);
dest.writeInt(mType);
dest.writeString(mAddress);
dest.writeString(mName);
dest.writeInt(mNativeType);
dest.writeParcelableArray(
mAudioProfiles.toArray(new AudioProfile[mAudioProfiles.size()]), flags);
dest.writeParcelableArray(
mAudioDescriptors.toArray(new AudioDescriptor[mAudioDescriptors.size()]), flags);
}
private AudioDeviceAttributes(@NonNull Parcel in) {
mRole = in.readInt();
mType = in.readInt();
mAddress = in.readString();
mName = in.readString();
mNativeType = in.readInt();
AudioProfile[] audioProfilesArray =
in.readParcelableArray(AudioProfile.class.getClassLoader(), AudioProfile.class);
mAudioProfiles = new ArrayList<AudioProfile>(Arrays.asList(audioProfilesArray));
AudioDescriptor[] audioDescriptorsArray = in.readParcelableArray(
AudioDescriptor.class.getClassLoader(), AudioDescriptor.class);
mAudioDescriptors = new ArrayList<AudioDescriptor>(Arrays.asList(audioDescriptorsArray));
}
public static final @NonNull Parcelable.Creator<AudioDeviceAttributes> CREATOR =

View File

@@ -421,7 +421,7 @@ public final class AudioDeviceInfo {
*/
public CharSequence getProductName() {
String portName = mPort.name();
return portName.length() != 0 ? portName : android.os.Build.MODEL;
return (portName != null && portName.length() != 0) ? portName : android.os.Build.MODEL;
}
/**

View File

@@ -5874,7 +5874,7 @@ public class AudioManager {
return false;
}
/**
/**
* Indicate wired accessory connection state change.
* @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
* @param state new connection state: 1 connected, 0 disconnected
@@ -5883,10 +5883,29 @@ public class AudioManager {
*/
@UnsupportedAppUsage
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public void setWiredDeviceConnectionState(int type, int state, String address, String name) {
public void setWiredDeviceConnectionState(int device, int state, String address,
String name) {
final IAudioService service = getService();
int role = isOutputDevice(device)
? AudioDeviceAttributes.ROLE_OUTPUT : AudioDeviceAttributes.ROLE_INPUT;
AudioDeviceAttributes attributes = new AudioDeviceAttributes(
role, AudioDeviceInfo.convertInternalDeviceToDeviceType(device), address,
name, new ArrayList<>()/*mAudioProfiles*/, new ArrayList<>()/*mAudioDescriptors*/);
setWiredDeviceConnectionState(attributes, state);
}
/**
* Indicate wired accessory connection state change and attributes.
* @param state new connection state: 1 connected, 0 disconnected
* @param attributes attributes of the connected device
* {@hide}
*/
@UnsupportedAppUsage
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes, int state) {
final IAudioService service = getService();
try {
service.setWiredDeviceConnectionState(type, state, address, name,
service.setWiredDeviceConnectionState(attributes, state,
mApplicationContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();

View File

@@ -18,10 +18,14 @@ package android.media;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;
/**
@@ -33,7 +37,7 @@ import java.util.stream.Collectors;
* be reported in different audio profiles. The application can choose any of the encapsulation
* types.
*/
public class AudioProfile {
public class AudioProfile implements Parcelable {
/**
* No encapsulation type is specified.
*/
@@ -57,9 +61,19 @@ public class AudioProfile {
private final int[] mChannelIndexMasks;
private final int mEncapsulationType;
AudioProfile(int format, @NonNull int[] samplingRates, @NonNull int[] channelMasks,
@NonNull int[] channelIndexMasks,
int encapsulationType) {
/**
* @hide
* Constructor from format, sampling rates, channel masks, channel index masks and
* encapsulation type.
* @param format the audio format
* @param samplingRates the supported sampling rates
* @param channelMasks the supported channel masks
* @param channelIndexMasks the supported channel index masks
* @param encapsulationType the encapsulation type of the encoding format
*/
@SystemApi
public AudioProfile(int format, @NonNull int[] samplingRates, @NonNull int[] channelMasks,
@NonNull int[] channelIndexMasks, int encapsulationType) {
mFormat = format;
mSamplingRates = samplingRates;
mChannelMasks = channelMasks;
@@ -113,6 +127,26 @@ public class AudioProfile {
return mEncapsulationType;
}
@Override
public int hashCode() {
return Objects.hash(mFormat, Arrays.hashCode(mSamplingRates),
Arrays.hashCode(mChannelMasks), Arrays.hashCode(mChannelIndexMasks),
mEncapsulationType);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AudioProfile that = (AudioProfile) o;
return ((mFormat == that.mFormat)
&& (hasIdenticalElements(mSamplingRates, that.mSamplingRates))
&& (hasIdenticalElements(mChannelMasks, that.mChannelMasks))
&& (hasIdenticalElements(mChannelIndexMasks, that.mChannelIndexMasks))
&& (mEncapsulationType == that.mEncapsulationType));
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("{");
@@ -126,6 +160,7 @@ public class AudioProfile {
if (mChannelIndexMasks != null && mChannelIndexMasks.length > 0) {
sb.append(", channel index masks=").append(Arrays.toString(mChannelIndexMasks));
}
sb.append(", encapsulation type=" + mEncapsulationType);
sb.append("}");
return sb.toString();
}
@@ -137,4 +172,50 @@ public class AudioProfile {
return Arrays.stream(ints).mapToObj(anInt -> String.format("0x%02X", anInt))
.collect(Collectors.joining(", "));
}
private static boolean hasIdenticalElements(int[] array1, int[] array2) {
int[] sortedArray1 = Arrays.copyOf(array1, array1.length);
Arrays.sort(sortedArray1);
int[] sortedArray2 = Arrays.copyOf(array2, array2.length);
Arrays.sort(sortedArray2);
return Arrays.equals(sortedArray1, sortedArray2);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mFormat);
dest.writeIntArray(mSamplingRates);
dest.writeIntArray(mChannelMasks);
dest.writeIntArray(mChannelIndexMasks);
dest.writeInt(mEncapsulationType);
}
private AudioProfile(@NonNull Parcel in) {
mFormat = in.readInt();
mSamplingRates = in.createIntArray();
mChannelMasks = in.createIntArray();
mChannelIndexMasks = in.createIntArray();
mEncapsulationType = in.readInt();
}
public static final @NonNull Parcelable.Creator<AudioProfile> CREATOR =
new Parcelable.Creator<AudioProfile>() {
/**
* Rebuilds an AudioProfile previously stored with writeToParcel().
* @param p Parcel object to read the AudioProfile from
* @return a new AudioProfile created from the data in the parcel
*/
public AudioProfile createFromParcel(Parcel p) {
return new AudioProfile(p);
}
public AudioProfile[] newArray(int size) {
return new AudioProfile[size];
}
};
}

View File

@@ -26,10 +26,12 @@ import android.bluetooth.BluetoothLeAudioCodecConfig;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.PackageManager;
import android.media.audio.common.AidlConversion;
import android.media.audiofx.AudioEffect;
import android.media.audiopolicy.AudioMix;
import android.os.Build;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Vibrator;
import android.telephony.TelephonyManager;
import android.util.Log;
@@ -1555,9 +1557,24 @@ public class AudioSystem
* {@link #AUDIO_STATUS_ERROR} or {@link #AUDIO_STATUS_SERVER_DIED}
*/
@UnsupportedAppUsage
public static native int setDeviceConnectionState(int device, int state,
String device_address, String device_name,
int codecFormat);
public static int setDeviceConnectionState(AudioDeviceAttributes attributes, int state,
int codecFormat) {
android.media.audio.common.AudioPort port =
AidlConversion.api2aidl_AudioDeviceAttributes_AudioPort(attributes);
Parcel parcel = Parcel.obtain();
port.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
try {
return setDeviceConnectionState(state, parcel, codecFormat);
} finally {
parcel.recycle();
}
}
/**
* @hide
*/
@UnsupportedAppUsage
public static native int setDeviceConnectionState(int state, Parcel parcel, int codecFormat);
/** @hide */
@UnsupportedAppUsage
public static native int getDeviceConnectionState(int device, String device_address);

View File

@@ -215,8 +215,7 @@ interface IAudioService {
IRingtonePlayer getRingtonePlayer();
int getUiSoundsStreamType();
void setWiredDeviceConnectionState(int type, int state, String address, String name,
String caller);
void setWiredDeviceConnectionState(in AudioDeviceAttributes aa, int state, String caller);
@UnsupportedAppUsage
AudioRoutesInfo startWatchingRoutes(in IAudioRoutesObserver observer);

View File

@@ -17,12 +17,17 @@
package android.media.audio.common;
import android.annotation.NonNull;
import android.media.AudioDescriptor;
import android.media.AudioDeviceAttributes;
import android.media.AudioFormat;
import android.media.AudioSystem;
import android.media.MediaFormat;
import android.os.Parcel;
import com.android.internal.annotations.VisibleForTesting;
import java.util.stream.Collectors;
/**
* This class provides utility functions for converting between
* the AIDL types defined in 'android.media.audio.common' and:
@@ -525,6 +530,351 @@ public class AidlConversion {
}
}
/**
* Convert from SDK AudioDeviceAttributes to AIDL AudioPort.
*/
public static AudioPort api2aidl_AudioDeviceAttributes_AudioPort(
@NonNull AudioDeviceAttributes attributes) {
AudioPort port = new AudioPort();
port.name = attributes.getName();
// TO DO: b/211611504 Convert attributes.getAudioProfiles() to AIDL as well.
port.profiles = new AudioProfile[]{};
port.extraAudioDescriptors = attributes.getAudioDescriptors().stream()
.map(descriptor -> api2aidl_AudioDescriptor_ExtraAudioDescriptor(descriptor))
.collect(Collectors.toList()).toArray(ExtraAudioDescriptor[]::new);
port.flags = new AudioIoFlags();
port.gains = new AudioGain[]{};
AudioPortDeviceExt deviceExt = new AudioPortDeviceExt();
deviceExt.device = new AudioDevice();
deviceExt.encodedFormats = new AudioFormatDescription[]{};
deviceExt.device.type =
api2aidl_NativeType_AudioDeviceDescription(attributes.getInternalType());
deviceExt.device.address = AudioDeviceAddress.id(attributes.getAddress());
port.ext = AudioPortExt.device(deviceExt);
return port;
}
/**
* Convert from SDK AudioDescriptor to AIDL ExtraAudioDescriptor.
*/
public static ExtraAudioDescriptor api2aidl_AudioDescriptor_ExtraAudioDescriptor(
@NonNull AudioDescriptor descriptor) {
ExtraAudioDescriptor extraDescriptor = new ExtraAudioDescriptor();
extraDescriptor.standard =
api2aidl_AudioDescriptorStandard_AudioStandard(descriptor.getStandard());
extraDescriptor.audioDescriptor = descriptor.getDescriptor();
extraDescriptor.encapsulationType =
api2aidl_AudioProfileEncapsulationType_AudioEncapsulationType(
descriptor.getEncapsulationType());
return extraDescriptor;
}
/**
* Convert from SDK AudioDescriptor to AIDL ExtraAudioDescriptor.
*/
public static @NonNull AudioDescriptor aidl2api_ExtraAudioDescriptor_AudioDescriptor(
@NonNull ExtraAudioDescriptor extraDescriptor) {
AudioDescriptor descriptor = new AudioDescriptor(
aidl2api_AudioStandard_AudioDescriptorStandard(extraDescriptor.standard),
aidl2api_AudioEncapsulationType_AudioProfileEncapsulationType(
extraDescriptor.encapsulationType),
extraDescriptor.audioDescriptor);
return descriptor;
}
/**
* Convert from SDK AudioDescriptor#mStandard to AIDL AudioStandard
*/
@AudioStandard
public static int api2aidl_AudioDescriptorStandard_AudioStandard(
@AudioDescriptor.AudioDescriptorStandard int standard) {
switch (standard) {
case AudioDescriptor.STANDARD_EDID:
return AudioStandard.EDID;
case AudioDescriptor.STANDARD_NONE:
default:
return AudioStandard.NONE;
}
}
/**
* Convert from AIDL AudioStandard to SDK AudioDescriptor#mStandard
*/
@AudioDescriptor.AudioDescriptorStandard
public static int aidl2api_AudioStandard_AudioDescriptorStandard(@AudioStandard int standard) {
switch (standard) {
case AudioStandard.EDID:
return AudioDescriptor.STANDARD_EDID;
case AudioStandard.NONE:
default:
return AudioDescriptor.STANDARD_NONE;
}
}
/**
* Convert from SDK AudioProfile.EncapsulationType to AIDL AudioEncapsulationType
*/
@AudioEncapsulationType
public static int api2aidl_AudioProfileEncapsulationType_AudioEncapsulationType(
@android.media.AudioProfile.EncapsulationType int type) {
switch (type) {
case android.media.AudioProfile.AUDIO_ENCAPSULATION_TYPE_IEC61937:
return AudioEncapsulationType.IEC61937;
case android.media.AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE:
default:
return AudioEncapsulationType.NONE;
}
}
/**
* Convert from AIDL AudioEncapsulationType to SDK AudioProfile.EncapsulationType
*/
@android.media.AudioProfile.EncapsulationType
public static int aidl2api_AudioEncapsulationType_AudioProfileEncapsulationType(
@AudioEncapsulationType int type) {
switch (type) {
case AudioEncapsulationType.IEC61937:
return android.media.AudioProfile.AUDIO_ENCAPSULATION_TYPE_IEC61937;
case AudioEncapsulationType.NONE:
default:
return android.media.AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE;
}
}
/**
* Convert from SDK native type to AIDL AudioDeviceDescription
*/
public static AudioDeviceDescription api2aidl_NativeType_AudioDeviceDescription(
int nativeType) {
AudioDeviceDescription aidl = new AudioDeviceDescription();
aidl.connection = "";
switch (nativeType) {
case AudioSystem.DEVICE_OUT_EARPIECE:
aidl.type = AudioDeviceType.OUT_SPEAKER_EARPIECE;
break;
case AudioSystem.DEVICE_OUT_SPEAKER:
aidl.type = AudioDeviceType.OUT_SPEAKER;
break;
case AudioSystem.DEVICE_OUT_WIRED_HEADPHONE:
aidl.type = AudioDeviceType.OUT_HEADPHONE;
aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
break;
case AudioSystem.DEVICE_OUT_BLUETOOTH_SCO:
aidl.type = AudioDeviceType.OUT_DEVICE;
aidl.connection = AudioDeviceDescription.CONNECTION_BT_SCO;
break;
case AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
aidl.type = AudioDeviceType.OUT_CARKIT;
aidl.connection = AudioDeviceDescription.CONNECTION_BT_SCO;
break;
case AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
aidl.type = AudioDeviceType.OUT_HEADPHONE;
aidl.connection = AudioDeviceDescription.CONNECTION_BT_A2DP;
break;
case AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
aidl.type = AudioDeviceType.OUT_SPEAKER;
aidl.connection = AudioDeviceDescription.CONNECTION_BT_A2DP;
break;
case AudioSystem.DEVICE_OUT_TELEPHONY_TX:
aidl.type = AudioDeviceType.OUT_TELEPHONY_TX;
break;
case AudioSystem.DEVICE_OUT_AUX_LINE:
aidl.type = AudioDeviceType.OUT_LINE_AUX;
break;
case AudioSystem.DEVICE_OUT_SPEAKER_SAFE:
aidl.type = AudioDeviceType.OUT_SPEAKER_SAFE;
break;
case AudioSystem.DEVICE_OUT_HEARING_AID:
aidl.type = AudioDeviceType.OUT_HEARING_AID;
aidl.connection = AudioDeviceDescription.CONNECTION_WIRELESS;
break;
case AudioSystem.DEVICE_OUT_ECHO_CANCELLER:
aidl.type = AudioDeviceType.OUT_ECHO_CANCELLER;
break;
case AudioSystem.DEVICE_OUT_BLE_SPEAKER:
aidl.type = AudioDeviceType.OUT_SPEAKER;
aidl.connection = AudioDeviceDescription.CONNECTION_BT_LE;
break;
case AudioSystem.DEVICE_IN_BUILTIN_MIC:
aidl.type = AudioDeviceType.IN_MICROPHONE;
break;
case AudioSystem.DEVICE_IN_BACK_MIC:
aidl.type = AudioDeviceType.IN_MICROPHONE_BACK;
break;
case AudioSystem.DEVICE_IN_TELEPHONY_RX:
aidl.type = AudioDeviceType.IN_TELEPHONY_RX;
break;
case AudioSystem.DEVICE_IN_TV_TUNER:
aidl.type = AudioDeviceType.IN_TV_TUNER;
break;
case AudioSystem.DEVICE_IN_LOOPBACK:
aidl.type = AudioDeviceType.IN_LOOPBACK;
break;
case AudioSystem.DEVICE_IN_BLUETOOTH_BLE:
aidl.type = AudioDeviceType.IN_DEVICE;
aidl.connection = AudioDeviceDescription.CONNECTION_BT_LE;
break;
case AudioSystem.DEVICE_IN_ECHO_REFERENCE:
aidl.type = AudioDeviceType.IN_ECHO_REFERENCE;
break;
case AudioSystem.DEVICE_IN_WIRED_HEADSET:
aidl.type = AudioDeviceType.IN_HEADSET;
aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
break;
case AudioSystem.DEVICE_OUT_WIRED_HEADSET:
aidl.type = AudioDeviceType.OUT_HEADSET;
aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
break;
case AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET:
aidl.type = AudioDeviceType.IN_HEADSET;
aidl.connection = AudioDeviceDescription.CONNECTION_BT_SCO;
break;
case AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
aidl.type = AudioDeviceType.OUT_HEADSET;
aidl.connection = AudioDeviceDescription.CONNECTION_BT_SCO;
break;
case AudioSystem.DEVICE_IN_HDMI:
aidl.type = AudioDeviceType.IN_DEVICE;
aidl.connection = AudioDeviceDescription.CONNECTION_HDMI;
break;
case AudioSystem.DEVICE_OUT_HDMI:
aidl.type = AudioDeviceType.OUT_DEVICE;
aidl.connection = AudioDeviceDescription.CONNECTION_HDMI;
break;
case AudioSystem.DEVICE_IN_REMOTE_SUBMIX:
aidl.type = AudioDeviceType.IN_SUBMIX;
break;
case AudioSystem.DEVICE_OUT_REMOTE_SUBMIX:
aidl.type = AudioDeviceType.OUT_SUBMIX;
break;
case AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET:
aidl.type = AudioDeviceType.IN_DOCK;
aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
break;
case AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET:
aidl.type = AudioDeviceType.OUT_DOCK;
aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
break;
case AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET:
aidl.type = AudioDeviceType.IN_DOCK;
aidl.connection = AudioDeviceDescription.CONNECTION_USB;
break;
case AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET:
aidl.type = AudioDeviceType.OUT_DOCK;
aidl.connection = AudioDeviceDescription.CONNECTION_USB;
break;
case AudioSystem.DEVICE_IN_USB_ACCESSORY:
aidl.type = AudioDeviceType.IN_ACCESSORY;
aidl.connection = AudioDeviceDescription.CONNECTION_USB;
break;
case AudioSystem.DEVICE_OUT_USB_ACCESSORY:
aidl.type = AudioDeviceType.OUT_ACCESSORY;
aidl.connection = AudioDeviceDescription.CONNECTION_USB;
break;
case AudioSystem.DEVICE_IN_USB_DEVICE:
aidl.type = AudioDeviceType.IN_DEVICE;
aidl.connection = AudioDeviceDescription.CONNECTION_USB;
break;
case AudioSystem.DEVICE_OUT_USB_DEVICE:
aidl.type = AudioDeviceType.OUT_DEVICE;
aidl.connection = AudioDeviceDescription.CONNECTION_USB;
break;
case AudioSystem.DEVICE_IN_FM_TUNER:
aidl.type = AudioDeviceType.IN_FM_TUNER;
break;
case AudioSystem.DEVICE_OUT_FM:
aidl.type = AudioDeviceType.OUT_FM;
break;
case AudioSystem.DEVICE_IN_LINE:
aidl.type = AudioDeviceType.IN_DEVICE;
aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
break;
case AudioSystem.DEVICE_OUT_LINE:
aidl.type = AudioDeviceType.OUT_DEVICE;
aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
break;
case AudioSystem.DEVICE_IN_SPDIF:
aidl.type = AudioDeviceType.IN_DEVICE;
aidl.connection = AudioDeviceDescription.CONNECTION_SPDIF;
break;
case AudioSystem.DEVICE_OUT_SPDIF:
aidl.type = AudioDeviceType.OUT_DEVICE;
aidl.connection = AudioDeviceDescription.CONNECTION_SPDIF;
break;
case AudioSystem.DEVICE_IN_BLUETOOTH_A2DP:
aidl.type = AudioDeviceType.IN_DEVICE;
aidl.connection = AudioDeviceDescription.CONNECTION_BT_A2DP;
break;
case AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP:
aidl.type = AudioDeviceType.OUT_DEVICE;
aidl.connection = AudioDeviceDescription.CONNECTION_BT_A2DP;
break;
case AudioSystem.DEVICE_IN_IP:
aidl.type = AudioDeviceType.IN_DEVICE;
aidl.connection = AudioDeviceDescription.CONNECTION_IP_V4;
break;
case AudioSystem.DEVICE_OUT_IP:
aidl.type = AudioDeviceType.OUT_DEVICE;
aidl.connection = AudioDeviceDescription.CONNECTION_IP_V4;
break;
case AudioSystem.DEVICE_IN_BUS:
aidl.type = AudioDeviceType.IN_DEVICE;
aidl.connection = AudioDeviceDescription.CONNECTION_BUS;
break;
case AudioSystem.DEVICE_OUT_BUS:
aidl.type = AudioDeviceType.OUT_DEVICE;
aidl.connection = AudioDeviceDescription.CONNECTION_BUS;
break;
case AudioSystem.DEVICE_IN_PROXY:
aidl.type = AudioDeviceType.IN_AFE_PROXY;
break;
case AudioSystem.DEVICE_OUT_PROXY:
aidl.type = AudioDeviceType.OUT_AFE_PROXY;
break;
case AudioSystem.DEVICE_IN_USB_HEADSET:
aidl.type = AudioDeviceType.IN_HEADSET;
aidl.connection = AudioDeviceDescription.CONNECTION_USB;
break;
case AudioSystem.DEVICE_OUT_USB_HEADSET:
aidl.type = AudioDeviceType.OUT_HEADSET;
aidl.connection = AudioDeviceDescription.CONNECTION_USB;
break;
case AudioSystem.DEVICE_IN_HDMI_ARC:
aidl.type = AudioDeviceType.IN_DEVICE;
aidl.connection = AudioDeviceDescription.CONNECTION_HDMI_ARC;
break;
case AudioSystem.DEVICE_OUT_HDMI_ARC:
aidl.type = AudioDeviceType.OUT_DEVICE;
aidl.connection = AudioDeviceDescription.CONNECTION_HDMI_ARC;
break;
case AudioSystem.DEVICE_IN_HDMI_EARC:
aidl.type = AudioDeviceType.IN_DEVICE;
aidl.connection = AudioDeviceDescription.CONNECTION_HDMI_EARC;
break;
case AudioSystem.DEVICE_OUT_HDMI_EARC:
aidl.type = AudioDeviceType.OUT_DEVICE;
aidl.connection = AudioDeviceDescription.CONNECTION_HDMI_EARC;
break;
case AudioSystem.DEVICE_IN_BLE_HEADSET:
aidl.type = AudioDeviceType.IN_HEADSET;
aidl.connection = AudioDeviceDescription.CONNECTION_BT_LE;
break;
case AudioSystem.DEVICE_OUT_BLE_HEADSET:
aidl.type = AudioDeviceType.OUT_HEADSET;
aidl.connection = AudioDeviceDescription.CONNECTION_BT_LE;
break;
case AudioSystem.DEVICE_IN_DEFAULT:
aidl.type = AudioDeviceType.IN_DEFAULT;
break;
case AudioSystem.DEVICE_OUT_DEFAULT:
aidl.type = AudioDeviceType.OUT_DEFAULT;
break;
default:
aidl.type = AudioDeviceType.NONE;
}
return aidl;
}
private static native int aidl2legacy_AudioChannelLayout_Parcel_audio_channel_mask_t(
Parcel aidl, boolean isInput);
private static native Parcel legacy2aidl_audio_channel_mask_t_AudioChannelLayout_Parcel(

View File

@@ -16,8 +16,18 @@
package android.media.audio.common;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import android.media.AudioAttributes;
import android.media.AudioDescriptor;
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
import android.media.AudioProfile;
import android.media.AudioSystem;
import android.media.AudioTrack;
import android.media.MediaFormat;
@@ -25,11 +35,12 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.runner.AndroidJUnit4;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.Arrays;
/**
* Unit tests for AidlConversion utilities.
*
@@ -417,10 +428,102 @@ public final class AidlConversionUnitTests {
() -> AidlConversion.legacy2aidl_audio_usage_t_AudioUsage(sInvalidValue));
}
@Test
public void testAudioDescriptorConversion_Default() {
ExtraAudioDescriptor aidl = createDefaultDescriptor();
AudioDescriptor audioDescriptor =
AidlConversion.aidl2api_ExtraAudioDescriptor_AudioDescriptor(aidl);
assertEquals(AudioDescriptor.STANDARD_NONE, audioDescriptor.getStandard());
assertEquals(
AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE, audioDescriptor.getEncapsulationType());
assertTrue(Arrays.equals(new byte[]{}, audioDescriptor.getDescriptor()));
ExtraAudioDescriptor reconstructedExtraDescriptor =
AidlConversion.api2aidl_AudioDescriptor_ExtraAudioDescriptor(audioDescriptor);
assertEquals(aidl, reconstructedExtraDescriptor);
}
@Test
public void testAudioDescriptorConversion() {
ExtraAudioDescriptor aidl = createEncapsulationDescriptor(new byte[]{0x05, 0x18, 0x4A});
AudioDescriptor audioDescriptor =
AidlConversion.aidl2api_ExtraAudioDescriptor_AudioDescriptor(aidl);
assertEquals(AudioDescriptor.STANDARD_EDID, audioDescriptor.getStandard());
assertEquals(AudioProfile.AUDIO_ENCAPSULATION_TYPE_IEC61937,
audioDescriptor.getEncapsulationType());
assertTrue(Arrays.equals(new byte[]{0x05, 0x18, 0x4A}, audioDescriptor.getDescriptor()));
ExtraAudioDescriptor reconstructedExtraDescriptor =
AidlConversion.api2aidl_AudioDescriptor_ExtraAudioDescriptor(audioDescriptor);
assertEquals(aidl, reconstructedExtraDescriptor);
}
@Test
public void testAudioDeviceAttributesConversion_Default() {
AudioDeviceAttributes attributes =
new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_DEFAULT, "myAddress");
AudioPort port = AidlConversion.api2aidl_AudioDeviceAttributes_AudioPort(attributes);
assertEquals("", port.name);
assertEquals(0, port.extraAudioDescriptors.length);
assertEquals("myAddress", port.ext.getDevice().device.address.getId());
assertEquals("", port.ext.getDevice().device.type.connection);
assertEquals(AudioDeviceType.OUT_DEFAULT, port.ext.getDevice().device.type.type);
}
@Test
public void testAudioDeviceAttributesConversion() {
AudioDescriptor audioDescriptor1 =
AidlConversion.aidl2api_ExtraAudioDescriptor_AudioDescriptor(
createEncapsulationDescriptor(new byte[]{0x05, 0x18, 0x4A}));
AudioDescriptor audioDescriptor2 =
AidlConversion.aidl2api_ExtraAudioDescriptor_AudioDescriptor(
createDefaultDescriptor());
AudioDeviceAttributes attributes =
new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT,
AudioDeviceInfo.TYPE_HDMI_ARC, "myAddress", "myName", new ArrayList<>(),
new ArrayList<>(Arrays.asList(audioDescriptor1, audioDescriptor2)));
AudioPort port = AidlConversion.api2aidl_AudioDeviceAttributes_AudioPort(
attributes);
assertEquals("myName", port.name);
assertEquals(2, port.extraAudioDescriptors.length);
assertEquals(AudioStandard.EDID, port.extraAudioDescriptors[0].standard);
assertEquals(AudioEncapsulationType.IEC61937,
port.extraAudioDescriptors[0].encapsulationType);
assertTrue(Arrays.equals(new byte[]{0x05, 0x18, 0x4A},
port.extraAudioDescriptors[0].audioDescriptor));
assertEquals(AudioStandard.NONE, port.extraAudioDescriptors[1].standard);
assertEquals(AudioEncapsulationType.NONE,
port.extraAudioDescriptors[1].encapsulationType);
assertTrue(Arrays.equals(new byte[]{},
port.extraAudioDescriptors[1].audioDescriptor));
assertEquals("myAddress", port.ext.getDevice().device.address.getId());
assertEquals(AudioDeviceDescription.CONNECTION_HDMI_ARC,
port.ext.getDevice().device.type.connection);
assertEquals(AudioDeviceType.OUT_DEVICE, port.ext.getDevice().device.type.type);
}
private static AudioFormatDescription createPcm16FormatAidl() {
final AudioFormatDescription aidl = new AudioFormatDescription();
aidl.type = AudioFormatType.PCM;
aidl.pcm = PcmType.INT_16_BIT;
return aidl;
}
private static ExtraAudioDescriptor createDefaultDescriptor() {
ExtraAudioDescriptor extraDescriptor = new ExtraAudioDescriptor();
extraDescriptor.standard = AudioStandard.NONE;
extraDescriptor.encapsulationType = AudioEncapsulationType.NONE;
extraDescriptor.audioDescriptor = new byte[]{};
return extraDescriptor;
}
private static ExtraAudioDescriptor createEncapsulationDescriptor(byte[] audioDescriptor) {
ExtraAudioDescriptor extraDescriptor = new ExtraAudioDescriptor();
extraDescriptor.standard = AudioStandard.EDID;
extraDescriptor.encapsulationType = AudioEncapsulationType.IEC61937;
extraDescriptor.audioDescriptor = audioDescriptor;
return extraDescriptor;
}
}

View File

@@ -500,12 +500,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
}
/*package*/ void setWiredDeviceConnectionState(int type,
@AudioService.ConnectionState int state, String address, String name,
String caller) {
/*package*/ void setWiredDeviceConnectionState(AudioDeviceAttributes attributes,
@AudioService.ConnectionState int state, String caller) {
//TODO move logging here just like in setBluetooth* methods
synchronized (mDeviceStateLock) {
mDeviceInventory.setWiredDeviceConnectionState(type, state, address, name, caller);
mDeviceInventory.setWiredDeviceConnectionState(attributes, state, caller);
}
}
@@ -1013,11 +1012,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
}
/*package*/ boolean handleDeviceConnection(boolean connect, int device, String address,
String deviceName) {
/*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, boolean connect) {
synchronized (mDeviceStateLock) {
return mDeviceInventory.handleDeviceConnection(connect, device, address, deviceName,
false /*for test*/);
return mDeviceInventory.handleDeviceConnection(attributes, connect, false /*for test*/);
}
}

View File

@@ -230,19 +230,15 @@ public class AudioDeviceInventory {
* A class just for packaging up a set of connection parameters.
*/
/*package*/ class WiredDeviceConnectionState {
public final int mType;
public final AudioDeviceAttributes mAttributes;
public final @AudioService.ConnectionState int mState;
public final String mAddress;
public final String mName;
public final String mCaller;
public boolean mForTest = false;
/*package*/ WiredDeviceConnectionState(int type, @AudioService.ConnectionState int state,
String address, String name, String caller) {
mType = type;
/*package*/ WiredDeviceConnectionState(AudioDeviceAttributes attributes,
@AudioService.ConnectionState int state, String caller) {
mAttributes = attributes;
mState = state;
mAddress = address;
mName = name;
mCaller = caller;
}
}
@@ -280,11 +276,10 @@ public class AudioDeviceInventory {
synchronized (mDevicesLock) {
//TODO iterate on mApmConnectedDevices instead once it handles all device types
for (DeviceInfo di : mConnectedDevices.values()) {
mAudioSystem.setDeviceConnectionState(
di.mDeviceType,
AudioSystem.DEVICE_STATE_AVAILABLE,
mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(di.mDeviceType,
di.mDeviceAddress,
di.mDeviceName,
di.mDeviceName),
AudioSystem.DEVICE_STATE_AVAILABLE,
di.mDeviceCodecFormat);
}
}
@@ -519,41 +514,45 @@ public class AudioDeviceInventory {
/*package*/ void onSetWiredDeviceConnectionState(
AudioDeviceInventory.WiredDeviceConnectionState wdcs) {
int type = wdcs.mAttributes.getInternalType();
AudioService.sDeviceLogger.log(new AudioServiceEvents.WiredDevConnectEvent(wdcs));
MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId
+ "onSetWiredDeviceConnectionState")
.set(MediaMetrics.Property.ADDRESS, wdcs.mAddress)
.set(MediaMetrics.Property.DEVICE, AudioSystem.getDeviceName(wdcs.mType))
.set(MediaMetrics.Property.ADDRESS, wdcs.mAttributes.getAddress())
.set(MediaMetrics.Property.DEVICE,
AudioSystem.getDeviceName(type))
.set(MediaMetrics.Property.STATE,
wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED
? MediaMetrics.Value.DISCONNECTED : MediaMetrics.Value.CONNECTED);
synchronized (mDevicesLock) {
if ((wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED)
&& DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(wdcs.mType)) {
&& DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(type)) {
mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/,
"onSetWiredDeviceConnectionState state DISCONNECTED");
}
if (!handleDeviceConnection(wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED,
wdcs.mType, wdcs.mAddress, wdcs.mName, wdcs.mForTest)) {
if (!handleDeviceConnection(wdcs.mAttributes,
wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED, wdcs.mForTest)) {
// change of connection state failed, bailout
mmi.set(MediaMetrics.Property.EARLY_RETURN, "change of connection state failed")
.record();
return;
}
if (wdcs.mState != AudioService.CONNECTION_STATE_DISCONNECTED) {
if (DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(wdcs.mType)) {
if (DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(type)) {
mDeviceBroker.setBluetoothA2dpOnInt(false, false /*fromA2dp*/,
"onSetWiredDeviceConnectionState state not DISCONNECTED");
}
mDeviceBroker.checkMusicActive(wdcs.mType, wdcs.mCaller);
mDeviceBroker.checkMusicActive(type, wdcs.mCaller);
}
if (wdcs.mType == AudioSystem.DEVICE_OUT_HDMI) {
if (type == AudioSystem.DEVICE_OUT_HDMI) {
mDeviceBroker.checkVolumeCecOnHdmiConnection(wdcs.mState, wdcs.mCaller);
}
sendDeviceConnectionIntent(wdcs.mType, wdcs.mState, wdcs.mAddress, wdcs.mName);
updateAudioRoutes(wdcs.mType, wdcs.mState);
sendDeviceConnectionIntent(type, wdcs.mState,
wdcs.mAttributes.getAddress(), wdcs.mAttributes.getName());
updateAudioRoutes(type, wdcs.mState);
}
mmi.record();
}
@@ -572,12 +571,12 @@ public class AudioDeviceInventory {
return;
}
// Toggle HDMI to retrigger broadcast with proper formats.
setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
AudioSystem.DEVICE_STATE_UNAVAILABLE, "", "",
"android"); // disconnect
setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
AudioSystem.DEVICE_STATE_AVAILABLE, "", "",
"android"); // reconnect
setWiredDeviceConnectionState(
new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_HDMI, ""),
AudioSystem.DEVICE_STATE_UNAVAILABLE, "android"); // disconnect
setWiredDeviceConnectionState(
new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_HDMI, ""),
AudioSystem.DEVICE_STATE_AVAILABLE, "android"); // reconnect
}
mmi.record();
}
@@ -707,16 +706,17 @@ public class AudioDeviceInventory {
/**
* Implements the communication with AudioSystem to (dis)connect a device in the native layers
* @param attributes the attributes of the device
* @param connect true if connection
* @param device the device type
* @param address the address of the device
* @param deviceName human-readable name of device
* @param isForTesting if true, not calling AudioSystem for the connection as this is
* just for testing
* @return false if an error was reported by AudioSystem
*/
/*package*/ boolean handleDeviceConnection(boolean connect, int device, String address,
String deviceName, boolean isForTesting) {
/*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, boolean connect,
boolean isForTesting) {
int device = attributes.getInternalType();
String address = attributes.getAddress();
String deviceName = attributes.getName();
if (AudioService.DEBUG_DEVICES) {
Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:"
+ Integer.toHexString(device) + " address:" + address
@@ -743,9 +743,8 @@ public class AudioDeviceInventory {
if (isForTesting) {
res = AudioSystem.AUDIO_STATUS_OK;
} else {
res = mAudioSystem.setDeviceConnectionState(device,
AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName,
AudioSystem.AUDIO_FORMAT_DEFAULT);
res = mAudioSystem.setDeviceConnectionState(attributes,
AudioSystem.DEVICE_STATE_AVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
}
if (res != AudioSystem.AUDIO_STATUS_OK) {
final String reason = "not connecting device 0x" + Integer.toHexString(device)
@@ -762,9 +761,8 @@ public class AudioDeviceInventory {
mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
return true;
} else if (!connect && isConnected) {
mAudioSystem.setDeviceConnectionState(device,
AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName,
AudioSystem.AUDIO_FORMAT_DEFAULT);
mAudioSystem.setDeviceConnectionState(attributes,
AudioSystem.DEVICE_STATE_UNAVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
// always remove even if disconnection failed
mConnectedDevices.remove(deviceKey);
mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
@@ -941,13 +939,13 @@ public class AudioDeviceInventory {
return delay;
}
/*package*/ int setWiredDeviceConnectionState(int type, @AudioService.ConnectionState int state,
String address, String name, String caller) {
/*package*/ int setWiredDeviceConnectionState(AudioDeviceAttributes attributes,
@AudioService.ConnectionState int state, String caller) {
synchronized (mDevicesLock) {
int delay = checkSendBecomingNoisyIntentInt(type, state, AudioSystem.DEVICE_NONE);
int delay = checkSendBecomingNoisyIntentInt(
attributes.getInternalType(), state, AudioSystem.DEVICE_NONE);
mDeviceBroker.postSetWiredDeviceConnectionState(
new WiredDeviceConnectionState(type, state, address, name, caller),
delay);
new WiredDeviceConnectionState(attributes, state, caller), delay);
return delay;
}
}
@@ -955,8 +953,7 @@ public class AudioDeviceInventory {
/*package*/ void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device,
@AudioService.ConnectionState int state) {
final WiredDeviceConnectionState connection = new WiredDeviceConnectionState(
device.getInternalType(), state, device.getAddress(),
"test device", "com.android.server.audio");
device, state, "com.android.server.audio");
connection.mForTest = true;
onSetWiredDeviceConnectionState(connection);
}
@@ -972,8 +969,9 @@ public class AudioDeviceInventory {
mDeviceBroker.setBluetoothA2dpOnInt(true, true /*fromA2dp*/, eventSource);
// at this point there could be another A2DP device already connected in APM, but it
// doesn't matter as this new one will overwrite the previous one
final int res = mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
AudioSystem.DEVICE_STATE_AVAILABLE, address, name, a2dpCodec);
final int res = mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address, name),
AudioSystem.DEVICE_STATE_AVAILABLE, a2dpCodec);
// TODO: log in MediaMetrics once distinction between connection failure and
// double connection is made.
@@ -1035,8 +1033,9 @@ public class AudioDeviceInventory {
// device to remove was visible by APM, update APM
mDeviceBroker.clearAvrcpAbsoluteVolumeSupported();
final int res = mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "", a2dpCodec);
final int res = mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
AudioSystem.DEVICE_STATE_UNAVAILABLE, a2dpCodec);
if (res != AudioSystem.AUDIO_STATUS_OK) {
AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
@@ -1074,8 +1073,9 @@ public class AudioDeviceInventory {
@GuardedBy("mDevicesLock")
private void makeA2dpSrcAvailable(String address) {
mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
AudioSystem.DEVICE_STATE_AVAILABLE, address, "",
mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
AudioSystem.DEVICE_STATE_AVAILABLE,
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.put(
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
@@ -1085,8 +1085,9 @@ public class AudioDeviceInventory {
@GuardedBy("mDevicesLock")
private void makeA2dpSrcUnavailable(String address) {
mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "",
mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
AudioSystem.DEVICE_STATE_UNAVAILABLE,
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.remove(
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
@@ -1099,8 +1100,9 @@ public class AudioDeviceInventory {
AudioSystem.DEVICE_OUT_HEARING_AID);
mDeviceBroker.postSetHearingAidVolumeIndex(hearingAidVolIndex, streamType);
mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
AudioSystem.DEVICE_STATE_AVAILABLE, address, name,
mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
AudioSystem.DEVICE_OUT_HEARING_AID, address, name),
AudioSystem.DEVICE_STATE_AVAILABLE,
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.put(
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address),
@@ -1122,8 +1124,9 @@ public class AudioDeviceInventory {
@GuardedBy("mDevicesLock")
private void makeHearingAidDeviceUnavailable(String address) {
mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "",
mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
AudioSystem.DEVICE_OUT_HEARING_AID, address),
AudioSystem.DEVICE_STATE_UNAVAILABLE,
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.remove(
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address));
@@ -1140,14 +1143,14 @@ public class AudioDeviceInventory {
private void makeLeAudioDeviceAvailable(String address, String name, int streamType, int device,
String eventSource) {
if (device != AudioSystem.DEVICE_NONE) {
/* Audio Policy sees Le Audio similar to A2DP. Let's make sure
* AUDIO_POLICY_FORCE_NO_BT_A2DP is not set
*/
mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/, eventSource);
AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_AVAILABLE,
address, name, AudioSystem.AUDIO_FORMAT_DEFAULT);
AudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(device, address, name),
AudioSystem.DEVICE_STATE_AVAILABLE,
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.put(DeviceInfo.makeDeviceListKey(device, address),
new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
mDeviceBroker.postAccessoryPlugMediaUnmute(device);
@@ -1168,8 +1171,9 @@ public class AudioDeviceInventory {
@GuardedBy("mDevicesLock")
private void makeLeAudioDeviceUnavailable(String address, int device) {
if (device != AudioSystem.DEVICE_NONE) {
AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_UNAVAILABLE,
address, "", AudioSystem.AUDIO_FORMAT_DEFAULT);
AudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(device, address),
AudioSystem.DEVICE_STATE_UNAVAILABLE,
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.remove(DeviceInfo.makeDeviceListKey(device, address));
}

View File

@@ -6371,23 +6371,23 @@ public class AudioService extends IAudioService.Stub
/**
* see AudioManager.setWiredDeviceConnectionState()
*/
public void setWiredDeviceConnectionState(int type,
@ConnectionState int state, String address, String name,
String caller) {
public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes,
@ConnectionState int state, String caller) {
enforceModifyAudioRoutingPermission();
if (state != CONNECTION_STATE_CONNECTED
&& state != CONNECTION_STATE_DISCONNECTED) {
throw new IllegalArgumentException("Invalid state " + state);
}
new MediaMetrics.Item(mMetricsId + "setWiredDeviceConnectionState")
.set(MediaMetrics.Property.ADDRESS, address)
.set(MediaMetrics.Property.ADDRESS, attributes.getAddress())
.set(MediaMetrics.Property.CLIENT_NAME, caller)
.set(MediaMetrics.Property.DEVICE, AudioSystem.getDeviceName(type))
.set(MediaMetrics.Property.NAME, name)
.set(MediaMetrics.Property.DEVICE,
AudioSystem.getDeviceName(attributes.getInternalType()))
.set(MediaMetrics.Property.NAME, attributes.getName())
.set(MediaMetrics.Property.STATE,
state == CONNECTION_STATE_CONNECTED ? "connected" : "disconnected")
.record();
mDeviceBroker.setWiredDeviceConnectionState(type, state, address, name, caller);
mDeviceBroker.setWiredDeviceConnectionState(attributes, state, caller);
}
/** @see AudioManager#setTestDeviceConnectionState(AudioDeviceAttributes, boolean) */

View File

@@ -116,10 +116,11 @@ public class AudioServiceEvents {
@Override
public String eventToString() {
return new StringBuilder("setWiredDeviceConnectionState(")
.append(" type:").append(Integer.toHexString(mState.mType))
.append(" type:").append(
Integer.toHexString(mState.mAttributes.getInternalType()))
.append(" state:").append(AudioSystem.deviceStateToString(mState.mState))
.append(" addr:").append(mState.mAddress)
.append(" name:").append(mState.mName)
.append(" addr:").append(mState.mAttributes.getAddress())
.append(" name:").append(mState.mAttributes.getName())
.append(") from ").append(mState.mCaller).toString();
}
}

View File

@@ -258,19 +258,16 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback {
}
/**
* Same as {@link AudioSystem#setDeviceConnectionState(int, int, String, String, int)}
* @param device
* Same as {@link AudioSystem#setDeviceConnectionState(AudioDeviceAttributes, int, int)}
* @param attributes
* @param state
* @param deviceAddress
* @param deviceName
* @param codecFormat
* @return
*/
public int setDeviceConnectionState(int device, int state, String deviceAddress,
String deviceName, int codecFormat) {
public int setDeviceConnectionState(AudioDeviceAttributes attributes, int state,
int codecFormat) {
invalidateRoutingCache();
return AudioSystem.setDeviceConnectionState(device, state, deviceAddress, deviceName,
codecFormat);
return AudioSystem.setDeviceConnectionState(attributes, state, codecFormat);
}
/**

View File

@@ -595,8 +595,9 @@ public class BtHelper {
String btDeviceName = getName(btDevice);
boolean result = false;
if (isActive) {
result |= mDeviceBroker.handleDeviceConnection(isActive, audioDevice.getInternalType(),
audioDevice.getAddress(), btDeviceName);
result |= mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
audioDevice.getInternalType(), audioDevice.getAddress(), btDeviceName),
isActive);
} else {
int[] outDeviceTypes = {
AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
@@ -604,13 +605,15 @@ public class BtHelper {
AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT
};
for (int outDeviceType : outDeviceTypes) {
result |= mDeviceBroker.handleDeviceConnection(
isActive, outDeviceType, audioDevice.getAddress(), btDeviceName);
result |= mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
outDeviceType, audioDevice.getAddress(), btDeviceName),
isActive);
}
}
// handleDeviceConnection() && result to make sure the method get executed
result = mDeviceBroker.handleDeviceConnection(
isActive, inDevice, audioDevice.getAddress(), btDeviceName) && result;
result = mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
inDevice, audioDevice.getAddress(), btDeviceName),
isActive) && result;
return result;
}

View File

@@ -41,7 +41,10 @@ import android.hardware.hdmi.HdmiRecordSources;
import android.hardware.hdmi.HdmiTimerRecordSources;
import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.media.AudioSystem;
import android.media.AudioDescriptor;
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceInfo;
import android.media.AudioProfile;
import android.media.tv.TvInputInfo;
import android.media.tv.TvInputManager.TvInputCallback;
import android.util.Slog;
@@ -58,6 +61,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
/**
* Represent a logical device of type TV residing in Android system.
@@ -816,12 +820,23 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
HdmiLogger.debug("Set Arc Status[old:%b new:%b]", mArcEstablished, enabled);
boolean oldStatus = mArcEstablished;
// 1. Enable/disable ARC circuit.
enableAudioReturnChannel(enabled);
// 2. Notify arc status to audio service.
notifyArcStatusToAudioService(enabled);
// 3. Update arc status;
mArcEstablished = enabled;
if (enabled) {
RequestSadAction action = new RequestSadAction(
this, Constants.ADDR_AUDIO_SYSTEM,
new RequestSadAction.RequestSadCallback() {
@Override
public void onRequestSadDone(List<byte[]> supportedSads) {
enableAudioReturnChannel(enabled);
notifyArcStatusToAudioService(enabled, supportedSads);
mArcEstablished = enabled;
}
});
addAndStartAction(action);
} else {
enableAudioReturnChannel(enabled);
notifyArcStatusToAudioService(enabled, new ArrayList<>());
mArcEstablished = enabled;
}
return oldStatus;
}
@@ -843,11 +858,15 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
return mService.isConnected(portId);
}
private void notifyArcStatusToAudioService(boolean enabled) {
private void notifyArcStatusToAudioService(boolean enabled, List<byte[]> supportedSads) {
// Note that we don't set any name to ARC.
mService.getAudioManager().setWiredDeviceConnectionState(
AudioSystem.DEVICE_OUT_HDMI_ARC,
enabled ? 1 : 0, "", "");
AudioDeviceAttributes attributes = new AudioDeviceAttributes(
AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_HDMI_ARC, "", "",
new ArrayList<AudioProfile>(), supportedSads.stream()
.map(sad -> new AudioDescriptor(AudioDescriptor.STANDARD_EDID,
AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE, sad))
.collect(Collectors.toList()));
mService.getAudioManager().setWiredDeviceConnectionState(attributes, enabled ? 1 : 0);
}
/**

View File

@@ -28,6 +28,7 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.Intent;
import android.media.AudioDeviceAttributes;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.BluetoothProfileConnectionInfo;
@@ -186,8 +187,9 @@ public class AudioDeviceBrokerTest {
doNothing().when(mSpySystemServer).broadcastStickyIntentToCurrentProfileGroup(
any(Intent.class));
mSpyDevInventory.setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,
AudioService.CONNECTION_STATE_CONNECTED, address, name, caller);
mSpyDevInventory.setWiredDeviceConnectionState(new AudioDeviceAttributes(
AudioSystem.DEVICE_OUT_WIRED_HEADSET, address, name),
AudioService.CONNECTION_STATE_CONNECTED, caller);
Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS);
// Verify that the sticky intent is broadcasted
@@ -246,11 +248,11 @@ public class AudioDeviceBrokerTest {
*/
private void checkSingleSystemConnection(BluetoothDevice btDevice) throws Exception {
final String expectedName = btDevice.getName() == null ? "" : btDevice.getName();
AudioDeviceAttributes expected = new AudioDeviceAttributes(
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, btDevice.getAddress(), expectedName);
verify(mSpyAudioSystem, times(1)).setDeviceConnectionState(
ArgumentMatchers.eq(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
ArgumentMatchers.argThat(x -> x.equalTypeAddress(expected)),
ArgumentMatchers.eq(AudioSystem.DEVICE_STATE_AVAILABLE),
ArgumentMatchers.eq(btDevice.getAddress()),
ArgumentMatchers.eq(expectedName),
anyInt() /*codec*/);
}
}

View File

@@ -48,11 +48,10 @@ public class NoOpAudioSystemAdapter extends AudioSystemAdapter {
//-----------------------------------------------------------------
// Overrides of AudioSystemAdapter
@Override
public int setDeviceConnectionState(int device, int state, String deviceAddress,
String deviceName, int codecFormat) {
Log.i(TAG, String.format("setDeviceConnectionState(0x%s, %d, %s, %s, 0x%s",
Integer.toHexString(device), state, deviceAddress, deviceName,
Integer.toHexString(codecFormat)));
public int setDeviceConnectionState(AudioDeviceAttributes attributes, int state,
int codecFormat) {
Log.i(TAG, String.format("setDeviceConnectionState(0x%s, %d, 0x%s",
attributes.toString(), state, Integer.toHexString(codecFormat)));
return AudioSystem.AUDIO_STATUS_OK;
}

View File

@@ -62,6 +62,23 @@ import java.util.concurrent.TimeUnit;
public class HdmiCecLocalDeviceTvTest {
private static final int TIMEOUT_MS = HdmiConfig.TIMEOUT_MS + 1;
private static final String[] SADS_NOT_TO_QUERY = new String[]{
HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MPEG1,
HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_AAC,
HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DTS,
HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_ATRAC,
HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_ONEBITAUDIO,
HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DDP,
HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DTSHD,
HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_TRUEHD,
HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DST,
HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_WMAPRO,
HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MAX};
private static final HdmiCecMessage SAD_QUERY =
HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(ADDR_TV, ADDR_AUDIO_SYSTEM,
new int[]{Constants.AUDIO_CODEC_LPCM, Constants.AUDIO_CODEC_DD,
Constants.AUDIO_CODEC_MP3, Constants.AUDIO_CODEC_MPEG2});
private HdmiControlService mHdmiControlService;
private HdmiCecController mHdmiCecController;
private HdmiCecLocalDeviceTv mHdmiCecLocalDeviceTv;
@@ -136,6 +153,10 @@ public class HdmiCecLocalDeviceTvTest {
mNativeWrapper.setPhysicalAddress(mTvPhysicalAddress);
mTestLooper.dispatchAll();
mTvLogicalAddress = mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress();
for (String sad : SADS_NOT_TO_QUERY) {
mHdmiControlService.getHdmiCecConfig().setIntValue(
sad, HdmiControlManager.QUERY_SAD_DISABLED);
}
mNativeWrapper.clearResultMessages();
}
@@ -442,6 +463,7 @@ public class HdmiCecLocalDeviceTvTest {
ADDR_TV,
ADDR_AUDIO_SYSTEM);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(SAD_QUERY);
}
@Test
@@ -463,6 +485,7 @@ public class HdmiCecLocalDeviceTvTest {
ADDR_TV,
ADDR_AUDIO_SYSTEM);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(SAD_QUERY);
}
@Test
@@ -485,6 +508,7 @@ public class HdmiCecLocalDeviceTvTest {
ADDR_TV,
ADDR_AUDIO_SYSTEM);
assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated);
assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
}
@Test

View File

@@ -17,6 +17,7 @@
package com.android.server.usb;
import android.annotation.NonNull;
import android.media.AudioDeviceAttributes;
import android.media.AudioSystem;
import android.media.IAudioService;
import android.os.RemoteException;
@@ -213,24 +214,25 @@ public final class UsbAlsaDevice {
int outputState = (enable && connected) ? 1 : 0;
if (outputState != mOutputState) {
mOutputState = outputState;
mAudioService.setWiredDeviceConnectionState(device, outputState,
alsaCardDeviceString,
mDeviceName, TAG);
AudioDeviceAttributes attributes = new AudioDeviceAttributes(device,
alsaCardDeviceString, mDeviceName);
mAudioService.setWiredDeviceConnectionState(attributes, outputState, TAG);
}
}
// Input Device
if (mHasInput) {
int device = mIsInputHeadset ? AudioSystem.DEVICE_IN_USB_HEADSET
int device = mIsInputHeadset
? AudioSystem.DEVICE_IN_USB_HEADSET
: AudioSystem.DEVICE_IN_USB_DEVICE;
boolean connected = isInputJackConnected();
Slog.i(TAG, "INPUT JACK connected: " + connected);
int inputState = (enable && connected) ? 1 : 0;
if (inputState != mInputState) {
mInputState = inputState;
mAudioService.setWiredDeviceConnectionState(
device, inputState, alsaCardDeviceString,
mDeviceName, TAG);
AudioDeviceAttributes attributes = new AudioDeviceAttributes(device,
alsaCardDeviceString, mDeviceName);
mAudioService.setWiredDeviceConnectionState(attributes, inputState, TAG);
}
}
} catch (RemoteException e) {