/* * 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_UsbAlsaMixerControl" #include #include #include "UsbAlsaMixerControl.h" namespace aidl::android::hardware::audio::core::usb { // static UsbAlsaMixerControl& UsbAlsaMixerControl::getInstance() { static UsbAlsaMixerControl gInstance; return gInstance; } void UsbAlsaMixerControl::setDeviceConnectionState(int card, bool masterMuted, float masterVolume, bool connected) { LOG(DEBUG) << __func__ << ": card=" << card << ", connected=" << connected; if (connected) { auto alsaMixer = std::make_shared(card); if (!alsaMixer->isValid()) { return; } alsaMixer->setMasterMute(masterMuted); alsaMixer->setMasterVolume(masterVolume); const std::lock_guard guard(mLock); mMixerControls.emplace(card, alsaMixer); } else { const std::lock_guard guard(mLock); mMixerControls.erase(card); } } ndk::ScopedAStatus UsbAlsaMixerControl::setMasterMute(bool mute) { auto alsaMixers = getAlsaMixers(); for (auto it = alsaMixers.begin(); it != alsaMixers.end(); ++it) { if (auto result = it->second->setMasterMute(mute); !result.isOk()) { // Return illegal state if there are multiple devices connected and one of them fails // to set master mute. Otherwise, return the error from calling `setMasterMute`. LOG(ERROR) << __func__ << ": failed to set master mute for card=" << it->first; return alsaMixers.size() > 1 ? ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE) : std::move(result); } } return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus UsbAlsaMixerControl::setMasterVolume(float volume) { auto alsaMixers = getAlsaMixers(); for (auto it = alsaMixers.begin(); it != alsaMixers.end(); ++it) { if (auto result = it->second->setMasterVolume(volume); !result.isOk()) { // Return illegal state if there are multiple devices connected and one of them fails // to set master volume. Otherwise, return the error from calling `setMasterVolume`. LOG(ERROR) << __func__ << ": failed to set master volume for card=" << it->first; return alsaMixers.size() > 1 ? ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE) : std::move(result); } } return ndk::ScopedAStatus::ok(); } 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; return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } return alsaMixer->setVolumes(volumes); } 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() { const std::lock_guard guard(mLock); return mMixerControls; } } // namespace aidl::android::hardware::audio::core::usb