tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_callback_ret.cpp (8196B)


      1 /*
      2 * Copyright � 2017 Mozilla Foundation
      3 *
      4 * This program is made available under an ISC-style license.  See the
      5 * accompanying file LICENSE for details.
      6 */
      7 
      8 /* libcubeb api/function test. Test that different return values from user
      9   specified callbacks are handled correctly. */
     10 #include "gtest/gtest.h"
     11 #if !defined(_XOPEN_SOURCE)
     12 #define _XOPEN_SOURCE 600
     13 #endif
     14 #include "cubeb/cubeb.h"
     15 #include <atomic>
     16 #include <memory>
     17 #include <string>
     18 
     19 // #define ENABLE_NORMAL_LOG
     20 // #define ENABLE_VERBOSE_LOG
     21 #include "common.h"
     22 
     23 const uint32_t SAMPLE_FREQUENCY = 48000;
     24 const cubeb_sample_format SAMPLE_FORMAT = CUBEB_SAMPLE_S16NE;
     25 
     26 enum test_direction { INPUT_ONLY, OUTPUT_ONLY, DUPLEX };
     27 
     28 // Structure which is used by data callbacks to track the total callbacks
     29 // executed vs the number of callbacks expected.
     30 struct user_state_callback_ret {
     31  std::atomic<int> cb_count{0};
     32  std::atomic<int> expected_cb_count{0};
     33  std::atomic<int> error_state{0};
     34 };
     35 
     36 // Data callback that always returns 0
     37 long
     38 data_cb_ret_zero(cubeb_stream * stream, void * user, const void * inputbuffer,
     39                 void * outputbuffer, long nframes)
     40 {
     41  user_state_callback_ret * u = (user_state_callback_ret *)user;
     42  // If this is the first time the callback has been called set our expected
     43  // callback count
     44  if (u->cb_count == 0) {
     45    u->expected_cb_count = 1;
     46  }
     47  u->cb_count++;
     48  if (nframes < 1) {
     49    // This shouldn't happen
     50    EXPECT_TRUE(false) << "nframes should not be 0 in data callback!";
     51  }
     52  return 0;
     53 }
     54 
     55 // Data callback that always returns nframes - 1
     56 long
     57 data_cb_ret_nframes_minus_one(cubeb_stream * stream, void * user,
     58                              const void * inputbuffer, void * outputbuffer,
     59                              long nframes)
     60 {
     61  user_state_callback_ret * u = (user_state_callback_ret *)user;
     62  // If this is the first time the callback has been called set our expected
     63  // callback count
     64  if (u->cb_count == 0) {
     65    u->expected_cb_count = 1;
     66  }
     67  u->cb_count++;
     68  if (nframes < 1) {
     69    // This shouldn't happen
     70    EXPECT_TRUE(false) << "nframes should not be 0 in data callback!";
     71  }
     72  if (outputbuffer != NULL) {
     73    // If we have an output buffer insert silence
     74    short * ob = (short *)outputbuffer;
     75    for (long i = 0; i < nframes - 1; i++) {
     76      ob[i] = 0;
     77    }
     78  }
     79  return nframes - 1;
     80 }
     81 
     82 // Data callback that always returns nframes
     83 long
     84 data_cb_ret_nframes(cubeb_stream * stream, void * user,
     85                    const void * inputbuffer, void * outputbuffer, long nframes)
     86 {
     87  user_state_callback_ret * u = (user_state_callback_ret *)user;
     88  u->cb_count++;
     89  // Every callback returns nframes, so every callback is expected
     90  u->expected_cb_count++;
     91  if (nframes < 1) {
     92    // This shouldn't happen
     93    EXPECT_TRUE(false) << "nframes should not be 0 in data callback!";
     94  }
     95  if (outputbuffer != NULL) {
     96    // If we have an output buffer insert silence
     97    short * ob = (short *)outputbuffer;
     98    for (long i = 0; i < nframes; i++) {
     99      ob[i] = 0;
    100    }
    101  }
    102  return nframes;
    103 }
    104 
    105 // Data callback that always returns CUBEB_ERROR
    106 long
    107 data_cb_ret_error(cubeb_stream * stream, void * user, const void * inputbuffer,
    108                  void * outputbuffer, long nframes)
    109 {
    110  user_state_callback_ret * u = (user_state_callback_ret *)user;
    111  // If this is the first time the callback has been called set our expected
    112  // callback count
    113  if (u->cb_count == 0) {
    114    u->expected_cb_count = 1;
    115  }
    116  u->cb_count++;
    117  if (nframes < 1) {
    118    // This shouldn't happen
    119    EXPECT_TRUE(false) << "nframes should not be 0 in data callback!";
    120  }
    121  return CUBEB_ERROR;
    122 }
    123 
    124 void
    125 state_cb_ret(cubeb_stream * stream, void * user, cubeb_state state)
    126 {
    127  if (stream == NULL)
    128    return;
    129  user_state_callback_ret * u = (user_state_callback_ret *)user;
    130 
    131  switch (state) {
    132  case CUBEB_STATE_STARTED:
    133    fprintf(stderr, "stream started\n");
    134    break;
    135  case CUBEB_STATE_STOPPED:
    136    fprintf(stderr, "stream stopped\n");
    137    break;
    138  case CUBEB_STATE_DRAINED:
    139    fprintf(stderr, "stream drained\n");
    140    break;
    141  case CUBEB_STATE_ERROR:
    142    fprintf(stderr, "stream error\n");
    143    u->error_state.fetch_add(1);
    144    break;
    145  default:
    146    fprintf(stderr, "unknown stream state %d\n", state);
    147  }
    148 }
    149 
    150 void
    151 run_test_callback(test_direction direction, cubeb_data_callback data_cb,
    152                  const std::string & test_desc)
    153 {
    154  cubeb * ctx;
    155  cubeb_stream * stream;
    156  cubeb_stream_params input_params;
    157  cubeb_stream_params output_params;
    158  int r;
    159  user_state_callback_ret user_state;
    160  uint32_t latency_frames = 0;
    161 
    162  r = common_init(&ctx, "Cubeb callback return value example");
    163  ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb library";
    164 
    165  std::unique_ptr<cubeb, decltype(&cubeb_destroy)> cleanup_cubeb_at_exit(
    166      ctx, cubeb_destroy);
    167 
    168  if ((direction == INPUT_ONLY || direction == DUPLEX) &&
    169      !can_run_audio_input_test(ctx)) {
    170    /* This test needs an available input device, skip it if this host does not
    171     * have one or if the backend doesn't implement input. */
    172    return;
    173  }
    174 
    175  // Setup all params, but only pass them later as required by direction
    176  input_params.format = SAMPLE_FORMAT;
    177  input_params.rate = SAMPLE_FREQUENCY;
    178  input_params.channels = 1;
    179  input_params.layout = CUBEB_LAYOUT_MONO;
    180  input_params.prefs = CUBEB_STREAM_PREF_NONE;
    181  output_params = input_params;
    182 
    183  r = cubeb_get_min_latency(ctx, &input_params, &latency_frames);
    184  if (r != CUBEB_OK) {
    185    // not fatal
    186    latency_frames = 1024;
    187  }
    188 
    189  switch (direction) {
    190  case INPUT_ONLY:
    191    r = cubeb_stream_init(ctx, &stream, "Cubeb callback ret input", NULL,
    192                          &input_params, NULL, NULL, latency_frames, data_cb,
    193                          state_cb_ret, &user_state);
    194    break;
    195  case OUTPUT_ONLY:
    196    r = cubeb_stream_init(ctx, &stream, "Cubeb callback ret output", NULL, NULL,
    197                          NULL, &output_params, latency_frames, data_cb,
    198                          state_cb_ret, &user_state);
    199    break;
    200  case DUPLEX:
    201    r = cubeb_stream_init(ctx, &stream, "Cubeb callback ret duplex", NULL,
    202                          &input_params, NULL, &output_params, latency_frames,
    203                          data_cb, state_cb_ret, &user_state);
    204    break;
    205  default:
    206    ASSERT_TRUE(false) << "Unrecognized test direction!";
    207  }
    208  EXPECT_EQ(r, CUBEB_OK) << "Error initializing cubeb stream";
    209 
    210  std::unique_ptr<cubeb_stream, decltype(&cubeb_stream_destroy)>
    211      cleanup_stream_at_exit(stream, cubeb_stream_destroy);
    212 
    213  cubeb_stream_start(stream);
    214  delay(100);
    215  cubeb_stream_stop(stream);
    216 
    217  ASSERT_EQ(user_state.expected_cb_count, user_state.cb_count)
    218      << "Callback called unexpected number of times for " << test_desc << "!";
    219  // TODO: On some test configurations, the data_callback is never called.
    220  if (data_cb == data_cb_ret_error && user_state.cb_count != 0) {
    221    ASSERT_EQ(user_state.error_state, 1) << "Callback expected error state";
    222  }
    223 }
    224 
    225 TEST(cubeb, test_input_callback)
    226 {
    227  run_test_callback(INPUT_ONLY, data_cb_ret_zero, "input only, return 0");
    228  run_test_callback(INPUT_ONLY, data_cb_ret_nframes_minus_one,
    229                    "input only, return nframes - 1");
    230  run_test_callback(INPUT_ONLY, data_cb_ret_nframes,
    231                    "input only, return nframes");
    232  run_test_callback(INPUT_ONLY, data_cb_ret_error,
    233                    "input only, return CUBEB_ERROR");
    234 }
    235 
    236 TEST(cubeb, test_output_callback)
    237 {
    238  run_test_callback(OUTPUT_ONLY, data_cb_ret_zero, "output only, return 0");
    239  run_test_callback(OUTPUT_ONLY, data_cb_ret_nframes_minus_one,
    240                    "output only, return nframes - 1");
    241  run_test_callback(OUTPUT_ONLY, data_cb_ret_nframes,
    242                    "output only, return nframes");
    243  run_test_callback(OUTPUT_ONLY, data_cb_ret_error,
    244                    "output only, return CUBEB_ERROR");
    245 }
    246 
    247 TEST(cubeb, test_duplex_callback)
    248 {
    249  run_test_callback(DUPLEX, data_cb_ret_zero, "duplex, return 0");
    250  run_test_callback(DUPLEX, data_cb_ret_nframes_minus_one,
    251                    "duplex, return nframes - 1");
    252  run_test_callback(DUPLEX, data_cb_ret_nframes, "duplex, return nframes");
    253  run_test_callback(DUPLEX, data_cb_ret_error, "duplex, return CUBEB_ERROR");
    254 }