diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index 5cdb89838159d..d06bbc61f6ebd 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -675,8 +675,44 @@ public final class AudioFormat implements Parcelable { public static final int CHANNEL_IN_Z_AXIS = 0x2000; public static final int CHANNEL_IN_VOICE_UPLINK = 0x4000; public static final int CHANNEL_IN_VOICE_DNLINK = 0x8000; + // CHANNEL_IN_BACK_LEFT to TOP_RIGHT are not microphone positions + // but surround channels which are used when dealing with multi-channel inputs, + // e.g. via HDMI input on TV. + /** @hide */ + public static final int CHANNEL_IN_BACK_LEFT = 0x10000; + /** @hide */ + public static final int CHANNEL_IN_BACK_RIGHT = 0x20000; + /** @hide */ + public static final int CHANNEL_IN_CENTER = 0x40000; + /** @hide */ + public static final int CHANNEL_IN_LOW_FREQUENCY = 0x100000; + /** @hide */ + public static final int CHANNEL_IN_TOP_LEFT = 0x200000; + /** @hide */ + public static final int CHANNEL_IN_TOP_RIGHT = 0x400000; public static final int CHANNEL_IN_MONO = CHANNEL_IN_FRONT; public static final int CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT); + // Surround channel masks corresponding to output masks, used for + // surround sound inputs. + /** @hide */ + public static final int CHANNEL_IN_2POINT0POINT2 = ( + CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT | CHANNEL_IN_TOP_LEFT | CHANNEL_IN_TOP_RIGHT); + /** @hide */ + public static final int CHANNEL_IN_2POINT1POINT2 = ( + CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT | CHANNEL_IN_TOP_LEFT | CHANNEL_IN_TOP_RIGHT + | CHANNEL_IN_LOW_FREQUENCY); + /** @hide */ + public static final int CHANNEL_IN_3POINT0POINT2 = ( + CHANNEL_IN_LEFT | CHANNEL_IN_CENTER | CHANNEL_IN_RIGHT | CHANNEL_IN_TOP_LEFT + | CHANNEL_IN_TOP_RIGHT); + /** @hide */ + public static final int CHANNEL_IN_3POINT1POINT2 = ( + CHANNEL_IN_LEFT | CHANNEL_IN_CENTER | CHANNEL_IN_RIGHT | CHANNEL_IN_TOP_LEFT + | CHANNEL_IN_TOP_RIGHT | CHANNEL_IN_LOW_FREQUENCY); + /** @hide */ + public static final int CHANNEL_IN_5POINT1 = ( + CHANNEL_IN_LEFT | CHANNEL_IN_CENTER | CHANNEL_IN_RIGHT | CHANNEL_IN_BACK_LEFT + | CHANNEL_IN_BACK_RIGHT | CHANNEL_IN_LOW_FREQUENCY); /** @hide */ public static final int CHANNEL_IN_FRONT_BACK = CHANNEL_IN_FRONT | CHANNEL_IN_BACK; // CHANNEL_IN_ALL is not yet defined; if added then it should match AUDIO_CHANNEL_IN_ALL diff --git a/media/java/android/media/audio/common/AidlConversion.java b/media/java/android/media/audio/common/AidlConversion.java index f96ba8cd7cb58..1053fb717fda9 100644 --- a/media/java/android/media/audio/common/AidlConversion.java +++ b/media/java/android/media/audio/common/AidlConversion.java @@ -131,6 +131,124 @@ public class AidlConversion { /** Convert from legacy audio_usage_t to AIDL AudioUsage. */ public static native int legacy2aidl_audio_usage_t_AudioUsage(int /*audio_usage_t*/ legacy); + /** Convert from a channel bit of AIDL AudioChannelLayout to SDK AudioFormat.CHANNEL_* bit. */ + private static int aidl2api_AudioChannelLayoutBit_AudioFormatChannel( + int aidlBit, boolean isInput) { + if (isInput) { + switch (aidlBit) { + case AudioChannelLayout.CHANNEL_FRONT_LEFT: + return AudioFormat.CHANNEL_IN_LEFT; + case AudioChannelLayout.CHANNEL_FRONT_RIGHT: + return AudioFormat.CHANNEL_IN_RIGHT; + case AudioChannelLayout.CHANNEL_FRONT_CENTER: + return AudioFormat.CHANNEL_IN_CENTER; + case AudioChannelLayout.CHANNEL_BACK_CENTER: + return AudioFormat.CHANNEL_IN_BACK; + // CHANNEL_IN_*_PROCESSED not supported + // CHANNEL_IN_PRESSURE not supported + // CHANNEL_IN_*_AXIS not supported + // CHANNEL_IN_VOICE_* not supported + case AudioChannelLayout.CHANNEL_BACK_LEFT: + return AudioFormat.CHANNEL_IN_BACK_LEFT; + case AudioChannelLayout.CHANNEL_BACK_RIGHT: + return AudioFormat.CHANNEL_IN_BACK_RIGHT; + case AudioChannelLayout.CHANNEL_LOW_FREQUENCY: + return AudioFormat.CHANNEL_IN_LOW_FREQUENCY; + case AudioChannelLayout.CHANNEL_TOP_SIDE_LEFT: + return AudioFormat.CHANNEL_IN_TOP_LEFT; + case AudioChannelLayout.CHANNEL_TOP_SIDE_RIGHT: + return AudioFormat.CHANNEL_IN_TOP_RIGHT; + default: + return AudioFormat.CHANNEL_INVALID; + } + } else { + switch (aidlBit) { + case AudioChannelLayout.CHANNEL_FRONT_LEFT: + return AudioFormat.CHANNEL_OUT_FRONT_LEFT; + case AudioChannelLayout.CHANNEL_FRONT_RIGHT: + return AudioFormat.CHANNEL_OUT_FRONT_RIGHT; + case AudioChannelLayout.CHANNEL_FRONT_CENTER: + return AudioFormat.CHANNEL_OUT_FRONT_CENTER; + case AudioChannelLayout.CHANNEL_LOW_FREQUENCY: + return AudioFormat.CHANNEL_OUT_LOW_FREQUENCY; + case AudioChannelLayout.CHANNEL_BACK_LEFT: + return AudioFormat.CHANNEL_OUT_BACK_LEFT; + case AudioChannelLayout.CHANNEL_BACK_RIGHT: + return AudioFormat.CHANNEL_OUT_BACK_RIGHT; + case AudioChannelLayout.CHANNEL_FRONT_LEFT_OF_CENTER: + return AudioFormat.CHANNEL_OUT_FRONT_LEFT_OF_CENTER; + case AudioChannelLayout.CHANNEL_FRONT_RIGHT_OF_CENTER: + return AudioFormat.CHANNEL_OUT_FRONT_RIGHT_OF_CENTER; + case AudioChannelLayout.CHANNEL_BACK_CENTER: + return AudioFormat.CHANNEL_OUT_BACK_CENTER; + case AudioChannelLayout.CHANNEL_SIDE_LEFT: + return AudioFormat.CHANNEL_OUT_SIDE_LEFT; + case AudioChannelLayout.CHANNEL_SIDE_RIGHT: + return AudioFormat.CHANNEL_OUT_SIDE_RIGHT; + case AudioChannelLayout.CHANNEL_TOP_CENTER: + return AudioFormat.CHANNEL_OUT_TOP_CENTER; + case AudioChannelLayout.CHANNEL_TOP_FRONT_LEFT: + return AudioFormat.CHANNEL_OUT_TOP_FRONT_LEFT; + case AudioChannelLayout.CHANNEL_TOP_FRONT_CENTER: + return AudioFormat.CHANNEL_OUT_TOP_FRONT_CENTER; + case AudioChannelLayout.CHANNEL_TOP_FRONT_RIGHT: + return AudioFormat.CHANNEL_OUT_TOP_FRONT_RIGHT; + case AudioChannelLayout.CHANNEL_TOP_BACK_LEFT: + return AudioFormat.CHANNEL_OUT_TOP_BACK_LEFT; + case AudioChannelLayout.CHANNEL_TOP_BACK_CENTER: + return AudioFormat.CHANNEL_OUT_TOP_BACK_CENTER; + case AudioChannelLayout.CHANNEL_TOP_BACK_RIGHT: + return AudioFormat.CHANNEL_OUT_TOP_BACK_RIGHT; + case AudioChannelLayout.CHANNEL_TOP_SIDE_LEFT: + return AudioFormat.CHANNEL_OUT_TOP_SIDE_LEFT; + case AudioChannelLayout.CHANNEL_TOP_SIDE_RIGHT: + return AudioFormat.CHANNEL_OUT_TOP_SIDE_RIGHT; + case AudioChannelLayout.CHANNEL_BOTTOM_FRONT_LEFT: + return AudioFormat.CHANNEL_OUT_BOTTOM_FRONT_LEFT; + case AudioChannelLayout.CHANNEL_BOTTOM_FRONT_CENTER: + return AudioFormat.CHANNEL_OUT_BOTTOM_FRONT_CENTER; + case AudioChannelLayout.CHANNEL_BOTTOM_FRONT_RIGHT: + return AudioFormat.CHANNEL_OUT_BOTTOM_FRONT_RIGHT; + case AudioChannelLayout.CHANNEL_LOW_FREQUENCY_2: + return AudioFormat.CHANNEL_OUT_LOW_FREQUENCY_2; + case AudioChannelLayout.CHANNEL_FRONT_WIDE_LEFT: + return AudioFormat.CHANNEL_OUT_FRONT_WIDE_LEFT; + case AudioChannelLayout.CHANNEL_FRONT_WIDE_RIGHT: + return AudioFormat.CHANNEL_OUT_FRONT_WIDE_RIGHT; + case AudioChannelLayout.CHANNEL_HAPTIC_A: + return AudioFormat.CHANNEL_OUT_HAPTIC_A; + case AudioChannelLayout.CHANNEL_HAPTIC_B: + return AudioFormat.CHANNEL_OUT_HAPTIC_B; + default: + return AudioFormat.CHANNEL_INVALID; + } + } + } + + /** + * Convert from a channel bitmask of AIDL AudioChannelLayout to + * SDK AudioFormat.CHANNEL_* bitmask. + */ + private static int aidl2api_AudioChannelLayoutBitMask_AudioFormatChannelMask( + int aidlBitMask, boolean isInput) { + int apiMask = 0; + for (int bit = 1 << 31; bit != 0; bit >>>= 1) { + if ((aidlBitMask & bit) == bit) { + int apiBit = aidl2api_AudioChannelLayoutBit_AudioFormatChannel(bit, isInput); + if (apiBit != AudioFormat.CHANNEL_INVALID) { + apiMask |= apiBit; + aidlBitMask &= ~bit; + if (aidlBitMask == 0) { + return apiMask; + } + } else { + break; + } + } + } + return AudioFormat.CHANNEL_INVALID; + } + /** Convert from AIDL AudioChannelLayout to SDK AudioFormat.CHANNEL_*. */ public static int aidl2api_AudioChannelLayout_AudioFormatChannelMask( @NonNull AudioChannelLayout aidlMask, boolean isInput) { @@ -155,8 +273,17 @@ public class AidlConversion { return AudioFormat.CHANNEL_IN_STEREO; case AudioChannelLayout.LAYOUT_FRONT_BACK: return AudioFormat.CHANNEL_IN_FRONT_BACK; - default: - return AudioFormat.CHANNEL_INVALID; + case AudioChannelLayout.LAYOUT_2POINT0POINT2: + return AudioFormat.CHANNEL_IN_2POINT0POINT2; + case AudioChannelLayout.LAYOUT_2POINT1POINT2: + return AudioFormat.CHANNEL_IN_2POINT1POINT2; + case AudioChannelLayout.LAYOUT_3POINT0POINT2: + return AudioFormat.CHANNEL_IN_3POINT0POINT2; + case AudioChannelLayout.LAYOUT_3POINT1POINT2: + return AudioFormat.CHANNEL_IN_3POINT1POINT2; + case AudioChannelLayout.LAYOUT_5POINT1: + return AudioFormat.CHANNEL_IN_5POINT1; + default: // fall through } } else { switch (aidlMask.getLayoutMask()) { @@ -264,10 +391,12 @@ public class AidlConversion { case AudioChannelLayout.LAYOUT_FRONT_BACK: return AudioFormat.CHANNEL_OUT_FRONT_CENTER | AudioFormat.CHANNEL_OUT_BACK_CENTER; - default: - return AudioFormat.CHANNEL_INVALID; + default: // fall through } } + // If a match for a predefined layout wasn't found, make a custom one from bits. + return aidl2api_AudioChannelLayoutBitMask_AudioFormatChannelMask( + aidlMask.getLayoutMask(), isInput); case AudioChannelLayout.voiceMask: if (isInput) { switch (aidlMask.getVoiceMask()) { diff --git a/media/tests/aidltests/src/com/android/media/AidlConversionUnitTests.java b/media/tests/aidltests/src/com/android/media/AidlConversionUnitTests.java index 5f64d2096ee70..414de89f82185 100644 --- a/media/tests/aidltests/src/com/android/media/AidlConversionUnitTests.java +++ b/media/tests/aidltests/src/com/android/media/AidlConversionUnitTests.java @@ -66,6 +66,19 @@ public final class AidlConversionUnitTests { assertEquals(AudioFormat.CHANNEL_OUT_MONO, api); } + @Test + public void testAudioChannelConversionApiOutputMask() { + final AudioChannelLayout aidl = AudioChannelLayout.layoutMask( + AudioChannelLayout.CHANNEL_FRONT_LEFT | AudioChannelLayout.CHANNEL_FRONT_RIGHT + | AudioChannelLayout.CHANNEL_FRONT_WIDE_LEFT + | AudioChannelLayout.CHANNEL_FRONT_WIDE_RIGHT); + final int api = AidlConversion.aidl2api_AudioChannelLayout_AudioFormatChannelMask( + aidl, false /*isInput*/); + assertEquals(AudioFormat.CHANNEL_OUT_FRONT_LEFT | AudioFormat.CHANNEL_OUT_FRONT_RIGHT + | AudioFormat.CHANNEL_OUT_FRONT_WIDE_LEFT + | AudioFormat.CHANNEL_OUT_FRONT_WIDE_RIGHT, api); + } + @Test public void testAudioChannelConversionApiInput() { final AudioChannelLayout aidl = AudioChannelLayout.layoutMask( @@ -75,6 +88,20 @@ public final class AidlConversionUnitTests { assertEquals(AudioFormat.CHANNEL_IN_MONO, api); } + @Test + public void testAudioChannelConversionApiInputMask() { + final AudioChannelLayout aidl = AudioChannelLayout.layoutMask( + AudioChannelLayout.CHANNEL_FRONT_LEFT | AudioChannelLayout.CHANNEL_FRONT_RIGHT + | AudioChannelLayout.CHANNEL_TOP_SIDE_LEFT + | AudioChannelLayout.CHANNEL_TOP_SIDE_RIGHT); + final int api = AidlConversion.aidl2api_AudioChannelLayout_AudioFormatChannelMask( + aidl, true /*isInput*/); + assertEquals(AudioFormat.CHANNEL_IN_LEFT | AudioFormat.CHANNEL_IN_RIGHT + // | AudioFormat.CHANNEL_IN_TOP_LEFT | AudioFormat.CHANNEL_IN_TOP_RIGHT, + | 0x200000 | 0x400000, // TODO: Replace with names when revealed. + api); + } + @Test public void testAudioChannelConversionApiIndex() { final AudioChannelLayout aidl = AudioChannelLayout.indexMask(