Enhance channel masks conversion between AIDL and SDK

Provide conversion for layouts not listed in
AudioChannelLayout::LAYOUT_* constants. In this case
the conversion is performed on bit-by-bit correspondence
between AudioChannelLayout::CHANNEL_* constants and
SDK channel bits from AudioFormat.

Added missing input channel bits to AudioFormat to match
native. Currently hidden, since we would need to update
docs if we reveal these bits and masks to apps.

Bug: 198812639
Bug: 204362366
Test: atest AidlConversionUnitTests
Change-Id: I7cb80fef2bfe9513f16dc632b22ef81b1e0f0526
This commit is contained in:
Mikhail Naganov
2021-10-29 22:34:26 +00:00
parent 25cd194f41
commit e1f9659e5d
3 changed files with 196 additions and 4 deletions

View File

@@ -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

View File

@@ -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()) {

View File

@@ -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(