AOSP AIDL USB audio HAL implementation.

Bug: 266216550
Test: atest VtsHalAudioCoreTargetTest
Change-Id: I82e053d3f6a918cafe0d43b030f724f63a99eb2a
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