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 #include <algorithm>
18 #include <cmath>
19
20 #define LOG_TAG "AHAL_AlsaMixer"
21 #include <android-base/logging.h>
22 #include <android/binder_status.h>
23 #include <error/expected_utils.h>
24
25 #include "Mixer.h"
26
27 namespace ndk {
28
29 // This enables use of 'error/expected_utils' for ScopedAStatus.
30
errorIsOk(const ScopedAStatus & s)31 inline bool errorIsOk(const ScopedAStatus& s) {
32 return s.isOk();
33 }
34
errorToString(const ScopedAStatus & s)35 inline std::string errorToString(const ScopedAStatus& s) {
36 return s.getDescription();
37 }
38
39 } // namespace ndk
40
41 namespace aidl::android::hardware::audio::core::alsa {
42
43 // static
44 const std::map<Mixer::Control, std::vector<Mixer::ControlNamesAndExpectedCtlType>>
45 Mixer::kPossibleControls = {
46 {Mixer::MASTER_SWITCH, {{"Master Playback Switch", MIXER_CTL_TYPE_BOOL}}},
47 {Mixer::MASTER_VOLUME, {{"Master Playback Volume", MIXER_CTL_TYPE_INT}}},
48 {Mixer::HW_VOLUME,
49 {{"Headphone Playback Volume", MIXER_CTL_TYPE_INT},
50 {"Headset Playback Volume", MIXER_CTL_TYPE_INT},
51 {"PCM Playback Volume", MIXER_CTL_TYPE_INT}}},
52 {Mixer::MIC_SWITCH, {{"Capture Switch", MIXER_CTL_TYPE_BOOL}}},
53 {Mixer::MIC_GAIN, {{"Capture Volume", MIXER_CTL_TYPE_INT}}}};
54
55 // static
initializeMixerControls(struct mixer * mixer)56 Mixer::Controls Mixer::initializeMixerControls(struct mixer* mixer) {
57 if (mixer == nullptr) return {};
58 Controls mixerControls;
59 std::string mixerCtlNames;
60 for (const auto& [control, possibleCtls] : kPossibleControls) {
61 for (const auto& [ctlName, expectedCtlType] : possibleCtls) {
62 struct mixer_ctl* ctl = mixer_get_ctl_by_name(mixer, ctlName.c_str());
63 if (ctl != nullptr && mixer_ctl_get_type(ctl) == expectedCtlType) {
64 mixerControls.emplace(control, ctl);
65 if (!mixerCtlNames.empty()) {
66 mixerCtlNames += ",";
67 }
68 mixerCtlNames += ctlName;
69 break;
70 }
71 }
72 }
73 LOG(DEBUG) << __func__ << ": available mixer control names=[" << mixerCtlNames << "]";
74 return mixerControls;
75 }
76
operator <<(std::ostream & s,Mixer::Control c)77 std::ostream& operator<<(std::ostream& s, Mixer::Control c) {
78 switch (c) {
79 case Mixer::Control::MASTER_SWITCH:
80 s << "master mute";
81 break;
82 case Mixer::Control::MASTER_VOLUME:
83 s << "master volume";
84 break;
85 case Mixer::Control::HW_VOLUME:
86 s << "volume";
87 break;
88 case Mixer::Control::MIC_SWITCH:
89 s << "mic mute";
90 break;
91 case Mixer::Control::MIC_GAIN:
92 s << "mic gain";
93 break;
94 }
95 return s;
96 }
97
Mixer(int card)98 Mixer::Mixer(int card) : mMixer(mixer_open(card)), mMixerControls(initializeMixerControls(mMixer)) {
99 if (!isValid()) {
100 PLOG(ERROR) << __func__ << ": failed to open mixer for card=" << card;
101 }
102 }
103
~Mixer()104 Mixer::~Mixer() {
105 if (isValid()) {
106 std::lock_guard l(mMixerAccess);
107 mixer_close(mMixer);
108 }
109 }
110
getMasterMute(bool * muted)111 ndk::ScopedAStatus Mixer::getMasterMute(bool* muted) {
112 return getMixerControlMute(MASTER_SWITCH, muted);
113 }
114
getMasterVolume(float * volume)115 ndk::ScopedAStatus Mixer::getMasterVolume(float* volume) {
116 return getMixerControlVolume(MASTER_VOLUME, volume);
117 }
118
getMicGain(float * gain)119 ndk::ScopedAStatus Mixer::getMicGain(float* gain) {
120 return getMixerControlVolume(MIC_GAIN, gain);
121 }
122
getMicMute(bool * muted)123 ndk::ScopedAStatus Mixer::getMicMute(bool* muted) {
124 return getMixerControlMute(MIC_SWITCH, muted);
125 }
126
getVolumes(std::vector<float> * volumes)127 ndk::ScopedAStatus Mixer::getVolumes(std::vector<float>* volumes) {
128 struct mixer_ctl* mctl;
129 RETURN_STATUS_IF_ERROR(findControl(Mixer::HW_VOLUME, &mctl));
130 std::vector<int> percents;
131 std::lock_guard l(mMixerAccess);
132 if (int err = getMixerControlPercent(mctl, &percents); err != 0) {
133 LOG(ERROR) << __func__ << ": failed to get volume, err=" << err;
134 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
135 }
136 std::transform(percents.begin(), percents.end(), std::back_inserter(*volumes),
137 [](int percent) -> float { return std::clamp(percent / 100.0f, 0.0f, 1.0f); });
138 return ndk::ScopedAStatus::ok();
139 }
140
setMasterMute(bool muted)141 ndk::ScopedAStatus Mixer::setMasterMute(bool muted) {
142 return setMixerControlMute(MASTER_SWITCH, muted);
143 }
144
setMasterVolume(float volume)145 ndk::ScopedAStatus Mixer::setMasterVolume(float volume) {
146 return setMixerControlVolume(MASTER_VOLUME, volume);
147 }
148
setMicGain(float gain)149 ndk::ScopedAStatus Mixer::setMicGain(float gain) {
150 return setMixerControlVolume(MIC_GAIN, gain);
151 }
152
setMicMute(bool muted)153 ndk::ScopedAStatus Mixer::setMicMute(bool muted) {
154 return setMixerControlMute(MIC_SWITCH, muted);
155 }
156
setVolumes(const std::vector<float> & volumes)157 ndk::ScopedAStatus Mixer::setVolumes(const std::vector<float>& volumes) {
158 struct mixer_ctl* mctl;
159 RETURN_STATUS_IF_ERROR(findControl(Mixer::HW_VOLUME, &mctl));
160 std::vector<int> percents;
161 std::transform(
162 volumes.begin(), volumes.end(), std::back_inserter(percents),
163 [](float volume) -> int { return std::floor(std::clamp(volume, 0.0f, 1.0f) * 100); });
164 std::lock_guard l(mMixerAccess);
165 if (int err = setMixerControlPercent(mctl, percents); err != 0) {
166 LOG(ERROR) << __func__ << ": failed to set volume, err=" << err;
167 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
168 }
169 return ndk::ScopedAStatus::ok();
170 }
171
findControl(Control ctl,struct mixer_ctl ** result)172 ndk::ScopedAStatus Mixer::findControl(Control ctl, struct mixer_ctl** result) {
173 if (!isValid()) {
174 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
175 }
176 if (auto it = mMixerControls.find(ctl); it != mMixerControls.end()) {
177 *result = it->second;
178 return ndk::ScopedAStatus::ok();
179 }
180 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
181 }
182
getMixerControlMute(Control ctl,bool * muted)183 ndk::ScopedAStatus Mixer::getMixerControlMute(Control ctl, bool* muted) {
184 struct mixer_ctl* mctl;
185 RETURN_STATUS_IF_ERROR(findControl(ctl, &mctl));
186 std::lock_guard l(mMixerAccess);
187 std::vector<int> mutedValues;
188 if (int err = getMixerControlValues(mctl, &mutedValues); err != 0) {
189 LOG(ERROR) << __func__ << ": failed to get " << ctl << ", err=" << err;
190 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
191 }
192 if (mutedValues.empty()) {
193 LOG(ERROR) << __func__ << ": got no values for " << ctl;
194 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
195 }
196 *muted = mutedValues[0] != 0;
197 return ndk::ScopedAStatus::ok();
198 }
199
getMixerControlVolume(Control ctl,float * volume)200 ndk::ScopedAStatus Mixer::getMixerControlVolume(Control ctl, float* volume) {
201 struct mixer_ctl* mctl;
202 RETURN_STATUS_IF_ERROR(findControl(ctl, &mctl));
203 std::lock_guard l(mMixerAccess);
204 std::vector<int> percents;
205 if (int err = getMixerControlPercent(mctl, &percents); err != 0) {
206 LOG(ERROR) << __func__ << ": failed to get " << ctl << ", err=" << err;
207 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
208 }
209 if (percents.empty()) {
210 LOG(ERROR) << __func__ << ": got no values for " << ctl;
211 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
212 }
213 *volume = std::clamp(percents[0] / 100.0f, 0.0f, 1.0f);
214 return ndk::ScopedAStatus::ok();
215 }
216
setMixerControlMute(Control ctl,bool muted)217 ndk::ScopedAStatus Mixer::setMixerControlMute(Control ctl, bool muted) {
218 struct mixer_ctl* mctl;
219 RETURN_STATUS_IF_ERROR(findControl(ctl, &mctl));
220 std::lock_guard l(mMixerAccess);
221 if (int err = setMixerControlValue(mctl, muted ? 0 : 1); err != 0) {
222 LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << muted << ", err=" << err;
223 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
224 }
225 return ndk::ScopedAStatus::ok();
226 }
227
setMixerControlVolume(Control ctl,float volume)228 ndk::ScopedAStatus Mixer::setMixerControlVolume(Control ctl, float volume) {
229 struct mixer_ctl* mctl;
230 RETURN_STATUS_IF_ERROR(findControl(ctl, &mctl));
231 volume = std::clamp(volume, 0.0f, 1.0f);
232 std::lock_guard l(mMixerAccess);
233 if (int err = setMixerControlPercent(mctl, std::floor(volume * 100)); err != 0) {
234 LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << volume << ", err=" << err;
235 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
236 }
237 return ndk::ScopedAStatus::ok();
238 }
239
getMixerControlPercent(struct mixer_ctl * ctl,std::vector<int> * percents)240 int Mixer::getMixerControlPercent(struct mixer_ctl* ctl, std::vector<int>* percents) {
241 const unsigned int n = mixer_ctl_get_num_values(ctl);
242 percents->resize(n);
243 for (unsigned int id = 0; id < n; id++) {
244 if (int valueOrError = mixer_ctl_get_percent(ctl, id); valueOrError >= 0) {
245 (*percents)[id] = valueOrError;
246 } else {
247 return valueOrError;
248 }
249 }
250 return 0;
251 }
252
getMixerControlValues(struct mixer_ctl * ctl,std::vector<int> * values)253 int Mixer::getMixerControlValues(struct mixer_ctl* ctl, std::vector<int>* values) {
254 const unsigned int n = mixer_ctl_get_num_values(ctl);
255 values->resize(n);
256 for (unsigned int id = 0; id < n; id++) {
257 if (int valueOrError = mixer_ctl_get_value(ctl, id); valueOrError >= 0) {
258 (*values)[id] = valueOrError;
259 } else {
260 return valueOrError;
261 }
262 }
263 return 0;
264 }
265
setMixerControlPercent(struct mixer_ctl * ctl,int percent)266 int Mixer::setMixerControlPercent(struct mixer_ctl* ctl, int percent) {
267 const unsigned int n = mixer_ctl_get_num_values(ctl);
268 for (unsigned int id = 0; id < n; id++) {
269 if (int error = mixer_ctl_set_percent(ctl, id, percent); error != 0) {
270 return error;
271 }
272 }
273 return 0;
274 }
275
setMixerControlPercent(struct mixer_ctl * ctl,const std::vector<int> & percents)276 int Mixer::setMixerControlPercent(struct mixer_ctl* ctl, const std::vector<int>& percents) {
277 const unsigned int n = mixer_ctl_get_num_values(ctl);
278 for (unsigned int id = 0; id < n; id++) {
279 if (int error = mixer_ctl_set_percent(ctl, id, id < percents.size() ? percents[id] : 0);
280 error != 0) {
281 return error;
282 }
283 }
284 return 0;
285 }
286
setMixerControlValue(struct mixer_ctl * ctl,int value)287 int Mixer::setMixerControlValue(struct mixer_ctl* ctl, int value) {
288 const unsigned int n = mixer_ctl_get_num_values(ctl);
289 for (unsigned int id = 0; id < n; id++) {
290 if (int error = mixer_ctl_set_value(ctl, id, value); error != 0) {
291 return error;
292 }
293 }
294 return 0;
295 }
296
297 } // namespace aidl::android::hardware::audio::core::alsa
298