Loading core/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -19859,6 +19859,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(); core/jni/android_media_AudioSystem.cpp +107 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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[] = Loading Loading @@ -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", Loading media/java/android/media/AudioManager.java +27 −0 Original line number Diff line number Diff line Loading @@ -7674,6 +7674,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. Loading media/java/android/media/AudioSystem.java +9 −0 Original line number Diff line number Diff line Loading @@ -2115,6 +2115,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 /** Loading Loading
core/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -19859,6 +19859,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();
core/jni/android_media_AudioSystem.cpp +107 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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[] = Loading Loading @@ -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", Loading
media/java/android/media/AudioManager.java +27 −0 Original line number Diff line number Diff line Loading @@ -7674,6 +7674,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. Loading
media/java/android/media/AudioSystem.java +9 −0 Original line number Diff line number Diff line Loading @@ -2115,6 +2115,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 /** Loading