• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
24 #include "Mixer.h"
25 
26 namespace aidl::android::hardware::audio::core::alsa {
27 
28 // static
29 const std::map<Mixer::Control, std::vector<Mixer::ControlNamesAndExpectedCtlType>>
30         Mixer::kPossibleControls = {
31                 {Mixer::MASTER_SWITCH, {{"Master Playback Switch", MIXER_CTL_TYPE_BOOL}}},
32                 {Mixer::MASTER_VOLUME, {{"Master Playback Volume", MIXER_CTL_TYPE_INT}}},
33                 {Mixer::HW_VOLUME,
34                  {{"Headphone Playback Volume", MIXER_CTL_TYPE_INT},
35                   {"Headset Playback Volume", MIXER_CTL_TYPE_INT},
36                   {"PCM Playback Volume", MIXER_CTL_TYPE_INT}}},
37                 {Mixer::MIC_SWITCH, {{"Capture Switch", MIXER_CTL_TYPE_BOOL}}},
38                 {Mixer::MIC_GAIN, {{"Capture Volume", MIXER_CTL_TYPE_INT}}}};
39 
40 // static
initializeMixerControls(struct mixer * mixer)41 Mixer::Controls Mixer::initializeMixerControls(struct mixer* mixer) {
42     if (mixer == nullptr) return {};
43     Controls mixerControls;
44     std::string mixerCtlNames;
45     for (const auto& [control, possibleCtls] : kPossibleControls) {
46         for (const auto& [ctlName, expectedCtlType] : possibleCtls) {
47             struct mixer_ctl* ctl = mixer_get_ctl_by_name(mixer, ctlName.c_str());
48             if (ctl != nullptr && mixer_ctl_get_type(ctl) == expectedCtlType) {
49                 mixerControls.emplace(control, ctl);
50                 if (!mixerCtlNames.empty()) {
51                     mixerCtlNames += ",";
52                 }
53                 mixerCtlNames += ctlName;
54                 break;
55             }
56         }
57     }
58     LOG(DEBUG) << __func__ << ": available mixer control names=[" << mixerCtlNames << "]";
59     return mixerControls;
60 }
61 
operator <<(std::ostream & s,Mixer::Control c)62 std::ostream& operator<<(std::ostream& s, Mixer::Control c) {
63     switch (c) {
64         case Mixer::Control::MASTER_SWITCH:
65             s << "master mute";
66             break;
67         case Mixer::Control::MASTER_VOLUME:
68             s << "master volume";
69             break;
70         case Mixer::Control::HW_VOLUME:
71             s << "volume";
72             break;
73         case Mixer::Control::MIC_SWITCH:
74             s << "mic mute";
75             break;
76         case Mixer::Control::MIC_GAIN:
77             s << "mic gain";
78             break;
79     }
80     return s;
81 }
82 
Mixer(int card)83 Mixer::Mixer(int card) : mMixer(mixer_open(card)), mMixerControls(initializeMixerControls(mMixer)) {
84     if (!isValid()) {
85         PLOG(ERROR) << __func__ << ": failed to open mixer for card=" << card;
86     }
87 }
88 
~Mixer()89 Mixer::~Mixer() {
90     if (isValid()) {
91         std::lock_guard l(mMixerAccess);
92         mixer_close(mMixer);
93     }
94 }
95 
setMasterMute(bool muted)96 ndk::ScopedAStatus Mixer::setMasterMute(bool muted) {
97     return setMixerControlMute(MASTER_SWITCH, muted);
98 }
99 
setMasterVolume(float volume)100 ndk::ScopedAStatus Mixer::setMasterVolume(float volume) {
101     return setMixerControlVolume(MASTER_VOLUME, volume);
102 }
103 
setMicGain(float gain)104 ndk::ScopedAStatus Mixer::setMicGain(float gain) {
105     return setMixerControlVolume(MIC_GAIN, gain);
106 }
107 
setMicMute(bool muted)108 ndk::ScopedAStatus Mixer::setMicMute(bool muted) {
109     return setMixerControlMute(MIC_SWITCH, muted);
110 }
111 
setVolumes(const std::vector<float> & volumes)112 ndk::ScopedAStatus Mixer::setVolumes(const std::vector<float>& volumes) {
113     if (!isValid()) {
114         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
115     }
116     auto it = mMixerControls.find(Mixer::HW_VOLUME);
117     if (it == mMixerControls.end()) {
118         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
119     }
120     std::vector<int> percents;
121     std::transform(
122             volumes.begin(), volumes.end(), std::back_inserter(percents),
123             [](float volume) -> int { return std::floor(std::clamp(volume, 0.0f, 1.0f) * 100); });
124     std::lock_guard l(mMixerAccess);
125     if (int err = setMixerControlPercent(it->second, percents); err != 0) {
126         LOG(ERROR) << __func__ << ": failed to set volume, err=" << err;
127         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
128     }
129     return ndk::ScopedAStatus::ok();
130 }
131 
setMixerControlMute(Mixer::Control ctl,bool muted)132 ndk::ScopedAStatus Mixer::setMixerControlMute(Mixer::Control ctl, bool muted) {
133     if (!isValid()) {
134         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
135     }
136     auto it = mMixerControls.find(ctl);
137     if (it == mMixerControls.end()) {
138         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
139     }
140     std::lock_guard l(mMixerAccess);
141     if (int err = setMixerControlValue(it->second, muted ? 0 : 1); err != 0) {
142         LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << muted << ", err=" << err;
143         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
144     }
145     return ndk::ScopedAStatus::ok();
146 }
147 
setMixerControlVolume(Control ctl,float volume)148 ndk::ScopedAStatus Mixer::setMixerControlVolume(Control ctl, float volume) {
149     if (!isValid()) {
150         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
151     }
152     auto it = mMixerControls.find(ctl);
153     if (it == mMixerControls.end()) {
154         return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
155     }
156     volume = std::clamp(volume, 0.0f, 1.0f);
157     std::lock_guard l(mMixerAccess);
158     if (int err = setMixerControlPercent(it->second, std::floor(volume * 100)); err != 0) {
159         LOG(ERROR) << __func__ << ": failed to set " << ctl << " to " << volume << ", err=" << err;
160         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
161     }
162     return ndk::ScopedAStatus::ok();
163 }
164 
setMixerControlPercent(struct mixer_ctl * ctl,int percent)165 int Mixer::setMixerControlPercent(struct mixer_ctl* ctl, int percent) {
166     int ret = 0;
167     const unsigned int n = mixer_ctl_get_num_values(ctl);
168     for (unsigned int id = 0; id < n; id++) {
169         if (int error = mixer_ctl_set_percent(ctl, id, percent); error != 0) {
170             ret = error;
171         }
172     }
173     return ret;
174 }
175 
setMixerControlPercent(struct mixer_ctl * ctl,const std::vector<int> & percents)176 int Mixer::setMixerControlPercent(struct mixer_ctl* ctl, const std::vector<int>& percents) {
177     int ret = 0;
178     const unsigned int n = mixer_ctl_get_num_values(ctl);
179     for (unsigned int id = 0; id < n; id++) {
180         if (int error = mixer_ctl_set_percent(ctl, id, id < percents.size() ? percents[id] : 0);
181             error != 0) {
182             ret = error;
183         }
184     }
185     return ret;
186 }
187 
setMixerControlValue(struct mixer_ctl * ctl,int value)188 int Mixer::setMixerControlValue(struct mixer_ctl* ctl, int value) {
189     int ret = 0;
190     const unsigned int n = mixer_ctl_get_num_values(ctl);
191     for (unsigned int id = 0; id < n; id++) {
192         if (int error = mixer_ctl_set_value(ctl, id, value); error != 0) {
193             ret = error;
194         }
195     }
196     return ret;
197 }
198 
199 }  // namespace aidl::android::hardware::audio::core::alsa
200