xref: /aosp_15_r20/external/tinyalsa_new/tests/src/mixer_test.cc (revision 02e95f1a335b55495d41ca67eaf42361f13704fa)
1*02e95f1aSMarcin Radomski /* mixer_test.c
2*02e95f1aSMarcin Radomski **
3*02e95f1aSMarcin Radomski ** Copyright 2020, The Android Open Source Project
4*02e95f1aSMarcin Radomski **
5*02e95f1aSMarcin Radomski ** Redistribution and use in source and binary forms, with or without
6*02e95f1aSMarcin Radomski ** modification, are permitted provided that the following conditions are met:
7*02e95f1aSMarcin Radomski **     * Redistributions of source code must retain the above copyright
8*02e95f1aSMarcin Radomski **       notice, this list of conditions and the following disclaimer.
9*02e95f1aSMarcin Radomski **     * Redistributions in binary form must reproduce the above copyright
10*02e95f1aSMarcin Radomski **       notice, this list of conditions and the following disclaimer in the
11*02e95f1aSMarcin Radomski **       documentation and/or other materials provided with the distribution.
12*02e95f1aSMarcin Radomski **     * Neither the name of The Android Open Source Project nor the names of
13*02e95f1aSMarcin Radomski **       its contributors may be used to endorse or promote products derived
14*02e95f1aSMarcin Radomski **       from this software without specific prior written permission.
15*02e95f1aSMarcin Radomski **
16*02e95f1aSMarcin Radomski ** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
17*02e95f1aSMarcin Radomski ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*02e95f1aSMarcin Radomski ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*02e95f1aSMarcin Radomski ** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
20*02e95f1aSMarcin Radomski ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*02e95f1aSMarcin Radomski ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22*02e95f1aSMarcin Radomski ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23*02e95f1aSMarcin Radomski ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*02e95f1aSMarcin Radomski ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*02e95f1aSMarcin Radomski ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26*02e95f1aSMarcin Radomski ** DAMAGE.
27*02e95f1aSMarcin Radomski */
28*02e95f1aSMarcin Radomski #include "pcm_test_device.h"
29*02e95f1aSMarcin Radomski 
30*02e95f1aSMarcin Radomski #include <limits>
31*02e95f1aSMarcin Radomski #include <string_view>
32*02e95f1aSMarcin Radomski #include <string>
33*02e95f1aSMarcin Radomski #include <thread>
34*02e95f1aSMarcin Radomski #include <type_traits>
35*02e95f1aSMarcin Radomski #include <unordered_map>
36*02e95f1aSMarcin Radomski #include <unordered_set>
37*02e95f1aSMarcin Radomski 
38*02e95f1aSMarcin Radomski #include <gtest/gtest.h>
39*02e95f1aSMarcin Radomski 
40*02e95f1aSMarcin Radomski #include "tinyalsa/mixer.h"
41*02e95f1aSMarcin Radomski 
42*02e95f1aSMarcin Radomski namespace tinyalsa {
43*02e95f1aSMarcin Radomski namespace testing {
44*02e95f1aSMarcin Radomski 
45*02e95f1aSMarcin Radomski #ifndef MAX_CARD_INDEX
46*02e95f1aSMarcin Radomski #define MAX_CARD_INDEX 2
47*02e95f1aSMarcin Radomski #endif
48*02e95f1aSMarcin Radomski 
49*02e95f1aSMarcin Radomski static constexpr unsigned int kMaxCardIndex = MAX_CARD_INDEX;
50*02e95f1aSMarcin Radomski 
51*02e95f1aSMarcin Radomski static constexpr int k100Percent = 100;
52*02e95f1aSMarcin Radomski static constexpr int k0Percent = 0;
53*02e95f1aSMarcin Radomski 
TEST(MixerTest,OpenAndClose)54*02e95f1aSMarcin Radomski TEST(MixerTest, OpenAndClose) {
55*02e95f1aSMarcin Radomski     // assume card 0 is always probed.
56*02e95f1aSMarcin Radomski     mixer *mixer_object = mixer_open(0);
57*02e95f1aSMarcin Radomski     EXPECT_NE(mixer_object, nullptr);
58*02e95f1aSMarcin Radomski     mixer_close(mixer_object);
59*02e95f1aSMarcin Radomski }
60*02e95f1aSMarcin Radomski 
TEST(MixerTest,NullParametersCheck)61*02e95f1aSMarcin Radomski TEST(MixerTest, NullParametersCheck) {
62*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_open(1000), nullptr);
63*02e95f1aSMarcin Radomski     mixer_close(nullptr);
64*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_add_new_ctls(nullptr), 0);
65*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_get_name(nullptr), nullptr);
66*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_get_num_ctls(nullptr), 0);
67*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_get_num_ctls_by_name(nullptr, ""), 0);
68*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_get_num_ctls_by_name(reinterpret_cast<const mixer *>(1), nullptr), 0);
69*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_get_ctl_const(nullptr, 0), nullptr);
70*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_get_ctl(nullptr, 0), nullptr);
71*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_get_ctl_by_name(nullptr, ""), nullptr);
72*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_get_ctl_by_name(reinterpret_cast<mixer *>(1), nullptr), nullptr);
73*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_get_ctl_by_name_and_index(nullptr, "", 0), nullptr);
74*02e95f1aSMarcin Radomski     EXPECT_EQ(
75*02e95f1aSMarcin Radomski             mixer_get_ctl_by_name_and_index(reinterpret_cast<mixer *>(1), nullptr, 0),
76*02e95f1aSMarcin Radomski             nullptr);
77*02e95f1aSMarcin Radomski     EXPECT_NE(mixer_subscribe_events(nullptr, 0), 0);
78*02e95f1aSMarcin Radomski     EXPECT_LT(mixer_wait_event(nullptr, 0), 0);
79*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_ctl_get_id(nullptr), std::numeric_limits<unsigned int>::max());
80*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_ctl_get_name(nullptr), nullptr);
81*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_ctl_get_type(nullptr), MIXER_CTL_TYPE_UNKNOWN);
82*02e95f1aSMarcin Radomski     EXPECT_STREQ(mixer_ctl_get_type_string(nullptr), "");
83*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_ctl_get_num_values(nullptr), 0);
84*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_ctl_get_num_enums(nullptr), 0);
85*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_ctl_get_enum_string(nullptr, 0), nullptr);
86*02e95f1aSMarcin Radomski     mixer_ctl_update(nullptr);
87*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_ctl_is_access_tlv_rw(nullptr), 0);
88*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_ctl_get_percent(nullptr, 0), -EINVAL);
89*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_ctl_set_percent(nullptr, 0, 0), -EINVAL);
90*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_ctl_get_value(nullptr, 0), -EINVAL);
91*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_ctl_get_array(nullptr, reinterpret_cast<void *>(1), 1), -EINVAL);
92*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_ctl_get_array(reinterpret_cast<mixer_ctl *>(1), nullptr, 1), -EINVAL);
93*02e95f1aSMarcin Radomski     EXPECT_EQ(
94*02e95f1aSMarcin Radomski             mixer_ctl_get_array(
95*02e95f1aSMarcin Radomski                 reinterpret_cast<mixer_ctl *>(1), reinterpret_cast<void *>(1), 0), -EINVAL);
96*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_ctl_set_value(nullptr, 0, 0), -EINVAL);
97*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_ctl_set_array(nullptr, reinterpret_cast<const void *>(1), 1), -EINVAL);
98*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_ctl_set_array(reinterpret_cast<mixer_ctl *>(1), nullptr, 1), -EINVAL);
99*02e95f1aSMarcin Radomski     EXPECT_EQ(
100*02e95f1aSMarcin Radomski             mixer_ctl_set_array(
101*02e95f1aSMarcin Radomski                 reinterpret_cast<mixer_ctl *>(1), reinterpret_cast<const void *>(1), 0), -EINVAL);
102*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_ctl_set_enum_by_string(nullptr, reinterpret_cast<const char *>(1)), -EINVAL);
103*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_ctl_set_enum_by_string(reinterpret_cast<mixer_ctl *>(1), nullptr), -EINVAL);
104*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_ctl_get_range_min(nullptr), -EINVAL);
105*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_ctl_get_range_max(nullptr), -EINVAL);
106*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_read_event(nullptr, reinterpret_cast<mixer_ctl_event *>(1)), -EINVAL);
107*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_read_event(reinterpret_cast<mixer *>(1), nullptr), -EINVAL);
108*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_consume_event(nullptr), -EINVAL);
109*02e95f1aSMarcin Radomski }
110*02e95f1aSMarcin Radomski 
111*02e95f1aSMarcin Radomski class MixerTest : public ::testing::TestWithParam<unsigned int> {
112*02e95f1aSMarcin Radomski   protected:
MixerTest()113*02e95f1aSMarcin Radomski     MixerTest() : mixer_object(nullptr) {}
114*02e95f1aSMarcin Radomski     virtual ~MixerTest() = default;
115*02e95f1aSMarcin Radomski 
SetUp()116*02e95f1aSMarcin Radomski     virtual void SetUp() override {
117*02e95f1aSMarcin Radomski         unsigned int card = GetParam();
118*02e95f1aSMarcin Radomski         mixer_object = mixer_open(card);
119*02e95f1aSMarcin Radomski         ASSERT_NE(mixer_object, nullptr);
120*02e95f1aSMarcin Radomski     }
121*02e95f1aSMarcin Radomski 
TearDown()122*02e95f1aSMarcin Radomski     virtual void TearDown() override {
123*02e95f1aSMarcin Radomski         mixer_close(mixer_object);
124*02e95f1aSMarcin Radomski     }
125*02e95f1aSMarcin Radomski 
126*02e95f1aSMarcin Radomski     mixer *mixer_object;
127*02e95f1aSMarcin Radomski };
128*02e95f1aSMarcin Radomski 
TEST_P(MixerTest,AddNewControls)129*02e95f1aSMarcin Radomski TEST_P(MixerTest, AddNewControls) {
130*02e95f1aSMarcin Radomski     ASSERT_EQ(mixer_add_new_ctls(mixer_object), 0);
131*02e95f1aSMarcin Radomski }
132*02e95f1aSMarcin Radomski 
TEST_P(MixerTest,GetName)133*02e95f1aSMarcin Radomski TEST_P(MixerTest, GetName) {
134*02e95f1aSMarcin Radomski     const char *name = mixer_get_name(mixer_object);
135*02e95f1aSMarcin Radomski     std::cout << name << std::endl;
136*02e95f1aSMarcin Radomski     ASSERT_STRNE(name, "");
137*02e95f1aSMarcin Radomski }
138*02e95f1aSMarcin Radomski 
TEST_P(MixerTest,GetNumberOfControls)139*02e95f1aSMarcin Radomski TEST_P(MixerTest, GetNumberOfControls) {
140*02e95f1aSMarcin Radomski     unsigned int nums = mixer_get_num_ctls(mixer_object);
141*02e95f1aSMarcin Radomski     std::cout << nums << std::endl;
142*02e95f1aSMarcin Radomski     ASSERT_GT(nums, 0);
143*02e95f1aSMarcin Radomski }
144*02e95f1aSMarcin Radomski 
145*02e95f1aSMarcin Radomski class MixerControlsTest : public MixerTest {
146*02e95f1aSMarcin Radomski   protected:
MixerControlsTest()147*02e95f1aSMarcin Radomski     MixerControlsTest() : number_of_controls(0), controls(nullptr) {}
148*02e95f1aSMarcin Radomski     virtual ~MixerControlsTest() = default;
149*02e95f1aSMarcin Radomski 
SetUp()150*02e95f1aSMarcin Radomski     virtual void SetUp() override {
151*02e95f1aSMarcin Radomski         MixerTest::SetUp();
152*02e95f1aSMarcin Radomski 
153*02e95f1aSMarcin Radomski         number_of_controls = mixer_get_num_ctls(mixer_object);
154*02e95f1aSMarcin Radomski         ASSERT_GT(number_of_controls, 0);
155*02e95f1aSMarcin Radomski 
156*02e95f1aSMarcin Radomski         controls = std::make_unique<const mixer_ctl *[]>(number_of_controls);
157*02e95f1aSMarcin Radomski         ASSERT_NE(controls, nullptr);
158*02e95f1aSMarcin Radomski 
159*02e95f1aSMarcin Radomski         for (unsigned int i = 0; i < number_of_controls; i++) {
160*02e95f1aSMarcin Radomski             controls[i] = mixer_get_ctl_const(mixer_object, i);
161*02e95f1aSMarcin Radomski             EXPECT_EQ(mixer_ctl_get_id(controls[i]), i);
162*02e95f1aSMarcin Radomski             EXPECT_STRNE(mixer_ctl_get_name(controls[i]), "");
163*02e95f1aSMarcin Radomski             EXPECT_NE(controls[i], nullptr);
164*02e95f1aSMarcin Radomski         }
165*02e95f1aSMarcin Radomski     }
166*02e95f1aSMarcin Radomski 
TearDown()167*02e95f1aSMarcin Radomski     virtual void TearDown() override {
168*02e95f1aSMarcin Radomski         controls = nullptr;
169*02e95f1aSMarcin Radomski         MixerTest::TearDown();
170*02e95f1aSMarcin Radomski     }
171*02e95f1aSMarcin Radomski 
172*02e95f1aSMarcin Radomski     unsigned int number_of_controls;
173*02e95f1aSMarcin Radomski     std::unique_ptr<const mixer_ctl *[]> controls;
174*02e95f1aSMarcin Radomski };
175*02e95f1aSMarcin Radomski 
TEST_P(MixerControlsTest,GetNumberOfControlsByName)176*02e95f1aSMarcin Radomski TEST_P(MixerControlsTest, GetNumberOfControlsByName) {
177*02e95f1aSMarcin Radomski     for (unsigned int i = 0; i < number_of_controls; ++i) {
178*02e95f1aSMarcin Radomski         const char *name = mixer_ctl_get_name(controls[i]);
179*02e95f1aSMarcin Radomski         ASSERT_GE(mixer_get_num_ctls_by_name(mixer_object, name), 1);
180*02e95f1aSMarcin Radomski     }
181*02e95f1aSMarcin Radomski 
182*02e95f1aSMarcin Radomski     std::string name{mixer_ctl_get_name(controls[0])};
183*02e95f1aSMarcin Radomski     name += "1";
184*02e95f1aSMarcin Radomski     ASSERT_EQ(mixer_get_num_ctls_by_name(mixer_object, name.c_str()), 0);
185*02e95f1aSMarcin Radomski }
186*02e95f1aSMarcin Radomski 
TEST_P(MixerControlsTest,GetControlById)187*02e95f1aSMarcin Radomski TEST_P(MixerControlsTest, GetControlById) {
188*02e95f1aSMarcin Radomski     for (unsigned int i = 0; i < number_of_controls; ++i) {
189*02e95f1aSMarcin Radomski         ASSERT_EQ(mixer_get_ctl(mixer_object, i), controls[i]);
190*02e95f1aSMarcin Radomski     }
191*02e95f1aSMarcin Radomski 
192*02e95f1aSMarcin Radomski     ASSERT_EQ(mixer_get_ctl(mixer_object, number_of_controls), nullptr);
193*02e95f1aSMarcin Radomski }
194*02e95f1aSMarcin Radomski 
TEST_P(MixerControlsTest,GetControlByName)195*02e95f1aSMarcin Radomski TEST_P(MixerControlsTest, GetControlByName) {
196*02e95f1aSMarcin Radomski     std::unordered_set<std::string> visited_names_set;
197*02e95f1aSMarcin Radomski     for (unsigned int i = 0; i < number_of_controls; ++i) {
198*02e95f1aSMarcin Radomski         std::string name{mixer_ctl_get_name(controls[i])};
199*02e95f1aSMarcin Radomski         if (visited_names_set.find(name) == visited_names_set.end()) {
200*02e95f1aSMarcin Radomski             ASSERT_EQ(mixer_get_ctl_by_name(mixer_object, name.c_str()), controls[i]);
201*02e95f1aSMarcin Radomski             visited_names_set.insert(name);
202*02e95f1aSMarcin Radomski         }
203*02e95f1aSMarcin Radomski     }
204*02e95f1aSMarcin Radomski }
205*02e95f1aSMarcin Radomski 
TEST_P(MixerControlsTest,GetControlByNameAndIndex)206*02e95f1aSMarcin Radomski TEST_P(MixerControlsTest, GetControlByNameAndIndex) {
207*02e95f1aSMarcin Radomski     std::unordered_map<std::string, int32_t> visited_names_and_count_map;
208*02e95f1aSMarcin Radomski     for (unsigned int i = 0; i < number_of_controls; ++i) {
209*02e95f1aSMarcin Radomski         std::string name{mixer_ctl_get_name(controls[i])};
210*02e95f1aSMarcin Radomski         if (visited_names_and_count_map.find(name) == visited_names_and_count_map.end()) {
211*02e95f1aSMarcin Radomski             visited_names_and_count_map[name] = 0;
212*02e95f1aSMarcin Radomski         }
213*02e95f1aSMarcin Radomski         ASSERT_EQ(
214*02e95f1aSMarcin Radomski                 mixer_get_ctl_by_name_and_index(mixer_object,
215*02e95f1aSMarcin Radomski                                                 name.c_str(),
216*02e95f1aSMarcin Radomski                                                 visited_names_and_count_map[name]),
217*02e95f1aSMarcin Radomski                 controls[i]);
218*02e95f1aSMarcin Radomski         visited_names_and_count_map[name] = visited_names_and_count_map[name] + 1;
219*02e95f1aSMarcin Radomski     }
220*02e95f1aSMarcin Radomski }
221*02e95f1aSMarcin Radomski 
IsValidTypeString(std::string & type)222*02e95f1aSMarcin Radomski static inline bool IsValidTypeString(std::string& type) {
223*02e95f1aSMarcin Radomski     return type == "BOOL" || type == "INT" || type == "ENUM" || type == "BYTE" ||
224*02e95f1aSMarcin Radomski             type == "IEC958" || type == "INT64";
225*02e95f1aSMarcin Radomski }
226*02e95f1aSMarcin Radomski 
TEST_P(MixerControlsTest,GetControlTypeString)227*02e95f1aSMarcin Radomski TEST_P(MixerControlsTest, GetControlTypeString) {
228*02e95f1aSMarcin Radomski     ASSERT_STREQ(mixer_ctl_get_type_string(nullptr), "");
229*02e95f1aSMarcin Radomski 
230*02e95f1aSMarcin Radomski     for (unsigned int i = 0; i < number_of_controls; ++i) {
231*02e95f1aSMarcin Radomski         std::string type{mixer_ctl_get_type_string(controls[i])};
232*02e95f1aSMarcin Radomski         ASSERT_TRUE(IsValidTypeString(type));
233*02e95f1aSMarcin Radomski     }
234*02e95f1aSMarcin Radomski }
235*02e95f1aSMarcin Radomski 
TEST_P(MixerControlsTest,GetNumberOfValues)236*02e95f1aSMarcin Radomski TEST_P(MixerControlsTest, GetNumberOfValues) {
237*02e95f1aSMarcin Radomski     ASSERT_EQ(mixer_ctl_get_num_values(nullptr), 0);
238*02e95f1aSMarcin Radomski }
239*02e95f1aSMarcin Radomski 
TEST_P(MixerControlsTest,GetNumberOfEnumsAndEnumString)240*02e95f1aSMarcin Radomski TEST_P(MixerControlsTest, GetNumberOfEnumsAndEnumString) {
241*02e95f1aSMarcin Radomski     for (unsigned int i = 0; i < number_of_controls; ++i) {
242*02e95f1aSMarcin Radomski         const mixer_ctl *control = controls[i];
243*02e95f1aSMarcin Radomski         if (mixer_ctl_get_type(control) == MIXER_CTL_TYPE_ENUM) {
244*02e95f1aSMarcin Radomski             unsigned int number_of_enums = mixer_ctl_get_num_enums(control);
245*02e95f1aSMarcin Radomski             ASSERT_GT(number_of_enums, 0);
246*02e95f1aSMarcin Radomski             for (unsigned int enum_id = 0; enum_id < number_of_enums; ++enum_id) {
247*02e95f1aSMarcin Radomski                 const char *enum_name = mixer_ctl_get_enum_string(
248*02e95f1aSMarcin Radomski                         const_cast<mixer_ctl *>(control),
249*02e95f1aSMarcin Radomski                         enum_id);
250*02e95f1aSMarcin Radomski                 ASSERT_STRNE(enum_name, "");
251*02e95f1aSMarcin Radomski             }
252*02e95f1aSMarcin Radomski         }
253*02e95f1aSMarcin Radomski     }
254*02e95f1aSMarcin Radomski }
255*02e95f1aSMarcin Radomski 
TEST_P(MixerControlsTest,UpdateControl)256*02e95f1aSMarcin Radomski TEST_P(MixerControlsTest, UpdateControl) {
257*02e95f1aSMarcin Radomski     for (unsigned int i = 0; i < number_of_controls; ++i) {
258*02e95f1aSMarcin Radomski         mixer_ctl_update(const_cast<mixer_ctl *>(controls[i]));
259*02e95f1aSMarcin Radomski     }
260*02e95f1aSMarcin Radomski }
261*02e95f1aSMarcin Radomski 
TEST_P(MixerControlsTest,GetPercent)262*02e95f1aSMarcin Radomski TEST_P(MixerControlsTest, GetPercent) {
263*02e95f1aSMarcin Radomski     for (unsigned int i = 0; i < number_of_controls; ++i) {
264*02e95f1aSMarcin Radomski         const mixer_ctl *control = controls[i];
265*02e95f1aSMarcin Radomski         if (mixer_ctl_get_type(control) == MIXER_CTL_TYPE_INT) {
266*02e95f1aSMarcin Radomski             unsigned int number_of_values = mixer_ctl_get_num_values(controls[i]);
267*02e95f1aSMarcin Radomski             std::unique_ptr<long []> values = std::make_unique<long []>(number_of_values);
268*02e95f1aSMarcin Radomski             mixer_ctl_get_array(control, values.get(), number_of_values);
269*02e95f1aSMarcin Radomski             for (unsigned int value_id = 0; value_id < number_of_values; ++value_id) {
270*02e95f1aSMarcin Radomski                 int max = mixer_ctl_get_range_max(control);
271*02e95f1aSMarcin Radomski                 int min = mixer_ctl_get_range_min(control);
272*02e95f1aSMarcin Radomski                 int percent = mixer_ctl_get_percent(control, value_id);
273*02e95f1aSMarcin Radomski                 ASSERT_GE(percent, k0Percent);
274*02e95f1aSMarcin Radomski                 ASSERT_LE(percent, k100Percent);
275*02e95f1aSMarcin Radomski                 int range = max - min;
276*02e95f1aSMarcin Radomski                 ASSERT_EQ(percent, (values[value_id] - min) * k100Percent / range);
277*02e95f1aSMarcin Radomski             }
278*02e95f1aSMarcin Radomski         } else {
279*02e95f1aSMarcin Radomski             ASSERT_EQ(mixer_ctl_get_percent(control, 0), -EINVAL);
280*02e95f1aSMarcin Radomski         }
281*02e95f1aSMarcin Radomski     }
282*02e95f1aSMarcin Radomski }
283*02e95f1aSMarcin Radomski 
TEST_P(MixerControlsTest,SetPercent)284*02e95f1aSMarcin Radomski TEST_P(MixerControlsTest, SetPercent) {
285*02e95f1aSMarcin Radomski     for (unsigned int i = 0; i < number_of_controls; ++i) {
286*02e95f1aSMarcin Radomski         const mixer_ctl *control = controls[i];
287*02e95f1aSMarcin Radomski         if (mixer_ctl_get_type(control) == MIXER_CTL_TYPE_INT) {
288*02e95f1aSMarcin Radomski             unsigned int number_of_values = mixer_ctl_get_num_values(controls[i]);
289*02e95f1aSMarcin Radomski             std::unique_ptr<long []> values = std::make_unique<long []>(number_of_values);
290*02e95f1aSMarcin Radomski             mixer_ctl_get_array(control, values.get(), number_of_values);
291*02e95f1aSMarcin Radomski             for (unsigned int value_id = 0; value_id < number_of_values; ++value_id) {
292*02e95f1aSMarcin Radomski                 int max = mixer_ctl_get_range_max(control);
293*02e95f1aSMarcin Radomski                 int min = mixer_ctl_get_range_min(control);
294*02e95f1aSMarcin Radomski                 int value = values[value_id];
295*02e95f1aSMarcin Radomski                 int percent = mixer_ctl_get_percent(control, value_id);
296*02e95f1aSMarcin Radomski                 if (mixer_ctl_set_percent(
297*02e95f1aSMarcin Radomski                         const_cast<mixer_ctl *>(control), value_id, k100Percent) == 0) {
298*02e95f1aSMarcin Radomski                     // note: some controls are able to be written, but their values might not be
299*02e95f1aSMarcin Radomski                     //   changed.
300*02e95f1aSMarcin Radomski                     mixer_ctl_get_array(control, values.get(), number_of_values);
301*02e95f1aSMarcin Radomski                     int new_value = values[value_id];
302*02e95f1aSMarcin Radomski                     ASSERT_TRUE(new_value == value || new_value == max);
303*02e95f1aSMarcin Radomski                 }
304*02e95f1aSMarcin Radomski                 if (mixer_ctl_set_percent(
305*02e95f1aSMarcin Radomski                         const_cast<mixer_ctl *>(control), value_id, k0Percent) == 0) {
306*02e95f1aSMarcin Radomski                     mixer_ctl_get_array(control, values.get(), number_of_values);
307*02e95f1aSMarcin Radomski                     int new_value = values[value_id];
308*02e95f1aSMarcin Radomski                     ASSERT_TRUE(new_value == value || new_value == min);
309*02e95f1aSMarcin Radomski                 }
310*02e95f1aSMarcin Radomski                 mixer_ctl_set_percent(const_cast<mixer_ctl *>(control), value_id, percent);
311*02e95f1aSMarcin Radomski             }
312*02e95f1aSMarcin Radomski         } else {
313*02e95f1aSMarcin Radomski             ASSERT_EQ(mixer_ctl_get_percent(control, 0), -EINVAL);
314*02e95f1aSMarcin Radomski         }
315*02e95f1aSMarcin Radomski     }
316*02e95f1aSMarcin Radomski }
317*02e95f1aSMarcin Radomski 
TEST_P(MixerControlsTest,Event)318*02e95f1aSMarcin Radomski TEST_P(MixerControlsTest, Event) {
319*02e95f1aSMarcin Radomski     ASSERT_EQ(mixer_subscribe_events(mixer_object, 1), 0);
320*02e95f1aSMarcin Radomski     const mixer_ctl *control = nullptr;
321*02e95f1aSMarcin Radomski     for (unsigned int i = 0; i < number_of_controls; ++i) {
322*02e95f1aSMarcin Radomski         std::string_view name{mixer_ctl_get_name(controls[i])};
323*02e95f1aSMarcin Radomski 
324*02e95f1aSMarcin Radomski         if (name.find("Volume") != std::string_view::npos) {
325*02e95f1aSMarcin Radomski             control = controls[i];
326*02e95f1aSMarcin Radomski         }
327*02e95f1aSMarcin Radomski     }
328*02e95f1aSMarcin Radomski 
329*02e95f1aSMarcin Radomski     if (control == nullptr) {
330*02e95f1aSMarcin Radomski         GTEST_SKIP() << "No volume control was found in the controls list.";
331*02e95f1aSMarcin Radomski     }
332*02e95f1aSMarcin Radomski 
333*02e95f1aSMarcin Radomski     auto *local_mixer_object = mixer_object;
334*02e95f1aSMarcin Radomski     int percent = mixer_ctl_get_percent(control, 0);
335*02e95f1aSMarcin Radomski     std::thread thread([local_mixer_object, control, percent] () {
336*02e95f1aSMarcin Radomski         std::this_thread::sleep_for(std::chrono::milliseconds(50));
337*02e95f1aSMarcin Radomski         mixer_ctl_set_percent(
338*02e95f1aSMarcin Radomski                 const_cast<mixer_ctl *>(control), 0,
339*02e95f1aSMarcin Radomski                 percent == k100Percent ? k0Percent : k100Percent);
340*02e95f1aSMarcin Radomski     });
341*02e95f1aSMarcin Radomski 
342*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_wait_event(mixer_object, 1000), 1);
343*02e95f1aSMarcin Radomski 
344*02e95f1aSMarcin Radomski     EXPECT_EQ(mixer_consume_event(mixer_object), 1);
345*02e95f1aSMarcin Radomski 
346*02e95f1aSMarcin Radomski     thread.join();
347*02e95f1aSMarcin Radomski     ASSERT_EQ(mixer_subscribe_events(mixer_object, 0), 0);
348*02e95f1aSMarcin Radomski 
349*02e95f1aSMarcin Radomski     mixer_ctl_set_percent(const_cast<mixer_ctl *>(control), 0, percent);
350*02e95f1aSMarcin Radomski }
351*02e95f1aSMarcin Radomski 
352*02e95f1aSMarcin Radomski INSTANTIATE_TEST_SUITE_P(
353*02e95f1aSMarcin Radomski     MixerTest,
354*02e95f1aSMarcin Radomski     MixerTest,
355*02e95f1aSMarcin Radomski     ::testing::Range<unsigned int>(
356*02e95f1aSMarcin Radomski         0,
357*02e95f1aSMarcin Radomski         kMaxCardIndex + 1
358*02e95f1aSMarcin Radomski     ));
359*02e95f1aSMarcin Radomski 
360*02e95f1aSMarcin Radomski INSTANTIATE_TEST_SUITE_P(
361*02e95f1aSMarcin Radomski     MixerControlsTest,
362*02e95f1aSMarcin Radomski     MixerControlsTest,
363*02e95f1aSMarcin Radomski     ::testing::Range<unsigned int>(
364*02e95f1aSMarcin Radomski         0,
365*02e95f1aSMarcin Radomski         kMaxCardIndex + 1
366*02e95f1aSMarcin Radomski     ));
367*02e95f1aSMarcin Radomski 
368*02e95f1aSMarcin Radomski } // namespace testing
369*02e95f1aSMarcin Radomski } // namespace tinyalsa
370