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 #include <vector>
7
8 extern "C" {
9 // For static function test.
10 #include "cras_alsa_helpers.c"
11 }
12
13 static int snd_pcm_sw_params_set_tstamp_type_called;
14 static int snd_pcm_sw_params_set_tstamp_mode_called;
15 static snd_pcm_uframes_t snd_pcm_htimestamp_avail_ret_val;
16 static timespec snd_pcm_htimestamp_tstamp_ret_val;
17 static std::vector<int> snd_pcm_sw_params_ret_vals;
18
ResetStubData()19 static void ResetStubData() {
20 snd_pcm_sw_params_set_tstamp_type_called = 0;
21 snd_pcm_sw_params_set_tstamp_mode_called = 0;
22 snd_pcm_htimestamp_avail_ret_val = 0;
23 snd_pcm_htimestamp_tstamp_ret_val.tv_sec = 0;
24 snd_pcm_htimestamp_tstamp_ret_val.tv_nsec = 0;
25 snd_pcm_sw_params_ret_vals.clear();
26 }
27
28 namespace {
29
create_chmap_cap(snd_pcm_chmap_type type,size_t channels)30 static snd_pcm_chmap_query_t *create_chmap_cap(snd_pcm_chmap_type type,
31 size_t channels)
32 {
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] =
51 {-1, -1, 0, 1, -1, -1, -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] =
104 {0, 1, 2, 3, 4, 5, -1, -1, -1, -1, -1};
105
106 fmt = cras_audio_format_create(SND_PCM_FORMAT_S16_LE, 44100, 6);
107 cras_audio_format_set_channel_layout(fmt, channel_layout);
108
109 /* Create a list of capabilities */
110 c = create_chmap_cap(SND_CHMAP_TYPE_FIXED, 6);
111 c->map.pos[0] = 3;
112 c->map.pos[1] = 4;
113 c->map.pos[2] = 5;
114 c->map.pos[3] = 6;
115 c->map.pos[4] = 7;
116 c->map.pos[5] = 8;
117 caps[0] = c;
118
119 c = create_chmap_cap(SND_CHMAP_TYPE_VAR, 2);
120 c->map.pos[0] = 6;
121 c->map.pos[1] = 4;
122 caps[1] = c;
123
124 c = create_chmap_cap(SND_CHMAP_TYPE_VAR, 6);
125 c->map.pos[0] = 9;
126 c->map.pos[1] = 10;
127 c->map.pos[2] = 5;
128 c->map.pos[3] = 6;
129 c->map.pos[4] = 7;
130 c->map.pos[5] = 8;
131 caps[2] = c;
132 caps[3] = NULL;
133
134 /* Test if there's a cap matches fmt */
135 c = cras_chmap_caps_match(caps, fmt);
136 ASSERT_NE((void *)NULL, c);
137
138 caps[0]->map.pos[0] = 7;
139 caps[0]->map.pos[1] = 8;
140 caps[0]->map.pos[4] = 3;
141 caps[0]->map.pos[5] = 4;
142 c = cras_chmap_caps_match(caps, fmt);
143 ASSERT_EQ((void *)NULL, c);
144
145 caps[0]->type = SND_CHMAP_TYPE_PAIRED;
146 c = cras_chmap_caps_match(caps, fmt);
147 ASSERT_NE((void *)NULL, c);
148
149 caps[0]->map.pos[0] = 8;
150 caps[0]->map.pos[1] = 7;
151 c = cras_chmap_caps_match(caps, fmt);
152 ASSERT_EQ((void *)NULL, c);
153
154 caps[0]->type = SND_CHMAP_TYPE_VAR;
155 c = cras_chmap_caps_match(caps, fmt);
156 ASSERT_NE((void *)NULL, c);
157
158 free(caps[0]);
159 free(caps[1]);
160 free(caps[2]);
161 free(caps[3]);
162 free(caps);
163 cras_audio_format_destroy(fmt);
164 }
165
TEST(AlsaHelper,Htimestamp)166 TEST(AlsaHelper, Htimestamp) {
167 snd_pcm_t *dummy_handle = reinterpret_cast<snd_pcm_t*>(0x1);
168 snd_pcm_uframes_t used;
169 snd_pcm_uframes_t severe_underrun_frames = 480;
170 struct timespec tstamp;
171 int htimestamp_enabled = 1;
172 const char *dev_name = "dev_name";
173
174 // Enable htimestamp use.
175 ResetStubData();
176 EXPECT_EQ(0, cras_alsa_set_swparams(dummy_handle, &htimestamp_enabled));
177 EXPECT_EQ(snd_pcm_sw_params_set_tstamp_mode_called, 1);
178 EXPECT_EQ(snd_pcm_sw_params_set_tstamp_type_called, 1);
179 EXPECT_EQ(1, htimestamp_enabled);
180
181 // Try to enable htimestamp use: not supported.
182 ResetStubData();
183 snd_pcm_sw_params_ret_vals.push_back(-EINVAL);
184 EXPECT_EQ(0, cras_alsa_set_swparams(dummy_handle, &htimestamp_enabled));
185 EXPECT_EQ(snd_pcm_sw_params_set_tstamp_mode_called, 2);
186 EXPECT_EQ(snd_pcm_sw_params_set_tstamp_type_called, 2);
187 EXPECT_EQ(0, htimestamp_enabled);
188
189 // Disable htimestamp use.
190 ResetStubData();
191 EXPECT_EQ(0, cras_alsa_set_swparams(dummy_handle, &htimestamp_enabled));
192 EXPECT_EQ(snd_pcm_sw_params_set_tstamp_mode_called, 0);
193 EXPECT_EQ(snd_pcm_sw_params_set_tstamp_type_called, 0);
194
195 ResetStubData();
196 tstamp.tv_sec = 0;
197 tstamp.tv_nsec = 0;
198 snd_pcm_htimestamp_avail_ret_val = 20000;
199 snd_pcm_htimestamp_tstamp_ret_val.tv_sec = 10;
200 snd_pcm_htimestamp_tstamp_ret_val.tv_nsec = 10000;
201
202 cras_alsa_get_avail_frames(dummy_handle, 48000, severe_underrun_frames,
203 dev_name, &used, &tstamp);
204 EXPECT_EQ(used, snd_pcm_htimestamp_avail_ret_val);
205 EXPECT_EQ(tstamp.tv_sec, snd_pcm_htimestamp_tstamp_ret_val.tv_sec);
206 EXPECT_EQ(tstamp.tv_nsec, snd_pcm_htimestamp_tstamp_ret_val.tv_nsec);
207 }
208
TEST(AlsaHelper,GetAvailFramesSevereUnderrun)209 TEST(AlsaHelper, GetAvailFramesSevereUnderrun) {
210 snd_pcm_t *dummy_handle = reinterpret_cast<snd_pcm_t*>(0x1);
211 snd_pcm_uframes_t avail;
212 snd_pcm_uframes_t severe_underrun_frames = 480;
213 snd_pcm_uframes_t buffer_size = 48000;
214 struct timespec tstamp;
215 int rc;
216 const char *dev_name = "dev_name";
217
218 ResetStubData();
219 snd_pcm_htimestamp_avail_ret_val = buffer_size + severe_underrun_frames + 1;
220 rc = cras_alsa_get_avail_frames(dummy_handle, buffer_size,
221 severe_underrun_frames, dev_name,
222 &avail, &tstamp);
223 // Returns -EPIPE when severe underrun happens.
224 EXPECT_EQ(rc, -EPIPE);
225
226 ResetStubData();
227 snd_pcm_htimestamp_avail_ret_val = buffer_size + severe_underrun_frames;
228 rc = cras_alsa_get_avail_frames(dummy_handle, buffer_size,
229 severe_underrun_frames, dev_name,
230 &avail, &tstamp);
231 // Underrun which is not severe enough will be masked.
232 // avail will be adjusted to buffer_size.
233 EXPECT_EQ(avail, buffer_size);
234 EXPECT_EQ(rc, 0);
235
236 ResetStubData();
237 snd_pcm_htimestamp_avail_ret_val = buffer_size - 1;
238 rc = cras_alsa_get_avail_frames(dummy_handle, buffer_size,
239 severe_underrun_frames, dev_name,
240 &avail, &tstamp);
241 // When avail < buffer_size, there is no underrun.
242 EXPECT_EQ(avail, buffer_size - 1);
243 EXPECT_EQ(rc, 0);
244 }
245 } // namespace
246
247 extern "C" {
248
snd_pcm_sw_params_current(snd_pcm_t * pcm,snd_pcm_sw_params_t * params)249 int snd_pcm_sw_params_current(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) {
250 return 0;
251 }
252
snd_pcm_sw_params_get_boundary(const snd_pcm_sw_params_t * params,snd_pcm_uframes_t * val)253 int snd_pcm_sw_params_get_boundary(const snd_pcm_sw_params_t *params,
254 snd_pcm_uframes_t *val) {
255 return 0;
256 }
257
snd_pcm_sw_params_set_stop_threshold(snd_pcm_t * pcm,snd_pcm_sw_params_t * params,snd_pcm_uframes_t val)258 int snd_pcm_sw_params_set_stop_threshold(snd_pcm_t *pcm,
259 snd_pcm_sw_params_t *params,
260 snd_pcm_uframes_t val) {
261 return 0;
262 }
263
snd_pcm_sw_params_set_start_threshold(snd_pcm_t * pcm,snd_pcm_sw_params_t * params,snd_pcm_uframes_t val)264 int snd_pcm_sw_params_set_start_threshold(snd_pcm_t *pcm,
265 snd_pcm_sw_params_t *params,
266 snd_pcm_uframes_t val) {
267 return 0;
268 }
269
snd_pcm_sw_params_set_period_event(snd_pcm_t * pcm,snd_pcm_sw_params_t * params,int val)270 int snd_pcm_sw_params_set_period_event(snd_pcm_t *pcm,
271 snd_pcm_sw_params_t *params, int val) {
272 return 0;
273 }
274
snd_pcm_sw_params_set_tstamp_mode(snd_pcm_t * pcm,snd_pcm_sw_params_t * params,snd_pcm_tstamp_t val)275 int snd_pcm_sw_params_set_tstamp_mode(snd_pcm_t *pcm,
276 snd_pcm_sw_params_t *params,
277 snd_pcm_tstamp_t val) {
278 snd_pcm_sw_params_set_tstamp_mode_called++;
279 return 0;
280 }
281
snd_pcm_sw_params_set_tstamp_type(snd_pcm_t * pcm,snd_pcm_sw_params_t * params,snd_pcm_tstamp_type_t val)282 int snd_pcm_sw_params_set_tstamp_type(snd_pcm_t *pcm,
283 snd_pcm_sw_params_t *params,
284 snd_pcm_tstamp_type_t val) {
285 snd_pcm_sw_params_set_tstamp_type_called++;
286 return 0;
287 }
288
snd_pcm_sw_params(snd_pcm_t * pcm,snd_pcm_sw_params_t * params)289 int snd_pcm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) {
290 int rc;
291
292 if (snd_pcm_sw_params_ret_vals.size() == 0)
293 return 0;
294 rc = snd_pcm_sw_params_ret_vals.back();
295 snd_pcm_sw_params_ret_vals.pop_back();
296 return rc;
297 }
298
snd_pcm_avail(snd_pcm_t * pcm)299 snd_pcm_sframes_t snd_pcm_avail(snd_pcm_t *pcm) {
300 return snd_pcm_htimestamp_avail_ret_val;
301 }
302
snd_pcm_htimestamp(snd_pcm_t * pcm,snd_pcm_uframes_t * avail,snd_htimestamp_t * tstamp)303 int snd_pcm_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail,
304 snd_htimestamp_t *tstamp) {
305 *avail = snd_pcm_htimestamp_avail_ret_val;
306 *tstamp = snd_pcm_htimestamp_tstamp_ret_val;
307 return 0;
308 }
309
310 }
311
main(int argc,char ** argv)312 int main(int argc, char **argv) {
313 ::testing::InitGoogleTest(&argc, argv);
314 return RUN_ALL_TESTS();
315 }
316