audio: Move tinyALSA-specific code to Module/StreamAlsa

Extract code interacting with tinyALSA which is not
specific to USB into "abstract" module and stream
implementations ModuleAlsa and StreamAlsa. Also, move
utility code which does not need module or stream
context into Utils.

This facilitates implementation of the CF core HAL which
also uses tinyALSA, allowing to share common code.

Bug: 264712385
Test: atest VtsHalAudioCoreTargetTest

Change-Id: I2134b15e970c78e8a48b254e15199b8207a8ab34
diff --git a/audio/aidl/default/usb/ModuleUsb.cpp b/audio/aidl/default/usb/ModuleUsb.cpp
index 5c9d477..a812e4d 100644
--- a/audio/aidl/default/usb/ModuleUsb.cpp
+++ b/audio/aidl/default/usb/ModuleUsb.cpp
@@ -14,68 +14,34 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AHAL_ModuleUsb"
-
 #include <vector>
 
+#define LOG_TAG "AHAL_ModuleUsb"
 #include <Utils.h>
 #include <android-base/logging.h>
-#include <tinyalsa/asoundlib.h>
 
 #include "UsbAlsaMixerControl.h"
-#include "UsbAlsaUtils.h"
+#include "alsa/Utils.h"
 #include "core-impl/ModuleUsb.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::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::AudioIoFlags;
 using aidl::android::media::audio::common::AudioOffloadInfo;
 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 aidl::android::media::audio::common::MicrophoneInfo;
 
 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;
+bool isUsbDevicePort(const AudioPort& audioPort) {
+    return audioPort.ext.getTag() == AudioPortExt::Tag::device &&
+           audioPort.ext.get<AudioPortExt::Tag::device>().device.type.connection ==
+                   AudioDeviceDescription::CONNECTION_USB;
 }
 
 }  // namespace
