Merge "Introduce AudioProfile to describe the capabilities of audio ports."

This commit is contained in:
TreeHugger Robot
2020-12-10 17:17:41 +00:00
committed by Android (Google) Code Review
7 changed files with 270 additions and 141 deletions

View File

@@ -24309,6 +24309,7 @@ package android.media {
public final class AudioDeviceInfo {
method @NonNull public String getAddress();
method @NonNull public java.util.List<android.media.AudioProfile> getAudioProfiles();
method @NonNull public int[] getChannelCounts();
method @NonNull public int[] getChannelIndexMasks();
method @NonNull public int[] getChannelMasks();
@@ -24726,6 +24727,13 @@ package android.media {
method @NonNull public android.media.AudioPresentation.Builder setProgramId(int);
}
public class AudioProfile {
method @NonNull public int[] getChannelIndexMasks();
method @NonNull public int[] getChannelMasks();
method public int getFormat();
method @NonNull public int[] getSampleRates();
}
public class AudioRecord implements android.media.AudioRecordingMonitor android.media.AudioRouting android.media.MicrophoneDirection {
ctor public AudioRecord(int, int, int, int, int) throws java.lang.IllegalArgumentException;
method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);

View File

@@ -48,8 +48,9 @@ static const char* const kClassPathName = "android/media/AudioSystem";
static jclass gArrayListClass;
static struct {
jmethodID add;
jmethodID toArray;
jmethodID cstor;
jmethodID add;
jmethodID toArray;
} gArrayListMethods;
static jclass gBooleanClass;
@@ -185,6 +186,9 @@ jmethodID gMidAudioRecordRoutingProxy_release;
jclass gClsAudioTrackRoutingProxy;
jclass gClsAudioRecordRoutingProxy;
jclass gAudioProfileClass;
jmethodID gAudioProfileCstor;
static Mutex gLock;
enum AudioError {
@@ -807,13 +811,6 @@ android_media_AudioSystem_checkAudioFlinger(JNIEnv *env, jobject clazz)
return (jint) check_AudioSystem_Command(AudioSystem::checkAudioFlinger());
}
static bool useInChannelMask(audio_port_type_t type, audio_port_role_t role)
{
return ((type == AUDIO_PORT_TYPE_DEVICE) && (role == AUDIO_PORT_ROLE_SOURCE)) ||
((type == AUDIO_PORT_TYPE_MIX) && (role == AUDIO_PORT_ROLE_SINK));
}
static void convertAudioGainConfigToNative(JNIEnv *env,
struct audio_gain_config *nAudioGainConfig,
const jobject jAudioGainConfig,
@@ -873,7 +870,7 @@ static jint convertAudioPortConfigToNative(JNIEnv *env,
configMask |= AUDIO_PORT_CONFIG_SAMPLE_RATE;
}
bool useInMask = useInChannelMask(nAudioPortConfig->type, nAudioPortConfig->role);
bool useInMask = audio_port_config_has_input_direction(nAudioPortConfig);
audio_channel_mask_t nMask;
jint jMask = env->GetIntField(jAudioPortConfig,
gAudioPortConfigFields.mChannelMask);
@@ -1000,7 +997,7 @@ static jint convertAudioPortConfigFromNative(JNIEnv *env,
audioportCreated = true;
}
bool useInMask = useInChannelMask(nAudioPortConfig->type, nAudioPortConfig->role);
bool useInMask = audio_port_config_has_input_direction(nAudioPortConfig);
audio_channel_mask_t nMask;
jint jMask;
@@ -1137,15 +1134,6 @@ exit:
return jStatus;
}
static bool hasFormat(int* formats, size_t size, int format) {
for (size_t index = 0; index < size; index++) {
if (formats[index] == format) {
return true; // found
}
}
return false; // not found
}
// TODO: pull out to separate file
template <typename T, size_t N>
static constexpr size_t array_size(const T (&)[N]) {
@@ -1167,43 +1155,46 @@ static jintArray convertEncapsulationInfoFromNative(JNIEnv *env, uint32_t encaps
return result;
}
static jint convertAudioPortFromNative(JNIEnv *env,
jobject *jAudioPort, const struct audio_port *nAudioPort)
{
static bool isAudioPortArrayCountOutOfBounds(const struct audio_port_v7 *nAudioPort,
std::stringstream &ss) {
ss << " num_audio_profiles " << nAudioPort->num_audio_profiles << " num_gains "
<< nAudioPort->num_gains;
if (nAudioPort->num_audio_profiles > array_size(nAudioPort->audio_profiles) ||
nAudioPort->num_gains > array_size(nAudioPort->gains)) {
return true;
}
for (size_t i = 0; i < nAudioPort->num_audio_profiles; ++i) {
ss << " (" << i << ") audio profile,"
<< " num_sample_rates " << nAudioPort->audio_profiles[i].num_sample_rates
<< " num_channel_masks " << nAudioPort->audio_profiles[i].num_channel_masks;
if (nAudioPort->audio_profiles[i].num_sample_rates >
array_size(nAudioPort->audio_profiles[i].sample_rates) ||
nAudioPort->audio_profiles[i].num_channel_masks >
array_size(nAudioPort->audio_profiles[i].channel_masks)) {
return true;
}
}
return false;
}
static jint convertAudioPortFromNative(JNIEnv *env, jobject *jAudioPort,
const struct audio_port_v7 *nAudioPort) {
jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
jintArray jSamplingRates = NULL;
jintArray jChannelMasks = NULL;
jintArray jChannelIndexMasks = NULL;
jintArray jEncapsulationModes = NULL;
jintArray jEncapsulationMetadataTypes = NULL;
int* cFormats = NULL;
jintArray jFormats = NULL;
jobjectArray jGains = NULL;
jobject jHandle = NULL;
jobject jAudioPortConfig = NULL;
jstring jDeviceName = NULL;
jobject jAudioProfiles = NULL;
bool useInMask;
size_t numPositionMasks = 0;
size_t numIndexMasks = 0;
size_t numUniqueFormats = 0;
ALOGV("convertAudioPortFromNative id %d role %d type %d name %s",
nAudioPort->id, nAudioPort->role, nAudioPort->type, nAudioPort->name);
// Verify audio port array count info.
if (nAudioPort->num_sample_rates > array_size(nAudioPort->sample_rates)
|| nAudioPort->num_channel_masks > array_size(nAudioPort->channel_masks)
|| nAudioPort->num_formats > array_size(nAudioPort->formats)
|| nAudioPort->num_gains > array_size(nAudioPort->gains)) {
std::stringstream ss;
ss << "convertAudioPortFromNative array count out of bounds:"
<< " num_sample_rates " << nAudioPort->num_sample_rates
<< " num_channel_masks " << nAudioPort->num_channel_masks
<< " num_formats " << nAudioPort->num_formats
<< " num_gains " << nAudioPort->num_gains
;
std::string s = ss.str();
if (std::stringstream ss; isAudioPortArrayCountOutOfBounds(nAudioPort, ss)) {
std::string s = "convertAudioPortFromNative array count out of bounds:" + ss.str();
// Prefer to log through Java wtf instead of native ALOGE.
ScopedLocalRef<jclass> jLogClass(env, env->FindClass("android/util/Log"));
@@ -1222,69 +1213,68 @@ static jint convertAudioPortFromNative(JNIEnv *env,
goto exit;
}
jSamplingRates = env->NewIntArray(nAudioPort->num_sample_rates);
if (jSamplingRates == NULL) {
useInMask = audio_has_input_direction(nAudioPort->type, nAudioPort->role);
jAudioProfiles = env->NewObject(gArrayListClass, gArrayListMethods.cstor);
if (jAudioProfiles == nullptr) {
jStatus = (jint)AUDIO_JAVA_ERROR;
goto exit;
}
if (nAudioPort->num_sample_rates) {
env->SetIntArrayRegion(jSamplingRates, 0, nAudioPort->num_sample_rates,
(jint *)nAudioPort->sample_rates);
}
// count up how many masks are positional and indexed
for(size_t index = 0; index < nAudioPort->num_channel_masks; index++) {
const audio_channel_mask_t mask = nAudioPort->channel_masks[index];
if (audio_channel_mask_get_representation(mask) == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
numIndexMasks++;
} else {
numPositionMasks++;
}
}
jChannelMasks = env->NewIntArray(numPositionMasks);
if (jChannelMasks == NULL) {
jStatus = (jint)AUDIO_JAVA_ERROR;
goto exit;
}
jChannelIndexMasks = env->NewIntArray(numIndexMasks);
if (jChannelIndexMasks == NULL) {
jStatus = (jint)AUDIO_JAVA_ERROR;
goto exit;
}
useInMask = useInChannelMask(nAudioPort->type, nAudioPort->role);
// put the masks in the output arrays
for (size_t maskIndex = 0, posMaskIndex = 0, indexedMaskIndex = 0;
maskIndex < nAudioPort->num_channel_masks; maskIndex++) {
const audio_channel_mask_t mask = nAudioPort->channel_masks[maskIndex];
if (audio_channel_mask_get_representation(mask) == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
jint jMask = audio_channel_mask_get_bits(mask);
env->SetIntArrayRegion(jChannelIndexMasks, indexedMaskIndex++, 1, &jMask);
} else {
jint jMask = useInMask ? inChannelMaskFromNative(mask)
: outChannelMaskFromNative(mask);
env->SetIntArrayRegion(jChannelMasks, posMaskIndex++, 1, &jMask);
}
}
// formats
if (nAudioPort->num_formats != 0) {
cFormats = new int[nAudioPort->num_formats];
for (size_t index = 0; index < nAudioPort->num_formats; index++) {
int format = audioFormatFromNative(nAudioPort->formats[index]);
if (!hasFormat(cFormats, numUniqueFormats, format)) {
cFormats[numUniqueFormats++] = format;
for (size_t i = 0; i < nAudioPort->num_audio_profiles; ++i) {
size_t numPositionMasks = 0;
size_t numIndexMasks = 0;
// count up how many masks are positional and indexed
for (size_t index = 0; index < nAudioPort->audio_profiles[i].num_channel_masks; index++) {
const audio_channel_mask_t mask = nAudioPort->audio_profiles[i].channel_masks[index];
if (audio_channel_mask_get_representation(mask) == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
numIndexMasks++;
} else {
numPositionMasks++;
}
}
}
jFormats = env->NewIntArray(numUniqueFormats);
if (jFormats == NULL) {
jStatus = (jint)AUDIO_JAVA_ERROR;
goto exit;
}
if (numUniqueFormats != 0) {
env->SetIntArrayRegion(jFormats, 0, numUniqueFormats, cFormats);
ScopedLocalRef<jintArray> jSamplingRates(env,
env->NewIntArray(nAudioPort->audio_profiles[i]
.num_sample_rates));
ScopedLocalRef<jintArray> jChannelMasks(env, env->NewIntArray(numPositionMasks));
ScopedLocalRef<jintArray> jChannelIndexMasks(env, env->NewIntArray(numIndexMasks));
if (!jSamplingRates.get() || !jChannelMasks.get() || !jChannelIndexMasks.get()) {
jStatus = (jint)AUDIO_JAVA_ERROR;
goto exit;
}
if (nAudioPort->audio_profiles[i].num_sample_rates) {
env->SetIntArrayRegion(jSamplingRates.get(), 0 /*start*/,
nAudioPort->audio_profiles[i].num_sample_rates,
(jint *)nAudioPort->audio_profiles[i].sample_rates);
}
// put the masks in the output arrays
for (size_t maskIndex = 0, posMaskIndex = 0, indexedMaskIndex = 0;
maskIndex < nAudioPort->audio_profiles[i].num_channel_masks; maskIndex++) {
const audio_channel_mask_t mask =
nAudioPort->audio_profiles[i].channel_masks[maskIndex];
if (audio_channel_mask_get_representation(mask) == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
jint jMask = audio_channel_mask_get_bits(mask);
env->SetIntArrayRegion(jChannelIndexMasks.get(), indexedMaskIndex++, 1, &jMask);
} else {
jint jMask =
useInMask ? inChannelMaskFromNative(mask) : outChannelMaskFromNative(mask);
env->SetIntArrayRegion(jChannelMasks.get(), posMaskIndex++, 1, &jMask);
}
}
ScopedLocalRef<jobject>
jAudioProfile(env,
env->NewObject(gAudioProfileClass, gAudioProfileCstor,
audioFormatFromNative(
nAudioPort->audio_profiles[i].format),
jSamplingRates.get(), jChannelMasks.get(),
jChannelIndexMasks.get()));
if (jAudioProfile == nullptr) {
jStatus = (jint)AUDIO_JAVA_ERROR;
goto exit;
}
env->CallBooleanMethod(jAudioProfiles, gArrayListMethods.add, jAudioProfile.get());
}
// gains
@@ -1342,18 +1332,16 @@ static jint convertAudioPortFromNative(JNIEnv *env,
convertEncapsulationInfoFromNative(env,
nAudioPort->ext.device
.encapsulation_metadata_types);
*jAudioPort = env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor, jHandle,
jDeviceName, jSamplingRates, jChannelMasks, jChannelIndexMasks,
jFormats, jGains, nAudioPort->ext.device.type, jAddress,
jEncapsulationModes, jEncapsulationMetadataTypes);
*jAudioPort =
env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor, jHandle, jDeviceName,
jAudioProfiles, jGains, nAudioPort->ext.device.type, jAddress,
jEncapsulationModes, jEncapsulationMetadataTypes);
env->DeleteLocalRef(jAddress);
} else if (nAudioPort->type == AUDIO_PORT_TYPE_MIX) {
ALOGV("convertAudioPortFromNative is a mix");
*jAudioPort = env->NewObject(gAudioMixPortClass, gAudioMixPortCstor,
jHandle, nAudioPort->ext.mix.handle,
nAudioPort->role, jDeviceName,
jSamplingRates, jChannelMasks, jChannelIndexMasks,
jFormats, jGains);
*jAudioPort = env->NewObject(gAudioMixPortClass, gAudioMixPortCstor, jHandle,
nAudioPort->ext.mix.handle, nAudioPort->role, jDeviceName,
jAudioProfiles, jGains);
} else {
ALOGE("convertAudioPortFromNative unknown nAudioPort type %d", nAudioPort->type);
jStatus = (jint)AUDIO_JAVA_ERROR;
@@ -1378,26 +1366,14 @@ exit:
if (jDeviceName != NULL) {
env->DeleteLocalRef(jDeviceName);
}
if (jSamplingRates != NULL) {
env->DeleteLocalRef(jSamplingRates);
}
if (jChannelMasks != NULL) {
env->DeleteLocalRef(jChannelMasks);
}
if (jChannelIndexMasks != NULL) {
env->DeleteLocalRef(jChannelIndexMasks);
}
if (jEncapsulationModes != NULL) {
env->DeleteLocalRef(jEncapsulationModes);
}
if (jEncapsulationMetadataTypes != NULL) {
env->DeleteLocalRef(jEncapsulationMetadataTypes);
}
if (cFormats != NULL) {
delete[] cFormats;
}
if (jFormats != NULL) {
env->DeleteLocalRef(jFormats);
if (jAudioProfiles != NULL) {
env->DeleteLocalRef(jAudioProfiles);
}
if (jGains != NULL) {
env->DeleteLocalRef(jGains);
@@ -1436,7 +1412,7 @@ android_media_AudioSystem_listAudioPorts(JNIEnv *env, jobject clazz,
unsigned int generation;
unsigned int numPorts;
jint *nGeneration;
struct audio_port *nPorts = NULL;
struct audio_port_v7 *nPorts = nullptr;
int attempts = MAX_PORT_GENERATION_SYNC_ATTEMPTS;
jint jStatus;
@@ -1448,11 +1424,8 @@ android_media_AudioSystem_listAudioPorts(JNIEnv *env, jobject clazz,
}
numPorts = 0;
status = AudioSystem::listAudioPorts(AUDIO_PORT_ROLE_NONE,
AUDIO_PORT_TYPE_NONE,
&numPorts,
NULL,
&generation1);
status = AudioSystem::listAudioPorts(AUDIO_PORT_ROLE_NONE, AUDIO_PORT_TYPE_NONE, &numPorts,
nullptr, &generation1);
if (status != NO_ERROR) {
ALOGE_IF(status != NO_ERROR, "AudioSystem::listAudioPorts error %d", status);
break;
@@ -1461,13 +1434,10 @@ android_media_AudioSystem_listAudioPorts(JNIEnv *env, jobject clazz,
jStatus = (jint)AUDIO_JAVA_SUCCESS;
goto exit;
}
nPorts = (struct audio_port *)realloc(nPorts, numPorts * sizeof(struct audio_port));
nPorts = (struct audio_port_v7 *)realloc(nPorts, numPorts * sizeof(struct audio_port_v7));
status = AudioSystem::listAudioPorts(AUDIO_PORT_ROLE_NONE,
AUDIO_PORT_TYPE_NONE,
&numPorts,
nPorts,
&generation);
status = AudioSystem::listAudioPorts(AUDIO_PORT_ROLE_NONE, AUDIO_PORT_TYPE_NONE, &numPorts,
nPorts, &generation);
ALOGV("listAudioPorts AudioSystem::listAudioPorts numPorts %d generation %d generation1 %d",
numPorts, generation, generation1);
} while (generation1 != generation && status == NO_ERROR);
@@ -2671,6 +2641,7 @@ int register_android_media_AudioSystem(JNIEnv *env)
jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass);
gArrayListMethods.cstor = GetMethodIDOrDie(env, arrayListClass, "<init>", "()V");
gArrayListMethods.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
gArrayListMethods.toArray = GetMethodIDOrDie(env, arrayListClass, "toArray", "()[Ljava/lang/Object;");
@@ -2733,7 +2704,7 @@ int register_android_media_AudioSystem(JNIEnv *env)
gAudioDevicePortClass = MakeGlobalRefOrDie(env, audioDevicePortClass);
gAudioDevicePortCstor =
GetMethodIDOrDie(env, audioDevicePortClass, "<init>",
"(Landroid/media/AudioHandle;Ljava/lang/String;[I[I[I[I"
"(Landroid/media/AudioHandle;Ljava/lang/String;Ljava/util/List;"
"[Landroid/media/AudioGain;ILjava/lang/String;[I[I)V");
// When access AudioPort as AudioDevicePort
@@ -2743,8 +2714,10 @@ int register_android_media_AudioSystem(JNIEnv *env)
jclass audioMixPortClass = FindClassOrDie(env, "android/media/AudioMixPort");
gAudioMixPortClass = MakeGlobalRefOrDie(env, audioMixPortClass);
gAudioMixPortCstor = GetMethodIDOrDie(env, audioMixPortClass, "<init>",
"(Landroid/media/AudioHandle;IILjava/lang/String;[I[I[I[I[Landroid/media/AudioGain;)V");
gAudioMixPortCstor =
GetMethodIDOrDie(env, audioMixPortClass, "<init>",
"(Landroid/media/AudioHandle;IILjava/lang/String;Ljava/util/List;"
"[Landroid/media/AudioGain;)V");
jclass audioGainClass = FindClassOrDie(env, "android/media/AudioGain");
gAudioGainClass = MakeGlobalRefOrDie(env, audioGainClass);
@@ -2846,6 +2819,10 @@ int register_android_media_AudioSystem(JNIEnv *env)
jclass listClass = FindClassOrDie(env, "java/util/List");
gListMethods.add = GetMethodIDOrDie(env, listClass, "add", "(Ljava/lang/Object;)Z");
jclass audioProfileClass = FindClassOrDie(env, "android/media/AudioProfile");
gAudioProfileClass = MakeGlobalRefOrDie(env, audioProfileClass);
gAudioProfileCstor = GetMethodIDOrDie(env, audioProfileClass, "<init>", "(I[I[I[I)V");
AudioSystem::addErrorCallback(android_media_AudioSystem_error_callback);
RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));

View File

@@ -23,6 +23,7 @@ import android.util.SparseIntArray;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.TreeSet;
@@ -497,6 +498,13 @@ public final class AudioDeviceInfo {
return encodings;
}
/**
* @return A list of {@link AudioProfile} supported by the audio devices.
*/
public @NonNull List<AudioProfile> getAudioProfiles() {
return mPort.profiles();
}
/**
* Returns an array of supported encapsulation modes for the device.
*

View File

@@ -21,6 +21,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import java.util.Arrays;
import java.util.List;
/**
* The AudioDevicePort is a specialized type of AudioPort
@@ -57,6 +58,18 @@ public class AudioDevicePort extends AudioPort {
mEncapsulationMetadataTypes = encapsulationMetadataTypes;
}
AudioDevicePort(AudioHandle handle, String deviceName, List<AudioProfile> profiles,
AudioGain[] gains, int type, String address, int[] encapsulationModes,
@AudioTrack.EncapsulationMetadataType int[] encapsulationMetadataTypes) {
super(handle,
AudioManager.isInputDevice(type) ? AudioPort.ROLE_SOURCE : AudioPort.ROLE_SINK,
deviceName, profiles, gains);
mType = type;
mAddress = address;
mEncapsulationModes = encapsulationModes;
mEncapsulationMetadataTypes = encapsulationMetadataTypes;
}
/**
* Get the device type (e.g AudioManager.DEVICE_OUT_SPEAKER)
*/

View File

@@ -19,6 +19,8 @@ package android.media;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import java.util.List;
/**
* The AudioMixPort is a specialized type of AudioPort
* describing an audio mix or stream at an input or output stream of the audio
@@ -42,6 +44,12 @@ public class AudioMixPort extends AudioPort {
mIoHandle = ioHandle;
}
AudioMixPort(AudioHandle handle, int ioHandle, int role, String deviceName,
List<AudioProfile> profiles, AudioGain[] gains) {
super(handle, role, deviceName, profiles, gains);
mIoHandle = ioHandle;
}
/**
* Build a specific configuration of this audio mix port for use by methods
* like AudioManager.connectAudioPatch().

View File

@@ -19,6 +19,13 @@ package android.media;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* An audio port is a node of the audio framework or hardware that can be connected to or
* disconnect from another audio node to create a specific audio routing configuration.
@@ -78,6 +85,7 @@ public class AudioPort {
private final int[] mChannelMasks;
private final int[] mChannelIndexMasks;
private final int[] mFormats;
private final List<AudioProfile> mProfiles;
@UnsupportedAppUsage
private final AudioGain[] mGains;
@UnsupportedAppUsage
@@ -87,7 +95,6 @@ public class AudioPort {
AudioPort(AudioHandle handle, int role, String name,
int[] samplingRates, int[] channelMasks, int[] channelIndexMasks,
int[] formats, AudioGain[] gains) {
mHandle = handle;
mRole = role;
mName = name;
@@ -96,6 +103,39 @@ public class AudioPort {
mChannelIndexMasks = channelIndexMasks;
mFormats = formats;
mGains = gains;
mProfiles = new ArrayList<>();
if (mFormats != null) {
for (int format : mFormats) {
mProfiles.add(new AudioProfile(
format, samplingRates, channelMasks, channelIndexMasks));
}
}
}
AudioPort(AudioHandle handle, int role, String name,
List<AudioProfile> profiles, AudioGain[] gains) {
mHandle = handle;
mRole = role;
mName = name;
mProfiles = profiles;
mGains = gains;
Set<Integer> formats = new HashSet<>();
Set<Integer> samplingRates = new HashSet<>();
Set<Integer> channelMasks = new HashSet<>();
Set<Integer> channelIndexMasks = new HashSet<>();
for (AudioProfile profile : profiles) {
formats.add(profile.getFormat());
samplingRates.addAll(Arrays.stream(profile.getSampleRates()).boxed()
.collect(Collectors.toList()));
channelMasks.addAll(Arrays.stream(profile.getChannelMasks()).boxed()
.collect(Collectors.toList()));
channelIndexMasks.addAll(Arrays.stream(profile.getChannelIndexMasks()).boxed()
.collect(Collectors.toList()));
}
mSamplingRates = samplingRates.stream().mapToInt(Number::intValue).toArray();
mChannelMasks = channelMasks.stream().mapToInt(Number::intValue).toArray();
mChannelIndexMasks = channelIndexMasks.stream().mapToInt(Number::intValue).toArray();
mFormats = formats.stream().mapToInt(Number::intValue).toArray();
}
AudioHandle handle() {
@@ -162,6 +202,13 @@ public class AudioPort {
return mFormats;
}
/**
* Get the list of supported audio profiles
*/
public List<AudioProfile> profiles() {
return mProfiles;
}
/**
* Get the list of gain descriptors
* Empty array if this port does not have gain control

View File

@@ -0,0 +1,68 @@
/*
* Copyright (C) 2020 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.media;
import android.annotation.NonNull;
/**
* AudioProfile is a class used by {@link AudioDeviceInfo} to list the audio formats, sampling rates
* and channel masks supported.
* Each AudioProfile is specific to an audio format and lists all sampling rates and channel masks
* supported for this format.
*/
public class AudioProfile {
private final int mFormat;
private final int[] mSamplingRates;
private final int[] mChannelMasks;
private final int[] mChannelIndexMasks;
AudioProfile(int format, @NonNull int[] samplingRates, @NonNull int[] channelMasks,
@NonNull int[] channelIndexMasks) {
mFormat = format;
mSamplingRates = samplingRates;
mChannelMasks = channelMasks;
mChannelIndexMasks = channelIndexMasks;
}
/**
* @return the encoding format for this AudioProfile.
*/
public @AudioFormat.Encoding int getFormat() {
return mFormat;
}
/**
* @return an array of channel position masks that are associated with the encoding format.
*/
public @NonNull int[] getChannelMasks() {
return mChannelMasks;
}
/**
* @return an array of channel index masks that are associated with the encoding format.
*/
public @NonNull int[] getChannelIndexMasks() {
return mChannelIndexMasks;
}
/**
* @return an array of sample rates that are associated with the encoding format.
*/
public @NonNull int[] getSampleRates() {
return mSamplingRates;
}
}