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 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 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 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 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 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 unsigned int underruns = 0; 172 int htimestamp_enabled = 1; 173 const char *dev_name = "dev_name"; 174 175 // Enable htimestamp use. 176 ResetStubData(); 177 EXPECT_EQ(0, cras_alsa_set_swparams(dummy_handle, &htimestamp_enabled)); 178 EXPECT_EQ(snd_pcm_sw_params_set_tstamp_mode_called, 1); 179 EXPECT_EQ(snd_pcm_sw_params_set_tstamp_type_called, 1); 180 EXPECT_EQ(1, htimestamp_enabled); 181 182 // Try to enable htimestamp use: not supported. 183 ResetStubData(); 184 snd_pcm_sw_params_ret_vals.push_back(-EINVAL); 185 EXPECT_EQ(0, cras_alsa_set_swparams(dummy_handle, &htimestamp_enabled)); 186 EXPECT_EQ(snd_pcm_sw_params_set_tstamp_mode_called, 2); 187 EXPECT_EQ(snd_pcm_sw_params_set_tstamp_type_called, 2); 188 EXPECT_EQ(0, htimestamp_enabled); 189 190 // Disable htimestamp use. 191 ResetStubData(); 192 EXPECT_EQ(0, cras_alsa_set_swparams(dummy_handle, &htimestamp_enabled)); 193 EXPECT_EQ(snd_pcm_sw_params_set_tstamp_mode_called, 0); 194 EXPECT_EQ(snd_pcm_sw_params_set_tstamp_type_called, 0); 195 196 ResetStubData(); 197 tstamp.tv_sec = 0; 198 tstamp.tv_nsec = 0; 199 snd_pcm_htimestamp_avail_ret_val = 20000; 200 snd_pcm_htimestamp_tstamp_ret_val.tv_sec = 10; 201 snd_pcm_htimestamp_tstamp_ret_val.tv_nsec = 10000; 202 203 cras_alsa_get_avail_frames(dummy_handle, 48000, severe_underrun_frames, 204 dev_name, &used, &tstamp, &underruns); 205 EXPECT_EQ(used, snd_pcm_htimestamp_avail_ret_val); 206 EXPECT_EQ(tstamp.tv_sec, snd_pcm_htimestamp_tstamp_ret_val.tv_sec); 207 EXPECT_EQ(tstamp.tv_nsec, snd_pcm_htimestamp_tstamp_ret_val.tv_nsec); 208 } 209 210 TEST(AlsaHelper, GetAvailFramesSevereUnderrun) { 211 snd_pcm_t *dummy_handle = reinterpret_cast<snd_pcm_t*>(0x1); 212 snd_pcm_uframes_t avail; 213 snd_pcm_uframes_t severe_underrun_frames = 480; 214 snd_pcm_uframes_t buffer_size = 48000; 215 struct timespec tstamp; 216 unsigned int underruns = 0; 217 int rc; 218 const char *dev_name = "dev_name"; 219 220 ResetStubData(); 221 snd_pcm_htimestamp_avail_ret_val = buffer_size + severe_underrun_frames + 1; 222 rc = cras_alsa_get_avail_frames(dummy_handle, buffer_size, 223 severe_underrun_frames, dev_name, 224 &avail, &tstamp, &underruns); 225 // Returns -EPIPE when severe underrun happens. 226 EXPECT_EQ(rc, -EPIPE); 227 EXPECT_EQ(1, underruns); 228 229 ResetStubData(); 230 snd_pcm_htimestamp_avail_ret_val = buffer_size + severe_underrun_frames; 231 rc = cras_alsa_get_avail_frames(dummy_handle, buffer_size, 232 severe_underrun_frames, dev_name, 233 &avail, &tstamp, &underruns); 234 // Underrun which is not severe enough will be masked. 235 // avail will be adjusted to buffer_size. 236 EXPECT_EQ(avail, buffer_size); 237 EXPECT_EQ(rc, 0); 238 EXPECT_EQ(2, underruns); 239 240 ResetStubData(); 241 snd_pcm_htimestamp_avail_ret_val = buffer_size; 242 rc = cras_alsa_get_avail_frames(dummy_handle, buffer_size, 243 severe_underrun_frames, dev_name, 244 &avail, &tstamp, &underruns); 245 // When avail == buffer_size, num_underruns will be increased. 246 EXPECT_EQ(avail, buffer_size); 247 EXPECT_EQ(rc, 0); 248 EXPECT_EQ(3, underruns); 249 250 ResetStubData(); 251 snd_pcm_htimestamp_avail_ret_val = buffer_size - 1; 252 rc = cras_alsa_get_avail_frames(dummy_handle, buffer_size, 253 severe_underrun_frames, dev_name, 254 &avail, &tstamp, &underruns); 255 // When avail < buffer_size, there is no underrun. 256 EXPECT_EQ(avail, buffer_size - 1); 257 EXPECT_EQ(rc, 0); 258 EXPECT_EQ(3, underruns); 259 } 260 } // namespace 261 262 extern "C" { 263 264 int snd_pcm_sw_params_current(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) { 265 return 0; 266 } 267 268 int snd_pcm_sw_params_get_boundary(const snd_pcm_sw_params_t *params, 269 snd_pcm_uframes_t *val) { 270 return 0; 271 } 272 273 int snd_pcm_sw_params_set_stop_threshold(snd_pcm_t *pcm, 274 snd_pcm_sw_params_t *params, 275 snd_pcm_uframes_t val) { 276 return 0; 277 } 278 279 int snd_pcm_sw_params_set_start_threshold(snd_pcm_t *pcm, 280 snd_pcm_sw_params_t *params, 281 snd_pcm_uframes_t val) { 282 return 0; 283 } 284 285 int snd_pcm_sw_params_set_period_event(snd_pcm_t *pcm, 286 snd_pcm_sw_params_t *params, int val) { 287 return 0; 288 } 289 290 int snd_pcm_sw_params_set_tstamp_mode(snd_pcm_t *pcm, 291 snd_pcm_sw_params_t *params, 292 snd_pcm_tstamp_t val) { 293 snd_pcm_sw_params_set_tstamp_mode_called++; 294 return 0; 295 } 296 297 int snd_pcm_sw_params_set_tstamp_type(snd_pcm_t *pcm, 298 snd_pcm_sw_params_t *params, 299 snd_pcm_tstamp_type_t val) { 300 snd_pcm_sw_params_set_tstamp_type_called++; 301 return 0; 302 } 303 304 int snd_pcm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) { 305 int rc; 306 307 if (snd_pcm_sw_params_ret_vals.size() == 0) 308 return 0; 309 rc = snd_pcm_sw_params_ret_vals.back(); 310 snd_pcm_sw_params_ret_vals.pop_back(); 311 return rc; 312 } 313 314 snd_pcm_sframes_t snd_pcm_avail(snd_pcm_t *pcm) { 315 return snd_pcm_htimestamp_avail_ret_val; 316 } 317 318 int snd_pcm_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail, 319 snd_htimestamp_t *tstamp) { 320 *avail = snd_pcm_htimestamp_avail_ret_val; 321 *tstamp = snd_pcm_htimestamp_tstamp_ret_val; 322 return 0; 323 } 324 325 } 326 327 int main(int argc, char **argv) { 328 ::testing::InitGoogleTest(&argc, argv); 329 return RUN_ALL_TESTS(); 330 } 331