Add getDirectProfilesForAttributes
Allows any app to query AudioManager on the available direct AudioProfiles for the specified AudioAttributes. Only the active paths that will be actually used to output sound are returned. go/audio-route-t Bug: 190810951 Test: atest android.media.audio.cts.DirectAudioProfilesForAttributesTest Change-Id: Ia5ce587addadb52725084bd32a6244577626f44d
This commit is contained in:
@@ -21110,6 +21110,7 @@ package android.media {
|
||||
method @Nullable public android.media.AudioDeviceInfo getCommunicationDevice();
|
||||
method public android.media.AudioDeviceInfo[] getDevices(int);
|
||||
method public static int getDirectPlaybackSupport(@NonNull android.media.AudioFormat, @NonNull android.media.AudioAttributes);
|
||||
method @NonNull public java.util.List<android.media.AudioProfile> getDirectProfilesForAttributes(@NonNull android.media.AudioAttributes);
|
||||
method public int getEncodedSurroundMode();
|
||||
method public java.util.List<android.media.MicrophoneInfo> getMicrophones() throws java.io.IOException;
|
||||
method public int getMode();
|
||||
|
||||
@@ -1236,6 +1236,65 @@ static bool isAudioPortArrayCountOutOfBounds(const struct audio_port_v7 *nAudioP
|
||||
return false;
|
||||
}
|
||||
|
||||
static jint convertAudioProfileFromNative(JNIEnv *env, jobject *jAudioProfile,
|
||||
const audio_profile *nAudioProfile, bool useInMask) {
|
||||
size_t numPositionMasks = 0;
|
||||
size_t numIndexMasks = 0;
|
||||
|
||||
// count up how many masks are positional and indexed
|
||||
for (size_t index = 0; index < nAudioProfile->num_channel_masks; index++) {
|
||||
const audio_channel_mask_t mask = nAudioProfile->channel_masks[index];
|
||||
if (audio_channel_mask_get_representation(mask) == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
|
||||
numIndexMasks++;
|
||||
} else {
|
||||
numPositionMasks++;
|
||||
}
|
||||
}
|
||||
|
||||
ScopedLocalRef<jintArray> jSamplingRates(env,
|
||||
env->NewIntArray(nAudioProfile->num_sample_rates));
|
||||
ScopedLocalRef<jintArray> jChannelMasks(env, env->NewIntArray(numPositionMasks));
|
||||
ScopedLocalRef<jintArray> jChannelIndexMasks(env, env->NewIntArray(numIndexMasks));
|
||||
if (!jSamplingRates.get() || !jChannelMasks.get() || !jChannelIndexMasks.get()) {
|
||||
return AUDIO_JAVA_ERROR;
|
||||
}
|
||||
|
||||
if (nAudioProfile->num_sample_rates) {
|
||||
env->SetIntArrayRegion(jSamplingRates.get(), 0 /*start*/, nAudioProfile->num_sample_rates,
|
||||
(jint *)nAudioProfile->sample_rates);
|
||||
}
|
||||
|
||||
// put the masks in the output arrays
|
||||
for (size_t maskIndex = 0, posMaskIndex = 0, indexedMaskIndex = 0;
|
||||
maskIndex < nAudioProfile->num_channel_masks; maskIndex++) {
|
||||
const audio_channel_mask_t mask = nAudioProfile->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);
|
||||
}
|
||||
}
|
||||
|
||||
int encapsulationType;
|
||||
if (audioEncapsulationTypeFromNative(nAudioProfile->encapsulation_type, &encapsulationType) !=
|
||||
NO_ERROR) {
|
||||
ALOGW("Unknown encapsulation type for JAVA API: %u", nAudioProfile->encapsulation_type);
|
||||
}
|
||||
|
||||
*jAudioProfile =
|
||||
env->NewObject(gAudioProfileClass, gAudioProfileCstor,
|
||||
audioFormatFromNative(nAudioProfile->format), jSamplingRates.get(),
|
||||
jChannelMasks.get(), jChannelIndexMasks.get(), encapsulationType);
|
||||
|
||||
if (jAudioProfile == nullptr) {
|
||||
return AUDIO_JAVA_ERROR;
|
||||
}
|
||||
|
||||
return AUDIO_JAVA_SUCCESS;
|
||||
}
|
||||
|
||||
static jint convertAudioPortFromNative(JNIEnv *env, jobject *jAudioPort,
|
||||
const struct audio_port_v7 *nAudioPort) {
|
||||
jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
|
||||
@@ -2814,6 +2873,50 @@ static jint android_media_AudioSystem_getDirectPlaybackSupport(JNIEnv *env, jobj
|
||||
return convertAudioDirectModeFromNative(directMode);
|
||||
}
|
||||
|
||||
static jint android_media_AudioSystem_getDirectProfilesForAttributes(JNIEnv *env, jobject thiz,
|
||||
jobject jAudioAttributes,
|
||||
jobject jAudioProfilesList) {
|
||||
ALOGV("getDirectProfilesForAttributes");
|
||||
|
||||
if (jAudioAttributes == nullptr) {
|
||||
ALOGE("jAudioAttributes is NULL");
|
||||
return (jint)AUDIO_JAVA_BAD_VALUE;
|
||||
}
|
||||
if (jAudioProfilesList == nullptr) {
|
||||
ALOGE("jAudioProfilesList is NULL");
|
||||
return (jint)AUDIO_JAVA_BAD_VALUE;
|
||||
}
|
||||
if (!env->IsInstanceOf(jAudioProfilesList, gArrayListClass)) {
|
||||
ALOGE("jAudioProfilesList not an ArrayList");
|
||||
return (jint)AUDIO_JAVA_BAD_VALUE;
|
||||
}
|
||||
|
||||
JNIAudioAttributeHelper::UniqueAaPtr paa = JNIAudioAttributeHelper::makeUnique();
|
||||
jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jAudioAttributes, paa.get());
|
||||
if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
|
||||
return jStatus;
|
||||
}
|
||||
|
||||
std::vector<audio_profile> audioProfiles;
|
||||
status_t status = AudioSystem::getDirectProfilesForAttributes(paa.get(), &audioProfiles);
|
||||
if (status != NO_ERROR) {
|
||||
ALOGE("AudioSystem::getDirectProfilesForAttributes error %d", status);
|
||||
jStatus = nativeToJavaStatus(status);
|
||||
return jStatus;
|
||||
}
|
||||
|
||||
for (const auto &audioProfile : audioProfiles) {
|
||||
jobject jAudioProfile;
|
||||
jStatus = convertAudioProfileFromNative(env, &jAudioProfile, &audioProfile, false);
|
||||
if (jStatus != AUDIO_JAVA_SUCCESS) {
|
||||
return jStatus;
|
||||
}
|
||||
env->CallBooleanMethod(jAudioProfilesList, gArrayListMethods.add, jAudioProfile);
|
||||
env->DeleteLocalRef(jAudioProfile);
|
||||
}
|
||||
return jStatus;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static const JNINativeMethod gMethods[] =
|
||||
@@ -2960,7 +3063,10 @@ static const JNINativeMethod gMethods[] =
|
||||
(void *)android_media_AudioSystem_canBeSpatialized},
|
||||
{"getDirectPlaybackSupport",
|
||||
"(Landroid/media/AudioFormat;Landroid/media/AudioAttributes;)I",
|
||||
(void *)android_media_AudioSystem_getDirectPlaybackSupport}};
|
||||
(void *)android_media_AudioSystem_getDirectPlaybackSupport},
|
||||
{"getDirectProfilesForAttributes",
|
||||
"(Landroid/media/AudioAttributes;Ljava/util/ArrayList;)I",
|
||||
(void *)android_media_AudioSystem_getDirectProfilesForAttributes}};
|
||||
|
||||
static const JNINativeMethod gEventHandlerMethods[] = {
|
||||
{"native_setup",
|
||||
|
||||
@@ -7670,6 +7670,33 @@ public class AudioManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of direct {@link AudioProfile} that are supported for the specified
|
||||
* {@link AudioAttributes}. This can be empty in case of an error or if no direct playback
|
||||
* is possible.
|
||||
*
|
||||
* <p>Direct playback means that the audio stream is not resampled or downmixed
|
||||
* by the framework. Checking for direct support can help the app select the representation
|
||||
* of audio content that most closely matches the capabilities of the device and peripherals
|
||||
* (e.g. A/V receiver) connected to it. Note that the provided stream can still be re-encoded
|
||||
* or mixed with other streams, if needed.
|
||||
* <p>When using this information to inform your application which audio format to play,
|
||||
* query again whenever audio output devices change (see {@link AudioDeviceCallback}).
|
||||
* @param attributes a non-null {@link AudioAttributes} instance.
|
||||
* @return a list of {@link AudioProfile}
|
||||
*/
|
||||
@NonNull
|
||||
public List<AudioProfile> getDirectProfilesForAttributes(@NonNull AudioAttributes attributes) {
|
||||
Objects.requireNonNull(attributes);
|
||||
ArrayList<AudioProfile> audioProfilesList = new ArrayList<>();
|
||||
int status = AudioSystem.getDirectProfilesForAttributes(attributes, audioProfilesList);
|
||||
if (status != SUCCESS) {
|
||||
Log.w(TAG, "getDirectProfilesForAttributes failed.");
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return audioProfilesList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type provided.
|
||||
|
||||
@@ -2108,6 +2108,15 @@ public class AudioSystem
|
||||
AudioFormat format,
|
||||
AudioDeviceAttributes[] devices);
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* @param attributes audio attributes describing the playback use case
|
||||
* @param audioProfilesList the list of AudioProfiles that can be played as direct output
|
||||
* @return {@link #SUCCESS} if the list of AudioProfiles was successfully created (can be empty)
|
||||
*/
|
||||
public static native int getDirectProfilesForAttributes(@NonNull AudioAttributes attributes,
|
||||
@NonNull ArrayList<AudioProfile> audioProfilesList);
|
||||
|
||||
// Items shared with audio service
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user