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