1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/libcubeb/tests/test_sanity.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,549 @@ 1.4 +/* 1.5 + * Copyright © 2011 Mozilla Foundation 1.6 + * 1.7 + * This program is made available under an ISC-style license. See the 1.8 + * accompanying file LICENSE for details. 1.9 + */ 1.10 +#ifdef NDEBUG 1.11 +#undef NDEBUG 1.12 +#endif 1.13 +#define _XOPEN_SOURCE 500 1.14 +#include "cubeb/cubeb.h" 1.15 +#include <assert.h> 1.16 +#include <stdio.h> 1.17 +#include <string.h> 1.18 +#include <math.h> 1.19 +#include "common.h" 1.20 + 1.21 +#if (defined(_WIN32) || defined(__WIN32__)) 1.22 +#define __func__ __FUNCTION__ 1.23 +#endif 1.24 + 1.25 +#define ARRAY_LENGTH(_x) (sizeof(_x) / sizeof(_x[0])) 1.26 +#define BEGIN_TEST fprintf(stderr, "START %s\n", __func__); 1.27 +#define END_TEST fprintf(stderr, "END %s\n", __func__); 1.28 + 1.29 +#define STREAM_LATENCY 100 1.30 +#define STREAM_RATE 44100 1.31 +#define STREAM_CHANNELS 1 1.32 +#define STREAM_FORMAT CUBEB_SAMPLE_S16LE 1.33 + 1.34 +static int dummy; 1.35 +static uint64_t total_frames_written; 1.36 +static int delay_callback; 1.37 + 1.38 +static long 1.39 +test_data_callback(cubeb_stream * stm, void * user_ptr, void * p, long nframes) 1.40 +{ 1.41 + assert(stm && user_ptr == &dummy && p && nframes > 0); 1.42 + memset(p, 0, nframes * sizeof(short)); 1.43 + total_frames_written += nframes; 1.44 + if (delay_callback) { 1.45 + delay(10); 1.46 + } 1.47 + return nframes; 1.48 +} 1.49 + 1.50 +void 1.51 +test_state_callback(cubeb_stream * stm, void * user_ptr, cubeb_state state) 1.52 +{ 1.53 +} 1.54 + 1.55 +static void 1.56 +test_init_destroy_context(void) 1.57 +{ 1.58 + int r; 1.59 + cubeb * ctx; 1.60 + 1.61 + BEGIN_TEST 1.62 + 1.63 + r = cubeb_init(&ctx, "test_sanity"); 1.64 + assert(r == 0 && ctx); 1.65 + 1.66 + cubeb_destroy(ctx); 1.67 + 1.68 + END_TEST 1.69 +} 1.70 + 1.71 +static void 1.72 +test_init_destroy_multiple_contexts(void) 1.73 +{ 1.74 + int i; 1.75 + int r; 1.76 + cubeb * ctx[4]; 1.77 + 1.78 + BEGIN_TEST 1.79 + 1.80 + for (i = 0; i < 4; ++i) { 1.81 + r = cubeb_init(&ctx[i], NULL); 1.82 + assert(r == 0 && ctx[i]); 1.83 + } 1.84 + 1.85 + /* destroy in a different order */ 1.86 + cubeb_destroy(ctx[2]); 1.87 + cubeb_destroy(ctx[0]); 1.88 + cubeb_destroy(ctx[3]); 1.89 + cubeb_destroy(ctx[1]); 1.90 + 1.91 + END_TEST 1.92 +} 1.93 + 1.94 +static void 1.95 +test_init_destroy_stream(void) 1.96 +{ 1.97 + int r; 1.98 + cubeb * ctx; 1.99 + cubeb_stream * stream; 1.100 + cubeb_stream_params params; 1.101 + 1.102 + BEGIN_TEST 1.103 + 1.104 + r = cubeb_init(&ctx, "test_sanity"); 1.105 + assert(r == 0 && ctx); 1.106 + 1.107 + params.format = STREAM_FORMAT; 1.108 + params.rate = STREAM_RATE; 1.109 + params.channels = STREAM_CHANNELS; 1.110 + 1.111 + r = cubeb_stream_init(ctx, &stream, "test", params, STREAM_LATENCY, 1.112 + test_data_callback, test_state_callback, &dummy); 1.113 + assert(r == 0 && stream); 1.114 + 1.115 + cubeb_stream_destroy(stream); 1.116 + cubeb_destroy(ctx); 1.117 + 1.118 + END_TEST 1.119 +} 1.120 + 1.121 +static void 1.122 +test_init_destroy_multiple_streams(void) 1.123 +{ 1.124 + int i; 1.125 + int r; 1.126 + cubeb * ctx; 1.127 + cubeb_stream * stream[16]; 1.128 + cubeb_stream_params params; 1.129 + 1.130 + BEGIN_TEST 1.131 + 1.132 + r = cubeb_init(&ctx, "test_sanity"); 1.133 + assert(r == 0 && ctx); 1.134 + 1.135 + params.format = STREAM_FORMAT; 1.136 + params.rate = STREAM_RATE; 1.137 + params.channels = STREAM_CHANNELS; 1.138 + 1.139 + for (i = 0; i < 16; ++i) { 1.140 + r = cubeb_stream_init(ctx, &stream[i], "test", params, STREAM_LATENCY, 1.141 + test_data_callback, test_state_callback, &dummy); 1.142 + assert(r == 0); 1.143 + assert(stream[i]); 1.144 + } 1.145 + 1.146 + for (i = 0; i < 16; ++i) { 1.147 + cubeb_stream_destroy(stream[i]); 1.148 + } 1.149 + 1.150 + cubeb_destroy(ctx); 1.151 + 1.152 + END_TEST 1.153 +} 1.154 + 1.155 +static void 1.156 +test_init_start_stop_destroy_multiple_streams(int early, int delay_ms) 1.157 +{ 1.158 + int i; 1.159 + int r; 1.160 + cubeb * ctx; 1.161 + cubeb_stream * stream[16]; 1.162 + cubeb_stream_params params; 1.163 + 1.164 + BEGIN_TEST 1.165 + 1.166 + r = cubeb_init(&ctx, "test_sanity"); 1.167 + assert(r == 0 && ctx); 1.168 + 1.169 + params.format = STREAM_FORMAT; 1.170 + params.rate = STREAM_RATE; 1.171 + params.channels = STREAM_CHANNELS; 1.172 + 1.173 + for (i = 0; i < 16; ++i) { 1.174 + r = cubeb_stream_init(ctx, &stream[i], "test", params, STREAM_LATENCY, 1.175 + test_data_callback, test_state_callback, &dummy); 1.176 + assert(r == 0); 1.177 + assert(stream[i]); 1.178 + if (early) { 1.179 + r = cubeb_stream_start(stream[i]); 1.180 + assert(r == 0); 1.181 + } 1.182 + } 1.183 + 1.184 + 1.185 + if (!early) { 1.186 + for (i = 0; i < 16; ++i) { 1.187 + r = cubeb_stream_start(stream[i]); 1.188 + assert(r == 0); 1.189 + } 1.190 + } 1.191 + 1.192 + if (delay_ms) { 1.193 + delay(delay_ms); 1.194 + } 1.195 + 1.196 + if (!early) { 1.197 + for (i = 0; i < 16; ++i) { 1.198 + r = cubeb_stream_stop(stream[i]); 1.199 + assert(r == 0); 1.200 + } 1.201 + } 1.202 + 1.203 + for (i = 0; i < 16; ++i) { 1.204 + if (early) { 1.205 + r = cubeb_stream_stop(stream[i]); 1.206 + assert(r == 0); 1.207 + } 1.208 + cubeb_stream_destroy(stream[i]); 1.209 + } 1.210 + 1.211 + cubeb_destroy(ctx); 1.212 + 1.213 + END_TEST 1.214 +} 1.215 + 1.216 +static void 1.217 +test_init_destroy_multiple_contexts_and_streams(void) 1.218 +{ 1.219 + int i, j; 1.220 + int r; 1.221 + cubeb * ctx[4]; 1.222 + cubeb_stream * stream[16]; 1.223 + cubeb_stream_params params; 1.224 + 1.225 + BEGIN_TEST 1.226 + 1.227 + params.format = STREAM_FORMAT; 1.228 + params.rate = STREAM_RATE; 1.229 + params.channels = STREAM_CHANNELS; 1.230 + 1.231 + for (i = 0; i < 4; ++i) { 1.232 + r = cubeb_init(&ctx[i], "test_sanity"); 1.233 + assert(r == 0 && ctx[i]); 1.234 + 1.235 + for (j = 0; j < 4; ++j) { 1.236 + r = cubeb_stream_init(ctx[i], &stream[i * 4 + j], "test", params, STREAM_LATENCY, 1.237 + test_data_callback, test_state_callback, &dummy); 1.238 + assert(r == 0); 1.239 + assert(stream[i * 4 + j]); 1.240 + } 1.241 + } 1.242 + 1.243 + for (i = 0; i < 4; ++i) { 1.244 + for (j = 0; j < 4; ++j) { 1.245 + cubeb_stream_destroy(stream[i * 4 + j]); 1.246 + } 1.247 + cubeb_destroy(ctx[i]); 1.248 + } 1.249 + 1.250 + END_TEST 1.251 +} 1.252 + 1.253 +static void 1.254 +test_basic_stream_operations(void) 1.255 +{ 1.256 + int r; 1.257 + cubeb * ctx; 1.258 + cubeb_stream * stream; 1.259 + cubeb_stream_params params; 1.260 + uint64_t position; 1.261 + 1.262 + BEGIN_TEST 1.263 + 1.264 + r = cubeb_init(&ctx, "test_sanity"); 1.265 + assert(r == 0 && ctx); 1.266 + 1.267 + params.format = STREAM_FORMAT; 1.268 + params.rate = STREAM_RATE; 1.269 + params.channels = STREAM_CHANNELS; 1.270 + 1.271 + r = cubeb_stream_init(ctx, &stream, "test", params, STREAM_LATENCY, 1.272 + test_data_callback, test_state_callback, &dummy); 1.273 + assert(r == 0 && stream); 1.274 + 1.275 + /* position and volume before stream has started */ 1.276 + r = cubeb_stream_get_position(stream, &position); 1.277 + assert(r == 0 && position == 0); 1.278 + 1.279 + r = cubeb_stream_start(stream); 1.280 + assert(r == 0); 1.281 + 1.282 + /* position and volume after while stream running */ 1.283 + r = cubeb_stream_get_position(stream, &position); 1.284 + assert(r == 0); 1.285 + 1.286 + r = cubeb_stream_stop(stream); 1.287 + assert(r == 0); 1.288 + 1.289 + /* position and volume after stream has stopped */ 1.290 + r = cubeb_stream_get_position(stream, &position); 1.291 + assert(r == 0); 1.292 + 1.293 + cubeb_stream_destroy(stream); 1.294 + cubeb_destroy(ctx); 1.295 + 1.296 + END_TEST 1.297 +} 1.298 + 1.299 +static void 1.300 +test_stream_position(void) 1.301 +{ 1.302 + int i; 1.303 + int r; 1.304 + cubeb * ctx; 1.305 + cubeb_stream * stream; 1.306 + cubeb_stream_params params; 1.307 + uint64_t position, last_position; 1.308 + 1.309 + BEGIN_TEST 1.310 + 1.311 + total_frames_written = 0; 1.312 + 1.313 + r = cubeb_init(&ctx, "test_sanity"); 1.314 + assert(r == 0 && ctx); 1.315 + 1.316 + params.format = STREAM_FORMAT; 1.317 + params.rate = STREAM_RATE; 1.318 + params.channels = STREAM_CHANNELS; 1.319 + 1.320 + r = cubeb_stream_init(ctx, &stream, "test", params, STREAM_LATENCY, 1.321 + test_data_callback, test_state_callback, &dummy); 1.322 + assert(r == 0 && stream); 1.323 + 1.324 + /* stream position should not advance before starting playback */ 1.325 + r = cubeb_stream_get_position(stream, &position); 1.326 + assert(r == 0 && position == 0); 1.327 + 1.328 + delay(500); 1.329 + 1.330 + r = cubeb_stream_get_position(stream, &position); 1.331 + assert(r == 0 && position == 0); 1.332 + 1.333 + /* stream position should advance during playback */ 1.334 + r = cubeb_stream_start(stream); 1.335 + assert(r == 0); 1.336 + 1.337 + /* XXX let start happen */ 1.338 + delay(500); 1.339 + 1.340 + /* stream should have prefilled */ 1.341 + assert(total_frames_written > 0); 1.342 + 1.343 + r = cubeb_stream_get_position(stream, &position); 1.344 + assert(r == 0); 1.345 + last_position = position; 1.346 + 1.347 + delay(500); 1.348 + 1.349 + r = cubeb_stream_get_position(stream, &position); 1.350 + assert(r == 0); 1.351 + assert(position >= last_position); 1.352 + last_position = position; 1.353 + 1.354 + /* stream position should not exceed total frames written */ 1.355 + for (i = 0; i < 5; ++i) { 1.356 + r = cubeb_stream_get_position(stream, &position); 1.357 + assert(r == 0); 1.358 + assert(position >= last_position); 1.359 + assert(position <= total_frames_written); 1.360 + last_position = position; 1.361 + delay(500); 1.362 + } 1.363 + 1.364 + assert(last_position != 0); 1.365 + 1.366 + /* stream position should not advance after stopping playback */ 1.367 + r = cubeb_stream_stop(stream); 1.368 + assert(r == 0); 1.369 + 1.370 + /* XXX allow stream to settle */ 1.371 + delay(500); 1.372 + 1.373 + r = cubeb_stream_get_position(stream, &position); 1.374 + assert(r == 0); 1.375 + last_position = position; 1.376 + 1.377 + delay(500); 1.378 + 1.379 + r = cubeb_stream_get_position(stream, &position); 1.380 + assert(r == 0); 1.381 + assert(position == last_position); 1.382 + 1.383 + cubeb_stream_destroy(stream); 1.384 + cubeb_destroy(ctx); 1.385 + 1.386 + END_TEST 1.387 +} 1.388 + 1.389 +static int do_drain; 1.390 +static int got_drain; 1.391 + 1.392 +static long 1.393 +test_drain_data_callback(cubeb_stream * stm, void * user_ptr, void * p, long nframes) 1.394 +{ 1.395 + assert(stm && user_ptr == &dummy && p && nframes > 0); 1.396 + if (do_drain == 1) { 1.397 + do_drain = 2; 1.398 + return 0; 1.399 + } 1.400 + /* once drain has started, callback must never be called again */ 1.401 + assert(do_drain != 2); 1.402 + memset(p, 0, nframes * sizeof(short)); 1.403 + total_frames_written += nframes; 1.404 + return nframes; 1.405 +} 1.406 + 1.407 +void 1.408 +test_drain_state_callback(cubeb_stream * stm, void * user_ptr, cubeb_state state) 1.409 +{ 1.410 + if (state == CUBEB_STATE_DRAINED) { 1.411 + assert(!got_drain); 1.412 + got_drain = 1; 1.413 + } 1.414 +} 1.415 + 1.416 +static void 1.417 +test_drain(void) 1.418 +{ 1.419 + int r; 1.420 + cubeb * ctx; 1.421 + cubeb_stream * stream; 1.422 + cubeb_stream_params params; 1.423 + uint64_t position; 1.424 + 1.425 + BEGIN_TEST 1.426 + 1.427 + total_frames_written = 0; 1.428 + 1.429 + r = cubeb_init(&ctx, "test_sanity"); 1.430 + assert(r == 0 && ctx); 1.431 + 1.432 + params.format = STREAM_FORMAT; 1.433 + params.rate = STREAM_RATE; 1.434 + params.channels = STREAM_CHANNELS; 1.435 + 1.436 + r = cubeb_stream_init(ctx, &stream, "test", params, STREAM_LATENCY, 1.437 + test_drain_data_callback, test_drain_state_callback, &dummy); 1.438 + assert(r == 0 && stream); 1.439 + 1.440 + r = cubeb_stream_start(stream); 1.441 + assert(r == 0); 1.442 + 1.443 + delay(500); 1.444 + 1.445 + do_drain = 1; 1.446 + 1.447 + for (;;) { 1.448 + r = cubeb_stream_get_position(stream, &position); 1.449 + assert(r == 0); 1.450 + if (got_drain) { 1.451 + break; 1.452 + } else { 1.453 + uint32_t i, skip = 0; 1.454 + /* Latency passed to cubeb_stream_init is not really honored on OSX, 1.455 + win32/winmm and android, skip this test. */ 1.456 + const char * backend_id = cubeb_get_backend_id(ctx); 1.457 + const char * latency_not_honored_bakends[] = { 1.458 + "audiounit", 1.459 + "winmm", 1.460 + "audiotrack", 1.461 + "opensl" 1.462 + }; 1.463 + 1.464 + for (i = 0; i < ARRAY_LENGTH(latency_not_honored_bakends); i++) { 1.465 + if (!strcmp(backend_id, latency_not_honored_bakends[i])) { 1.466 + skip = 1; 1.467 + } 1.468 + } 1.469 + if (!skip) { 1.470 + /* Position should roughly be equal to the number of written frames. We 1.471 + * need to take the latency into account. */ 1.472 + int latency = (STREAM_LATENCY * STREAM_RATE) / 1000; 1.473 + assert(position + latency <= total_frames_written); 1.474 + } 1.475 + } 1.476 + delay(500); 1.477 + } 1.478 + 1.479 + r = cubeb_stream_get_position(stream, &position); 1.480 + assert(r == 0); 1.481 + assert(got_drain); 1.482 + 1.483 + // Disabled due to failures in the ALSA backend. 1.484 + //assert(position == total_frames_written); 1.485 + 1.486 + cubeb_stream_destroy(stream); 1.487 + cubeb_destroy(ctx); 1.488 + 1.489 + END_TEST 1.490 +} 1.491 + 1.492 +int is_windows_7() 1.493 +{ 1.494 +#if (defined(_WIN32) || defined(__WIN32__)) 1.495 + OSVERSIONINFOEX osvi; 1.496 + DWORDLONG condition_mask = 0; 1.497 + 1.498 + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); 1.499 + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); 1.500 + 1.501 + // NT 6.1 is Windows 7 1.502 + osvi.dwMajorVersion = 6; 1.503 + osvi.dwMinorVersion = 1; 1.504 + 1.505 + VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, VER_EQUAL); 1.506 + VER_SET_CONDITION(condition_mask, VER_MINORVERSION, VER_EQUAL); 1.507 + 1.508 + return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION, condition_mask); 1.509 +#else 1.510 + return 0; 1.511 +#endif 1.512 +} 1.513 + 1.514 +int 1.515 +main(int argc, char * argv[]) 1.516 +{ 1.517 + test_init_destroy_context(); 1.518 + test_init_destroy_multiple_contexts(); 1.519 + test_init_destroy_stream(); 1.520 + test_init_destroy_multiple_streams(); 1.521 + test_basic_stream_operations(); 1.522 + test_stream_position(); 1.523 + 1.524 + /* Sometimes, when using WASAPI on windows 7 (vista and 8 are okay), and 1.525 + * calling Activate a lot on an AudioClient, 0x800700b7 is returned. This is 1.526 + * the HRESULT value for "Cannot create a file when that file already exists", 1.527 + * and is not documented as a possible return value for this call. Hence, we 1.528 + * try to limit the number of streams we create in this test. */ 1.529 + if (!is_windows_7()) { 1.530 + test_init_destroy_multiple_contexts_and_streams(); 1.531 + 1.532 + delay_callback = 0; 1.533 + test_init_start_stop_destroy_multiple_streams(0, 0); 1.534 + test_init_start_stop_destroy_multiple_streams(1, 0); 1.535 + test_init_start_stop_destroy_multiple_streams(0, 150); 1.536 + test_init_start_stop_destroy_multiple_streams(1, 150); 1.537 + delay_callback = 1; 1.538 + test_init_start_stop_destroy_multiple_streams(0, 0); 1.539 + test_init_start_stop_destroy_multiple_streams(1, 0); 1.540 + test_init_start_stop_destroy_multiple_streams(0, 150); 1.541 + test_init_start_stop_destroy_multiple_streams(1, 150); 1.542 + } 1.543 + delay_callback = 0; 1.544 + test_drain(); 1.545 +/* 1.546 + to implement: 1.547 + test_eos_during_prefill(); 1.548 + test_stream_destroy_pending_drain(); 1.549 +*/ 1.550 + printf("\n"); 1.551 + return 0; 1.552 +}