diff --git a/audio/aidl/common/include/Utils.h b/audio/aidl/common/include/Utils.h index 2aaa78162c..d87bbd4934 100644 --- a/audio/aidl/common/include/Utils.h +++ b/audio/aidl/common/include/Utils.h @@ -104,6 +104,30 @@ constexpr bool isTelephonyDeviceType( device == ::aidl::android::media::audio::common::AudioDeviceType::OUT_TELEPHONY_TX; } +constexpr bool isUsbInputDeviceType(::aidl::android::media::audio::common::AudioDeviceType type) { + switch (type) { + case ::aidl::android::media::audio::common::AudioDeviceType::IN_DOCK: + case ::aidl::android::media::audio::common::AudioDeviceType::IN_ACCESSORY: + case ::aidl::android::media::audio::common::AudioDeviceType::IN_DEVICE: + case ::aidl::android::media::audio::common::AudioDeviceType::IN_HEADSET: + return true; + default: + return false; + } +} + +constexpr bool isUsbOutputtDeviceType(::aidl::android::media::audio::common::AudioDeviceType type) { + switch (type) { + case ::aidl::android::media::audio::common::AudioDeviceType::OUT_DOCK: + case ::aidl::android::media::audio::common::AudioDeviceType::OUT_ACCESSORY: + case ::aidl::android::media::audio::common::AudioDeviceType::OUT_DEVICE: + case ::aidl::android::media::audio::common::AudioDeviceType::OUT_HEADSET: + return true; + default: + return false; + } +} + constexpr bool isValidAudioMode(::aidl::android::media::audio::common::AudioMode mode) { return std::find(kValidAudioModes.begin(), kValidAudioModes.end(), mode) != kValidAudioModes.end(); diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp index 856f83f7bb..21616be67d 100644 --- a/audio/aidl/default/Android.bp +++ b/audio/aidl/default/Android.bp @@ -11,12 +11,14 @@ cc_defaults { name: "aidlaudioservice_defaults", vendor: true, shared_libs: [ + "libalsautilsv2", "libaudioaidlcommon", "libbase", "libbinder_ndk", "libcutils", "libfmq", "libstagefright_foundation", + "libtinyalsav2", "libutils", "libxml2", "android.hardware.common-V2-ndk", @@ -71,6 +73,9 @@ cc_library_static { "Stream.cpp", "StreamStub.cpp", "Telephony.cpp", + "usb/ModuleUsb.cpp", + "usb/StreamUsb.cpp", + "usb/UsbAlsaUtils.cpp", ], generated_sources: [ "audio_policy_configuration_aidl_default", diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp index 905ff2ccaa..2f6ab2fe7a 100644 --- a/audio/aidl/default/Module.cpp +++ b/audio/aidl/default/Module.cpp @@ -27,8 +27,10 @@ #include "core-impl/Bluetooth.h" #include "core-impl/Module.h" +#include "core-impl/ModuleUsb.h" #include "core-impl/SoundDose.h" #include "core-impl/StreamStub.h" +#include "core-impl/StreamUsb.h" #include "core-impl/Telephony.h" #include "core-impl/utils.h" @@ -104,6 +106,42 @@ bool findAudioProfile(const AudioPort& port, const AudioFormatDescription& forma } // namespace +// static +std::shared_ptr Module::createInstance(Type type) { + switch (type) { + case Module::Type::USB: + return ndk::SharedRefBase::make(type); + case Type::DEFAULT: + case Type::R_SUBMIX: + default: + return ndk::SharedRefBase::make(type); + } +} + +// static +StreamIn::CreateInstance Module::getStreamInCreator(Type type) { + switch (type) { + case Type::USB: + return StreamInUsb::createInstance; + case Type::DEFAULT: + case Type::R_SUBMIX: + default: + return StreamInStub::createInstance; + } +} + +// static +StreamOut::CreateInstance Module::getStreamOutCreator(Type type) { + switch (type) { + case Type::USB: + return StreamOutUsb::createInstance; + case Type::DEFAULT: + case Type::R_SUBMIX: + default: + return StreamOutStub::createInstance; + } +} + void Module::cleanUpPatch(int32_t patchId) { erase_all_values(mPatches, std::set{patchId}); } @@ -153,6 +191,7 @@ ndk::ScopedAStatus Module::createStreamContext( std::make_unique(1, true /*configureEventFlagWord*/), std::make_unique(1, true /*configureEventFlagWord*/), portConfigIt->format.value(), portConfigIt->channelMask.value(), + portConfigIt->sampleRate.value().value, std::make_unique(frameSize * in_bufferSizeFrames), asyncCallback, outEventCallback, params); if (temp.isValid()) { @@ -261,6 +300,7 @@ internal::Configuration& Module::getConfig() { break; case Type::USB: mConfig = std::move(internal::getUsbConfiguration()); + break; } } return *mConfig; @@ -401,6 +441,8 @@ ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdA if (!mDebug.simulateDeviceConnections) { // In a real HAL here we would attempt querying the profiles from the device. LOG(ERROR) << __func__ << ": failed to query supported device profiles"; + // TODO: Check the return value when it is ready for actual devices. + populateConnectedDevicePort(&connectedPort); return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } @@ -560,10 +602,9 @@ ndk::ScopedAStatus Module::openInputStream(const OpenInputStreamArguments& in_ar } context.fillDescriptor(&_aidl_return->desc); std::shared_ptr stream; - // TODO: Add a mapping from module instance names to a corresponding 'createInstance'. - if (auto status = StreamInStub::createInstance(in_args.sinkMetadata, std::move(context), - mConfig->microphones, &stream); - !status.isOk()) { + ndk::ScopedAStatus status = getStreamInCreator(mType)(in_args.sinkMetadata, std::move(context), + mConfig->microphones, &stream); + if (!status.isOk()) { return status; } StreamWrapper streamWrapper(stream); @@ -615,10 +656,9 @@ ndk::ScopedAStatus Module::openOutputStream(const OpenOutputStreamArguments& in_ } context.fillDescriptor(&_aidl_return->desc); std::shared_ptr stream; - // TODO: Add a mapping from module instance names to a corresponding 'createInstance'. - if (auto status = StreamOutStub::createInstance(in_args.sourceMetadata, std::move(context), - in_args.offloadInfo, &stream); - !status.isOk()) { + ndk::ScopedAStatus status = getStreamOutCreator(mType)( + in_args.sourceMetadata, std::move(context), in_args.offloadInfo, &stream); + if (!status.isOk()) { return status; } StreamWrapper streamWrapper(stream); @@ -696,6 +736,10 @@ ndk::ScopedAStatus Module::setAudioPatch(const AudioPatch& in_requested, AudioPa } } + if (auto status = checkAudioPatchEndpointsMatch(sources, sinks); !status.isOk()) { + return status; + } + auto& patches = getConfig().patches; auto existing = patches.end(); std::optional patchesBackup; @@ -1190,4 +1234,16 @@ bool Module::isMmapSupported() { return mIsMmapSupported.value(); } +ndk::ScopedAStatus Module::populateConnectedDevicePort(AudioPort* audioPort __unused) { + LOG(DEBUG) << __func__ << ": do nothing and return ok"; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Module::checkAudioPatchEndpointsMatch( + const std::vector& sources __unused, + const std::vector& sinks __unused) { + LOG(DEBUG) << __func__ << ": do nothing and return ok"; + return ndk::ScopedAStatus::ok(); +} + } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/StreamStub.cpp b/audio/aidl/default/StreamStub.cpp index 544217992f..85d1e16053 100644 --- a/audio/aidl/default/StreamStub.cpp +++ b/audio/aidl/default/StreamStub.cpp @@ -22,6 +22,7 @@ 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::AudioOffloadInfo; namespace aidl::android::hardware::audio::core { @@ -68,6 +69,11 @@ DriverStub::DriverStub(const StreamContext& context, bool isInput) return ::android::OK; } +::android::status_t DriverStub::setConnectedDevices( + const std::vector& connectedDevices __unused) { + return ::android::OK; +} + // static ndk::ScopedAStatus StreamInStub::createInstance(const SinkMetadata& sinkMetadata, StreamContext&& context, diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h index 80a22dc0e3..fab1c14df1 100644 --- a/audio/aidl/default/include/core-impl/Module.h +++ b/audio/aidl/default/include/core-impl/Module.h @@ -35,6 +35,10 @@ class Module : public BnModule { explicit Module(Type type) : mType(type) {} + static std::shared_ptr createInstance(Type type); + static StreamIn::CreateInstance getStreamInCreator(Type type); + static StreamOut::CreateInstance getStreamOutCreator(Type type); + private: struct VendorDebug { static const std::string kForceTransientBurstName; @@ -163,6 +167,17 @@ class Module : public BnModule { std::shared_ptr mSoundDose; ndk::SpAIBinder mSoundDoseBinder; std::optional mIsMmapSupported; + + protected: + // If the module is unable to populate the connected device port correctly, the returned error + // code must correspond to the errors of `IModule.connectedExternalDevice` method. + virtual ndk::ScopedAStatus populateConnectedDevicePort( + ::aidl::android::media::audio::common::AudioPort* audioPort); + // If the module finds that the patch endpoints configurations are not matched, the returned + // error code must correspond to the errors of `IModule.setAudioPatch` method. + virtual ndk::ScopedAStatus checkAudioPatchEndpointsMatch( + const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources, + const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks); }; } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/ModuleUsb.h b/audio/aidl/default/include/core-impl/ModuleUsb.h new file mode 100644 index 0000000000..7b177e86e1 --- /dev/null +++ b/audio/aidl/default/include/core-impl/ModuleUsb.h @@ -0,0 +1,47 @@ +/* + * 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 "core-impl/Module.h" + +namespace aidl::android::hardware::audio::core { + +class ModuleUsb : public Module { + public: + explicit ModuleUsb(Module::Type type) : Module(type) {} + + private: + // IModule interfaces + ndk::ScopedAStatus getTelephony(std::shared_ptr* _aidl_return) override; + ndk::ScopedAStatus getBluetooth(std::shared_ptr* _aidl_return) override; + ndk::ScopedAStatus getMasterMute(bool* _aidl_return) override; + ndk::ScopedAStatus setMasterMute(bool in_mute) override; + ndk::ScopedAStatus getMasterVolume(float* _aidl_return) override; + ndk::ScopedAStatus setMasterVolume(float in_volume) override; + ndk::ScopedAStatus getMicMute(bool* _aidl_return) override; + ndk::ScopedAStatus setMicMute(bool in_mute) override; + + // Module interfaces + ndk::ScopedAStatus populateConnectedDevicePort( + ::aidl::android::media::audio::common::AudioPort* audioPort) override; + ndk::ScopedAStatus checkAudioPatchEndpointsMatch( + const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources, + const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks) + override; +}; + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h index 7cd4259948..f8c12e6063 100644 --- a/audio/aidl/default/include/core-impl/Stream.h +++ b/audio/aidl/default/include/core-impl/Stream.h @@ -77,7 +77,8 @@ class StreamContext { StreamContext(std::unique_ptr commandMQ, std::unique_ptr replyMQ, const ::aidl::android::media::audio::common::AudioFormatDescription& format, const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout, - std::unique_ptr dataMQ, std::shared_ptr asyncCallback, + int sampleRate, std::unique_ptr dataMQ, + std::shared_ptr asyncCallback, std::shared_ptr outEventCallback, DebugParameters debugParameters) : mCommandMQ(std::move(commandMQ)), @@ -85,6 +86,7 @@ class StreamContext { mReplyMQ(std::move(replyMQ)), mFormat(format), mChannelLayout(channelLayout), + mSampleRate(sampleRate), mDataMQ(std::move(dataMQ)), mAsyncCallback(asyncCallback), mOutEventCallback(outEventCallback), @@ -95,6 +97,7 @@ class StreamContext { mReplyMQ(std::move(other.mReplyMQ)), mFormat(other.mFormat), mChannelLayout(other.mChannelLayout), + mSampleRate(other.mSampleRate), mDataMQ(std::move(other.mDataMQ)), mAsyncCallback(std::move(other.mAsyncCallback)), mOutEventCallback(std::move(other.mOutEventCallback)), @@ -105,6 +108,7 @@ class StreamContext { mReplyMQ = std::move(other.mReplyMQ); mFormat = std::move(other.mFormat); mChannelLayout = std::move(other.mChannelLayout); + mSampleRate = other.mSampleRate; mDataMQ = std::move(other.mDataMQ); mAsyncCallback = std::move(other.mAsyncCallback); mOutEventCallback = std::move(other.mOutEventCallback); @@ -131,6 +135,7 @@ class StreamContext { } ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); } int getTransientStateDelayMs() const { return mDebugParameters.transientStateDelayMs; } + int getSampleRate() const { return mSampleRate; } bool isValid() const; void reset(); @@ -140,6 +145,7 @@ class StreamContext { std::unique_ptr mReplyMQ; ::aidl::android::media::audio::common::AudioFormatDescription mFormat; ::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout; + int mSampleRate; std::unique_ptr mDataMQ; std::shared_ptr mAsyncCallback; std::shared_ptr mOutEventCallback; // Only used by output streams @@ -151,6 +157,11 @@ struct DriverInterface { virtual ~DriverInterface() = default; // This function is called once, on the main thread, before starting the worker thread. virtual ::android::status_t init() = 0; + // This function is called from Binder pool thread. It must be done in a thread-safe manner + // if this method and other methods in this interface share data. + virtual ::android::status_t setConnectedDevices( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& + connectedDevices) = 0; // All the functions below are called on the worker thread. virtual ::android::status_t drain(StreamDescriptor::DrainMode mode) = 0; virtual ::android::status_t flush() = 0; @@ -370,6 +381,7 @@ class StreamCommonImpl : public StreamCommonInterface { const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) { mWorker->setIsConnected(!devices.empty()); mConnectedDevices = devices; + mDriver->setConnectedDevices(devices); } ndk::ScopedAStatus updateMetadata(const Metadata& metadata); diff --git a/audio/aidl/default/include/core-impl/StreamStub.h b/audio/aidl/default/include/core-impl/StreamStub.h index 98a062a02e..aea9da5696 100644 --- a/audio/aidl/default/include/core-impl/StreamStub.h +++ b/audio/aidl/default/include/core-impl/StreamStub.h @@ -24,6 +24,9 @@ class DriverStub : public DriverInterface { public: DriverStub(const StreamContext& context, bool isInput); ::android::status_t init() override; + ::android::status_t setConnectedDevices( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& connectedDevices) + override; ::android::status_t drain(StreamDescriptor::DrainMode) override; ::android::status_t flush() override; ::android::status_t pause() override; diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h new file mode 100644 index 0000000000..8ac1f34f2c --- /dev/null +++ b/audio/aidl/default/include/core-impl/StreamUsb.h @@ -0,0 +1,94 @@ +/* + * 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 + +#include + +#include "core-impl/Stream.h" + +extern "C" { +#include +#include "alsa_device_proxy.h" +} + +namespace aidl::android::hardware::audio::core { + +class DriverUsb : public DriverInterface { + public: + DriverUsb(const StreamContext& context, bool isInput); + ::android::status_t init() override; + ::android::status_t setConnectedDevices( + const std::vector<::aidl::android::media::audio::common::AudioDevice>& connectedDevices) + override; + ::android::status_t drain(StreamDescriptor::DrainMode) override; + ::android::status_t flush() override; + ::android::status_t pause() override; + ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, + int32_t* latencyMs) override; + ::android::status_t standby() override; + + private: + ::android::status_t exitStandby(); + + std::mutex mLock; + + const size_t mFrameSizeBytes; + std::optional mConfig; + const bool mIsInput; + // Cached device addresses for connected devices. + std::vector<::aidl::android::media::audio::common::AudioDeviceAddress> mConnectedDevices + GUARDED_BY(mLock); + std::vector> mAlsaDeviceProxies GUARDED_BY(mLock); + bool mIsStandby = false; +}; + +class StreamInUsb final : public StreamIn { + ndk::ScopedAStatus getActiveMicrophones( + std::vector* _aidl_return) override; + + public: + static ndk::ScopedAStatus createInstance( + const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, + StreamContext&& context, const std::vector& microphones, + std::shared_ptr* result); + + private: + friend class ndk::SharedRefBase; + StreamInUsb(const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata, + StreamContext&& context, const std::vector& microphones); +}; + +class StreamOutUsb final : public StreamOut { + public: + static ndk::ScopedAStatus createInstance( + const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, + StreamContext&& context, + const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& + offloadInfo, + std::shared_ptr* result); + + private: + friend class ndk::SharedRefBase; + StreamOutUsb(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata, + StreamContext&& context, + const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>& + offloadInfo); +}; + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/utils.h b/audio/aidl/default/include/core-impl/utils.h index 9d06f08679..ae33227068 100644 --- a/audio/aidl/default/include/core-impl/utils.h +++ b/audio/aidl/default/include/core-impl/utils.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include @@ -101,4 +102,21 @@ std::vector selectByIds(std::vector& v, const std::vector& ids, return result; } +// Assuming that M is a map whose keys' type is K and values' type is V, +// return the corresponding value of the given key from the map or default +// value if the key is not found. +template +auto findValueOrDefault(const M& m, const K& key, V defaultValue) { + auto it = m.find(key); + return it == m.end() ? defaultValue : it->second; +} + +// Assuming that M is a map whose keys' type is K, return the given key if it +// is found from the map or default value. +template +auto findKeyOrDefault(const M& m, const K& key, K defaultValue) { + auto it = m.find(key); + return it == m.end() ? defaultValue : key; +} + } // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/main.cpp b/audio/aidl/default/main.cpp index 1933509c38..aeca8bcedd 100644 --- a/audio/aidl/default/main.cpp +++ b/audio/aidl/default/main.cpp @@ -25,9 +25,11 @@ #include "core-impl/Config.h" #include "core-impl/Module.h" +#include "core-impl/ModuleUsb.h" using aidl::android::hardware::audio::core::Config; using aidl::android::hardware::audio::core::Module; +using aidl::android::hardware::audio::core::ModuleUsb; int main() { // Random values are used in the implementation. @@ -46,7 +48,7 @@ int main() { // Make modules auto createModule = [](Module::Type type, const std::string& instance) { - auto module = ndk::SharedRefBase::make(type); + auto module = Module::createInstance(type); ndk::SpAIBinder moduleBinder = module->asBinder(); const std::string moduleName = std::string(Module::descriptor).append("/").append(instance); AIBinder_setMinSchedulerPolicy(moduleBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO); diff --git a/audio/aidl/default/usb/ModuleUsb.cpp b/audio/aidl/default/usb/ModuleUsb.cpp new file mode 100644 index 0000000000..e8034209d8 --- /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 + +#include +#include +#include + +#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 populateChannelMasksFromProfile(const alsa_device_profile* profile, + bool isInput) { + std::vector 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 populateSampleRatesFromProfile(const alsa_device_profile* profile) { + std::vector 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* _aidl_return) { + *_aidl_return = nullptr; + LOG(DEBUG) << __func__ << ": returning null"; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus ModuleUsb::getBluetooth(std::shared_ptr* _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(); + 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(); + 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 channels = populateChannelMasksFromProfile(&profile, isInput); + std::vector 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& sources, const std::vector& 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 0000000000..22e36ac76f --- /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 + +#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& 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> 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 connectedDevices; + { + std::lock_guard guard(mLock); + connectedDevices = mConnectedDevices; + } + std::vector> alsaDeviceProxies; + for (const auto& device : connectedDevices) { + alsa_device_profile profile; + profile.card = device.get()[0]; + profile.device = device.get()[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(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& microphones, + std::shared_ptr* result) { + std::shared_ptr stream = + ndk::SharedRefBase::make(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& 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* _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& offloadInfo, + std::shared_ptr* result) { + if (offloadInfo.has_value()) { + LOG(ERROR) << __func__ << ": offload is not supported"; + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + std::shared_ptr stream = + ndk::SharedRefBase::make(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& 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 0000000000..3c79e1dfc0 --- /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 +#include + +#include +#include +#include + +#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; +using AudioFormatDescToPcmFormatMap = std::map; +using PcmFormatToAudioFormatDescMap = std::map; + +static const AudioChannelLayout INVALID_CHANNEL_LAYOUT = + AudioChannelLayout::make(0); + +#define DEFINE_CHANNEL_LAYOUT_MASK(n) \ + AudioChannelLayout::make(AudioChannelLayout::LAYOUT_##n) + +static const std::set 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 SUPPORTED_IN_CHANNEL_LAYOUTS = { + DEFINE_CHANNEL_LAYOUT_MASK(MONO), + DEFINE_CHANNEL_LAYOUT_MASK(STEREO), +}; + +#define DEFINE_CHANNEL_INDEX_MASK(n) \ + AudioChannelLayout::make(AudioChannelLayout::INDEX_MASK_##n) + +static const std::set 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& 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 0000000000..2d2f0f4342 --- /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 +#include + +extern "C" { +#include +} + +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