media/libcubeb/tests/test_sanity.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /*
michael@0 2 * Copyright © 2011 Mozilla Foundation
michael@0 3 *
michael@0 4 * This program is made available under an ISC-style license. See the
michael@0 5 * accompanying file LICENSE for details.
michael@0 6 */
michael@0 7 #ifdef NDEBUG
michael@0 8 #undef NDEBUG
michael@0 9 #endif
michael@0 10 #define _XOPEN_SOURCE 500
michael@0 11 #include "cubeb/cubeb.h"
michael@0 12 #include <assert.h>
michael@0 13 #include <stdio.h>
michael@0 14 #include <string.h>
michael@0 15 #include <math.h>
michael@0 16 #include "common.h"
michael@0 17
michael@0 18 #if (defined(_WIN32) || defined(__WIN32__))
michael@0 19 #define __func__ __FUNCTION__
michael@0 20 #endif
michael@0 21
michael@0 22 #define ARRAY_LENGTH(_x) (sizeof(_x) / sizeof(_x[0]))
michael@0 23 #define BEGIN_TEST fprintf(stderr, "START %s\n", __func__);
michael@0 24 #define END_TEST fprintf(stderr, "END %s\n", __func__);
michael@0 25
michael@0 26 #define STREAM_LATENCY 100
michael@0 27 #define STREAM_RATE 44100
michael@0 28 #define STREAM_CHANNELS 1
michael@0 29 #define STREAM_FORMAT CUBEB_SAMPLE_S16LE
michael@0 30
michael@0 31 static int dummy;
michael@0 32 static uint64_t total_frames_written;
michael@0 33 static int delay_callback;
michael@0 34
michael@0 35 static long
michael@0 36 test_data_callback(cubeb_stream * stm, void * user_ptr, void * p, long nframes)
michael@0 37 {
michael@0 38 assert(stm && user_ptr == &dummy && p && nframes > 0);
michael@0 39 memset(p, 0, nframes * sizeof(short));
michael@0 40 total_frames_written += nframes;
michael@0 41 if (delay_callback) {
michael@0 42 delay(10);
michael@0 43 }
michael@0 44 return nframes;
michael@0 45 }
michael@0 46
michael@0 47 void
michael@0 48 test_state_callback(cubeb_stream * stm, void * user_ptr, cubeb_state state)
michael@0 49 {
michael@0 50 }
michael@0 51
michael@0 52 static void
michael@0 53 test_init_destroy_context(void)
michael@0 54 {
michael@0 55 int r;
michael@0 56 cubeb * ctx;
michael@0 57
michael@0 58 BEGIN_TEST
michael@0 59
michael@0 60 r = cubeb_init(&ctx, "test_sanity");
michael@0 61 assert(r == 0 && ctx);
michael@0 62
michael@0 63 cubeb_destroy(ctx);
michael@0 64
michael@0 65 END_TEST
michael@0 66 }
michael@0 67
michael@0 68 static void
michael@0 69 test_init_destroy_multiple_contexts(void)
michael@0 70 {
michael@0 71 int i;
michael@0 72 int r;
michael@0 73 cubeb * ctx[4];
michael@0 74
michael@0 75 BEGIN_TEST
michael@0 76
michael@0 77 for (i = 0; i < 4; ++i) {
michael@0 78 r = cubeb_init(&ctx[i], NULL);
michael@0 79 assert(r == 0 && ctx[i]);
michael@0 80 }
michael@0 81
michael@0 82 /* destroy in a different order */
michael@0 83 cubeb_destroy(ctx[2]);
michael@0 84 cubeb_destroy(ctx[0]);
michael@0 85 cubeb_destroy(ctx[3]);
michael@0 86 cubeb_destroy(ctx[1]);
michael@0 87
michael@0 88 END_TEST
michael@0 89 }
michael@0 90
michael@0 91 static void
michael@0 92 test_init_destroy_stream(void)
michael@0 93 {
michael@0 94 int r;
michael@0 95 cubeb * ctx;
michael@0 96 cubeb_stream * stream;
michael@0 97 cubeb_stream_params params;
michael@0 98
michael@0 99 BEGIN_TEST
michael@0 100
michael@0 101 r = cubeb_init(&ctx, "test_sanity");
michael@0 102 assert(r == 0 && ctx);
michael@0 103
michael@0 104 params.format = STREAM_FORMAT;
michael@0 105 params.rate = STREAM_RATE;
michael@0 106 params.channels = STREAM_CHANNELS;
michael@0 107
michael@0 108 r = cubeb_stream_init(ctx, &stream, "test", params, STREAM_LATENCY,
michael@0 109 test_data_callback, test_state_callback, &dummy);
michael@0 110 assert(r == 0 && stream);
michael@0 111
michael@0 112 cubeb_stream_destroy(stream);
michael@0 113 cubeb_destroy(ctx);
michael@0 114
michael@0 115 END_TEST
michael@0 116 }
michael@0 117
michael@0 118 static void
michael@0 119 test_init_destroy_multiple_streams(void)
michael@0 120 {
michael@0 121 int i;
michael@0 122 int r;
michael@0 123 cubeb * ctx;
michael@0 124 cubeb_stream * stream[16];
michael@0 125 cubeb_stream_params params;
michael@0 126
michael@0 127 BEGIN_TEST
michael@0 128
michael@0 129 r = cubeb_init(&ctx, "test_sanity");
michael@0 130 assert(r == 0 && ctx);
michael@0 131
michael@0 132 params.format = STREAM_FORMAT;
michael@0 133 params.rate = STREAM_RATE;
michael@0 134 params.channels = STREAM_CHANNELS;
michael@0 135
michael@0 136 for (i = 0; i < 16; ++i) {
michael@0 137 r = cubeb_stream_init(ctx, &stream[i], "test", params, STREAM_LATENCY,
michael@0 138 test_data_callback, test_state_callback, &dummy);
michael@0 139 assert(r == 0);
michael@0 140 assert(stream[i]);
michael@0 141 }
michael@0 142
michael@0 143 for (i = 0; i < 16; ++i) {
michael@0 144 cubeb_stream_destroy(stream[i]);
michael@0 145 }
michael@0 146
michael@0 147 cubeb_destroy(ctx);
michael@0 148
michael@0 149 END_TEST
michael@0 150 }
michael@0 151
michael@0 152 static void
michael@0 153 test_init_start_stop_destroy_multiple_streams(int early, int delay_ms)
michael@0 154 {
michael@0 155 int i;
michael@0 156 int r;
michael@0 157 cubeb * ctx;
michael@0 158 cubeb_stream * stream[16];
michael@0 159 cubeb_stream_params params;
michael@0 160
michael@0 161 BEGIN_TEST
michael@0 162
michael@0 163 r = cubeb_init(&ctx, "test_sanity");
michael@0 164 assert(r == 0 && ctx);
michael@0 165
michael@0 166 params.format = STREAM_FORMAT;
michael@0 167 params.rate = STREAM_RATE;
michael@0 168 params.channels = STREAM_CHANNELS;
michael@0 169
michael@0 170 for (i = 0; i < 16; ++i) {
michael@0 171 r = cubeb_stream_init(ctx, &stream[i], "test", params, STREAM_LATENCY,
michael@0 172 test_data_callback, test_state_callback, &dummy);
michael@0 173 assert(r == 0);
michael@0 174 assert(stream[i]);
michael@0 175 if (early) {
michael@0 176 r = cubeb_stream_start(stream[i]);
michael@0 177 assert(r == 0);
michael@0 178 }
michael@0 179 }
michael@0 180
michael@0 181
michael@0 182 if (!early) {
michael@0 183 for (i = 0; i < 16; ++i) {
michael@0 184 r = cubeb_stream_start(stream[i]);
michael@0 185 assert(r == 0);
michael@0 186 }
michael@0 187 }
michael@0 188
michael@0 189 if (delay_ms) {
michael@0 190 delay(delay_ms);
michael@0 191 }
michael@0 192
michael@0 193 if (!early) {
michael@0 194 for (i = 0; i < 16; ++i) {
michael@0 195 r = cubeb_stream_stop(stream[i]);
michael@0 196 assert(r == 0);
michael@0 197 }
michael@0 198 }
michael@0 199
michael@0 200 for (i = 0; i < 16; ++i) {
michael@0 201 if (early) {
michael@0 202 r = cubeb_stream_stop(stream[i]);
michael@0 203 assert(r == 0);
michael@0 204 }
michael@0 205 cubeb_stream_destroy(stream[i]);
michael@0 206 }
michael@0 207
michael@0 208 cubeb_destroy(ctx);
michael@0 209
michael@0 210 END_TEST
michael@0 211 }
michael@0 212
michael@0 213 static void
michael@0 214 test_init_destroy_multiple_contexts_and_streams(void)
michael@0 215 {
michael@0 216 int i, j;
michael@0 217 int r;
michael@0 218 cubeb * ctx[4];
michael@0 219 cubeb_stream * stream[16];
michael@0 220 cubeb_stream_params params;
michael@0 221
michael@0 222 BEGIN_TEST
michael@0 223
michael@0 224 params.format = STREAM_FORMAT;
michael@0 225 params.rate = STREAM_RATE;
michael@0 226 params.channels = STREAM_CHANNELS;
michael@0 227
michael@0 228 for (i = 0; i < 4; ++i) {
michael@0 229 r = cubeb_init(&ctx[i], "test_sanity");
michael@0 230 assert(r == 0 && ctx[i]);
michael@0 231
michael@0 232 for (j = 0; j < 4; ++j) {
michael@0 233 r = cubeb_stream_init(ctx[i], &stream[i * 4 + j], "test", params, STREAM_LATENCY,
michael@0 234 test_data_callback, test_state_callback, &dummy);
michael@0 235 assert(r == 0);
michael@0 236 assert(stream[i * 4 + j]);
michael@0 237 }
michael@0 238 }
michael@0 239
michael@0 240 for (i = 0; i < 4; ++i) {
michael@0 241 for (j = 0; j < 4; ++j) {
michael@0 242 cubeb_stream_destroy(stream[i * 4 + j]);
michael@0 243 }
michael@0 244 cubeb_destroy(ctx[i]);
michael@0 245 }
michael@0 246
michael@0 247 END_TEST
michael@0 248 }
michael@0 249
michael@0 250 static void
michael@0 251 test_basic_stream_operations(void)
michael@0 252 {
michael@0 253 int r;
michael@0 254 cubeb * ctx;
michael@0 255 cubeb_stream * stream;
michael@0 256 cubeb_stream_params params;
michael@0 257 uint64_t position;
michael@0 258
michael@0 259 BEGIN_TEST
michael@0 260
michael@0 261 r = cubeb_init(&ctx, "test_sanity");
michael@0 262 assert(r == 0 && ctx);
michael@0 263
michael@0 264 params.format = STREAM_FORMAT;
michael@0 265 params.rate = STREAM_RATE;
michael@0 266 params.channels = STREAM_CHANNELS;
michael@0 267
michael@0 268 r = cubeb_stream_init(ctx, &stream, "test", params, STREAM_LATENCY,
michael@0 269 test_data_callback, test_state_callback, &dummy);
michael@0 270 assert(r == 0 && stream);
michael@0 271
michael@0 272 /* position and volume before stream has started */
michael@0 273 r = cubeb_stream_get_position(stream, &position);
michael@0 274 assert(r == 0 && position == 0);
michael@0 275
michael@0 276 r = cubeb_stream_start(stream);
michael@0 277 assert(r == 0);
michael@0 278
michael@0 279 /* position and volume after while stream running */
michael@0 280 r = cubeb_stream_get_position(stream, &position);
michael@0 281 assert(r == 0);
michael@0 282
michael@0 283 r = cubeb_stream_stop(stream);
michael@0 284 assert(r == 0);
michael@0 285
michael@0 286 /* position and volume after stream has stopped */
michael@0 287 r = cubeb_stream_get_position(stream, &position);
michael@0 288 assert(r == 0);
michael@0 289
michael@0 290 cubeb_stream_destroy(stream);
michael@0 291 cubeb_destroy(ctx);
michael@0 292
michael@0 293 END_TEST
michael@0 294 }
michael@0 295
michael@0 296 static void
michael@0 297 test_stream_position(void)
michael@0 298 {
michael@0 299 int i;
michael@0 300 int r;
michael@0 301 cubeb * ctx;
michael@0 302 cubeb_stream * stream;
michael@0 303 cubeb_stream_params params;
michael@0 304 uint64_t position, last_position;
michael@0 305
michael@0 306 BEGIN_TEST
michael@0 307
michael@0 308 total_frames_written = 0;
michael@0 309
michael@0 310 r = cubeb_init(&ctx, "test_sanity");
michael@0 311 assert(r == 0 && ctx);
michael@0 312
michael@0 313 params.format = STREAM_FORMAT;
michael@0 314 params.rate = STREAM_RATE;
michael@0 315 params.channels = STREAM_CHANNELS;
michael@0 316
michael@0 317 r = cubeb_stream_init(ctx, &stream, "test", params, STREAM_LATENCY,
michael@0 318 test_data_callback, test_state_callback, &dummy);
michael@0 319 assert(r == 0 && stream);
michael@0 320
michael@0 321 /* stream position should not advance before starting playback */
michael@0 322 r = cubeb_stream_get_position(stream, &position);
michael@0 323 assert(r == 0 && position == 0);
michael@0 324
michael@0 325 delay(500);
michael@0 326
michael@0 327 r = cubeb_stream_get_position(stream, &position);
michael@0 328 assert(r == 0 && position == 0);
michael@0 329
michael@0 330 /* stream position should advance during playback */
michael@0 331 r = cubeb_stream_start(stream);
michael@0 332 assert(r == 0);
michael@0 333
michael@0 334 /* XXX let start happen */
michael@0 335 delay(500);
michael@0 336
michael@0 337 /* stream should have prefilled */
michael@0 338 assert(total_frames_written > 0);
michael@0 339
michael@0 340 r = cubeb_stream_get_position(stream, &position);
michael@0 341 assert(r == 0);
michael@0 342 last_position = position;
michael@0 343
michael@0 344 delay(500);
michael@0 345
michael@0 346 r = cubeb_stream_get_position(stream, &position);
michael@0 347 assert(r == 0);
michael@0 348 assert(position >= last_position);
michael@0 349 last_position = position;
michael@0 350
michael@0 351 /* stream position should not exceed total frames written */
michael@0 352 for (i = 0; i < 5; ++i) {
michael@0 353 r = cubeb_stream_get_position(stream, &position);
michael@0 354 assert(r == 0);
michael@0 355 assert(position >= last_position);
michael@0 356 assert(position <= total_frames_written);
michael@0 357 last_position = position;
michael@0 358 delay(500);
michael@0 359 }
michael@0 360
michael@0 361 assert(last_position != 0);
michael@0 362
michael@0 363 /* stream position should not advance after stopping playback */
michael@0 364 r = cubeb_stream_stop(stream);
michael@0 365 assert(r == 0);
michael@0 366
michael@0 367 /* XXX allow stream to settle */
michael@0 368 delay(500);
michael@0 369
michael@0 370 r = cubeb_stream_get_position(stream, &position);
michael@0 371 assert(r == 0);
michael@0 372 last_position = position;
michael@0 373
michael@0 374 delay(500);
michael@0 375
michael@0 376 r = cubeb_stream_get_position(stream, &position);
michael@0 377 assert(r == 0);
michael@0 378 assert(position == last_position);
michael@0 379
michael@0 380 cubeb_stream_destroy(stream);
michael@0 381 cubeb_destroy(ctx);
michael@0 382
michael@0 383 END_TEST
michael@0 384 }
michael@0 385
michael@0 386 static int do_drain;
michael@0 387 static int got_drain;
michael@0 388
michael@0 389 static long
michael@0 390 test_drain_data_callback(cubeb_stream * stm, void * user_ptr, void * p, long nframes)
michael@0 391 {
michael@0 392 assert(stm && user_ptr == &dummy && p && nframes > 0);
michael@0 393 if (do_drain == 1) {
michael@0 394 do_drain = 2;
michael@0 395 return 0;
michael@0 396 }
michael@0 397 /* once drain has started, callback must never be called again */
michael@0 398 assert(do_drain != 2);
michael@0 399 memset(p, 0, nframes * sizeof(short));
michael@0 400 total_frames_written += nframes;
michael@0 401 return nframes;
michael@0 402 }
michael@0 403
michael@0 404 void
michael@0 405 test_drain_state_callback(cubeb_stream * stm, void * user_ptr, cubeb_state state)
michael@0 406 {
michael@0 407 if (state == CUBEB_STATE_DRAINED) {
michael@0 408 assert(!got_drain);
michael@0 409 got_drain = 1;
michael@0 410 }
michael@0 411 }
michael@0 412
michael@0 413 static void
michael@0 414 test_drain(void)
michael@0 415 {
michael@0 416 int r;
michael@0 417 cubeb * ctx;
michael@0 418 cubeb_stream * stream;
michael@0 419 cubeb_stream_params params;
michael@0 420 uint64_t position;
michael@0 421
michael@0 422 BEGIN_TEST
michael@0 423
michael@0 424 total_frames_written = 0;
michael@0 425
michael@0 426 r = cubeb_init(&ctx, "test_sanity");
michael@0 427 assert(r == 0 && ctx);
michael@0 428
michael@0 429 params.format = STREAM_FORMAT;
michael@0 430 params.rate = STREAM_RATE;
michael@0 431 params.channels = STREAM_CHANNELS;
michael@0 432
michael@0 433 r = cubeb_stream_init(ctx, &stream, "test", params, STREAM_LATENCY,
michael@0 434 test_drain_data_callback, test_drain_state_callback, &dummy);
michael@0 435 assert(r == 0 && stream);
michael@0 436
michael@0 437 r = cubeb_stream_start(stream);
michael@0 438 assert(r == 0);
michael@0 439
michael@0 440 delay(500);
michael@0 441
michael@0 442 do_drain = 1;
michael@0 443
michael@0 444 for (;;) {
michael@0 445 r = cubeb_stream_get_position(stream, &position);
michael@0 446 assert(r == 0);
michael@0 447 if (got_drain) {
michael@0 448 break;
michael@0 449 } else {
michael@0 450 uint32_t i, skip = 0;
michael@0 451 /* Latency passed to cubeb_stream_init is not really honored on OSX,
michael@0 452 win32/winmm and android, skip this test. */
michael@0 453 const char * backend_id = cubeb_get_backend_id(ctx);
michael@0 454 const char * latency_not_honored_bakends[] = {
michael@0 455 "audiounit",
michael@0 456 "winmm",
michael@0 457 "audiotrack",
michael@0 458 "opensl"
michael@0 459 };
michael@0 460
michael@0 461 for (i = 0; i < ARRAY_LENGTH(latency_not_honored_bakends); i++) {
michael@0 462 if (!strcmp(backend_id, latency_not_honored_bakends[i])) {
michael@0 463 skip = 1;
michael@0 464 }
michael@0 465 }
michael@0 466 if (!skip) {
michael@0 467 /* Position should roughly be equal to the number of written frames. We
michael@0 468 * need to take the latency into account. */
michael@0 469 int latency = (STREAM_LATENCY * STREAM_RATE) / 1000;
michael@0 470 assert(position + latency <= total_frames_written);
michael@0 471 }
michael@0 472 }
michael@0 473 delay(500);
michael@0 474 }
michael@0 475
michael@0 476 r = cubeb_stream_get_position(stream, &position);
michael@0 477 assert(r == 0);
michael@0 478 assert(got_drain);
michael@0 479
michael@0 480 // Disabled due to failures in the ALSA backend.
michael@0 481 //assert(position == total_frames_written);
michael@0 482
michael@0 483 cubeb_stream_destroy(stream);
michael@0 484 cubeb_destroy(ctx);
michael@0 485
michael@0 486 END_TEST
michael@0 487 }
michael@0 488
michael@0 489 int is_windows_7()
michael@0 490 {
michael@0 491 #if (defined(_WIN32) || defined(__WIN32__))
michael@0 492 OSVERSIONINFOEX osvi;
michael@0 493 DWORDLONG condition_mask = 0;
michael@0 494
michael@0 495 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
michael@0 496 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
michael@0 497
michael@0 498 // NT 6.1 is Windows 7
michael@0 499 osvi.dwMajorVersion = 6;
michael@0 500 osvi.dwMinorVersion = 1;
michael@0 501
michael@0 502 VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, VER_EQUAL);
michael@0 503 VER_SET_CONDITION(condition_mask, VER_MINORVERSION, VER_EQUAL);
michael@0 504
michael@0 505 return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION, condition_mask);
michael@0 506 #else
michael@0 507 return 0;
michael@0 508 #endif
michael@0 509 }
michael@0 510
michael@0 511 int
michael@0 512 main(int argc, char * argv[])
michael@0 513 {
michael@0 514 test_init_destroy_context();
michael@0 515 test_init_destroy_multiple_contexts();
michael@0 516 test_init_destroy_stream();
michael@0 517 test_init_destroy_multiple_streams();
michael@0 518 test_basic_stream_operations();
michael@0 519 test_stream_position();
michael@0 520
michael@0 521 /* Sometimes, when using WASAPI on windows 7 (vista and 8 are okay), and
michael@0 522 * calling Activate a lot on an AudioClient, 0x800700b7 is returned. This is
michael@0 523 * the HRESULT value for "Cannot create a file when that file already exists",
michael@0 524 * and is not documented as a possible return value for this call. Hence, we
michael@0 525 * try to limit the number of streams we create in this test. */
michael@0 526 if (!is_windows_7()) {
michael@0 527 test_init_destroy_multiple_contexts_and_streams();
michael@0 528
michael@0 529 delay_callback = 0;
michael@0 530 test_init_start_stop_destroy_multiple_streams(0, 0);
michael@0 531 test_init_start_stop_destroy_multiple_streams(1, 0);
michael@0 532 test_init_start_stop_destroy_multiple_streams(0, 150);
michael@0 533 test_init_start_stop_destroy_multiple_streams(1, 150);
michael@0 534 delay_callback = 1;
michael@0 535 test_init_start_stop_destroy_multiple_streams(0, 0);
michael@0 536 test_init_start_stop_destroy_multiple_streams(1, 0);
michael@0 537 test_init_start_stop_destroy_multiple_streams(0, 150);
michael@0 538 test_init_start_stop_destroy_multiple_streams(1, 150);
michael@0 539 }
michael@0 540 delay_callback = 0;
michael@0 541 test_drain();
michael@0 542 /*
michael@0 543 to implement:
michael@0 544 test_eos_during_prefill();
michael@0 545 test_stream_destroy_pending_drain();
michael@0 546 */
michael@0 547 printf("\n");
michael@0 548 return 0;
michael@0 549 }

mercurial