@@ -122,55 +88,11 @@
 }
 
 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) {
+    if (!isUsbDevicePort(*audioPort)) {
         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 = audioPort->flags.getTag() == AudioIoFlags::input;
-    alsa_device_profile profile;
-    profile_init(&profile, isInput ? PCM_IN : PCM_OUT);
-    profile.card = alsaAddress[0];
-    profile.device = alsaAddress[1];
-    if (!profile_read_device_info(&profile)) {
-        LOG(ERROR) << __func__ << ": failed to read device info, card=" << profile.card
-                   << ", device=" << profile.device;
-        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] != PCM_FORMAT_INVALID;
-         ++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();
+    return ModuleAlsa::populateConnectedDevicePort(audioPort);
 }
 
 ndk::ScopedAStatus ModuleUsb::checkAudioPatchEndpointsMatch(
@@ -191,15 +113,14 @@
 
 void ModuleUsb::onExternalDeviceConnectionChanged(
         const ::aidl::android::media::audio::common::AudioPort& audioPort, bool connected) {
-    if (audioPort.ext.getTag() != AudioPortExt::Tag::device) {
+    if (!isUsbDevicePort(audioPort)) {
         return;
     }
-    const auto& address = audioPort.ext.get<AudioPortExt::Tag::device>().device.address;
-    if (address.getTag() != AudioDeviceAddress::alsa) {
+    auto profile = alsa::getDeviceProfile(audioPort);
+    if (!profile.has_value()) {
         return;
     }
-    const int card = address.get<AudioDeviceAddress::alsa>()[0];
-    usb::UsbAlsaMixerControl::getInstance().setDeviceConnectionState(card, getMasterMute(),
+    usb::UsbAlsaMixerControl::getInstance().setDeviceConnectionState(profile->card, getMasterMute(),
                                                                      getMasterVolume(), connected);
 }
 
diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp
index 17e1ab4..da0ad11 100644
--- a/audio/aidl/default/usb/StreamUsb.cpp
+++ b/audio/aidl/default/usb/StreamUsb.cpp
@@ -23,64 +23,20 @@
 #include <error/expected_utils.h>
 
 #include "UsbAlsaMixerControl.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::getChannelCount;
 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;
-using aidl::android::media::audio::common::AudioPortExt;
 using aidl::android::media::audio::common::MicrophoneDynamicInfo;
 using aidl::android::media::audio::common::MicrophoneInfo;
-using android::OK;
-using android::status_t;
 
 namespace aidl::android::hardware::audio::core {
 
 StreamUsb::StreamUsb(const Metadata& metadata, StreamContext&& context)
-    : StreamCommonImpl(metadata, std::move(context)),
-      mFrameSizeBytes(getContext().getFrameSize()),
-      mIsInput(isInput(metadata)),
-      mConfig(maybePopulateConfig(getContext(), mIsInput)) {}
-
-// static
-std::optional<struct pcm_config> StreamUsb::maybePopulateConfig(const StreamContext& context,
-                                                                bool 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 std::nullopt;
-    }
-    config.format = usb::aidl2legacy_AudioFormatDescription_pcm_format(context.getFormat());
-    if (config.format == PCM_FORMAT_INVALID) {
-        LOG(ERROR) << __func__ << ": invalid format=" << context.getFormat().toString();
-        return std::nullopt;
-    }
-    config.rate = context.getSampleRate();
-    if (config.rate == 0) {
-        LOG(ERROR) << __func__ << ": invalid sample rate=" << config.rate;
-        return std::nullopt;
-    }
-    return config;
-}
-
-::android::status_t StreamUsb::init() {
-    return mConfig.has_value() ? ::android::OK : ::android::NO_INIT;
-}
-
-const StreamCommonInterface::ConnectedDevices& StreamUsb::getConnectedDevices() const {
-    std::lock_guard guard(mLock);
-    return mConnectedDevices;
-}
+    : StreamAlsa(metadata, std::move(context)) {}
 
 ndk::ScopedAStatus StreamUsb::setConnectedDevices(
         const std::vector<AudioDevice>& connectedDevices) {
@@ -89,14 +45,19 @@
                    << ") for input stream";
         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
     }
+    std::vector<alsa::DeviceProfile> connectedDeviceProfiles;
     for (const auto& connectedDevice : connectedDevices) {
-        if (connectedDevice.address.getTag() != AudioDeviceAddress::alsa) {
-            LOG(ERROR) << __func__ << ": bad device address" << connectedDevice.address.toString();
+        auto profile = alsa::getDeviceProfile(connectedDevice, mIsInput);
+        if (!profile.has_value()) {
+            LOG(ERROR) << __func__
+                       << ": unsupported device address=" << connectedDevice.address.toString();
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
         }
+        connectedDeviceProfiles.push_back(*profile);
     }
-    std::lock_guard guard(mLock);
     RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices));
+    std::lock_guard guard(mLock);
+    mConnectedDeviceProfiles = std::move(connectedDeviceProfiles);
     mConnectedDevicesUpdated.store(true, std::memory_order_release);
     return ndk::ScopedAStatus::ok();
 }
@@ -119,87 +80,22 @@
 ::android::status_t StreamUsb::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
                                         int32_t* latencyMs) {
     if (mConnectedDevicesUpdated.load(std::memory_order_acquire)) {
-        // 'setConnectedDevices' has been called. I/O will be restarted.
+        // 'setConnectedDevices' was called. I/O will be restarted.
         *actualFrameCount = 0;
         *latencyMs = StreamDescriptor::LATENCY_UNKNOWN;
         return ::android::OK;
     }
-    const size_t bytesToTransfer = frameCount * mFrameSizeBytes;
-    unsigned maxLatency = 0;
-    if (mIsInput) {
-        if (mAlsaDeviceProxies.empty()) {
-            LOG(FATAL) << __func__ << ": no input devices";
-            return ::android::NO_INIT;
-        }
-        // For input case, only support single device.
-        proxy_read(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer);
-        maxLatency = proxy_get_latency(mAlsaDeviceProxies[0].get());
-    } else {
-        for (auto& proxy : mAlsaDeviceProxies) {
-            proxy_write(proxy.get(), buffer, bytesToTransfer);
-            maxLatency = std::max(maxLatency, proxy_get_latency(proxy.get()));
-        }
-    }
-    *actualFrameCount = frameCount;
-    maxLatency = std::min(maxLatency, static_cast<unsigned>(std::numeric_limits<int32_t>::max()));
-    *latencyMs = maxLatency;
-    return ::android::OK;
+    return StreamAlsa::transfer(buffer, frameCount, actualFrameCount, latencyMs);
 }
 
-::android::status_t StreamUsb::standby() {
-    mAlsaDeviceProxies.clear();
-    return ::android::OK;
-}
-
-void StreamUsb::shutdown() {
-    mAlsaDeviceProxies.clear();
-}
-
-::android::status_t StreamUsb::start() {
-    std::vector<AudioDeviceAddress> connectedDevices;
+std::vector<alsa::DeviceProfile> StreamUsb::getDeviceProfiles() {
+    std::vector<alsa::DeviceProfile> connectedDevices;
     {
         std::lock_guard guard(mLock);
-        std::transform(mConnectedDevices.begin(), mConnectedDevices.end(),
-                       std::back_inserter(connectedDevices),
-                       [](const auto& device) { return device.address; });
+        connectedDevices = mConnectedDeviceProfiles;
         mConnectedDevicesUpdated.store(false, std::memory_order_release);
     }
-    decltype(mAlsaDeviceProxies) alsaDeviceProxies;
-    for (const auto& device : connectedDevices) {
-        alsa_device_profile profile;
-        profile_init(&profile, mIsInput ? PCM_IN : PCM_OUT);
-        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;
-        }
-
-        AlsaDeviceProxy 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,
-                                    const_cast<struct pcm_config*>(&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;
-        }
-        if (int err = proxy_open(proxy.get()); err != 0) {
-            LOG(ERROR) << __func__ << ": failed to open device, address=" << device.toString()
-                       << " error=" << err;
-            return ::android::UNKNOWN_ERROR;
-        }
-        alsaDeviceProxies.push_back(std::move(proxy));
-    }
-    mAlsaDeviceProxies = std::move(alsaDeviceProxies);
-    return ::android::OK;
+    return connectedDevices;
 }
 
 StreamInUsb::StreamInUsb(const SinkMetadata& sinkMetadata, StreamContext&& context,
@@ -214,9 +110,9 @@
 
 StreamOutUsb::StreamOutUsb(const SourceMetadata& sourceMetadata, StreamContext&& context,
                            const std::optional<AudioOffloadInfo>& offloadInfo)
-    : StreamUsb(sourceMetadata, std::move(context)), StreamOut(offloadInfo) {
-    mChannelCount = getChannelCount(getContext().getChannelLayout());
-}
+    : StreamUsb(sourceMetadata, std::move(context)),
+      StreamOut(offloadInfo),
+      mChannelCount(getChannelCount(getContext().getChannelLayout())) {}
 
 ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector<float>* _aidl_return) {
     *_aidl_return = mHwVolumes;
@@ -224,17 +120,17 @@
 }
 
 ndk::ScopedAStatus StreamOutUsb::setHwVolume(const std::vector<float>& in_channelVolumes) {
+    // Avoid using mConnectedDeviceProfiles because it requires a lock.
     for (const auto& device : getConnectedDevices()) {
-        if (device.address.getTag() != AudioDeviceAddress::alsa) {
-            LOG(DEBUG) << __func__ << ": skip as the device address is not alsa";
-            continue;
-        }
-        const int card = device.address.get<AudioDeviceAddress::alsa>()[0];
-        if (auto result =
-                    usb::UsbAlsaMixerControl::getInstance().setVolumes(card, in_channelVolumes);
-            !result.isOk()) {
-            LOG(ERROR) << __func__ << ": failed to set volume for device, card=" << card;
-            return result;
+        if (auto deviceProfile = alsa::getDeviceProfile(device, mIsInput);
+            deviceProfile.has_value()) {
+            if (auto result = usb::UsbAlsaMixerControl::getInstance().setVolumes(
+                        deviceProfile->card, in_channelVolumes);
+                !result.isOk()) {
+                LOG(ERROR) << __func__
+                           << ": failed to set volume for device address=" << *deviceProfile;
+                return result;
+            }
         }
     }
     mHwVolumes = in_channelVolumes;
diff --git a/audio/aidl/default/usb/UsbAlsaMixerControl.cpp b/audio/aidl/default/usb/UsbAlsaMixerControl.cpp
index 6c0c24b..769d739 100644
--- a/audio/aidl/default/usb/UsbAlsaMixerControl.cpp
+++ b/audio/aidl/default/usb/UsbAlsaMixerControl.cpp
@@ -17,144 +17,12 @@
 #define LOG_TAG "AHAL_UsbAlsaMixerControl"
 #include <android-base/logging.h>
 
-#include <cmath>
-#include <string>
-#include <vector>
-
 #include <android/binder_status.h>
 
 #include "UsbAlsaMixerControl.h"
 
 namespace aidl::android::hardware::audio::core::usb {
 
-//-----------------------------------------------------------------------------
-
-MixerControl::MixerControl(struct mixer_ctl* ctl)
-    : mCtl(ctl),
-      mNumValues(mixer_ctl_get_num_values(ctl)),
-      mMinValue(mixer_ctl_get_range_min(ctl)),
-      mMaxValue(mixer_ctl_get_range_max(ctl)) {}
-
-unsigned int MixerControl::getNumValues() const {
-    return mNumValues;
-}
-
-int MixerControl::getMaxValue() const {
-    return mMaxValue;
-}
-
-int MixerControl::getMinValue() const {
-    return mMinValue;
-}
-
-int MixerControl::setArray(const void* array, size_t count) {
-    const std::lock_guard guard(mLock);
-    return mixer_ctl_set_array(mCtl, array, count);
-}
-
-//-----------------------------------------------------------------------------
-
-// static
-const std::map<AlsaMixer::Control, std::vector<AlsaMixer::ControlNamesAndExpectedCtlType>>
-        AlsaMixer::kPossibleControls = {
-                {AlsaMixer::MASTER_SWITCH, {{"Master Playback Switch", MIXER_CTL_TYPE_BOOL}}},
-                {AlsaMixer::MASTER_VOLUME, {{"Master Playback Volume", MIXER_CTL_TYPE_INT}}},
-                {AlsaMixer::HW_VOLUME,
-                 {{"Headphone Playback Volume", MIXER_CTL_TYPE_INT},
-                  {"Headset Playback Volume", MIXER_CTL_TYPE_INT},
-                  {"PCM Playback Volume", MIXER_CTL_TYPE_INT}}}};
-
-// static
-std::map<AlsaMixer::Control, std::shared_ptr<MixerControl>> AlsaMixer::initializeMixerControls(
-        struct mixer* mixer) {
-    std::map<AlsaMixer::Control, std::shared_ptr<MixerControl>> mixerControls;
-    std::string mixerCtlNames;
-    for (const auto& [control, possibleCtls] : kPossibleControls) {
-        for (const auto& [ctlName, expectedCtlType] : possibleCtls) {
-            struct mixer_ctl* ctl = mixer_get_ctl_by_name(mixer, ctlName.c_str());
-            if (ctl != nullptr && mixer_ctl_get_type(ctl) == expectedCtlType) {
-                mixerControls.emplace(control, std::make_unique<MixerControl>(ctl));
-                if (!mixerCtlNames.empty()) {
-                    mixerCtlNames += ",";
-                }
-                mixerCtlNames += ctlName;
-                break;
-            }
-        }
-    }
-    LOG(DEBUG) << __func__ << ": available mixer control names=[" << mixerCtlNames << "]";
-    return mixerControls;
-}
-
-AlsaMixer::AlsaMixer(struct mixer* mixer)
-    : mMixer(mixer), mMixerControls(initializeMixerControls(mMixer)) {}
-
-AlsaMixer::~AlsaMixer() {
-    mixer_close(mMixer);
-}
-
-namespace {
-
-int volumeFloatToInteger(float fValue, int maxValue, int minValue) {
-    return minValue + std::ceil((maxValue - minValue) * fValue);
-}
-
-}  // namespace
-
-ndk::ScopedAStatus AlsaMixer::setMasterMute(bool muted) {
-    auto it = mMixerControls.find(AlsaMixer::MASTER_SWITCH);
-    if (it == mMixerControls.end()) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
-    }
-    const int numValues = it->second->getNumValues();
-    std::vector<int> values(numValues, muted ? 0 : 1);
-    if (int err = it->second->setArray(values.data(), numValues); err != 0) {
-        LOG(ERROR) << __func__ << ": failed to set master mute, err=" << err;
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-    }
-    return ndk::ScopedAStatus::ok();
-}
-
-ndk::ScopedAStatus AlsaMixer::setMasterVolume(float volume) {
-    auto it = mMixerControls.find(AlsaMixer::MASTER_VOLUME);
-    if (it == mMixerControls.end()) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
-    }
-    const int numValues = it->second->getNumValues();
-    std::vector<int> values(numValues, volumeFloatToInteger(volume, it->second->getMaxValue(),
-                                                            it->second->getMinValue()));
-    if (int err = it->second->setArray(values.data(), numValues); err != 0) {
-        LOG(ERROR) << __func__ << ": failed to set master volume, err=" << err;
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-    }
-    return ndk::ScopedAStatus::ok();
-}
-
-ndk::ScopedAStatus AlsaMixer::setVolumes(std::vector<float> volumes) {
-    auto it = mMixerControls.find(AlsaMixer::HW_VOLUME);
-    if (it == mMixerControls.end()) {
-        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
-    }
-    const int numValues = it->second->getNumValues();
-    if (numValues < 0) {
-        LOG(FATAL) << __func__ << ": negative number of values: " << numValues;
-    }
-    const int maxValue = it->second->getMaxValue();
-    const int minValue = it->second->getMinValue();
-    std::vector<int> values;
-    size_t i = 0;
-    for (; i < static_cast<size_t>(numValues) && i < values.size(); ++i) {
-        values.emplace_back(volumeFloatToInteger(volumes[i], maxValue, minValue));
-    }
-    if (int err = it->second->setArray(values.data(), values.size()); err != 0) {
-        LOG(ERROR) << __func__ << ": failed to set volume, err=" << err;
-        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
-    }
-    return ndk::ScopedAStatus::ok();
-}
-
-//-----------------------------------------------------------------------------
-
 // static
 UsbAlsaMixerControl& UsbAlsaMixerControl::getInstance() {
     static UsbAlsaMixerControl gInstance;
@@ -170,7 +38,7 @@
             PLOG(ERROR) << __func__ << ": failed to open mixer for card=" << card;
             return;
         }
-        auto alsaMixer = std::make_shared<AlsaMixer>(mixer);
+        auto alsaMixer = std::make_shared<alsa::Mixer>(mixer);
         alsaMixer->setMasterMute(masterMuted);
         alsaMixer->setMasterVolume(masterVolume);
         const std::lock_guard guard(mLock);
@@ -209,7 +77,7 @@
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus UsbAlsaMixerControl::setVolumes(int card, std::vector<float> volumes) {
+ndk::ScopedAStatus UsbAlsaMixerControl::setVolumes(int card, const std::vector<float>& volumes) {
     auto alsaMixer = getAlsaMixer(card);
     if (alsaMixer == nullptr) {
         LOG(ERROR) << __func__ << ": no mixer control found for card=" << card;
@@ -218,13 +86,13 @@
     return alsaMixer->setVolumes(volumes);
 }
 
-std::shared_ptr<AlsaMixer> UsbAlsaMixerControl::getAlsaMixer(int card) {
+std::shared_ptr<alsa::Mixer> UsbAlsaMixerControl::getAlsaMixer(int card) {
     const std::lock_guard guard(mLock);
     const auto it = mMixerControls.find(card);
     return it == mMixerControls.end() ? nullptr : it->second;
 }
 
-std::map<int, std::shared_ptr<AlsaMixer>> UsbAlsaMixerControl::getAlsaMixers() {
+std::map<int, std::shared_ptr<alsa::Mixer>> UsbAlsaMixerControl::getAlsaMixers() {
     const std::lock_guard guard(mLock);
     return mMixerControls;
 }
diff --git a/audio/aidl/default/usb/UsbAlsaMixerControl.h b/audio/aidl/default/usb/UsbAlsaMixerControl.h
index cbcddd8..c3265f8 100644
--- a/audio/aidl/default/usb/UsbAlsaMixerControl.h
+++ b/audio/aidl/default/usb/UsbAlsaMixerControl.h
@@ -19,67 +19,15 @@
 #include <map>
 #include <memory>
 #include <mutex>
-#include <optional>
-#include <string>
 #include <vector>
 
 #include <android-base/thread_annotations.h>
 #include <android/binder_auto_utils.h>
 
-extern "C" {
-#include <tinyalsa/mixer.h>
-}
+#include "alsa/Mixer.h"
 
 namespace aidl::android::hardware::audio::core::usb {
 
-class MixerControl {
-  public:
-    explicit MixerControl(struct mixer_ctl* ctl);
-
-    unsigned int getNumValues() const;
-    int getMaxValue() const;
-    int getMinValue() const;
-    int setArray(const void* array, size_t count);
-
-  private:
-    std::mutex mLock;
-    // The mixer_ctl object is owned by ALSA and will be released when the mixer is closed.
-    struct mixer_ctl* mCtl GUARDED_BY(mLock);
-    const unsigned int mNumValues;
-    const int mMinValue;
-    const int mMaxValue;
-};
-
-class AlsaMixer {
-  public:
-    explicit AlsaMixer(struct mixer* mixer);
-
-    ~AlsaMixer();
-
-    bool isValid() const { return mMixer != nullptr; }
-
-    ndk::ScopedAStatus setMasterMute(bool muted);
-    ndk::ScopedAStatus setMasterVolume(float volume);
-    ndk::ScopedAStatus setVolumes(std::vector<float> volumes);
-
-  private:
-    enum Control {
-        MASTER_SWITCH,
-        MASTER_VOLUME,
-        HW_VOLUME,
-    };
-    using ControlNamesAndExpectedCtlType = std::pair<std::string, enum mixer_ctl_type>;
-    static const std::map<Control, std::vector<ControlNamesAndExpectedCtlType>> kPossibleControls;
-    static std::map<Control, std::shared_ptr<MixerControl>> initializeMixerControls(
-            struct mixer* mixer);
-
-    // The mixer object is owned by ALSA and will be released when the mixer is closed.
-    struct mixer* mMixer;
-    // `mMixerControls` will only be initialized in constructor. After that, it wil only be
-    // read but not be modified.
-    const std::map<Control, std::shared_ptr<MixerControl>> mMixerControls;
-};
-
 class UsbAlsaMixerControl {
   public:
     static UsbAlsaMixerControl& getInstance();
@@ -91,16 +39,16 @@
     ndk::ScopedAStatus setMasterMute(bool muted);
     ndk::ScopedAStatus setMasterVolume(float volume);
     // The volume settings can be different on sound cards. It is controlled by streams.
-    ndk::ScopedAStatus setVolumes(int card, std::vector<float> volumes);
+    ndk::ScopedAStatus setVolumes(int card, const std::vector<float>& volumes);
 
   private:
-    std::shared_ptr<AlsaMixer> getAlsaMixer(int card);
-    std::map<int, std::shared_ptr<AlsaMixer>> getAlsaMixers();
+    std::shared_ptr<alsa::Mixer> getAlsaMixer(int card);
+    std::map<int, std::shared_ptr<alsa::Mixer>> getAlsaMixers();
 
     std::mutex mLock;
     // A map whose key is the card number and value is a shared pointer to corresponding
     // AlsaMixer object.
-    std::map<int, std::shared_ptr<AlsaMixer>> mMixerControls GUARDED_BY(mLock);
+    std::map<int, std::shared_ptr<alsa::Mixer>> mMixerControls GUARDED_BY(mLock);
 };
 
 }  // namespace aidl::android::hardware::audio::core::usb
diff --git a/audio/aidl/default/usb/UsbAlsaUtils.cpp b/audio/aidl/default/usb/UsbAlsaUtils.cpp
deleted file mode 100644
index 74d9c28..0000000
--- a/audio/aidl/default/usb/UsbAlsaUtils.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * 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::hardware::audio::common::getChannelCount;
-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;
-
-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::FIXED_Q_8_24), PCM_FORMAT_S24_LE},
-            {make_AudioFormatDescription(PcmType::INT_24_BIT), 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
diff --git a/audio/aidl/default/usb/UsbAlsaUtils.h b/audio/aidl/default/usb/UsbAlsaUtils.h
deleted file mode 100644
index 2d2f0f4..0000000
--- a/audio/aidl/default/usb/UsbAlsaUtils.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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