blob: f0393e3a7eaea034f362631cdca6c035c4a59e92 [file] [log] [blame]
Mikhail Naganovc337a872023-07-07 12:01:17 -07001/*
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_AlsaMixer"
18#include <android-base/logging.h>
19
20#include <cmath>
21
22#include <android/binder_status.h>
23
24#include "Mixer.h"
25
26namespace aidl::android::hardware::audio::core::alsa {
27
28//-----------------------------------------------------------------------------
29
30MixerControl::MixerControl(struct mixer_ctl* ctl)
31 : mCtl(ctl),
32 mNumValues(mixer_ctl_get_num_values(ctl)),
33 mMinValue(mixer_ctl_get_range_min(ctl)),
34 mMaxValue(mixer_ctl_get_range_max(ctl)) {}
35
36unsigned int MixerControl::getNumValues() const {
37 return mNumValues;
38}
39
40int MixerControl::getMaxValue() const {
41 return mMaxValue;
42}
43
44int MixerControl::getMinValue() const {
45 return mMinValue;
46}
47
48int MixerControl::setArray(const void* array, size_t count) {
49 const std::lock_guard guard(mLock);
50 return mixer_ctl_set_array(mCtl, array, count);
51}
52
53//-----------------------------------------------------------------------------
54
55// static
56const std::map<Mixer::Control, std::vector<Mixer::ControlNamesAndExpectedCtlType>>
57 Mixer::kPossibleControls = {
58 {Mixer::MASTER_SWITCH, {{"Master Playback Switch", MIXER_CTL_TYPE_BOOL}}},
59 {Mixer::MASTER_VOLUME, {{"Master Playback Volume", MIXER_CTL_TYPE_INT}}},
60 {Mixer::HW_VOLUME,
61 {{"Headphone Playback Volume", MIXER_CTL_TYPE_INT},
62 {"Headset Playback Volume", MIXER_CTL_TYPE_INT},
63 {"PCM Playback Volume", MIXER_CTL_TYPE_INT}}}};
64
65// static
66std::map<Mixer::Control, std::shared_ptr<MixerControl>> Mixer::initializeMixerControls(
67 struct mixer* mixer) {
68 std::map<Mixer::Control, std::shared_ptr<MixerControl>> mixerControls;
69 std::string mixerCtlNames;
70 for (const auto& [control, possibleCtls] : kPossibleControls) {
71 for (const auto& [ctlName, expectedCtlType] : possibleCtls) {
72 struct mixer_ctl* ctl = mixer_get_ctl_by_name(mixer, ctlName.c_str());
73 if (ctl != nullptr && mixer_ctl_get_type(ctl) == expectedCtlType) {
74 mixerControls.emplace(control, std::make_unique<MixerControl>(ctl));
75 if (!mixerCtlNames.empty()) {
76 mixerCtlNames += ",";
77 }
78 mixerCtlNames += ctlName;
79 break;
80 }
81 }
82 }
83 LOG(DEBUG) << __func__ << ": available mixer control names=[" << mixerCtlNames << "]";
84 return mixerControls;
85}
86
87Mixer::Mixer(struct mixer* mixer)
88 : mMixer(mixer), mMixerControls(initializeMixerControls(mMixer)) {}
89
90Mixer::~Mixer() {
91 mixer_close(mMixer);
92}
93
94namespace {
95
96int volumeFloatToInteger(float fValue, int maxValue, int minValue) {
97 return minValue + std::ceil((maxValue - minValue) * fValue);
98}
99
100} // namespace
101
102ndk::ScopedAStatus Mixer::setMasterMute(bool muted) {
103 auto it = mMixerControls.find(Mixer::MASTER_SWITCH);
104 if (it == mMixerControls.end()) {
105 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
106 }
107 const int numValues = it->second->getNumValues();
108 std::vector<int> values(numValues, muted ? 0 : 1);
109 if (int err = it->second->setArray(values.data(), numValues); err != 0) {
110 LOG(ERROR) << __func__ << ": failed to set master mute, err=" << err;
111 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
112 }
113 return ndk::ScopedAStatus::ok();
114}
115
116ndk::ScopedAStatus Mixer::setMasterVolume(float volume) {
117 auto it = mMixerControls.find(Mixer::MASTER_VOLUME);
118 if (it == mMixerControls.end()) {
119 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
120 }
121 const int numValues = it->second->getNumValues();
122 std::vector<int> values(numValues, volumeFloatToInteger(volume, it->second->getMaxValue(),
123 it->second->getMinValue()));
124 if (int err = it->second->setArray(values.data(), numValues); err != 0) {
125 LOG(ERROR) << __func__ << ": failed to set master volume, err=" << err;
126 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
127 }
128 return ndk::ScopedAStatus::ok();
129}
130
131ndk::ScopedAStatus Mixer::setVolumes(const std::vector<float>& volumes) {
132 auto it = mMixerControls.find(Mixer::HW_VOLUME);
133 if (it == mMixerControls.end()) {
134 return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
135 }
136 const int numValues = it->second->getNumValues();
137 if (numValues < 0) {
138 LOG(FATAL) << __func__ << ": negative number of values: " << numValues;
139 }
140 const int maxValue = it->second->getMaxValue();
141 const int minValue = it->second->getMinValue();
142 std::vector<int> values;
143 size_t i = 0;
144 for (; i < static_cast<size_t>(numValues) && i < values.size(); ++i) {
145 values.emplace_back(volumeFloatToInteger(volumes[i], maxValue, minValue));
146 }
147 if (int err = it->second->setArray(values.data(), values.size()); err != 0) {
148 LOG(ERROR) << __func__ << ": failed to set volume, err=" << err;
149 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
150 }
151 return ndk::ScopedAStatus::ok();
152}
153
154} // namespace aidl::android::hardware::audio::core::alsa