From a4513dcf05154e8db981ef83d99401c6a9af01e2 Mon Sep 17 00:00:00 2001 From: Mikhail Naganov Date: Fri, 7 Jul 2023 12:01:17 -0700 Subject: [PATCH] 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 (cherry picked from commit c337a8799b8cc3029aaee2addee9c4212e812b3c) Merged-In: I2134b15e970c78e8a48b254e15199b8207a8ab34 --- audio/aidl/default/Android.bp | 5 +- audio/aidl/default/alsa/Mixer.cpp | 154 +++++++++ audio/aidl/default/alsa/Mixer.h | 82 +++++ audio/aidl/default/alsa/ModuleAlsa.cpp | 67 ++++ audio/aidl/default/alsa/StreamAlsa.cpp | 103 ++++++ audio/aidl/default/alsa/Utils.cpp | 293 ++++++++++++++++++ audio/aidl/default/alsa/Utils.h | 70 +++++ .../default/include/core-impl/ModuleAlsa.h | 38 +++ .../default/include/core-impl/ModuleUsb.h | 6 +- .../default/include/core-impl/StreamAlsa.h | 54 ++++ .../default/include/core-impl/StreamUsb.h | 33 +- audio/aidl/default/usb/ModuleUsb.cpp | 103 +----- audio/aidl/default/usb/StreamUsb.cpp | 160 ++-------- .../aidl/default/usb/UsbAlsaMixerControl.cpp | 140 +-------- audio/aidl/default/usb/UsbAlsaMixerControl.h | 62 +--- audio/aidl/default/usb/UsbAlsaUtils.cpp | 181 ----------- audio/aidl/default/usb/UsbAlsaUtils.h | 39 --- 17 files changed, 923 insertions(+), 667 deletions(-) create mode 100644 audio/aidl/default/alsa/Mixer.cpp create mode 100644 audio/aidl/default/alsa/Mixer.h create mode 100644 audio/aidl/default/alsa/ModuleAlsa.cpp create mode 100644 audio/aidl/default/alsa/StreamAlsa.cpp create mode 100644 audio/aidl/default/alsa/Utils.cpp create mode 100644 audio/aidl/default/alsa/Utils.h create mode 100644 audio/aidl/default/include/core-impl/ModuleAlsa.h create mode 100644 audio/aidl/default/include/core-impl/StreamAlsa.h delete mode 100644 audio/aidl/default/usb/UsbAlsaUtils.cpp delete mode 100644 audio/aidl/default/usb/UsbAlsaUtils.h diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp index 78b59d4efe..69443d4194 100644 --- a/audio/aidl/default/Android.bp +++ b/audio/aidl/default/Android.bp @@ -77,6 +77,10 @@ cc_library { "Stream.cpp", "StreamStub.cpp", "Telephony.cpp", + "alsa/Mixer.cpp", + "alsa/ModuleAlsa.cpp", + "alsa/StreamAlsa.cpp", + "alsa/Utils.cpp", "r_submix/ModuleRemoteSubmix.cpp", "r_submix/RemoteSubmixUtils.cpp", "r_submix/SubmixRoute.cpp", @@ -84,7 +88,6 @@ cc_library { "usb/ModuleUsb.cpp", "usb/StreamUsb.cpp", "usb/UsbAlsaMixerControl.cpp", - "usb/UsbAlsaUtils.cpp", ], generated_sources: [ "audio_policy_configuration_aidl_default", diff --git a/audio/aidl/default/alsa/Mixer.cpp b/audio/aidl/default/alsa/Mixer.cpp new file mode 100644 index 0000000000..f0393e3a7e --- /dev/null +++ b/audio/aidl/default/alsa/Mixer.cpp @@ -0,0 +1,154 @@ +/* + * 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_AlsaMixer" +#include + +#include + +#include + +#include "Mixer.h" + +namespace aidl::android::hardware::audio::core::alsa { + +//----------------------------------------------------------------------------- + +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> + Mixer::kPossibleControls = { + {Mixer::MASTER_SWITCH, {{"Master Playback Switch", MIXER_CTL_TYPE_BOOL}}}, + {Mixer::MASTER_VOLUME, {{"Master Playback Volume", MIXER_CTL_TYPE_INT}}}, + {Mixer::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> Mixer::initializeMixerControls( + struct mixer* mixer) { + std::map> 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(ctl)); + if (!mixerCtlNames.empty()) { + mixerCtlNames += ","; + } + mixerCtlNames += ctlName; + break; + } + } + } + LOG(DEBUG) << __func__ << ": available mixer control names=[" << mixerCtlNames << "]"; + return mixerControls; +} + +Mixer::Mixer(struct mixer* mixer) + : mMixer(mixer), mMixerControls(initializeMixerControls(mMixer)) {} + +Mixer::~Mixer() { + mixer_close(mMixer); +} + +namespace { + +int volumeFloatToInteger(float fValue, int maxValue, int minValue) { + return minValue + std::ceil((maxValue - minValue) * fValue); +} + +} // namespace + +ndk::ScopedAStatus Mixer::setMasterMute(bool muted) { + auto it = mMixerControls.find(Mixer::MASTER_SWITCH); + if (it == mMixerControls.end()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + const int numValues = it->second->getNumValues(); + std::vector 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 Mixer::setMasterVolume(float volume) { + auto it = mMixerControls.find(Mixer::MASTER_VOLUME); + if (it == mMixerControls.end()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + const int numValues = it->second->getNumValues(); + std::vector 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 Mixer::setVolumes(const std::vector& volumes) { + auto it = mMixerControls.find(Mixer::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 values; + size_t i = 0; + for (; i < static_cast(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(); +} + +} // namespace aidl::android::hardware::audio::core::alsa diff --git a/audio/aidl/default/alsa/Mixer.h b/audio/aidl/default/alsa/Mixer.h new file mode 100644 index 0000000000..de9e6f42cd --- /dev/null +++ b/audio/aidl/default/alsa/Mixer.h @@ -0,0 +1,82 @@ +/* + * 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 +#include +#include + +#include +#include + +extern "C" { +#include +} + +namespace aidl::android::hardware::audio::core::alsa { + +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 Mixer { + public: + explicit Mixer(struct mixer* mixer); + + ~Mixer(); + + bool isValid() const { return mMixer != nullptr; } + + ndk::ScopedAStatus setMasterMute(bool muted); + ndk::ScopedAStatus setMasterVolume(float volume); + ndk::ScopedAStatus setVolumes(const std::vector& volumes); + + private: + enum Control { + MASTER_SWITCH, + MASTER_VOLUME, + HW_VOLUME, + }; + using ControlNamesAndExpectedCtlType = std::pair; + static const std::map> kPossibleControls; + static std::map> 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> mMixerControls; +}; + +} // namespace aidl::android::hardware::audio::core::alsa diff --git a/audio/aidl/default/alsa/ModuleAlsa.cpp b/audio/aidl/default/alsa/ModuleAlsa.cpp new file mode 100644 index 0000000000..8e75d56843 --- /dev/null +++ b/audio/aidl/default/alsa/ModuleAlsa.cpp @@ -0,0 +1,67 @@ +/* + * 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_ModuleAlsa" + +#include + +#include + +#include "Utils.h" +#include "core-impl/ModuleAlsa.h" + +extern "C" { +#include "alsa_device_profile.h" +} + +using aidl::android::media::audio::common::AudioChannelLayout; +using aidl::android::media::audio::common::AudioFormatType; +using aidl::android::media::audio::common::AudioPort; +using aidl::android::media::audio::common::AudioProfile; + +namespace aidl::android::hardware::audio::core { + +ndk::ScopedAStatus ModuleAlsa::populateConnectedDevicePort(AudioPort* audioPort) { + auto deviceProfile = alsa::getDeviceProfile(*audioPort); + if (!deviceProfile.has_value()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + auto profile = alsa::readAlsaDeviceInfo(*deviceProfile); + if (!profile.has_value()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + + std::vector channels = alsa::getChannelMasksFromProfile(&profile.value()); + std::vector sampleRates = alsa::getSampleRatesFromProfile(&profile.value()); + + 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 = + alsa::c2aidl_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(); +} + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/alsa/StreamAlsa.cpp b/audio/aidl/default/alsa/StreamAlsa.cpp new file mode 100644 index 0000000000..ecb3c78a65 --- /dev/null +++ b/audio/aidl/default/alsa/StreamAlsa.cpp @@ -0,0 +1,103 @@ +/* + * 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 + +#define LOG_TAG "AHAL_StreamAlsa" +#include + +#include +#include + +#include "core-impl/StreamAlsa.h" + +namespace aidl::android::hardware::audio::core { + +StreamAlsa::StreamAlsa(const Metadata& metadata, StreamContext&& context) + : StreamCommonImpl(metadata, std::move(context)), + mFrameSizeBytes(getContext().getFrameSize()), + mIsInput(isInput(metadata)), + mConfig(alsa::getPcmConfig(getContext(), mIsInput)) {} + +::android::status_t StreamAlsa::init() { + return mConfig.has_value() ? ::android::OK : ::android::NO_INIT; +} + +::android::status_t StreamAlsa::standby() { + mAlsaDeviceProxies.clear(); + return ::android::OK; +} + +::android::status_t StreamAlsa::start() { + decltype(mAlsaDeviceProxies) alsaDeviceProxies; + for (const auto& device : getDeviceProfiles()) { + auto profile = alsa::readAlsaDeviceInfo(device); + if (!profile.has_value()) { + LOG(ERROR) << __func__ << ": unable to read device info, device address=" << device; + return ::android::UNKNOWN_ERROR; + } + + auto proxy = alsa::makeDeviceProxy(); + // 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.value(), + const_cast(&mConfig.value()), + true /*require_exact_match*/); + err != 0) { + LOG(ERROR) << __func__ << ": fail to prepare for device address=" << device + << " error=" << err; + return ::android::UNKNOWN_ERROR; + } + if (int err = proxy_open(proxy.get()); err != 0) { + LOG(ERROR) << __func__ << ": failed to open device, address=" << device + << " error=" << err; + return ::android::UNKNOWN_ERROR; + } + alsaDeviceProxies.push_back(std::move(proxy)); + } + mAlsaDeviceProxies = std::move(alsaDeviceProxies); + return ::android::OK; +} + +::android::status_t StreamAlsa::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, + int32_t* latencyMs) { + 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(std::numeric_limits::max())); + *latencyMs = maxLatency; + return ::android::OK; +} + +void StreamAlsa::shutdown() { + mAlsaDeviceProxies.clear(); +} + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/alsa/Utils.cpp b/audio/aidl/default/alsa/Utils.cpp new file mode 100644 index 0000000000..162f8529cf --- /dev/null +++ b/audio/aidl/default/alsa/Utils.cpp @@ -0,0 +1,293 @@ +/* + * 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 + +#define LOG_TAG "AHAL_AlsaUtils" +#include +#include +#include +#include + +#include "Utils.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::AudioDeviceAddress; +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::AudioPortExt; +using aidl::android::media::audio::common::PcmType; + +namespace aidl::android::hardware::audio::core::alsa { + +namespace { + +using AudioChannelCountToMaskMap = std::map; +using AudioFormatDescToPcmFormatMap = std::map; +using PcmFormatToAudioFormatDescMap = std::map; + +AudioChannelLayout getInvalidChannelLayout() { + static const AudioChannelLayout invalidChannelLayout = + AudioChannelLayout::make(0); + return invalidChannelLayout; +} + +static AudioChannelCountToMaskMap make_ChannelCountToMaskMap( + const std::set& channelMasks) { + AudioChannelCountToMaskMap channelMaskToCountMap; + for (const auto& channelMask : channelMasks) { + channelMaskToCountMap.emplace(getChannelCount(channelMask), channelMask); + } + return channelMaskToCountMap; +} + +#define DEFINE_CHANNEL_LAYOUT_MASK(n) \ + AudioChannelLayout::make(AudioChannelLayout::LAYOUT_##n) + +const AudioChannelCountToMaskMap& getSupportedChannelOutLayoutMap() { + static const std::set supportedOutChannelLayouts = { + 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 AudioChannelCountToMaskMap outLayouts = + make_ChannelCountToMaskMap(supportedOutChannelLayouts); + return outLayouts; +} + +const AudioChannelCountToMaskMap& getSupportedChannelInLayoutMap() { + static const std::set supportedInChannelLayouts = { + DEFINE_CHANNEL_LAYOUT_MASK(MONO), + DEFINE_CHANNEL_LAYOUT_MASK(STEREO), + }; + static const AudioChannelCountToMaskMap inLayouts = + make_ChannelCountToMaskMap(supportedInChannelLayouts); + return inLayouts; +} + +#undef DEFINE_CHANNEL_LAYOUT_MASK +#define DEFINE_CHANNEL_INDEX_MASK(n) \ + AudioChannelLayout::make(AudioChannelLayout::INDEX_MASK_##n) + +const AudioChannelCountToMaskMap& getSupportedChannelIndexLayoutMap() { + static const std::set supportedIndexChannelLayouts = { + 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 const AudioChannelCountToMaskMap indexLayouts = + make_ChannelCountToMaskMap(supportedIndexChannelLayouts); + return indexLayouts; +} + +#undef DEFINE_CHANNEL_INDEX_MASK + +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 + +std::ostream& operator<<(std::ostream& os, const DeviceProfile& device) { + return os << "<" << device.card << "," << device.device << ">"; +} + +AudioChannelLayout getChannelLayoutMaskFromChannelCount(unsigned int channelCount, int isInput) { + return findValueOrDefault( + isInput ? getSupportedChannelInLayoutMap() : getSupportedChannelOutLayoutMap(), + channelCount, getInvalidChannelLayout()); +} + +AudioChannelLayout getChannelIndexMaskFromChannelCount(unsigned int channelCount) { + return findValueOrDefault(getSupportedChannelIndexLayoutMap(), channelCount, + getInvalidChannelLayout()); +} + +unsigned int getChannelCountFromChannelMask(const AudioChannelLayout& channelMask, bool isInput) { + switch (channelMask.getTag()) { + case AudioChannelLayout::Tag::layoutMask: { + return findKeyOrDefault( + isInput ? getSupportedChannelInLayoutMap() : getSupportedChannelOutLayoutMap(), + static_cast(getChannelCount(channelMask)), 0u /*defaultValue*/); + } + case AudioChannelLayout::Tag::indexMask: { + return findKeyOrDefault(getSupportedChannelIndexLayoutMap(), + static_cast(getChannelCount(channelMask)), + 0u /*defaultValue*/); + } + case AudioChannelLayout::Tag::none: + case AudioChannelLayout::Tag::invalid: + case AudioChannelLayout::Tag::voiceMask: + default: + return 0; + } +} + +std::vector getChannelMasksFromProfile(const alsa_device_profile* profile) { + const bool isInput = profile->direction == PCM_IN; + std::vector channels; + for (size_t i = 0; i < AUDIO_PORT_MAX_CHANNEL_MASKS && profile->channel_counts[i] != 0; ++i) { + auto layoutMask = + alsa::getChannelLayoutMaskFromChannelCount(profile->channel_counts[i], isInput); + if (layoutMask.getTag() == AudioChannelLayout::Tag::layoutMask) { + channels.push_back(layoutMask); + } + auto indexMask = alsa::getChannelIndexMaskFromChannelCount(profile->channel_counts[i]); + if (indexMask.getTag() == AudioChannelLayout::Tag::indexMask) { + channels.push_back(indexMask); + } + } + return channels; +} + +std::optional getDeviceProfile( + const ::aidl::android::media::audio::common::AudioDevice& audioDevice, bool isInput) { + if (audioDevice.address.getTag() != AudioDeviceAddress::Tag::alsa) { + LOG(ERROR) << __func__ << ": not alsa address: " << audioDevice.toString(); + return std::nullopt; + } + auto& alsaAddress = audioDevice.address.get(); + if (alsaAddress.size() != 2 || alsaAddress[0] < 0 || alsaAddress[1] < 0) { + LOG(ERROR) << __func__ + << ": malformed alsa address: " << ::android::internal::ToString(alsaAddress); + return std::nullopt; + } + return DeviceProfile{.card = alsaAddress[0], + .device = alsaAddress[1], + .direction = isInput ? PCM_IN : PCM_OUT}; +} + +std::optional getDeviceProfile( + const ::aidl::android::media::audio::common::AudioPort& audioPort) { + if (audioPort.ext.getTag() != AudioPortExt::Tag::device) { + LOG(ERROR) << __func__ << ": port id " << audioPort.id << " is not a device port"; + return std::nullopt; + } + auto& devicePort = audioPort.ext.get(); + return getDeviceProfile(devicePort.device, audioPort.flags.getTag() == AudioIoFlags::input); +} + +std::optional getPcmConfig(const StreamContext& context, bool isInput) { + struct pcm_config config; + config.channels = alsa::getChannelCountFromChannelMask(context.getChannelLayout(), isInput); + if (config.channels == 0) { + LOG(ERROR) << __func__ << ": invalid channel=" << context.getChannelLayout().toString(); + return std::nullopt; + } + config.format = alsa::aidl2c_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; +} + +std::vector getSampleRatesFromProfile(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; +} + +DeviceProxy makeDeviceProxy() { + return DeviceProxy(new alsa_device_proxy, [](alsa_device_proxy* proxy) { + if (proxy != nullptr) { + proxy_close(proxy); + delete proxy; + } + }); +} + +std::optional readAlsaDeviceInfo(const DeviceProfile& deviceProfile) { + alsa_device_profile profile; + profile_init(&profile, deviceProfile.direction); + profile.card = deviceProfile.card; + profile.device = deviceProfile.device; + if (!profile_read_device_info(&profile)) { + LOG(ERROR) << __func__ << ": failed to read device info, card=" << profile.card + << ", device=" << profile.device; + return std::nullopt; + } + return profile; +} + +AudioFormatDescription c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy) { + return findValueOrDefault(getPcmFormatToAudioFormatDescMap(), legacy, AudioFormatDescription()); +} + +pcm_format aidl2c_AudioFormatDescription_pcm_format(const AudioFormatDescription& aidl) { + return findValueOrDefault(getAudioFormatDescriptorToPcmFormatMap(), aidl, PCM_FORMAT_INVALID); +} + +} // namespace aidl::android::hardware::audio::core::alsa diff --git a/audio/aidl/default/alsa/Utils.h b/audio/aidl/default/alsa/Utils.h new file mode 100644 index 0000000000..c1b9b380c0 --- /dev/null +++ b/audio/aidl/default/alsa/Utils.h @@ -0,0 +1,70 @@ +/* + * 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 +#include +#include + +#include +#include +#include + +#include "core-impl/Stream.h" + +extern "C" { +#include +#include "alsa_device_profile.h" +#include "alsa_device_proxy.h" +} + +namespace aidl::android::hardware::audio::core::alsa { + +struct DeviceProfile { + int card; + int device; + int direction; /* PCM_OUT or PCM_IN */ +}; +std::ostream& operator<<(std::ostream& os, const DeviceProfile& device); +using DeviceProxyDeleter = std::function; +using DeviceProxy = std::unique_ptr; + +::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); +std::vector<::aidl::android::media::audio::common::AudioChannelLayout> getChannelMasksFromProfile( + const alsa_device_profile* profile); +std::optional getDeviceProfile( + const ::aidl::android::media::audio::common::AudioDevice& audioDevice, bool isInput); +std::optional getDeviceProfile( + const ::aidl::android::media::audio::common::AudioPort& audioPort); +std::optional getPcmConfig(const StreamContext& context, bool isInput); +std::vector getSampleRatesFromProfile(const alsa_device_profile* profile); +DeviceProxy makeDeviceProxy(); +std::optional readAlsaDeviceInfo(const DeviceProfile& deviceProfile); + +::aidl::android::media::audio::common::AudioFormatDescription +c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy); +pcm_format aidl2c_AudioFormatDescription_pcm_format( + const ::aidl::android::media::audio::common::AudioFormatDescription& aidl); + +} // namespace aidl::android::hardware::audio::core::alsa diff --git a/audio/aidl/default/include/core-impl/ModuleAlsa.h b/audio/aidl/default/include/core-impl/ModuleAlsa.h new file mode 100644 index 0000000000..5815961f7c --- /dev/null +++ b/audio/aidl/default/include/core-impl/ModuleAlsa.h @@ -0,0 +1,38 @@ +/* + * 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 { + +// This class is intended to be used as a base class for implementations +// that use TinyAlsa. This can be either a primary module or a USB Audio +// module. This class does not define a complete module implementation, +// and should never be used on its own. Derived classes are expected to +// provide necessary overrides for all interface methods omitted here. +class ModuleAlsa : public Module { + public: + explicit ModuleAlsa(Module::Type type) : Module(type) {} + + protected: + // Extension methods of 'Module'. + ndk::ScopedAStatus populateConnectedDevicePort( + ::aidl::android::media::audio::common::AudioPort* audioPort) override; +}; + +} // 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 index 5a5429db64..ea7cc48214 100644 --- a/audio/aidl/default/include/core-impl/ModuleUsb.h +++ b/audio/aidl/default/include/core-impl/ModuleUsb.h @@ -16,13 +16,13 @@ #pragma once -#include "core-impl/Module.h" +#include "core-impl/ModuleAlsa.h" namespace aidl::android::hardware::audio::core { -class ModuleUsb : public Module { +class ModuleUsb final : public ModuleAlsa { public: - explicit ModuleUsb(Module::Type type) : Module(type) {} + explicit ModuleUsb(Module::Type type) : ModuleAlsa(type) {} private: // IModule interfaces diff --git a/audio/aidl/default/include/core-impl/StreamAlsa.h b/audio/aidl/default/include/core-impl/StreamAlsa.h new file mode 100644 index 0000000000..edfc72860c --- /dev/null +++ b/audio/aidl/default/include/core-impl/StreamAlsa.h @@ -0,0 +1,54 @@ +/* + * 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 "Stream.h" +#include "alsa/Utils.h" + +namespace aidl::android::hardware::audio::core { + +// This class is intended to be used as a base class for implementations +// that use TinyAlsa. +// This class does not define a complete stream implementation, +// and should never be used on its own. Derived classes are expected to +// provide necessary overrides for all interface methods omitted here. +class StreamAlsa : public StreamCommonImpl { + public: + StreamAlsa(const Metadata& metadata, StreamContext&& context); + // Methods of 'DriverInterface'. + ::android::status_t init() override; + ::android::status_t standby() override; + ::android::status_t start() override; + ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, + int32_t* latencyMs) override; + void shutdown() override; + + protected: + // Called from 'start' to initialize 'mAlsaDeviceProxies', the vector must be non-empty. + virtual std::vector getDeviceProfiles() = 0; + + const size_t mFrameSizeBytes; + const bool mIsInput; + const std::optional mConfig; + // All fields below are only used on the worker thread. + std::vector mAlsaDeviceProxies; +}; + +} // namespace aidl::android::hardware::audio::core diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h index 8c40782db1..44f742a4dd 100644 --- a/audio/aidl/default/include/core-impl/StreamUsb.h +++ b/audio/aidl/default/include/core-impl/StreamUsb.h @@ -17,55 +17,34 @@ #pragma once #include -#include #include -#include #include #include -#include "core-impl/Stream.h" - -extern "C" { -#include -#include "alsa_device_proxy.h" -} +#include "StreamAlsa.h" namespace aidl::android::hardware::audio::core { -class StreamUsb : public StreamCommonImpl { +class StreamUsb : public StreamAlsa { public: StreamUsb(const Metadata& metadata, StreamContext&& context); // Methods of 'DriverInterface'. - ::android::status_t init() override; ::android::status_t drain(StreamDescriptor::DrainMode) override; ::android::status_t flush() override; ::android::status_t pause() override; - ::android::status_t standby() override; - ::android::status_t start() override; ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount, int32_t* latencyMs) override; - void shutdown() override; // Overridden methods of 'StreamCommonImpl', called on a Binder thread. - const ConnectedDevices& getConnectedDevices() const override; ndk::ScopedAStatus setConnectedDevices(const ConnectedDevices& devices) override; - private: - using AlsaDeviceProxyDeleter = std::function; - using AlsaDeviceProxy = std::unique_ptr; - - static std::optional maybePopulateConfig(const StreamContext& context, - bool isInput); + protected: + std::vector getDeviceProfiles() override; mutable std::mutex mLock; - - const size_t mFrameSizeBytes; - const bool mIsInput; - const std::optional mConfig; + std::vector mConnectedDeviceProfiles GUARDED_BY(mLock); std::atomic mConnectedDevicesUpdated = false; - // All fields below are only used on the worker thread. - std::vector mAlsaDeviceProxies; }; class StreamInUsb final : public StreamUsb, public StreamIn { @@ -94,7 +73,7 @@ class StreamOutUsb final : public StreamUsb, public StreamOut { ndk::ScopedAStatus getHwVolume(std::vector* _aidl_return) override; ndk::ScopedAStatus setHwVolume(const std::vector& in_channelVolumes) override; - int mChannelCount; + const int mChannelCount; std::vector mHwVolumes; }; diff --git a/audio/aidl/default/usb/ModuleUsb.cpp b/audio/aidl/default/usb/ModuleUsb.cpp index 5c9d4776ee..a812e4d3a1 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 +#define LOG_TAG "AHAL_ModuleUsb" #include #include -#include #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 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; +bool isUsbDevicePort(const AudioPort& audioPort) { + return audioPort.ext.getTag() == AudioPortExt::Tag::device && + audioPort.ext.get().device.type.connection == + AudioDeviceDescription::CONNECTION_USB; } } // namespace @@ -122,55 +88,11 @@ ndk::ScopedAStatus ModuleUsb::createOutputStream(const SourceMetadata& sourceMet } 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) { + 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(); - 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 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] != 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 @@ ndk::ScopedAStatus ModuleUsb::checkAudioPatchEndpointsMatch( 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().device.address; - if (address.getTag() != AudioDeviceAddress::alsa) { + auto profile = alsa::getDeviceProfile(audioPort); + if (!profile.has_value()) { return; } - const int card = address.get()[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 17e1ab42f1..da0ad11be2 100644 --- a/audio/aidl/default/usb/StreamUsb.cpp +++ b/audio/aidl/default/usb/StreamUsb.cpp @@ -23,64 +23,20 @@ #include #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 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& connectedDevices) { @@ -89,14 +45,19 @@ ndk::ScopedAStatus StreamUsb::setConnectedDevices( << ") for input stream"; return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } + std::vector 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 @@ ndk::ScopedAStatus StreamUsb::setConnectedDevices( ::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(std::numeric_limits::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 connectedDevices; +std::vector StreamUsb::getDeviceProfiles() { + std::vector 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()[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; - } - - 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(&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 @@ ndk::ScopedAStatus StreamInUsb::getActiveMicrophones( StreamOutUsb::StreamOutUsb(const SourceMetadata& sourceMetadata, StreamContext&& context, const std::optional& 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* _aidl_return) { *_aidl_return = mHwVolumes; @@ -224,17 +120,17 @@ ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector* _aidl_return) { } ndk::ScopedAStatus StreamOutUsb::setHwVolume(const std::vector& 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()[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 6c0c24bc09..769d739969 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 -#include -#include -#include - #include #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::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::initializeMixerControls( - struct mixer* mixer) { - std::map> 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(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 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 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 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 values; - size_t i = 0; - for (; i < static_cast(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 @@ void UsbAlsaMixerControl::setDeviceConnectionState(int card, bool masterMuted, f PLOG(ERROR) << __func__ << ": failed to open mixer for card=" << card; return; } - auto alsaMixer = std::make_shared(mixer); + auto alsaMixer = std::make_shared(mixer); alsaMixer->setMasterMute(masterMuted); alsaMixer->setMasterVolume(masterVolume); const std::lock_guard guard(mLock); @@ -209,7 +77,7 @@ ndk::ScopedAStatus UsbAlsaMixerControl::setMasterVolume(float volume) { return ndk::ScopedAStatus::ok(); } -ndk::ScopedAStatus UsbAlsaMixerControl::setVolumes(int card, std::vector volumes) { +ndk::ScopedAStatus UsbAlsaMixerControl::setVolumes(int card, const std::vector& volumes) { auto alsaMixer = getAlsaMixer(card); if (alsaMixer == nullptr) { LOG(ERROR) << __func__ << ": no mixer control found for card=" << card; @@ -218,13 +86,13 @@ ndk::ScopedAStatus UsbAlsaMixerControl::setVolumes(int card, std::vector return alsaMixer->setVolumes(volumes); } -std::shared_ptr UsbAlsaMixerControl::getAlsaMixer(int card) { +std::shared_ptr 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> UsbAlsaMixerControl::getAlsaMixers() { +std::map> 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 cbcddd82c6..c3265f8fd3 100644 --- a/audio/aidl/default/usb/UsbAlsaMixerControl.h +++ b/audio/aidl/default/usb/UsbAlsaMixerControl.h @@ -19,67 +19,15 @@ #include #include #include -#include -#include #include #include #include -extern "C" { -#include -} +#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 volumes); - - private: - enum Control { - MASTER_SWITCH, - MASTER_VOLUME, - HW_VOLUME, - }; - using ControlNamesAndExpectedCtlType = std::pair; - static const std::map> kPossibleControls; - static std::map> 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> mMixerControls; -}; - class UsbAlsaMixerControl { public: static UsbAlsaMixerControl& getInstance(); @@ -91,16 +39,16 @@ class UsbAlsaMixerControl { 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 volumes); + ndk::ScopedAStatus setVolumes(int card, const std::vector& volumes); private: - std::shared_ptr getAlsaMixer(int card); - std::map> getAlsaMixers(); + std::shared_ptr getAlsaMixer(int card); + std::map> getAlsaMixers(); std::mutex mLock; // A map whose key is the card number and value is a shared pointer to corresponding // AlsaMixer object. - std::map> mMixerControls GUARDED_BY(mLock); + std::map> 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 74d9c289a5..0000000000 --- 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 -#include - -#include -#include -#include - -#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; -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::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 2d2f0f4342..0000000000 --- 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 -#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