blob: b5337d164241499b443ad7466e677b708587820a [file] [log] [blame]
jiabin783c48b2023-02-28 18:28:06 +00001/*
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 <cmath>
21#include <string>
22#include <vector>
23
24#include <android/binder_status.h>
25
26#include "UsbAlsaMixerControl.h"
27
28namespace aidl::android::hardware::audio::core::usb {
29
30//-----------------------------------------------------------------------------
31
32MixerControl::MixerControl(struct mixer_ctl* ctl)
33 : mCtl(ctl),
34 mNumValues(mixer_ctl_get_num_values(ctl)),
35 mMinValue(mixer_ctl_get_range_min(ctl)),
36 mMaxValue(mixer_ctl_get_range_max(ctl)) {}
37
38unsigned int MixerControl::getNumValues() const {
39 return mNumValues;
40}
41
42int MixerControl::getMaxValue() const {
43 return mMaxValue;
44}
45
46int MixerControl::getMinValue() const {
47 return mMinValue;
48}
49
50int MixerControl::setArray(const void* array, size_t count) {
51 const std::lock_guard guard(mLock);
52 return mixer_ctl_set_array(mCtl, array, count);
53}
54
55//-----------------------------------------------------------------------------
56
57// static
58const std::map<AlsaMixer::Control, std::vector<AlsaMixer::ControlNamesAndExpectedCtlType>>
59 AlsaMixer::kPossibleControls = {
60 {AlsaMixer::MASTER_SWITCH, {{"Master Playback Switch", MIXER_CTL_TYPE_BOOL}}},
61 {AlsaMixer::MASTER_VOLUME, {{"Master Playback Volume", MIXER_CTL_TYPE_INT}}},
62 {AlsaMixer::HW_VOLUME,
63 {{"Headphone Playback Volume", MIXER_CTL_TYPE_INT},
64 {"Headset Playback Volume", MIXER_CTL_TYPE_INT},
65 {"PCM Playback Volume", MIXER_CTL_TYPE_INT}}}};
66
67// static
68std::map<AlsaMixer::Control, std::shared_ptr<MixerControl>> AlsaMixer::initializeMixerControls(
69 struct mixer* mixer) {
70 std::map<AlsaMixer::Control, std::shared_ptr<MixerControl>> mixerControls;
71 std::string mixerCtlNames;
72 for (const auto& [control, possibleCtls] : kPossibleControls) {
73 for (const auto& [ctlName, expectedCtlType] : possibleCtls) {
74 struct mixer_ctl* ctl = mixer_get_ctl_by_name(mixer, ctlName.c_str());
75 if (ctl != nullptr && mixer_ctl_get_type(ctl) == expectedCtlType) {
76 mixerControls.emplace(control, std::make_unique<MixerControl>(ctl));
77 if (!mixerCtlNames.empty()) {
78 mixerCtlNames += ",";
79 }
80 mixerCtlNames += ctlName;
81 break;
82 }
83 }
84 }
85 LOG(DEBUG) << __func__ << ": available mixer control names=[" << mixerCtlNames << "]";
86 return mixerControls;
87}
88
89AlsaMixer::AlsaMixer(struct mixer* mixer)
90 : mMixer(mixer), mMixerControls(initializeMixerControls(mMixer)) {}
91
92AlsaMixer::~AlsaMixer() {
93 mixer_close(mMixer);
94}
95
96namespace {
97
98int volumeFloatToInteger(float fValue, int maxValue, int minValue) {
99 return minValue + std::ceil((maxValue - minValue) * fValue);
100}
101
102float volumeIntegerToFloat(int iValue, int maxValue, int minValue) {
103 if (iValue > maxValue) {
104 return 1.0f;
105 }
106 if (iValue < minValue) {
107 return 0.0f;
108 }
109 return static_cast<float>(iValue - minValue) / (maxValue - minValue);
110}
111
112} // namespace
113
114ndk::ScopedAStatus AlsaMixer::setMasterMute(bool muted) {
115 auto it = mMixerControls.find(AlsaMixer::MASTER_SWITCH);
116 if (it == mMixerControls.end()) {
117 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
118 }
119 const int numValues = it->second->getNumValues();
120 std::vector<int> values(numValues, muted ? 0 : 1);
121 if (int err = it->second->setArray(values.data(), numValues); err != 0) {
122 LOG(ERROR) << __func__ << ": failed to set master mute, err=" << err;
123 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
124 }
125 return ndk::ScopedAStatus::ok();
126}
127
128ndk::ScopedAStatus AlsaMixer::setMasterVolume(float volume) {
129 auto it = mMixerControls.find(AlsaMixer::MASTER_VOLUME);
130 if (it == mMixerControls.end()) {
131 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
132 }
133 const int numValues = it->second->getNumValues();
134 std::vector<int> values(numValues, volumeFloatToInteger(volume, it->second->getMaxValue(),
135 it->second->getMinValue()));
136 if (int err = it->second->setArray(values.data(), numValues); err != 0) {
137 LOG(ERROR) << __func__ << ": failed to set master volume, err=" << err;
138 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
139 }
140 return ndk::ScopedAStatus::ok();
141}
142
143ndk::ScopedAStatus AlsaMixer::setVolumes(std::vector<float> volumes) {
144 auto it = mMixerControls.find(AlsaMixer::HW_VOLUME);
145 if (it == mMixerControls.end()) {
146 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
147 }
148 const int numValues = it->second->getNumValues();
149 const int maxValue = it->second->getMaxValue();
150 const int minValue = it->second->getMinValue();
151 std::vector<int> values;
152 size_t i = 0;
153 for (; i < numValues && i < values.size(); ++i) {
154 values.emplace_back(volumeFloatToInteger(volumes[i], maxValue, minValue));
155 }
156 if (int err = it->second->setArray(values.data(), values.size()); err != 0) {
157 LOG(ERROR) << __func__ << ": failed to set volume, err=" << err;
158 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
159 }
160 return ndk::ScopedAStatus::ok();
161}
162
163//-----------------------------------------------------------------------------
164
165// static
166UsbAlsaMixerControl& UsbAlsaMixerControl::getInstance() {
167 static UsbAlsaMixerControl gInstance;
168 return gInstance;
169}
170
171void UsbAlsaMixerControl::setDeviceConnectionState(int card, bool masterMuted, float masterVolume,
172 bool connected) {
173 LOG(DEBUG) << __func__ << ": card=" << card << ", connected=" << connected;
174 if (connected) {
175 struct mixer* mixer = mixer_open(card);
176 if (mixer == nullptr) {
177 PLOG(ERROR) << __func__ << ": failed to open mixer for card=" << card;
178 return;
179 }
180 auto alsaMixer = std::make_shared<AlsaMixer>(mixer);
181 alsaMixer->setMasterMute(masterMuted);
182 alsaMixer->setMasterVolume(masterVolume);
183 const std::lock_guard guard(mLock);
184 mMixerControls.emplace(card, alsaMixer);
185 } else {
186 const std::lock_guard guard(mLock);
187 mMixerControls.erase(card);
188 }
189}
190
191ndk::ScopedAStatus UsbAlsaMixerControl::setMasterMute(bool mute) {
192 auto alsaMixers = getAlsaMixers();
193 for (auto it = alsaMixers.begin(); it != alsaMixers.end(); ++it) {
194 if (auto result = it->second->setMasterMute(mute); !result.isOk()) {
195 // Return illegal state if there are multiple devices connected and one of them fails
196 // to set master mute. Otherwise, return the error from calling `setMasterMute`.
197 LOG(ERROR) << __func__ << ": failed to set master mute for card=" << it->first;
198 return alsaMixers.size() > 1 ? ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE)
199 : std::move(result);
200 }
201 }
202 return ndk::ScopedAStatus::ok();
203}
204
205ndk::ScopedAStatus UsbAlsaMixerControl::setMasterVolume(float volume) {
206 auto alsaMixers = getAlsaMixers();
207 for (auto it = alsaMixers.begin(); it != alsaMixers.end(); ++it) {
208 if (auto result = it->second->setMasterVolume(volume); !result.isOk()) {
209 // Return illegal state if there are multiple devices connected and one of them fails
210 // to set master volume. Otherwise, return the error from calling `setMasterVolume`.
211 LOG(ERROR) << __func__ << ": failed to set master volume for card=" << it->first;
212 return alsaMixers.size() > 1 ? ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE)
213 : std::move(result);
214 }
215 }
216 return ndk::ScopedAStatus::ok();
217}
218
219ndk::ScopedAStatus UsbAlsaMixerControl::setVolumes(int card, std::vector<float> volumes) {
220 auto alsaMixer = getAlsaMixer(card);
221 if (alsaMixer == nullptr) {
222 LOG(ERROR) << __func__ << ": no mixer control found for card=" << card;
223 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
224 }
225 return alsaMixer->setVolumes(volumes);
226}
227
228std::shared_ptr<AlsaMixer> UsbAlsaMixerControl::getAlsaMixer(int card) {
229 const std::lock_guard guard(mLock);
230 const auto it = mMixerControls.find(card);
231 return it == mMixerControls.end() ? nullptr : it->second;
232}
233
234std::map<int, std::shared_ptr<AlsaMixer>> UsbAlsaMixerControl::getAlsaMixers() {
235 const std::lock_guard guard(mLock);
236 return mMixerControls;
237}
238
239} // namespace aidl::android::hardware::audio::core::usb