1 // Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <gtest/gtest.h>
6
7 #include <vector>
8
9 extern "C" {
10 // For static function test.
11 #include "cras_alsa_helpers.c"
12 }
13
14 static int snd_pcm_sw_params_set_tstamp_type_called;
15 static int snd_pcm_sw_params_set_tstamp_mode_called;
16 static snd_pcm_uframes_t snd_pcm_htimestamp_avail_ret_val;
17 static timespec snd_pcm_htimestamp_tstamp_ret_val;
18 static std::vector<int> snd_pcm_sw_params_ret_vals;
19
ResetStubData()20 static void ResetStubData() {
21 snd_pcm_sw_params_set_tstamp_type_called = 0;
22 snd_pcm_sw_params_set_tstamp_mode_called = 0;
23 snd_pcm_htimestamp_avail_ret_val = 0;
24 snd_pcm_htimestamp_tstamp_ret_val.tv_sec = 0;
25 snd_pcm_htimestamp_tstamp_ret_val.tv_nsec = 0;
26 snd_pcm_sw_params_ret_vals.clear();
27 }
28
29 namespace {
30
create_chmap_cap(snd_pcm_chmap_type type,size_t channels)31 static snd_pcm_chmap_query_t* create_chmap_cap(snd_pcm_chmap_type type,
32 size_t channels) {
33 snd_pcm_chmap_query_t* c;
34 c = (snd_pcm_chmap_query_t*)calloc(channels + 2, sizeof(int));
35 c->type = type;
36 c->map.channels = channels;
37 return c;
38 }
39
TEST(AlsaHelper,MatchChannelMapCapabilityStereo)40 TEST(AlsaHelper, MatchChannelMapCapabilityStereo) {
41 snd_pcm_chmap_query_t** caps;
42 snd_pcm_chmap_query_t* c;
43 struct cras_audio_format* fmt;
44
45 caps = (snd_pcm_chmap_query_t**)calloc(4, sizeof(*caps));
46
47 /* Layout (CRAS_CH_RL, CRAS_CH_RR) corresponds to
48 * ALSA channel map (5, 6)
49 */
50 int8_t channel_layout[CRAS_CH_MAX] = {-1, -1, 0, 1, -1, -1,
51 -1, -1, -1, -1, -1};
52
53 fmt = cras_audio_format_create(SND_PCM_FORMAT_S16_LE, 44100, 2);
54 cras_audio_format_set_channel_layout(fmt, channel_layout);
55
56 /* Create a list of capabilities */
57 c = create_chmap_cap(SND_CHMAP_TYPE_FIXED, 3);
58 c->map.pos[0] = 3;
59 c->map.pos[1] = 4;
60 c->map.pos[2] = 5;
61 caps[0] = c;
62
63 c = create_chmap_cap(SND_CHMAP_TYPE_VAR, 2);
64 c->map.pos[0] = 5;
65 c->map.pos[1] = 6;
66 caps[1] = c;
67
68 c = create_chmap_cap(SND_CHMAP_TYPE_VAR, 2);
69 c->map.pos[0] = 9;
70 c->map.pos[1] = 10;
71 caps[2] = c;
72
73 caps[3] = NULL;
74
75 /* Test if there's a cap matches fmt */
76 c = cras_chmap_caps_match(caps, fmt);
77 ASSERT_NE((void*)NULL, c);
78
79 caps[1]->map.pos[0] = 5;
80 caps[1]->map.pos[1] = 7;
81
82 c = cras_chmap_caps_match(caps, fmt);
83 ASSERT_EQ((void*)NULL, c);
84
85 free(caps[0]);
86 free(caps[1]);
87 free(caps[2]);
88 free(caps[3]);
89 free(caps);
90 cras_audio_format_destroy(fmt);
91 }
92
TEST(AlsaHelper,MatchChannelMapCapability51)93 TEST(AlsaHelper, MatchChannelMapCapability51) {
94 snd_pcm_chmap_query_t** caps = NULL;
95 snd_pcm_chmap_query_t* c = NULL;
96 struct cras_audio_format* fmt;
97
98 caps = (snd_pcm_chmap_query_t**)calloc(4, sizeof(*caps));
99
100 /* Layout (CRAS_CH_FL, CRAS_CH_FR, CRAS_CH_RL, CRAS_CH_RR, CRAS_CH_FC)
101 * corresponds to ALSA channel map (3, 4, 5, 6, 7)
102 */
103 int8_t channel_layout[CRAS_CH_MAX] = {0, 1, 2, 3, 4, 5, -1, -1, -1, -1, -1};
104
105 fmt = cras_audio_format_create(SND_PCM_FORMAT_S16_LE, 44100, 6);
106 cras_audio_format_set_channel_layout(fmt, channel_layout);
107
108 /* Create a list of capabilities */
109 c = create_chmap_cap(SND_CHMAP_TYPE_FIXED, 6);
110 c->map.pos[0] = 3;
111 c->map.pos[1] = 4;
112 c->map.pos[2] = 5;
113 c->map.pos[3] = 6;
114 c->map.pos[4] = 7;
115 c->map.pos[5] = 8;
116 caps[0] = c;
117
118 c = create_chmap_cap(SND_CHMAP_TYPE_VAR, 2);
119 c->map.pos[0] = 6;
120 c->map.pos[1] = 4;
121 caps[1] = c;
122
123 c = create_chmap_cap(SND_CHMAP_TYPE_VAR, 6);
124 c->map.pos[0] = 9;
125 c->map.pos[1] = 10;
126 c->map.pos[2] = 5;
127 c->map.pos[3] = 6;
128 c->map.pos[4] = 7;
129 c->map.pos[5] = 8;
130 caps[2] = c;
131 caps[3] = NULL;
132
133 /* Test if there's a cap matches fmt */
134 c = cras_chmap_caps_match(caps, fmt);
135 ASSERT_NE((void*)NULL, c);
136
137 caps[0]->map.pos[0] = 7;
138 caps[0]->map.pos[1] = 8;
139 caps[0]->map.pos[4] = 3;
140 caps[0]->map.pos[5] = 4;
141 c = cras_chmap_caps_match(caps, fmt);
142 ASSERT_EQ((void*)NULL, c);
143
144 caps[0]->type = SND_CHMAP_TYPE_PAIRED;
145 c = cras_chmap_caps_match(caps, fmt);
146 ASSERT_NE((void*)NULL, c);
147
148 caps[0]->map.pos[0] = 8;
149 caps[0]->map.pos[1] = 7;
150 c = cras_chmap_caps_match(caps, fmt);
151 ASSERT_EQ((void*)NULL, c);
152
153 caps[0]->type = SND_CHMAP_TYPE_VAR;
154 c = cras_chmap_caps_match(caps, fmt);
155 ASSERT_NE((void*)NULL, c);
156
157 free(caps[0]);
158 free(caps[1]);
159 free(caps[2]);
160 free(caps[3]);
161 free(caps);
162 cras_audio_format_destroy(fmt);
163 }
164
TEST(AlsaHelper,Htimestamp)165 TEST(AlsaHelper, Htimestamp) {
166 snd_pcm_t* mock_handle = reinterpret_cast<snd_pcm_t*>(0x1);
167 snd_pcm_uframes_t used;
168 snd_pcm_uframes_t severe_underrun_frames = 480;
169 struct timespec tstamp;
170 const char* dev_name = "dev_name";
171
172 ResetStubData();
173 tstamp.tv_sec = 0;
174 tstamp.tv_nsec = 0;
175 snd_pcm_htimestamp_avail_ret_val = 20000;
176 snd_pcm_htimestamp_tstamp_ret_val.tv_sec = 10;
177 snd_pcm_htimestamp_tstamp_ret_val.tv_nsec = 10000;
178
179 cras_alsa_get_avail_frames(mock_handle, 48000, severe_underrun_frames,
180 dev_name, &used, &tstamp);
181 EXPECT_EQ(used, snd_pcm_htimestamp_avail_ret_val);
182 EXPECT_EQ(tstamp.tv_sec, snd_pcm_htimestamp_tstamp_ret_val.tv_sec);
183 EXPECT_EQ(tstamp.tv_nsec, snd_pcm_htimestamp_tstamp_ret_val.tv_nsec);
184 }
185
TEST(AlsaHelper,GetAvailFramesSevereUnderrun)186 TEST(AlsaHelper, GetAvailFramesSevereUnderrun) {
187 snd_pcm_t* mock_handle = reinterpret_cast<snd_pcm_t*>(0x1);
188 snd_pcm_uframes_t avail;
189 snd_pcm_uframes_t severe_underrun_frames = 480;
190 snd_pcm_uframes_t buffer_size = 48000;
191 struct timespec tstamp;
192 int rc;
193 const char* dev_name = "dev_name";
194
195 ResetStubData();
196 snd_pcm_htimestamp_avail_ret_val = buffer_size + severe_underrun_frames + 1;
197 rc = cras_alsa_get_avail_frames(mock_handle, buffer_size,
198 severe_underrun_frames, dev_name, &avail,
199 &tstamp);
200 // Returns -EPIPE when severe underrun happens.
201 EXPECT_EQ(rc, -EPIPE);
202
203 ResetStubData();
204 snd_pcm_htimestamp_avail_ret_val = buffer_size + severe_underrun_frames;
205 rc = cras_alsa_get_avail_frames(mock_handle, buffer_size,
206 severe_underrun_frames, dev_name, &avail,
207 &tstamp);
208 // Underrun which is not severe enough will be masked.
209 // avail will be adjusted to buffer_size.
210 EXPECT_EQ(avail, buffer_size);
211 EXPECT_EQ(rc, 0);
212
213 ResetStubData();
214 snd_pcm_htimestamp_avail_ret_val = buffer_size - 1;
215 rc = cras_alsa_get_avail_frames(mock_handle, buffer_size,
216 severe_underrun_frames, dev_name, &avail,
217 &tstamp);
218 // When avail < buffer_size, there is no underrun.
219 EXPECT_EQ(avail, buffer_size - 1);
220 EXPECT_EQ(rc, 0);
221 }
222 } // namespace
223
224 extern "C" {
225
snd_pcm_sw_params_current(snd_pcm_t * pcm,snd_pcm_sw_params_t * params)226 int snd_pcm_sw_params_current(snd_pcm_t* pcm, snd_pcm_sw_params_t* params) {
227 return 0;
228 }
229
snd_pcm_sw_params_get_boundary(const snd_pcm_sw_params_t * params,snd_pcm_uframes_t * val)230 int snd_pcm_sw_params_get_boundary(const snd_pcm_sw_params_t* params,
231 snd_pcm_uframes_t* val) {
232 return 0;
233 }
234
snd_pcm_sw_params_set_stop_threshold(snd_pcm_t * pcm,snd_pcm_sw_params_t * params,snd_pcm_uframes_t val)235 int snd_pcm_sw_params_set_stop_threshold(snd_pcm_t* pcm,
236 snd_pcm_sw_params_t* params,
237 snd_pcm_uframes_t val) {
238 return 0;
239 }
240
snd_pcm_sw_params_set_start_threshold(snd_pcm_t * pcm,snd_pcm_sw_params_t * params,snd_pcm_uframes_t val)241 int snd_pcm_sw_params_set_start_threshold(snd_pcm_t* pcm,
242 snd_pcm_sw_params_t* params,
243 snd_pcm_uframes_t val) {
244 return 0;
245 }
246
snd_pcm_sw_params_set_period_event(snd_pcm_t * pcm,snd_pcm_sw_params_t * params,int val)247 int snd_pcm_sw_params_set_period_event(snd_pcm_t* pcm,
248 snd_pcm_sw_params_t* params,
249 int val) {
250 return 0;
251 }
252
snd_pcm_sw_params_set_tstamp_mode(snd_pcm_t * pcm,snd_pcm_sw_params_t * params,snd_pcm_tstamp_t val)253 int snd_pcm_sw_params_set_tstamp_mode(snd_pcm_t* pcm,
254 snd_pcm_sw_params_t* params,
255 snd_pcm_tstamp_t val) {
256 snd_pcm_sw_params_set_tstamp_mode_called++;
257 return 0;
258 }
259
snd_pcm_sw_params_set_tstamp_type(snd_pcm_t * pcm,snd_pcm_sw_params_t * params,snd_pcm_tstamp_type_t val)260 int snd_pcm_sw_params_set_tstamp_type(snd_pcm_t* pcm,
261 snd_pcm_sw_params_t* params,
262 snd_pcm_tstamp_type_t val) {
263 snd_pcm_sw_params_set_tstamp_type_called++;
264 return 0;
265 }
266
snd_pcm_sw_params(snd_pcm_t * pcm,snd_pcm_sw_params_t * params)267 int snd_pcm_sw_params(snd_pcm_t* pcm, snd_pcm_sw_params_t* params) {
268 int rc;
269
270 if (snd_pcm_sw_params_ret_vals.size() == 0)
271 return 0;
272 rc = snd_pcm_sw_params_ret_vals.back();
273 snd_pcm_sw_params_ret_vals.pop_back();
274 return rc;
275 }
276
snd_pcm_avail(snd_pcm_t * pcm)277 snd_pcm_sframes_t snd_pcm_avail(snd_pcm_t* pcm) {
278 return snd_pcm_htimestamp_avail_ret_val;
279 }
280
snd_pcm_htimestamp(snd_pcm_t * pcm,snd_pcm_uframes_t * avail,snd_htimestamp_t * tstamp)281 int snd_pcm_htimestamp(snd_pcm_t* pcm,
282 snd_pcm_uframes_t* avail,
283 snd_htimestamp_t* tstamp) {
284 *avail = snd_pcm_htimestamp_avail_ret_val;
285 *tstamp = snd_pcm_htimestamp_tstamp_ret_val;
286 return 0;
287 }
288 }
289
main(int argc,char ** argv)290 int main(int argc, char** argv) {
291 ::testing::InitGoogleTest(&argc, argv);
292 return RUN_ALL_TESTS();
293 }
294