1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "AHAL_UsbAlsaMixerControl"
18 #include <android-base/logging.h>
19
20 #include <android/binder_status.h>
21
22 #include "UsbAlsaMixerControl.h"
23
24 namespace aidl::android::hardware::audio::core::usb {
25
26 // static
getInstance()27 UsbAlsaMixerControl& UsbAlsaMixerControl::getInstance() {
28 static UsbAlsaMixerControl gInstance;
29 return gInstance;
30 }
31
setDeviceConnectionState(int card,bool masterMuted,float masterVolume,bool connected)32 void UsbAlsaMixerControl::setDeviceConnectionState(int card, bool masterMuted, float masterVolume,
33 bool connected) {
34 LOG(DEBUG) << __func__ << ": card=" << card << ", connected=" << connected;
35 if (connected) {
36 auto alsaMixer = std::make_shared<alsa::Mixer>(card);
37 if (!alsaMixer->isValid()) {
38 return;
39 }
40 alsaMixer->setMasterMute(masterMuted);
41 alsaMixer->setMasterVolume(masterVolume);
42 const std::lock_guard guard(mLock);
43 mMixerControls.emplace(card, alsaMixer);
44 } else {
45 const std::lock_guard guard(mLock);
46 mMixerControls.erase(card);
47 }
48 }
49
setMasterMute(bool mute)50 ndk::ScopedAStatus UsbAlsaMixerControl::setMasterMute(bool mute) {
51 auto alsaMixers = getAlsaMixers();
52 for (auto it = alsaMixers.begin(); it != alsaMixers.end(); ++it) {
53 if (auto result = it->second->setMasterMute(mute); !result.isOk()) {
54 // Return illegal state if there are multiple devices connected and one of them fails
55 // to set master mute. Otherwise, return the error from calling `setMasterMute`.
56 LOG(ERROR) << __func__ << ": failed to set master mute for card=" << it->first;
57 return alsaMixers.size() > 1 ? ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE)
58 : std::move(result);
59 }
60 }
61 return ndk::ScopedAStatus::ok();
62 }
63
setMasterVolume(float volume)64 ndk::ScopedAStatus UsbAlsaMixerControl::setMasterVolume(float volume) {
65 auto alsaMixers = getAlsaMixers();
66 for (auto it = alsaMixers.begin(); it != alsaMixers.end(); ++it) {
67 if (auto result = it->second->setMasterVolume(volume); !result.isOk()) {
68 // Return illegal state if there are multiple devices connected and one of them fails
69 // to set master volume. Otherwise, return the error from calling `setMasterVolume`.
70 LOG(ERROR) << __func__ << ": failed to set master volume for card=" << it->first;
71 return alsaMixers.size() > 1 ? ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE)
72 : std::move(result);
73 }
74 }
75 return ndk::ScopedAStatus::ok();
76 }
77
setVolumes(int card,const std::vector<float> & volumes)78 ndk::ScopedAStatus UsbAlsaMixerControl::setVolumes(int card, const std::vector<float>& volumes) {
79 auto alsaMixer = getAlsaMixer(card);
80 if (alsaMixer == nullptr) {
81 LOG(ERROR) << __func__ << ": no mixer control found for card=" << card;
82 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
83 }
84 return alsaMixer->setVolumes(volumes);
85 }
86
getAlsaMixer(int card)87 std::shared_ptr<alsa::Mixer> UsbAlsaMixerControl::getAlsaMixer(int card) {
88 const std::lock_guard guard(mLock);
89 const auto it = mMixerControls.find(card);
90 return it == mMixerControls.end() ? nullptr : it->second;
91 }
92
getAlsaMixers()93 std::map<int, std::shared_ptr<alsa::Mixer>> UsbAlsaMixerControl::getAlsaMixers() {
94 const std::lock_guard guard(mLock);
95 return mMixerControls;
96 }
97
98 } // namespace aidl::android::hardware::audio::core::usb
99