media/libcubeb/tests/test_sanity.cpp

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

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

mercurial