AOSP AIDL USB audio HAL implementation.

Bug: 266216550
Test: atest VtsHalAudioCoreTargetTest
Change-Id: I82e053d3f6a918cafe0d43b030f724f63a99eb2a
diff --git a/audio/aidl/default/usb/ModuleUsb.cpp b/audio/aidl/default/usb/ModuleUsb.cpp
new file mode 100644
index 0000000..e803420
--- /dev/null
+++ b/audio/aidl/default/usb/ModuleUsb.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#define LOG_TAG "AHAL_ModuleUsb"
+
+#include <vector>
+
+#include <Utils.h>
+#include <android-base/logging.h>
+#include <tinyalsa/asoundlib.h>
+
+#include "UsbAlsaUtils.h"
+#include "core-impl/ModuleUsb.h"
+
+extern "C" {
+#include "alsa_device_profile.h"
+}
+
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioDeviceDescription;
+using aidl::android::media::audio::common::AudioDeviceType;
+using aidl::android::media::audio::common::AudioFormatDescription;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioProfile;
+using android::hardware::audio::common::isUsbInputDeviceType;
+
+namespace aidl::android::hardware::audio::core {
+
+namespace {
+
+std::vector<AudioChannelLayout> populateChannelMasksFromProfile(const alsa_device_profile* profile,
+                                                                bool isInput) {
+    std::vector<AudioChannelLayout> channels;
+    for (size_t i = 0; i < AUDIO_PORT_MAX_CHANNEL_MASKS && profile->channel_counts[i] != 0; ++i) {
+        auto layoutMask =
+                usb::getChannelLayoutMaskFromChannelCount(profile->channel_counts[i], isInput);
+        if (layoutMask.getTag() == AudioChannelLayout::Tag::layoutMask) {
+            channels.push_back(layoutMask);
+        }
+        auto indexMask = usb::getChannelIndexMaskFromChannelCount(profile->channel_counts[i]);
+        if (indexMask.getTag() == AudioChannelLayout::Tag::indexMask) {
+            channels.push_back(indexMask);
+        }
+    }
+    return channels;
+}
+
+std::vector<int> populateSampleRatesFromProfile(const alsa_device_profile* profile) {
+    std::vector<int> sampleRates;
+    for (int i = 0; i < std::min(MAX_PROFILE_SAMPLE_RATES, AUDIO_PORT_MAX_SAMPLING_RATES) &&
+                    profile->sample_rates[i] != 0;
+         i++) {
+        sampleRates.push_back(profile->sample_rates[i]);
+    }
+    return sampleRates;
+}
+
+}  // namespace
+
+ndk::ScopedAStatus ModuleUsb::getTelephony(std::shared_ptr<ITelephony>* _aidl_return) {
+    *_aidl_return = nullptr;
+    LOG(DEBUG) << __func__ << ": returning null";
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleUsb::getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) {
+    *_aidl_return = nullptr;
+    LOG(DEBUG) << __func__ << ": returning null";
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleUsb::getMasterMute(bool* _aidl_return __unused) {
+    LOG(DEBUG) << __func__ << ": is not supported";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus ModuleUsb::setMasterMute(bool in_mute __unused) {
+    LOG(DEBUG) << __func__ << ": is not supported";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus ModuleUsb::getMasterVolume(float* _aidl_return __unused) {
+    LOG(DEBUG) << __func__ << ": is not supported";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus ModuleUsb::setMasterVolume(float in_volume __unused) {
+    LOG(DEBUG) << __func__ << ": is not supported";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus ModuleUsb::getMicMute(bool* _aidl_return __unused) {
+    LOG(DEBUG) << __func__ << ": is not supported";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus ModuleUsb::setMicMute(bool in_mute __unused) {
+    LOG(DEBUG) << __func__ << ": is not supported";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus ModuleUsb::populateConnectedDevicePort(AudioPort* audioPort) {
+    if (audioPort->ext.getTag() != AudioPortExt::Tag::device) {
+        LOG(ERROR) << __func__ << ": port id " << audioPort->id << " is not a device port";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    auto& devicePort = audioPort->ext.get<AudioPortExt::Tag::device>();
+    if (devicePort.device.type.connection != AudioDeviceDescription::CONNECTION_USB) {
+        LOG(ERROR) << __func__ << ": port id " << audioPort->id << " is not a usb device port";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    if (devicePort.device.address.getTag() != AudioDeviceAddress::Tag::alsa) {
+        LOG(ERROR) << __func__ << ": port id " << audioPort->id << " is not using alsa address";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    auto& alsaAddress = devicePort.device.address.get<AudioDeviceAddress::Tag::alsa>();
+    if (alsaAddress.size() != 2 || alsaAddress[0] < 0 || alsaAddress[1] < 0) {
+        LOG(ERROR) << __func__ << ": port id " << audioPort->id << " invalid alsa address";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    const bool isInput = isUsbInputDeviceType(devicePort.device.type.type);
+    alsa_device_profile profile;
+    profile_init(&profile, isInput ? PCM_IN : PCM_OUT);
+    if (!profile_read_device_info(&profile)) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+
+    std::vector<AudioChannelLayout> channels = populateChannelMasksFromProfile(&profile, isInput);
+    std::vector<int> sampleRates = populateSampleRatesFromProfile(&profile);
+
+    for (size_t i = 0; i < std::min(MAX_PROFILE_FORMATS, AUDIO_PORT_MAX_AUDIO_PROFILES) &&
+                       profile.formats[i] != 0;
+         ++i) {
+        auto audioFormatDescription =
+                usb::legacy2aidl_pcm_format_AudioFormatDescription(profile.formats[i]);
+        if (audioFormatDescription.type == AudioFormatType::DEFAULT) {
+            LOG(WARNING) << __func__ << ": unknown pcm type=" << profile.formats[i];
+            continue;
+        }
+        AudioProfile audioProfile = {.format = audioFormatDescription,
+                                     .channelMasks = channels,
+                                     .sampleRates = sampleRates};
+        audioPort->profiles.push_back(std::move(audioProfile));
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleUsb::checkAudioPatchEndpointsMatch(
+        const std::vector<AudioPortConfig*>& sources, const std::vector<AudioPortConfig*>& sinks) {
+    for (const auto& source : sources) {
+        for (const auto& sink : sinks) {
+            if (source->sampleRate != sink->sampleRate ||
+                source->channelMask != sink->channelMask || source->format != sink->format) {
+                LOG(ERROR) << __func__
+                           << ": mismatch port configuration, source=" << source->toString()
+                           << ", sink=" << sink->toString();
+                return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+            }
+        }
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp
new file mode 100644
index 0000000..22e36ac
--- /dev/null
+++ b/audio/aidl/default/usb/StreamUsb.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#define LOG_TAG "AHAL_StreamUsb"
+#include <android-base/logging.h>
+
+#include "UsbAlsaUtils.h"
+#include "core-impl/Module.h"
+#include "core-impl/StreamUsb.h"
+
+extern "C" {
+#include "alsa_device_profile.h"
+}
+
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioOffloadInfo;
+
+namespace aidl::android::hardware::audio::core {
+
+DriverUsb::DriverUsb(const StreamContext& context, bool isInput)
+    : mFrameSizeBytes(context.getFrameSize()), mIsInput(isInput) {
+    struct pcm_config config;
+    config.channels = usb::getChannelCountFromChannelMask(context.getChannelLayout(), isInput);
+    if (config.channels == 0) {
+        LOG(ERROR) << __func__ << ": invalid channel=" << context.getChannelLayout().toString();
+        return;
+    }
+    config.format = usb::aidl2legacy_AudioFormatDescription_pcm_format(context.getFormat());
+    if (config.format == PCM_FORMAT_INVALID) {
+        LOG(ERROR) << __func__ << ": invalid format=" << context.getFormat().toString();
+        return;
+    }
+    config.rate = context.getSampleRate();
+    if (config.rate == 0) {
+        LOG(ERROR) << __func__ << ": invalid sample rate=" << config.rate;
+        return;
+    }
+    mConfig = config;
+}
+
+::android::status_t DriverUsb::init() {
+    return mConfig.has_value() ? ::android::OK : ::android::NO_INIT;
+}
+
+::android::status_t DriverUsb::setConnectedDevices(
+        const std::vector<AudioDevice>& connectedDevices) {
+    if (mIsInput && connectedDevices.size() > 1) {
+        LOG(ERROR) << __func__ << ": wrong device size(" << connectedDevices.size()
+                   << ") for input stream";
+        return ::android::BAD_VALUE;
+    }
+    for (const auto& connectedDevice : connectedDevices) {
+        if (connectedDevice.address.getTag() != AudioDeviceAddress::alsa) {
+            LOG(ERROR) << __func__ << ": bad device address" << connectedDevice.address.toString();
+            return ::android::BAD_VALUE;
+        }
+    }
+    std::lock_guard guard(mLock);
+    mAlsaDeviceProxies.clear();
+    mConnectedDevices.clear();
+    for (const auto& connectedDevice : connectedDevices) {
+        mConnectedDevices.push_back(connectedDevice.address);
+    }
+    return ::android::OK;
+}
+
+::android::status_t DriverUsb::drain(StreamDescriptor::DrainMode) {
+    usleep(1000);
+    return ::android::OK;
+}
+
+::android::status_t DriverUsb::flush() {
+    usleep(1000);
+    return ::android::OK;
+}
+
+::android::status_t DriverUsb::pause() {
+    usleep(1000);
+    return ::android::OK;
+}
+
+::android::status_t DriverUsb::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
+                                        int32_t* latencyMs) {
+    if (!mConfig.has_value() || mConnectedDevices.empty()) {
+        return ::android::NO_INIT;
+    }
+    if (mIsStandby) {
+        if (::android::status_t status = exitStandby(); status != ::android::OK) {
+            return status;
+        }
+    }
+    std::vector<std::shared_ptr<alsa_device_proxy>> alsaDeviceProxies;
+    {
+        std::lock_guard guard(mLock);
+        alsaDeviceProxies = mAlsaDeviceProxies;
+    }
+    const size_t bytesToTransfer = frameCount * mFrameSizeBytes;
+    if (mIsInput) {
+        // For input case, only support single device.
+        proxy_read(alsaDeviceProxies[0].get(), buffer, bytesToTransfer);
+    } else {
+        for (auto& proxy : alsaDeviceProxies) {
+            proxy_write(proxy.get(), buffer, bytesToTransfer);
+        }
+    }
+    *actualFrameCount = frameCount;
+    *latencyMs = Module::kLatencyMs;
+    return ::android::OK;
+}
+
+::android::status_t DriverUsb::standby() {
+    if (!mIsStandby) {
+        std::lock_guard guard(mLock);
+        mAlsaDeviceProxies.clear();
+        mIsStandby = true;
+    }
+    return ::android::OK;
+}
+
+::android::status_t DriverUsb::exitStandby() {
+    std::vector<AudioDeviceAddress> connectedDevices;
+    {
+        std::lock_guard guard(mLock);
+        connectedDevices = mConnectedDevices;
+    }
+    std::vector<std::shared_ptr<alsa_device_proxy>> alsaDeviceProxies;
+    for (const auto& device : connectedDevices) {
+        alsa_device_profile profile;
+        profile.card = device.get<AudioDeviceAddress::alsa>()[0];
+        profile.device = device.get<AudioDeviceAddress::alsa>()[1];
+        if (!profile_read_device_info(&profile)) {
+            LOG(ERROR) << __func__
+                       << ": unable to read device info, device address=" << device.toString();
+            return ::android::UNKNOWN_ERROR;
+        }
+
+        auto proxy = std::shared_ptr<alsa_device_proxy>(new alsa_device_proxy(),
+                                                        [](alsa_device_proxy* proxy) {
+                                                            proxy_close(proxy);
+                                                            free(proxy);
+                                                        });
+        // Always ask for alsa configure as required since the configuration should be supported
+        // by the connected device. That is guaranteed by `setAudioPortConfig` and
+        // `setAudioPatch`.
+        if (int err =
+                    proxy_prepare(proxy.get(), &profile, &mConfig.value(), true /*is_bit_perfect*/);
+            err != 0) {
+            LOG(ERROR) << __func__ << ": fail to prepare for device address=" << device.toString()
+                       << " error=" << err;
+            return ::android::UNKNOWN_ERROR;
+        }
+        alsaDeviceProxies.push_back(std::move(proxy));
+    }
+    {
+        std::lock_guard guard(mLock);
+        mAlsaDeviceProxies = alsaDeviceProxies;
+    }
+    mIsStandby = false;
+    return ::android::OK;
+}
+
+// static
+ndk::ScopedAStatus StreamInUsb::createInstance(const SinkMetadata& sinkMetadata,
+                                               StreamContext&& context,
+                                               const std::vector<MicrophoneInfo>& microphones,
+                                               std::shared_ptr<StreamIn>* result) {
+    std::shared_ptr<StreamIn> stream =
+            ndk::SharedRefBase::make<StreamInUsb>(sinkMetadata, std::move(context), microphones);
+    if (auto status = initInstance(stream); !status.isOk()) {
+        return status;
+    }
+    *result = std::move(stream);
+    return ndk::ScopedAStatus::ok();
+}
+
+StreamInUsb::StreamInUsb(const SinkMetadata& sinkMetadata, StreamContext&& context,
+                         const std::vector<MicrophoneInfo>& microphones)
+    : StreamIn(
+              sinkMetadata, std::move(context),
+              [](const StreamContext& ctx) -> DriverInterface* {
+                  return new DriverUsb(ctx, true /*isInput*/);
+              },
+              [](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* {
+                  // The default worker implementation is used.
+                  return new StreamInWorker(ctx, driver);
+              },
+              microphones) {}
+
+ndk::ScopedAStatus StreamInUsb::getActiveMicrophones(
+        std::vector<MicrophoneDynamicInfo>* _aidl_return __unused) {
+    LOG(DEBUG) << __func__ << ": not supported";
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+// static
+ndk::ScopedAStatus StreamOutUsb::createInstance(const SourceMetadata& sourceMetadata,
+                                                StreamContext&& context,
+                                                const std::optional<AudioOffloadInfo>& offloadInfo,
+                                                std::shared_ptr<StreamOut>* result) {
+    if (offloadInfo.has_value()) {
+        LOG(ERROR) << __func__ << ": offload is not supported";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    std::shared_ptr<StreamOut> stream =
+            ndk::SharedRefBase::make<StreamOutUsb>(sourceMetadata, std::move(context), offloadInfo);
+    if (auto status = initInstance(stream); !status.isOk()) {
+        return status;
+    }
+    *result = std::move(stream);
+    return ndk::ScopedAStatus::ok();
+}
+
+StreamOutUsb::StreamOutUsb(const SourceMetadata& sourceMetadata, StreamContext&& context,
+                           const std::optional<AudioOffloadInfo>& offloadInfo)
+    : StreamOut(
+              sourceMetadata, std::move(context),
+              [](const StreamContext& ctx) -> DriverInterface* {
+                  return new DriverUsb(ctx, false /*isInput*/);
+              },
+              [](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* {
+                  // The default worker implementation is used.
+                  return new StreamOutWorker(ctx, driver);
+              },
+              offloadInfo) {}
+
+}  // namespace aidl::android::hardware::audio::core
\ No newline at end of file
diff --git a/audio/aidl/default/usb/UsbAlsaUtils.cpp b/audio/aidl/default/usb/UsbAlsaUtils.cpp
new file mode 100644
index 0000000..3c79e1d
--- /dev/null
+++ b/audio/aidl/default/usb/UsbAlsaUtils.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#include <map>
+#include <set>
+
+#include <Utils.h>
+#include <aidl/android/media/audio/common/AudioFormatType.h>
+#include <aidl/android/media/audio/common/PcmType.h>
+
+#include "UsbAlsaUtils.h"
+#include "core-impl/utils.h"
+
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioFormatDescription;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::PcmType;
+using android::hardware::audio::common::getChannelCount;
+
+namespace aidl::android::hardware::audio::core::usb {
+
+namespace {
+
+using AudioChannelCountToMaskMap = std::map<unsigned int, AudioChannelLayout>;
+using AudioFormatDescToPcmFormatMap = std::map<AudioFormatDescription, enum pcm_format>;
+using PcmFormatToAudioFormatDescMap = std::map<enum pcm_format, AudioFormatDescription>;
+
+static const AudioChannelLayout INVALID_CHANNEL_LAYOUT =
+        AudioChannelLayout::make<AudioChannelLayout::Tag::invalid>(0);
+
+#define DEFINE_CHANNEL_LAYOUT_MASK(n) \
+    AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(AudioChannelLayout::LAYOUT_##n)
+
+static const std::set<AudioChannelLayout> SUPPORTED_OUT_CHANNEL_LAYOUTS = {
+        DEFINE_CHANNEL_LAYOUT_MASK(MONO),          DEFINE_CHANNEL_LAYOUT_MASK(STEREO),
+        DEFINE_CHANNEL_LAYOUT_MASK(2POINT1),       DEFINE_CHANNEL_LAYOUT_MASK(QUAD),
+        DEFINE_CHANNEL_LAYOUT_MASK(PENTA),         DEFINE_CHANNEL_LAYOUT_MASK(5POINT1),
+        DEFINE_CHANNEL_LAYOUT_MASK(6POINT1),       DEFINE_CHANNEL_LAYOUT_MASK(7POINT1),
+        DEFINE_CHANNEL_LAYOUT_MASK(7POINT1POINT4), DEFINE_CHANNEL_LAYOUT_MASK(22POINT2),
+};
+
+static const std::set<AudioChannelLayout> SUPPORTED_IN_CHANNEL_LAYOUTS = {
+        DEFINE_CHANNEL_LAYOUT_MASK(MONO),
+        DEFINE_CHANNEL_LAYOUT_MASK(STEREO),
+};
+
+#define DEFINE_CHANNEL_INDEX_MASK(n) \
+    AudioChannelLayout::make<AudioChannelLayout::Tag::indexMask>(AudioChannelLayout::INDEX_MASK_##n)
+
+static const std::set<AudioChannelLayout> SUPPORTED_INDEX_CHANNEL_LAYOUTS = {
+        DEFINE_CHANNEL_INDEX_MASK(1),  DEFINE_CHANNEL_INDEX_MASK(2),  DEFINE_CHANNEL_INDEX_MASK(3),
+        DEFINE_CHANNEL_INDEX_MASK(4),  DEFINE_CHANNEL_INDEX_MASK(5),  DEFINE_CHANNEL_INDEX_MASK(6),
+        DEFINE_CHANNEL_INDEX_MASK(7),  DEFINE_CHANNEL_INDEX_MASK(8),  DEFINE_CHANNEL_INDEX_MASK(9),
+        DEFINE_CHANNEL_INDEX_MASK(10), DEFINE_CHANNEL_INDEX_MASK(11), DEFINE_CHANNEL_INDEX_MASK(12),
+        DEFINE_CHANNEL_INDEX_MASK(13), DEFINE_CHANNEL_INDEX_MASK(14), DEFINE_CHANNEL_INDEX_MASK(15),
+        DEFINE_CHANNEL_INDEX_MASK(16), DEFINE_CHANNEL_INDEX_MASK(17), DEFINE_CHANNEL_INDEX_MASK(18),
+        DEFINE_CHANNEL_INDEX_MASK(19), DEFINE_CHANNEL_INDEX_MASK(20), DEFINE_CHANNEL_INDEX_MASK(21),
+        DEFINE_CHANNEL_INDEX_MASK(22), DEFINE_CHANNEL_INDEX_MASK(23), DEFINE_CHANNEL_INDEX_MASK(24),
+};
+
+static AudioChannelCountToMaskMap make_ChannelCountToMaskMap(
+        const std::set<AudioChannelLayout>& channelMasks) {
+    AudioChannelCountToMaskMap channelMaskToCountMap;
+    for (const auto& channelMask : channelMasks) {
+        channelMaskToCountMap.emplace(getChannelCount(channelMask), channelMask);
+    }
+    return channelMaskToCountMap;
+}
+
+const AudioChannelCountToMaskMap& getSupportedChannelOutLayoutMap() {
+    static const AudioChannelCountToMaskMap outLayouts =
+            make_ChannelCountToMaskMap(SUPPORTED_OUT_CHANNEL_LAYOUTS);
+    return outLayouts;
+}
+
+const AudioChannelCountToMaskMap& getSupportedChannelInLayoutMap() {
+    static const AudioChannelCountToMaskMap inLayouts =
+            make_ChannelCountToMaskMap(SUPPORTED_IN_CHANNEL_LAYOUTS);
+    return inLayouts;
+}
+
+const AudioChannelCountToMaskMap& getSupportedChannelIndexLayoutMap() {
+    static const AudioChannelCountToMaskMap indexLayouts =
+            make_ChannelCountToMaskMap(SUPPORTED_INDEX_CHANNEL_LAYOUTS);
+    return indexLayouts;
+}
+
+AudioFormatDescription make_AudioFormatDescription(AudioFormatType type) {
+    AudioFormatDescription result;
+    result.type = type;
+    return result;
+}
+
+AudioFormatDescription make_AudioFormatDescription(PcmType pcm) {
+    auto result = make_AudioFormatDescription(AudioFormatType::PCM);
+    result.pcm = pcm;
+    return result;
+}
+
+const AudioFormatDescToPcmFormatMap& getAudioFormatDescriptorToPcmFormatMap() {
+    static const AudioFormatDescToPcmFormatMap formatDescToPcmFormatMap = {
+            {make_AudioFormatDescription(PcmType::UINT_8_BIT), PCM_FORMAT_S8},
+            {make_AudioFormatDescription(PcmType::INT_16_BIT), PCM_FORMAT_S16_LE},
+            {make_AudioFormatDescription(PcmType::INT_24_BIT), PCM_FORMAT_S24_LE},
+            {make_AudioFormatDescription(PcmType::FIXED_Q_8_24), PCM_FORMAT_S24_3LE},
+            {make_AudioFormatDescription(PcmType::INT_32_BIT), PCM_FORMAT_S32_LE},
+            {make_AudioFormatDescription(PcmType::FLOAT_32_BIT), PCM_FORMAT_FLOAT_LE},
+    };
+    return formatDescToPcmFormatMap;
+}
+
+static PcmFormatToAudioFormatDescMap make_PcmFormatToAudioFormatDescMap(
+        const AudioFormatDescToPcmFormatMap& formatDescToPcmFormatMap) {
+    PcmFormatToAudioFormatDescMap result;
+    for (const auto& formatPair : formatDescToPcmFormatMap) {
+        result.emplace(formatPair.second, formatPair.first);
+    }
+    return result;
+}
+
+const PcmFormatToAudioFormatDescMap& getPcmFormatToAudioFormatDescMap() {
+    static const PcmFormatToAudioFormatDescMap pcmFormatToFormatDescMap =
+            make_PcmFormatToAudioFormatDescMap(getAudioFormatDescriptorToPcmFormatMap());
+    return pcmFormatToFormatDescMap;
+}
+
+}  // namespace
+
+AudioChannelLayout getChannelLayoutMaskFromChannelCount(unsigned int channelCount, int isInput) {
+    return findValueOrDefault(
+            isInput ? getSupportedChannelInLayoutMap() : getSupportedChannelOutLayoutMap(),
+            channelCount, INVALID_CHANNEL_LAYOUT);
+}
+
+AudioChannelLayout getChannelIndexMaskFromChannelCount(unsigned int channelCount) {
+    return findValueOrDefault(getSupportedChannelIndexLayoutMap(), channelCount,
+                              INVALID_CHANNEL_LAYOUT);
+}
+
+unsigned int getChannelCountFromChannelMask(const AudioChannelLayout& channelMask, bool isInput) {
+    switch (channelMask.getTag()) {
+        case AudioChannelLayout::Tag::layoutMask: {
+            return findKeyOrDefault(
+                    isInput ? getSupportedChannelInLayoutMap() : getSupportedChannelOutLayoutMap(),
+                    (unsigned int)getChannelCount(channelMask), 0u /*defaultValue*/);
+        }
+        case AudioChannelLayout::Tag::indexMask: {
+            return findKeyOrDefault(getSupportedChannelIndexLayoutMap(),
+                                    (unsigned int)getChannelCount(channelMask),
+                                    0u /*defaultValue*/);
+        }
+        case AudioChannelLayout::Tag::none:
+        case AudioChannelLayout::Tag::invalid:
+        case AudioChannelLayout::Tag::voiceMask:
+        default:
+            return 0;
+    }
+}
+
+AudioFormatDescription legacy2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy) {
+    return findValueOrDefault(getPcmFormatToAudioFormatDescMap(), legacy, AudioFormatDescription());
+}
+
+pcm_format aidl2legacy_AudioFormatDescription_pcm_format(const AudioFormatDescription& aidl) {
+    return findValueOrDefault(getAudioFormatDescriptorToPcmFormatMap(), aidl, PCM_FORMAT_INVALID);
+}
+
+}  // namespace aidl::android::hardware::audio::core::usb
\ No newline at end of file
diff --git a/audio/aidl/default/usb/UsbAlsaUtils.h b/audio/aidl/default/usb/UsbAlsaUtils.h
new file mode 100644
index 0000000..2d2f0f4
--- /dev/null
+++ b/audio/aidl/default/usb/UsbAlsaUtils.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#pragma once
+
+#include <aidl/android/media/audio/common/AudioChannelLayout.h>
+#include <aidl/android/media/audio/common/AudioFormatDescription.h>
+
+extern "C" {
+#include <tinyalsa/pcm.h>
+}
+
+namespace aidl::android::hardware::audio::core::usb {
+
+::aidl::android::media::audio::common::AudioChannelLayout getChannelLayoutMaskFromChannelCount(
+        unsigned int channelCount, int isInput);
+::aidl::android::media::audio::common::AudioChannelLayout getChannelIndexMaskFromChannelCount(
+        unsigned int channelCount);
+unsigned int getChannelCountFromChannelMask(
+        const ::aidl::android::media::audio::common::AudioChannelLayout& channelMask, bool isInput);
+::aidl::android::media::audio::common::AudioFormatDescription
+legacy2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy);
+pcm_format aidl2legacy_AudioFormatDescription_pcm_format(
+        const ::aidl::android::media::audio::common::AudioFormatDescription& aidl);
+
+}  // namespace aidl::android::hardware::audio::core::usb
\ No newline at end of file