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 =
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index a23c844..778436c 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -303,6 +303,7 @@
local_include_dir: "aidl",
srcs: [
"aidl/android/media/AudioAttributesInternal.aidl",
+ "aidl/android/media/AudioChannelLayout.aidl",
"aidl/android/media/AudioChannelMask.aidl",
"aidl/android/media/AudioClient.aidl",
"aidl/android/media/AudioConfig.aidl",
diff --git a/media/libaudioclient/aidl/android/media/AudioChannelLayout.aidl b/media/libaudioclient/aidl/android/media/AudioChannelLayout.aidl
new file mode 100644
index 0000000..9b6d59f
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/AudioChannelLayout.aidl
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * This structure describes a layout of a multi-channel stream.
+ * There are two possible ways for representing a layout:
+ *
+ * - indexed mask, which tells what channels of an audio frame are used, but
+ * doesn't label them in any way, thus a correspondence between channels in
+ * the same position of frames originating from different streams must be
+ * established externally;
+ *
+ * - layout mask, which gives a label to each channel, thus allowing to
+ * match channels between streams of different layouts.
+ *
+ * Both representations are agnostic of the direction of audio transfer. Also,
+ * by construction, the number of bits set to '1' in the mask indicates the
+ * 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.
+ */
+union AudioChannelLayout {
+ /**
+ * This variant is used for representing the "null" ("none") value
+ * for the channel layout. The field value must always be '0'.
+ */
+ int none = 0;
+ /**
+ * This variant is used for indicating an "invalid" layout for use by the
+ * framework only. HAL implementations must not accept or emit
+ * AudioChannelLayout values for this variant. The field value must always
+ * be '0'.
+ */
+ int invalid = 0;
+ /**
+ * This variant is used for representing indexed masks. The value
+ * must be one of the 'INDEX_MASK_*' constants. The 'indexMask' field
+ * must have at least one bit set.
+ */
+ int indexMask;
+ /**
+ * This variant is used for representing layout masks.
+ * It is recommended to use one of 'LAYOUT_*' values. The 'layoutMask' field
+ * must have at least one bit set.
+ */
+ int layoutMask;
+
+ /**
+ * 'INDEX_MASK_' constants define how many channels are used.
+ */
+ const int INDEX_MASK_1 = (1 << 1) - 1;
+ const int INDEX_MASK_2 = (1 << 2) - 1;
+ const int INDEX_MASK_3 = (1 << 3) - 1;
+ const int INDEX_MASK_4 = (1 << 4) - 1;
+ const int INDEX_MASK_5 = (1 << 5) - 1;
+ const int INDEX_MASK_6 = (1 << 6) - 1;
+ const int INDEX_MASK_7 = (1 << 7) - 1;
+ const int INDEX_MASK_8 = (1 << 8) - 1;
+ const int INDEX_MASK_9 = (1 << 9) - 1;
+ const int INDEX_MASK_10 = (1 << 10) - 1;
+ const int INDEX_MASK_11 = (1 << 11) - 1;
+ const int INDEX_MASK_12 = (1 << 12) - 1;
+ const int INDEX_MASK_13 = (1 << 13) - 1;
+ const int INDEX_MASK_14 = (1 << 14) - 1;
+ const int INDEX_MASK_15 = (1 << 15) - 1;
+ const int INDEX_MASK_16 = (1 << 16) - 1;
+ const int INDEX_MASK_17 = (1 << 17) - 1;
+ const int INDEX_MASK_18 = (1 << 18) - 1;
+ const int INDEX_MASK_19 = (1 << 19) - 1;
+ const int INDEX_MASK_20 = (1 << 20) - 1;
+ const int INDEX_MASK_21 = (1 << 21) - 1;
+ const int INDEX_MASK_22 = (1 << 22) - 1;
+ const int INDEX_MASK_23 = (1 << 23) - 1;
+ const int INDEX_MASK_24 = (1 << 24) - 1;
+
+ /**
+ * 'LAYOUT_*' constants define channel layouts recognized by
+ * the audio system. 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 LAYOUT_MONO = CHANNEL_FRONT_LEFT;
+ const int LAYOUT_STEREO =
+ CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT;
+ const int LAYOUT_2POINT1 =
+ CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | CHANNEL_LOW_FREQUENCY;
+ const int LAYOUT_TRI =
+ CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | CHANNEL_FRONT_CENTER;
+ const int LAYOUT_TRI_BACK =
+ CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | CHANNEL_BACK_CENTER;
+ const int LAYOUT_3POINT1 =
+ CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | CHANNEL_FRONT_CENTER |
+ CHANNEL_LOW_FREQUENCY;
+ const int LAYOUT_2POINT0POINT2 =
+ CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+ CHANNEL_TOP_SIDE_LEFT | CHANNEL_TOP_SIDE_RIGHT;
+ const int LAYOUT_2POINT1POINT2 =
+ LAYOUT_2POINT0POINT2 | CHANNEL_LOW_FREQUENCY;
+ const int LAYOUT_3POINT0POINT2 =
+ CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+ CHANNEL_FRONT_CENTER |
+ CHANNEL_TOP_SIDE_LEFT | CHANNEL_TOP_SIDE_RIGHT;
+ const int LAYOUT_3POINT1POINT2 =
+ LAYOUT_3POINT0POINT2 | CHANNEL_LOW_FREQUENCY;
+ const int LAYOUT_QUAD =
+ CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+ CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT;
+ const int LAYOUT_QUAD_SIDE =
+ CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+ CHANNEL_SIDE_LEFT | CHANNEL_SIDE_RIGHT;
+ const int LAYOUT_SURROUND =
+ CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+ CHANNEL_FRONT_CENTER | CHANNEL_BACK_CENTER;
+ const int LAYOUT_PENTA = LAYOUT_QUAD | CHANNEL_FRONT_CENTER;
+ const int LAYOUT_5POINT1 =
+ CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+ CHANNEL_FRONT_CENTER | CHANNEL_LOW_FREQUENCY |
+ CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT;
+ const int LAYOUT_5POINT1_SIDE =
+ CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+ CHANNEL_FRONT_CENTER | CHANNEL_LOW_FREQUENCY |
+ CHANNEL_SIDE_LEFT | CHANNEL_SIDE_RIGHT;
+ const int LAYOUT_5POINT1POINT2 = LAYOUT_5POINT1 |
+ CHANNEL_TOP_SIDE_LEFT | CHANNEL_TOP_SIDE_RIGHT;
+ const int LAYOUT_5POINT1POINT4 = LAYOUT_5POINT1 |
+ CHANNEL_TOP_FRONT_LEFT | CHANNEL_TOP_FRONT_RIGHT |
+ CHANNEL_TOP_BACK_LEFT | CHANNEL_TOP_BACK_RIGHT;
+ const int LAYOUT_6POINT1 =
+ CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+ CHANNEL_FRONT_CENTER | CHANNEL_LOW_FREQUENCY |
+ CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT | CHANNEL_BACK_CENTER;
+ const int LAYOUT_7POINT1 = LAYOUT_5POINT1 |
+ CHANNEL_SIDE_LEFT | CHANNEL_SIDE_RIGHT;
+ const int LAYOUT_7POINT1POINT2 = LAYOUT_7POINT1 |
+ CHANNEL_TOP_SIDE_LEFT | CHANNEL_TOP_SIDE_RIGHT;
+ const int LAYOUT_7POINT1POINT4 = LAYOUT_7POINT1 |
+ CHANNEL_TOP_FRONT_LEFT | CHANNEL_TOP_FRONT_RIGHT |
+ CHANNEL_TOP_BACK_LEFT | CHANNEL_TOP_BACK_RIGHT;
+ const int LAYOUT_9POINT1POINT4 = LAYOUT_7POINT1POINT4 |
+ CHANNEL_FRONT_WIDE_LEFT | CHANNEL_FRONT_WIDE_RIGHT;
+ const int LAYOUT_9POINT1POINT6 = LAYOUT_9POINT1POINT4 |
+ CHANNEL_TOP_SIDE_LEFT | CHANNEL_TOP_SIDE_RIGHT;
+ const int LAYOUT_13POINT_360RA =
+ CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
+ CHANNEL_FRONT_CENTER |
+ CHANNEL_SIDE_LEFT | CHANNEL_SIDE_RIGHT |
+ CHANNEL_TOP_FRONT_LEFT | CHANNEL_TOP_FRONT_RIGHT |
+ CHANNEL_TOP_FRONT_CENTER |
+ CHANNEL_TOP_BACK_LEFT | CHANNEL_TOP_BACK_RIGHT |
+ CHANNEL_BOTTOM_FRONT_LEFT | CHANNEL_BOTTOM_FRONT_RIGHT |
+ CHANNEL_BOTTOM_FRONT_CENTER;
+ const int LAYOUT_22POINT2 = LAYOUT_7POINT1POINT4 |
+ CHANNEL_FRONT_LEFT_OF_CENTER | CHANNEL_FRONT_RIGHT_OF_CENTER |
+ CHANNEL_BACK_CENTER | CHANNEL_TOP_CENTER |
+ CHANNEL_TOP_FRONT_CENTER | CHANNEL_TOP_BACK_CENTER |
+ CHANNEL_TOP_SIDE_LEFT | CHANNEL_TOP_SIDE_RIGHT |
+ CHANNEL_BOTTOM_FRONT_LEFT | CHANNEL_BOTTOM_FRONT_RIGHT |
+ CHANNEL_BOTTOM_FRONT_CENTER |
+ CHANNEL_LOW_FREQUENCY_2;
+ const int LAYOUT_MONO_HAPTIC_A =
+ LAYOUT_MONO | CHANNEL_HAPTIC_A;
+ const int LAYOUT_STEREO_HAPTIC_A =
+ LAYOUT_STEREO | CHANNEL_HAPTIC_A;
+ const int LAYOUT_HAPTIC_AB =
+ CHANNEL_HAPTIC_A | CHANNEL_HAPTIC_B;
+ const int LAYOUT_MONO_HAPTIC_AB =
+ LAYOUT_MONO | LAYOUT_HAPTIC_AB;
+ const int LAYOUT_STEREO_HAPTIC_AB =
+ 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
+ * in an array. This should improve readability by allowing code to use
+ * symbolic indices instead of hard-coded [0] and [1].
+ *
+ * For multi-channel beyond stereo, the platform convention is that channels
+ * are interleaved in order from least significant channel mask bit to most
+ * significant channel mask bit, with unused bits skipped. Any exceptions
+ * to this convention will be noted at the appropriate API.
+ */
+ const int INTERLEAVE_LEFT = 0;
+ const int INTERLEAVE_RIGHT = 1;
+
+ /**
+ * 'CHANNEL_*' constants are used to build 'LAYOUT_*' masks.
+ * Each constant must have exactly one bit set.
+ */
+ const int CHANNEL_FRONT_LEFT = 1 << 0;
+ const int CHANNEL_FRONT_RIGHT = 1 << 1;
+ const int CHANNEL_FRONT_CENTER = 1 << 2;
+ const int CHANNEL_LOW_FREQUENCY = 1 << 3;
+ const int CHANNEL_BACK_LEFT = 1 << 4;
+ const int CHANNEL_BACK_RIGHT = 1 << 5;
+ const int CHANNEL_FRONT_LEFT_OF_CENTER = 1 << 6;
+ const int CHANNEL_FRONT_RIGHT_OF_CENTER = 1 << 7;
+ const int CHANNEL_BACK_CENTER = 1 << 8;
+ const int CHANNEL_SIDE_LEFT = 1 << 9;
+ const int CHANNEL_SIDE_RIGHT = 1 << 10;
+ const int CHANNEL_TOP_CENTER = 1 << 11;
+ const int CHANNEL_TOP_FRONT_LEFT = 1 << 12;
+ const int CHANNEL_TOP_FRONT_CENTER = 1 << 13;
+ const int CHANNEL_TOP_FRONT_RIGHT = 1 << 14;
+ const int CHANNEL_TOP_BACK_LEFT = 1 << 15;
+ const int CHANNEL_TOP_BACK_CENTER = 1 << 16;
+ const int CHANNEL_TOP_BACK_RIGHT = 1 << 17;
+ const int CHANNEL_TOP_SIDE_LEFT = 1 << 18;
+ const int CHANNEL_TOP_SIDE_RIGHT = 1 << 19;
+ const int CHANNEL_BOTTOM_FRONT_LEFT = 1 << 20;
+ const int CHANNEL_BOTTOM_FRONT_CENTER = 1 << 21;
+ const int CHANNEL_BOTTOM_FRONT_RIGHT = 1 << 22;
+ 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;
+}
diff --git a/media/libaudioclient/include/media/AidlConversion.h b/media/libaudioclient/include/media/AidlConversion.h
index 422d94f..eb84b2d 100644
--- a/media/libaudioclient/include/media/AidlConversion.h
+++ b/media/libaudioclient/include/media/AidlConversion.h
@@ -22,6 +22,7 @@
#include <system/audio.h>
#include <android/media/AudioAttributesInternal.h>
+#include <android/media/AudioChannelLayout.h>
#include <android/media/AudioClient.h>
#include <android/media/AudioConfig.h>
#include <android/media/AudioConfigBase.h>
@@ -140,6 +141,11 @@
ConversionResult<media::AudioFormatSys> legacy2aidl_audio_format_t_AudioFormat(
audio_format_t legacy);
+ConversionResult<audio_channel_mask_t> aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
+ const media::AudioChannelLayout& aidl, bool isOutput);
+ConversionResult<media::AudioChannelLayout> legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
+ audio_channel_mask_t legacy, bool isOutput);
+
ConversionResult<audio_devices_t> aidl2legacy_AudioDeviceDescription_audio_devices_t(
const media::AudioDeviceDescription& aidl);
ConversionResult<media::AudioDeviceDescription> legacy2aidl_audio_devices_t_AudioDeviceDescription(
diff --git a/media/libaudioclient/include/media/AudioCommonTypes.h b/media/libaudioclient/include/media/AudioCommonTypes.h
index 613d6bd..2a46e05 100644
--- a/media/libaudioclient/include/media/AudioCommonTypes.h
+++ b/media/libaudioclient/include/media/AudioCommonTypes.h
@@ -19,6 +19,7 @@
#include <functional>
+#include <android/media/AudioChannelLayout.h>
#include <android/media/AudioDeviceDescription.h>
#include <android/media/AudioFormatDescription.h>
#include <binder/Parcelable.h>
@@ -37,9 +38,29 @@
namespace std {
-// Note: when extending Audio{Device|Format}Description we need to account for the
-// possibility of comparison between different versions of it, e.g. a HAL
-// may be using a previous version of the AIDL interface.
+// Note: when extending the types hashed below we need to account for the
+// possibility of processing types belonging to different versions of the type,
+// e.g. a HAL may be using a previous version of the AIDL interface.
+
+template<> struct hash<android::media::AudioChannelLayout>
+{
+ std::size_t operator()(const android::media::AudioChannelLayout& acl) const noexcept {
+ using Tag = android::media::AudioChannelLayout::Tag;
+ const size_t seed = std::hash<Tag>{}(acl.getTag());
+ switch (acl.getTag()) {
+ case Tag::none:
+ return hash_combine(seed, std::hash<int32_t>{}(acl.get<Tag::none>()));
+ case Tag::invalid:
+ return hash_combine(seed, std::hash<int32_t>{}(acl.get<Tag::invalid>()));
+ case Tag::indexMask:
+ 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>()));
+ }
+ return seed;
+ }
+};
+
template<> struct hash<android::media::AudioDeviceDescription>
{
std::size_t operator()(const android::media::AudioDeviceDescription& add) const noexcept {
diff --git a/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp b/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
index ca609ab..e549354 100644
--- a/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
+++ b/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
@@ -24,12 +24,26 @@
namespace {
-size_t hash(const media::AudioDeviceDescription& add) {
- return std::hash<media::AudioDeviceDescription>{}(add);
+template<typename T> size_t hash(const T& t) {
+ return std::hash<T>{}(t);
}
-size_t hash(const media::AudioFormatDescription& afd) {
- return std::hash<media::AudioFormatDescription>{}(afd);
+media::AudioChannelLayout make_ACL_None() {
+ return media::AudioChannelLayout{};
+}
+
+media::AudioChannelLayout make_ACL_Invalid() {
+ return media::AudioChannelLayout::make<media::AudioChannelLayout::Tag::invalid>(0);
+}
+
+media::AudioChannelLayout make_ACL_Stereo() {
+ return media::AudioChannelLayout::make<media::AudioChannelLayout::Tag::layoutMask>(
+ media::AudioChannelLayout::LAYOUT_STEREO);
+}
+
+media::AudioChannelLayout make_ACL_ChannelIndex2() {
+ return media::AudioChannelLayout::make<media::AudioChannelLayout::Tag::indexMask>(
+ media::AudioChannelLayout::INDEX_MASK_2);
}
media::AudioDeviceDescription make_AudioDeviceDescription(media::AudioDeviceType type,
@@ -135,6 +149,11 @@
}
};
+TEST_F(HashIdentityTest, AudioChannelLayoutHashIdentity) {
+ verifyHashIdentity<media::AudioChannelLayout>({
+ make_ACL_None, make_ACL_Invalid, make_ACL_Stereo, make_ACL_ChannelIndex2});
+}
+
TEST_F(HashIdentityTest, AudioDeviceDescriptionHashIdentity) {
verifyHashIdentity<media::AudioDeviceDescription>({
make_ADD_None, make_ADD_DefaultIn, make_ADD_DefaultOut, make_ADD_WiredHeadset,
@@ -147,6 +166,25 @@
make_AFD_Encap, make_AFD_Encap_with_Enc});
}
+using ChannelLayoutParam = std::tuple<media::AudioChannelLayout, bool /*isOutput*/>;
+class AudioChannelLayoutRoundTripTest :
+ public testing::TestWithParam<ChannelLayoutParam> {};
+TEST_P(AudioChannelLayoutRoundTripTest, Aidl2Legacy2Aidl) {
+ const auto initial = std::get<0>(GetParam());
+ const bool isOutput = std::get<1>(GetParam());
+ auto conv = aidl2legacy_AudioChannelLayout_audio_channel_mask_t(initial, isOutput);
+ ASSERT_TRUE(conv.ok());
+ auto convBack = legacy2aidl_audio_channel_mask_t_AudioChannelLayout(conv.value(), isOutput);
+ ASSERT_TRUE(convBack.ok());
+ EXPECT_EQ(initial, convBack.value());
+}
+INSTANTIATE_TEST_SUITE_P(AudioChannelLayoutRoundTrip,
+ AudioChannelLayoutRoundTripTest,
+ testing::Combine(
+ testing::Values(media::AudioChannelLayout{}, make_ACL_Invalid(), make_ACL_Stereo(),
+ make_ACL_ChannelIndex2()),
+ testing::Values(true, false)));
+
class AudioDeviceDescriptionRoundTripTest :
public testing::TestWithParam<media::AudioDeviceDescription> {};
TEST_P(AudioDeviceDescriptionRoundTripTest, Aidl2Legacy2Aidl) {