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