Update AudioChannelLayout to address some issues
Changes made:
- haptic channels moved to the MSB part of the integer;
- "voice up/down link" channel moved into their own
union variant.
Bug: 188932434
Bug: 193562113
Bug: 193563345
Test: atest audio_aidl_conversion_tests
Change-Id: Idedab7142fe05ecfcbcc57c8a359a9d541395c96
diff --git a/media/libaudioclient/AidlConversion.cpp b/media/libaudioclient/AidlConversion.cpp
index 298e596..bb67b53 100644
--- a/media/libaudioclient/AidlConversion.cpp
+++ b/media/libaudioclient/AidlConversion.cpp
@@ -475,10 +475,7 @@
DEFINE_INPUT_LAYOUT(2POINT1POINT2),
DEFINE_INPUT_LAYOUT(3POINT0POINT2),
DEFINE_INPUT_LAYOUT(3POINT1POINT2),
- DEFINE_INPUT_LAYOUT(5POINT1),
- DEFINE_INPUT_LAYOUT(VOICE_UPLINK_MONO),
- DEFINE_INPUT_LAYOUT(VOICE_DNLINK_MONO),
- DEFINE_INPUT_LAYOUT(VOICE_CALL_MONO)
+ DEFINE_INPUT_LAYOUT(5POINT1)
#undef DEFINE_INPUT_LAYOUT
};
return pairs;
@@ -527,6 +524,22 @@
return pairs;
}
+const detail::AudioChannelPairs& getVoiceAudioChannelPairs() {
+ static const detail::AudioChannelPairs pairs = {
+#define DEFINE_VOICE_LAYOUT(n) \
+ { \
+ AUDIO_CHANNEL_IN_VOICE_##n, \
+ media::AudioChannelLayout::make<media::AudioChannelLayout::Tag::voiceMask>( \
+ media::AudioChannelLayout::VOICE_##n) \
+ }
+ DEFINE_VOICE_LAYOUT(UPLINK_MONO),
+ DEFINE_VOICE_LAYOUT(DNLINK_MONO),
+ DEFINE_VOICE_LAYOUT(CALL_MONO)
+#undef DEFINE_VOICE_LAYOUT
+ };
+ return pairs;
+}
+
media::AudioDeviceDescription make_AudioDeviceDescription(media::AudioDeviceType type,
const std::string& connection = "") {
media::AudioDeviceDescription result;
@@ -1080,6 +1093,17 @@
}
template<typename S, typename T>
+std::unordered_map<S, T> make_DirectMap(
+ const std::vector<std::pair<S, T>>& v1, const std::vector<std::pair<S, T>>& v2) {
+ std::unordered_map<S, T> result(v1.begin(), v1.end());
+ LOG_ALWAYS_FATAL_IF(result.size() != v1.size(), "Duplicate key elements detected in v1");
+ result.insert(v2.begin(), v2.end());
+ LOG_ALWAYS_FATAL_IF(result.size() != v1.size() + v2.size(),
+ "Duplicate key elements detected in v1+v2");
+ return result;
+}
+
+template<typename S, typename T>
std::unordered_map<T, S> make_ReverseMap(const std::vector<std::pair<S, T>>& v) {
std::unordered_map<T, S> result;
std::transform(v.begin(), v.end(), std::inserter(result, result.begin()),
@@ -1099,6 +1123,7 @@
static const ReverseMap mIdx = make_ReverseMap(getIndexAudioChannelPairs());
static const ReverseMap mIn = make_ReverseMap(getInAudioChannelPairs());
static const ReverseMap mOut = make_ReverseMap(getOutAudioChannelPairs());
+ static const ReverseMap mVoice = make_ReverseMap(getVoiceAudioChannelPairs());
auto convert = [](const media::AudioChannelLayout& aidl, const ReverseMap& m,
const char* func, const char* type) -> ConversionResult<audio_channel_mask_t> {
@@ -1120,6 +1145,8 @@
return convert(aidl, mIdx, __func__, "index");
case Tag::layoutMask:
return convert(aidl, isOutput ? mOut : mIn, __func__, isOutput ? "output" : "input");
+ case Tag::voiceMask:
+ return convert(aidl, mVoice, __func__, "voice");
}
ALOGE("%s: unexpected tag value %d", __func__, aidl.getTag());
return unexpected(BAD_VALUE);
@@ -1130,7 +1157,8 @@
using DirectMap = std::unordered_map<audio_channel_mask_t, media::AudioChannelLayout>;
using Tag = media::AudioChannelLayout::Tag;
static const DirectMap mIdx = make_DirectMap(getIndexAudioChannelPairs());
- static const DirectMap mIn = make_DirectMap(getInAudioChannelPairs());
+ static const DirectMap mInAndVoice = make_DirectMap(
+ getInAudioChannelPairs(), getVoiceAudioChannelPairs());
static const DirectMap mOut = make_DirectMap(getOutAudioChannelPairs());
auto convert = [](const audio_channel_mask_t legacy, const DirectMap& m,
@@ -1154,7 +1182,8 @@
if (repr == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
return convert(legacy, mIdx, __func__, "index");
} else if (repr == AUDIO_CHANNEL_REPRESENTATION_POSITION) {
- return convert(legacy, isOutput ? mOut : mIn, __func__, isOutput ? "output" : "input");
+ return convert(legacy, isOutput ? mOut : mInAndVoice, __func__,
+ isOutput ? "output" : "input / voice");
}
ALOGE("%s: unknown representation %d in audio_channel_mask_t value 0x%x",
diff --git a/media/libaudioclient/aidl/android/media/AudioChannelLayout.aidl b/media/libaudioclient/aidl/android/media/AudioChannelLayout.aidl
index 9b6d59f..fdc8184 100644
--- a/media/libaudioclient/aidl/android/media/AudioChannelLayout.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioChannelLayout.aidl
@@ -33,6 +33,10 @@
* number of channels in the audio frame. A channel mask per se only defines the
* presence or absence of a channel, not the order. Please see 'INTERLEAVE_*'
* constants for the platform convention of order.
+ *
+ * The structure also defines a "voice mask" which is a special case of
+ * layout mask, intended for processing voice audio from telecommunication
+ * use cases.
*/
union AudioChannelLayout {
/**
@@ -59,6 +63,12 @@
* must have at least one bit set.
*/
int layoutMask;
+ /**
+ * This variant is used for processing of voice audio input and output.
+ * It is recommended to use one of 'VOICE_*' values. The 'voiceMask' field
+ * must have at least one bit set.
+ */
+ int voiceMask;
/**
* 'INDEX_MASK_' constants define how many channels are used.
@@ -183,12 +193,6 @@
LAYOUT_STEREO | LAYOUT_HAPTIC_AB;
const int LAYOUT_FRONT_BACK =
CHANNEL_FRONT_CENTER | CHANNEL_BACK_CENTER;
- const int LAYOUT_VOICE_UPLINK_MONO =
- LAYOUT_MONO | CHANNEL_VOICE_UPLINK;
- const int LAYOUT_VOICE_DNLINK_MONO =
- LAYOUT_MONO | CHANNEL_VOICE_DNLINK;
- const int LAYOUT_VOICE_CALL_MONO =
- CHANNEL_VOICE_UPLINK | CHANNEL_VOICE_DNLINK;
/**
* Expresses the convention when stereo audio samples are stored interleaved
@@ -204,8 +208,10 @@
const int INTERLEAVE_RIGHT = 1;
/**
- * 'CHANNEL_*' constants are used to build 'LAYOUT_*' masks.
- * Each constant must have exactly one bit set.
+ * 'CHANNEL_*' constants are used to build 'LAYOUT_*' masks. Each constant
+ * must have exactly one bit set. The values do not match
+ * 'android.media.AudioFormat.CHANNEL_OUT_*' constants from the SDK
+ * for better efficiency in masks processing.
*/
const int CHANNEL_FRONT_LEFT = 1 << 0;
const int CHANNEL_FRONT_RIGHT = 1 << 1;
@@ -233,8 +239,30 @@
const int CHANNEL_LOW_FREQUENCY_2 = 1 << 23;
const int CHANNEL_FRONT_WIDE_LEFT = 1 << 24;
const int CHANNEL_FRONT_WIDE_RIGHT = 1 << 25;
- const int CHANNEL_VOICE_UPLINK = 1 << 26;
- const int CHANNEL_VOICE_DNLINK = 1 << 27;
- const int CHANNEL_HAPTIC_B = 1 << 28; // B then A to match legacy const.
- const int CHANNEL_HAPTIC_A = 1 << 29;
+ /**
+ * Haptic channels are not part of multichannel standards, however they
+ * enhance user experience when playing so they are packed together with the
+ * channels of the program. To avoid collision with positional channels the
+ * values for haptic channels start at the MSB of an integer (after the sign
+ * bit) and move down to LSB.
+ */
+ const int CHANNEL_HAPTIC_B = 1 << 29;
+ const int CHANNEL_HAPTIC_A = 1 << 30;
+
+ /**
+ * 'VOICE_*' constants define layouts for voice audio. The order of the
+ * channels in the frame is assumed to be from the LSB to MSB for all the
+ * bits set to '1'.
+ */
+ const int VOICE_UPLINK_MONO = CHANNEL_VOICE_UPLINK;
+ const int VOICE_DNLINK_MONO = CHANNEL_VOICE_DNLINK;
+ const int VOICE_CALL_MONO = CHANNEL_VOICE_UPLINK | CHANNEL_VOICE_DNLINK;
+
+ /**
+ * 'CHANNEL_VOICE_*' constants are used to build 'VOICE_*' masks. Each
+ * constant must have exactly one bit set. Use the same values as
+ * 'android.media.AudioFormat.CHANNEL_IN_VOICE_*' constants from the SDK.
+ */
+ const int CHANNEL_VOICE_UPLINK = 0x4000;
+ const int CHANNEL_VOICE_DNLINK = 0x8000;
}
diff --git a/media/libaudioclient/include/media/AudioCommonTypes.h b/media/libaudioclient/include/media/AudioCommonTypes.h
index 2a46e05..a368e74 100644
--- a/media/libaudioclient/include/media/AudioCommonTypes.h
+++ b/media/libaudioclient/include/media/AudioCommonTypes.h
@@ -56,6 +56,8 @@
return hash_combine(seed, std::hash<int32_t>{}(acl.get<Tag::indexMask>()));
case Tag::layoutMask:
return hash_combine(seed, std::hash<int32_t>{}(acl.get<Tag::layoutMask>()));
+ case Tag::voiceMask:
+ return hash_combine(seed, std::hash<int32_t>{}(acl.get<Tag::voiceMask>()));
}
return seed;
}
diff --git a/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp b/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
index e549354..b6e597d 100644
--- a/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
+++ b/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
@@ -46,6 +46,11 @@
media::AudioChannelLayout::INDEX_MASK_2);
}
+media::AudioChannelLayout make_ACL_VoiceCall() {
+ return media::AudioChannelLayout::make<media::AudioChannelLayout::Tag::voiceMask>(
+ media::AudioChannelLayout::VOICE_CALL_MONO);
+}
+
media::AudioDeviceDescription make_AudioDeviceDescription(media::AudioDeviceType type,
const std::string& connection = "") {
media::AudioDeviceDescription result;
@@ -151,7 +156,8 @@
TEST_F(HashIdentityTest, AudioChannelLayoutHashIdentity) {
verifyHashIdentity<media::AudioChannelLayout>({
- make_ACL_None, make_ACL_Invalid, make_ACL_Stereo, make_ACL_ChannelIndex2});
+ make_ACL_None, make_ACL_Invalid, make_ACL_Stereo, make_ACL_ChannelIndex2,
+ make_ACL_VoiceCall});
}
TEST_F(HashIdentityTest, AudioDeviceDescriptionHashIdentity) {
@@ -184,6 +190,10 @@
testing::Values(media::AudioChannelLayout{}, make_ACL_Invalid(), make_ACL_Stereo(),
make_ACL_ChannelIndex2()),
testing::Values(true, false)));
+INSTANTIATE_TEST_SUITE_P(AudioChannelVoiceRoundTrip,
+ AudioChannelLayoutRoundTripTest,
+ // In legacy constants the voice call is only defined for input.
+ testing::Combine(testing::Values(make_ACL_VoiceCall()), testing::Values(false)));
class AudioDeviceDescriptionRoundTripTest :
public testing::TestWithParam<media::AudioDeviceDescription> {};