Define an extensible audio channel layout description

The new way for describing audio channel layouts which can
be used both in framework <-> framework and framework <->
HAL interfaces and directly supports extensions by vendors.

The mapping is defined between the legacy audio_channel_mask_t
and the new descriptions.

Bug: 188932434
Test: atest audio_aidl_conversion_tests
Change-Id: I23e387b2424e1d07a7637a2797f0e905a02feab1
diff --git a/media/libaudioclient/AidlConversion.cpp b/media/libaudioclient/AidlConversion.cpp
index fa78f43..298e596 100644
--- a/media/libaudioclient/AidlConversion.cpp
+++ b/media/libaudioclient/AidlConversion.cpp
@@ -412,12 +412,121 @@
 namespace {
 
 namespace detail {
+using AudioChannelPair = std::pair<audio_channel_mask_t, media::AudioChannelLayout>;
+using AudioChannelPairs = std::vector<AudioChannelPair>;
 using AudioDevicePair = std::pair<audio_devices_t, media::AudioDeviceDescription>;
 using AudioDevicePairs = std::vector<AudioDevicePair>;
 using AudioFormatPair = std::pair<audio_format_t, media::AudioFormatDescription>;
 using AudioFormatPairs = std::vector<AudioFormatPair>;
 }
 
+const detail::AudioChannelPairs& getIndexAudioChannelPairs() {
+    static const detail::AudioChannelPairs pairs = {
+#define DEFINE_INDEX_MASK(n)                                                                \
+            {                                                                               \
+                AUDIO_CHANNEL_INDEX_MASK_##n,                                               \
+                media::AudioChannelLayout::make<media::AudioChannelLayout::Tag::indexMask>( \
+                        media::AudioChannelLayout::INDEX_MASK_##n)                          \
+            }
+
+            DEFINE_INDEX_MASK(1),
+            DEFINE_INDEX_MASK(2),
+            DEFINE_INDEX_MASK(3),
+            DEFINE_INDEX_MASK(4),
+            DEFINE_INDEX_MASK(5),
+            DEFINE_INDEX_MASK(6),
+            DEFINE_INDEX_MASK(7),
+            DEFINE_INDEX_MASK(8),
+            DEFINE_INDEX_MASK(9),
+            DEFINE_INDEX_MASK(10),
+            DEFINE_INDEX_MASK(11),
+            DEFINE_INDEX_MASK(12),
+            DEFINE_INDEX_MASK(13),
+            DEFINE_INDEX_MASK(14),
+            DEFINE_INDEX_MASK(15),
+            DEFINE_INDEX_MASK(16),
+            DEFINE_INDEX_MASK(17),
+            DEFINE_INDEX_MASK(18),
+            DEFINE_INDEX_MASK(19),
+            DEFINE_INDEX_MASK(20),
+            DEFINE_INDEX_MASK(21),
+            DEFINE_INDEX_MASK(22),
+            DEFINE_INDEX_MASK(23),
+            DEFINE_INDEX_MASK(24)
+#undef DEFINE_INDEX_MASK
+    };
+    return pairs;
+}
+
+const detail::AudioChannelPairs& getInAudioChannelPairs() {
+    static const detail::AudioChannelPairs pairs = {
+#define DEFINE_INPUT_LAYOUT(n)                                                               \
+            {                                                                                \
+                AUDIO_CHANNEL_IN_##n,                                                        \
+                media::AudioChannelLayout::make<media::AudioChannelLayout::Tag::layoutMask>( \
+                        media::AudioChannelLayout::LAYOUT_##n)                               \
+            }
+
+        DEFINE_INPUT_LAYOUT(MONO),
+        DEFINE_INPUT_LAYOUT(STEREO),
+        DEFINE_INPUT_LAYOUT(FRONT_BACK),
+        // AUDIO_CHANNEL_IN_6 not supported
+        DEFINE_INPUT_LAYOUT(2POINT0POINT2),
+        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)
+#undef DEFINE_INPUT_LAYOUT
+    };
+    return pairs;
+}
+
+const detail::AudioChannelPairs& getOutAudioChannelPairs() {
+    static const detail::AudioChannelPairs pairs = {
+#define DEFINE_OUTPUT_LAYOUT(n)                                                              \
+            {                                                                                \
+                AUDIO_CHANNEL_OUT_##n,                                                       \
+                media::AudioChannelLayout::make<media::AudioChannelLayout::Tag::layoutMask>( \
+                        media::AudioChannelLayout::LAYOUT_##n)                               \
+            }
+
+        DEFINE_OUTPUT_LAYOUT(MONO),
+        DEFINE_OUTPUT_LAYOUT(STEREO),
+        DEFINE_OUTPUT_LAYOUT(2POINT1),
+        DEFINE_OUTPUT_LAYOUT(TRI),
+        DEFINE_OUTPUT_LAYOUT(TRI_BACK),
+        DEFINE_OUTPUT_LAYOUT(3POINT1),
+        DEFINE_OUTPUT_LAYOUT(2POINT0POINT2),
+        DEFINE_OUTPUT_LAYOUT(2POINT1POINT2),
+        DEFINE_OUTPUT_LAYOUT(3POINT0POINT2),
+        DEFINE_OUTPUT_LAYOUT(3POINT1POINT2),
+        DEFINE_OUTPUT_LAYOUT(QUAD),
+        DEFINE_OUTPUT_LAYOUT(QUAD_SIDE),
+        DEFINE_OUTPUT_LAYOUT(SURROUND),
+        DEFINE_OUTPUT_LAYOUT(PENTA),
+        DEFINE_OUTPUT_LAYOUT(5POINT1),
+        DEFINE_OUTPUT_LAYOUT(5POINT1_SIDE),
+        DEFINE_OUTPUT_LAYOUT(5POINT1POINT2),
+        DEFINE_OUTPUT_LAYOUT(5POINT1POINT4),
+        DEFINE_OUTPUT_LAYOUT(6POINT1),
+        DEFINE_OUTPUT_LAYOUT(7POINT1),
+        DEFINE_OUTPUT_LAYOUT(7POINT1POINT2),
+        DEFINE_OUTPUT_LAYOUT(7POINT1POINT4),
+        DEFINE_OUTPUT_LAYOUT(13POINT_360RA),
+        DEFINE_OUTPUT_LAYOUT(22POINT2),
+        DEFINE_OUTPUT_LAYOUT(MONO_HAPTIC_A),
+        DEFINE_OUTPUT_LAYOUT(STEREO_HAPTIC_A),
+        DEFINE_OUTPUT_LAYOUT(HAPTIC_AB),
+        DEFINE_OUTPUT_LAYOUT(MONO_HAPTIC_AB),
+        DEFINE_OUTPUT_LAYOUT(STEREO_HAPTIC_AB)
+#undef DEFINE_OUTPUT_LAYOUT
+    };
+    return pairs;
+}
+
 media::AudioDeviceDescription make_AudioDeviceDescription(media::AudioDeviceType type,
         const std::string& connection = "") {
     media::AudioDeviceDescription result;
@@ -983,6 +1092,76 @@
 
 }  // namespace
 
+ConversionResult<audio_channel_mask_t> aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
+        const media::AudioChannelLayout& aidl, bool isOutput) {
+    using ReverseMap = std::unordered_map<media::AudioChannelLayout, audio_channel_mask_t>;
+    using Tag = media::AudioChannelLayout::Tag;
+    static const ReverseMap mIdx = make_ReverseMap(getIndexAudioChannelPairs());
+    static const ReverseMap mIn = make_ReverseMap(getInAudioChannelPairs());
+    static const ReverseMap mOut = make_ReverseMap(getOutAudioChannelPairs());
+
+    auto convert = [](const media::AudioChannelLayout& aidl, const ReverseMap& m,
+            const char* func, const char* type) -> ConversionResult<audio_channel_mask_t> {
+        if (auto it = m.find(aidl); it != m.end()) {
+            return it->second;
+        } else {
+            ALOGE("%s: no legacy %s audio_channel_mask_t found for %s", func, type,
+                    aidl.toString().c_str());
+            return unexpected(BAD_VALUE);
+        }
+    };
+
+    switch (aidl.getTag()) {
+        case Tag::none:
+            return AUDIO_CHANNEL_NONE;
+        case Tag::invalid:
+            return AUDIO_CHANNEL_INVALID;
+        case Tag::indexMask:
+            return convert(aidl, mIdx, __func__, "index");
+        case Tag::layoutMask:
+            return convert(aidl, isOutput ? mOut : mIn, __func__, isOutput ? "output" : "input");
+    }
+    ALOGE("%s: unexpected tag value %d", __func__, aidl.getTag());
+    return unexpected(BAD_VALUE);
+}
+
+ConversionResult<media::AudioChannelLayout> legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
+        audio_channel_mask_t legacy, bool isOutput) {
+    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 mOut = make_DirectMap(getOutAudioChannelPairs());
+
+    auto convert = [](const audio_channel_mask_t legacy, const DirectMap& m,
+            const char* func, const char* type) -> ConversionResult<media::AudioChannelLayout> {
+        if (auto it = m.find(legacy); it != m.end()) {
+            return it->second;
+        } else {
+            ALOGE("%s: no AudioChannelLayout found for legacy %s audio_channel_mask_t value 0x%x",
+                    func, type, legacy);
+            return unexpected(BAD_VALUE);
+        }
+    };
+
+    if (legacy == AUDIO_CHANNEL_NONE) {
+        return media::AudioChannelLayout{};
+    } else if (legacy == AUDIO_CHANNEL_INVALID) {
+        return media::AudioChannelLayout::make<Tag::invalid>(0);
+    }
+
+    const audio_channel_representation_t repr = audio_channel_mask_get_representation(legacy);
+    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");
+    }
+
+    ALOGE("%s: unknown representation %d in audio_channel_mask_t value 0x%x",
+            __func__, repr, legacy);
+    return unexpected(BAD_VALUE);
+}
+
 ConversionResult<audio_devices_t> aidl2legacy_AudioDeviceDescription_audio_devices_t(
         const media::AudioDeviceDescription& aidl) {
     static const std::unordered_map<media::AudioDeviceDescription, audio_devices_t> m =