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 #pragma once
18 
19 #include <iostream>
20 #include <map>
21 #include <memory>
22 #include <mutex>
23 #include <string>
24 #include <vector>
25 
26 #include <android-base/thread_annotations.h>
27 #include <android/binder_auto_utils.h>
28 
29 extern "C" {
30 #include <tinyalsa/mixer.h>
31 }
32 
33 namespace aidl::android::hardware::audio::core::alsa {
34 
35 class Mixer {
36   public:
37     explicit Mixer(int card);
38     ~Mixer();
39 
isValid()40     bool isValid() const { return mMixer != nullptr; }
41 
42     ndk::ScopedAStatus getMasterMute(bool* muted);
43     ndk::ScopedAStatus getMasterVolume(float* volume);
44     ndk::ScopedAStatus getMicGain(float* gain);
45     ndk::ScopedAStatus getMicMute(bool* muted);
46     ndk::ScopedAStatus getVolumes(std::vector<float>* volumes);
47     ndk::ScopedAStatus setMasterMute(bool muted);
48     ndk::ScopedAStatus setMasterVolume(float volume);
49     ndk::ScopedAStatus setMicGain(float gain);
50     ndk::ScopedAStatus setMicMute(bool muted);
51     ndk::ScopedAStatus setVolumes(const std::vector<float>& volumes);
52 
53   private:
54     enum Control {
55         MASTER_SWITCH,
56         MASTER_VOLUME,
57         HW_VOLUME,
58         MIC_SWITCH,
59         MIC_GAIN,
60     };
61     using ControlNamesAndExpectedCtlType = std::pair<std::string, enum mixer_ctl_type>;
62     using Controls = std::map<Control, struct mixer_ctl*>;
63 
64     friend std::ostream& operator<<(std::ostream&, Control);
65     static const std::map<Control, std::vector<ControlNamesAndExpectedCtlType>> kPossibleControls;
66     static Controls initializeMixerControls(struct mixer* mixer);
67 
68     ndk::ScopedAStatus findControl(Control ctl, struct mixer_ctl** result);
69     ndk::ScopedAStatus getMixerControlMute(Control ctl, bool* muted);
70     ndk::ScopedAStatus getMixerControlVolume(Control ctl, float* volume);
71     ndk::ScopedAStatus setMixerControlMute(Control ctl, bool muted);
72     ndk::ScopedAStatus setMixerControlVolume(Control ctl, float volume);
73 
74     int getMixerControlPercent(struct mixer_ctl* ctl, std::vector<int>* percents)
75             REQUIRES(mMixerAccess);
76     int getMixerControlValues(struct mixer_ctl* ctl, std::vector<int>* values)
77             REQUIRES(mMixerAccess);
78     int setMixerControlPercent(struct mixer_ctl* ctl, int percent) REQUIRES(mMixerAccess);
79     int setMixerControlPercent(struct mixer_ctl* ctl, const std::vector<int>& percents)
80             REQUIRES(mMixerAccess);
81     int setMixerControlValue(struct mixer_ctl* ctl, int value) REQUIRES(mMixerAccess);
82 
83     // Since ALSA functions do not use internal locking, enforce thread safety at our level.
84     std::mutex mMixerAccess;
85     // The mixer object is owned by ALSA and will be released when the mixer is closed.
86     struct mixer* const mMixer;
87     // `mMixerControls` will only be initialized in constructor. After that, it will only be
88     // read but not be modified. Each mixer_ctl object is owned by ALSA, it's life span is
89     // the same as of the mixer itself.
90     const Controls mMixerControls;
91 };
92 
93 }  // namespace aidl::android::hardware::audio::core::alsa
94