示例#1
0
static void
test_init_start_stop_destroy_multiple_streams(int early, int delay_ms)
{
  int i;
  int r;
  cubeb * ctx;
  cubeb_stream * stream[8];
  cubeb_stream_params params;

  BEGIN_TEST

  r = cubeb_init(&ctx, "test_sanity");
  assert(r == 0 && ctx);

  params.format = STREAM_FORMAT;
  params.rate = STREAM_RATE;
  params.channels = STREAM_CHANNELS;

  for (i = 0; i < 8; ++i) {
    r = cubeb_stream_init(ctx, &stream[i], "test", params, STREAM_LATENCY,
                          test_data_callback, test_state_callback, &dummy);
    assert(r == 0);
    assert(stream[i]);
    if (early) {
      r = cubeb_stream_start(stream[i]);
      assert(r == 0);
    }
  }


  if (!early) {
    for (i = 0; i < 8; ++i) {
      r = cubeb_stream_start(stream[i]);
      assert(r == 0);
    }
  }

  if (delay_ms) {
    delay(delay_ms);
  }

  if (!early) {
    for (i = 0; i < 8; ++i) {
      r = cubeb_stream_stop(stream[i]);
      assert(r == 0);
    }
  }

  for (i = 0; i < 8; ++i) {
    if (early) {
      r = cubeb_stream_stop(stream[i]);
      assert(r == 0);
    }
    cubeb_stream_destroy(stream[i]);
  }

  cubeb_destroy(ctx);

  END_TEST
}
示例#2
0
static void
test_init_start_stop_destroy_multiple_streams(int early, int delay_ms)
{
  size_t i;
  int r;
  cubeb * ctx;
  cubeb_stream * stream[8];
  cubeb_stream_params params;

  r = common_init(&ctx, "test_sanity");
  ASSERT_EQ(r, CUBEB_OK);
  ASSERT_NE(ctx, nullptr);

  params.format = STREAM_FORMAT;
  params.rate = STREAM_RATE;
  params.channels = STREAM_CHANNELS;
  params.layout = STREAM_LAYOUT;

  for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
    r = cubeb_stream_init(ctx, &stream[i], "test", NULL, NULL, NULL, &params, STREAM_LATENCY,
                          test_data_callback, test_state_callback, &dummy);
    ASSERT_EQ(r, CUBEB_OK);
    ASSERT_NE(stream[i], nullptr);
    if (early) {
      r = cubeb_stream_start(stream[i]);
      ASSERT_EQ(r, CUBEB_OK);
    }
  }

  if (!early) {
    for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
      r = cubeb_stream_start(stream[i]);
      ASSERT_EQ(r, CUBEB_OK);
    }
  }

  if (delay_ms) {
    delay(delay_ms);
  }

  if (!early) {
    for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
      r = cubeb_stream_stop(stream[i]);
      ASSERT_EQ(r, CUBEB_OK);
    }
  }

  for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
    if (early) {
      r = cubeb_stream_stop(stream[i]);
      ASSERT_EQ(r, CUBEB_OK);
    }
    cubeb_stream_destroy(stream[i]);
  }

  cubeb_destroy(ctx);
}
示例#3
0
TEST(cubeb, configure_stream_undefined_layout)
{
  int r;
  cubeb * ctx;
  cubeb_stream * stream;
  cubeb_stream_params params;

  r = common_init(&ctx, "test_sanity");
  ASSERT_EQ(r, CUBEB_OK);
  ASSERT_NE(ctx, nullptr);

  params.format = STREAM_FORMAT;
  params.rate = STREAM_RATE;
  params.channels = 2; // panning
  params.layout = CUBEB_LAYOUT_UNDEFINED;

  r = cubeb_stream_init(ctx, &stream, "test", NULL, NULL, NULL, &params, STREAM_LATENCY,
                        test_data_callback, test_state_callback, &dummy);
  ASSERT_EQ(r, CUBEB_OK);
  ASSERT_NE(stream, nullptr);

  r = cubeb_stream_start(stream);
  ASSERT_EQ(r, CUBEB_OK);

  delay(100);

  r = cubeb_stream_stop(stream);
  ASSERT_EQ(r, CUBEB_OK);

  cubeb_stream_destroy(stream);
  cubeb_destroy(ctx);
}
示例#4
0
bool CubebStream::SetRunning(bool running)
{
  if (running)
    return cubeb_stream_start(m_stream) == CUBEB_OK;
  else
    return cubeb_stream_stop(m_stream) == CUBEB_OK;
}
示例#5
0
void
AudioCallbackDriver::Stop()
{
    if (cubeb_stream_stop(mAudioStream) != CUBEB_OK) {
        NS_WARNING("Could not stop cubeb stream for MSG.");
    }
}
示例#6
0
int main(int /*argc*/, char * /*argv*/[])
{
#ifdef CUBEB_GECKO_BUILD
  ScopedXPCOM xpcom("test_duplex");
#endif

  cubeb *ctx;
  cubeb_stream *stream;
  cubeb_stream_params input_params;
  cubeb_stream_params output_params;
  int r;
  user_state stream_state = { false };
  uint32_t latency_frames = 0;

  r = cubeb_init(&ctx, "Cubeb duplex example");
  if (r != CUBEB_OK) {
    fprintf(stderr, "Error initializing cubeb library\n");
    return r;
  }

  /* This test needs an available input device, skip it if this host does not
   * have one. */
  if (!has_available_input_device(ctx)) {
    return 0;
  }

  /* typical user-case: mono input, stereo output, low latency. */
  input_params.format = STREAM_FORMAT;
  input_params.rate = 48000;
  input_params.channels = 1;
  output_params.format = STREAM_FORMAT;
  output_params.rate = 48000;
  output_params.channels = 2;

  r = cubeb_get_min_latency(ctx, output_params, &latency_frames);

  if (r != CUBEB_OK) {
    fprintf(stderr, "Could not get minimal latency\n");
    return r;
  }

  r = cubeb_stream_init(ctx, &stream, "Cubeb duplex",
                        NULL, &input_params, NULL, &output_params,
                        latency_frames, data_cb, state_cb, &stream_state);
  if (r != CUBEB_OK) {
    fprintf(stderr, "Error initializing cubeb stream\n");
    return r;
  }

  cubeb_stream_start(stream);
  delay(500);
  cubeb_stream_stop(stream);

  cubeb_stream_destroy(stream);
  cubeb_destroy(ctx);

  assert(stream_state.seen_noise);

  return CUBEB_OK;
}
示例#7
0
int run_test(int num_channels, int sampling_rate, int is_float)
{
  int r = CUBEB_OK;

  cubeb *ctx = NULL;
  synth_state* synth = NULL;
  cubeb_stream *stream = NULL;
  const char * backend_id = NULL;

  r = cubeb_init(&ctx, "Cubeb audio test: channels");
  if (r != CUBEB_OK) {
    fprintf(stderr, "Error initializing cubeb library\n");
    goto cleanup;
  }

  backend_id = cubeb_get_backend_id(ctx);

  if ((is_float && !supports_float32(backend_id)) ||
      (!is_float && !supports_int16(backend_id)) ||
      !supports_channel_count(backend_id, num_channels)) {
    /* don't treat this as a test failure. */
    goto cleanup;
  }

  fprintf(stderr, "Testing %d channel(s), %d Hz, %s (%s)\n", num_channels, sampling_rate, is_float ? "float" : "short", cubeb_get_backend_id(ctx));

  cubeb_stream_params params;
  params.format = is_float ? CUBEB_SAMPLE_FLOAT32NE : CUBEB_SAMPLE_S16NE;
  params.rate = sampling_rate;
  params.channels = num_channels;

  synth = synth_create(params.channels, params.rate);
  if (synth == NULL) {
    fprintf(stderr, "Out of memory\n");
    goto cleanup;
  }

  r = cubeb_stream_init(ctx, &stream, "test tone", NULL, NULL, NULL, &params,
                        4096, is_float ? data_cb_float : data_cb_short, state_cb_audio, synth);
  if (r != CUBEB_OK) {
    fprintf(stderr, "Error initializing cubeb stream: %d\n", r);
    goto cleanup;
  }

  cubeb_stream_start(stream);
  delay(200);
  cubeb_stream_stop(stream);

cleanup:
  cubeb_stream_destroy(stream);
  cubeb_destroy(ctx);
  synth_destroy(synth);

  return r;
}
示例#8
0
TEST(cubeb, duplex)
{
  cubeb *ctx;
  cubeb_stream *stream;
  cubeb_stream_params input_params;
  cubeb_stream_params output_params;
  int r;
  user_state_duplex stream_state = { false };
  uint32_t latency_frames = 0;

  r = cubeb_init(&ctx, "Cubeb duplex example", NULL);
  ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb library";

  std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
    cleanup_cubeb_at_exit(ctx, cubeb_destroy);

  /* This test needs an available input device, skip it if this host does not
   * have one. */
  if (!has_available_input_device(ctx)) {
    return;
  }

  /* typical user-case: mono input, stereo output, low latency. */
  input_params.format = STREAM_FORMAT;
  input_params.rate = 48000;
  input_params.channels = 1;
  input_params.layout = CUBEB_LAYOUT_MONO;
  output_params.format = STREAM_FORMAT;
  output_params.rate = 48000;
  output_params.channels = 2;
  output_params.layout = CUBEB_LAYOUT_STEREO;

  r = cubeb_get_min_latency(ctx, output_params, &latency_frames);
  ASSERT_EQ(r, CUBEB_OK) << "Could not get minimal latency";

  r = cubeb_stream_init(ctx, &stream, "Cubeb duplex",
                        NULL, &input_params, NULL, &output_params,
                        latency_frames, data_cb_duplex, state_cb_duplex, &stream_state);
  ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb stream";

  std::unique_ptr<cubeb_stream, decltype(&cubeb_stream_destroy)>
    cleanup_stream_at_exit(stream, cubeb_stream_destroy);

  cubeb_stream_start(stream);
  delay(500);
  cubeb_stream_stop(stream);

  ASSERT_TRUE(stream_state.seen_audio);
}
示例#9
0
TEST(cubeb, record)
{
  if (cubeb_set_log_callback(CUBEB_LOG_DISABLED, nullptr /*print_log*/) != CUBEB_OK) {
    printf("Set log callback failed\n");
  }
  cubeb *ctx;
  cubeb_stream *stream;
  cubeb_stream_params params;
  int r;
  user_state_record stream_state = { false };

  r = cubeb_init(&ctx, "Cubeb record example");
  if (r != CUBEB_OK) {
    fprintf(stderr, "Error initializing cubeb library\n");
    ASSERT_EQ(r, CUBEB_OK);
  }

  /* This test needs an available input device, skip it if this host does not
   * have one. */
  if (!has_available_input_device(ctx)) {
    return;
  }

  params.format = STREAM_FORMAT;
  params.rate = SAMPLE_FREQUENCY;
  params.channels = 1;
  params.layout = CUBEB_LAYOUT_MONO;

  r = cubeb_stream_init(ctx, &stream, "Cubeb record (mono)", NULL, &params, NULL, nullptr,
                        4096, data_cb_record, state_cb_record, &stream_state);
  if (r != CUBEB_OK) {
    fprintf(stderr, "Error initializing cubeb stream\n");
    ASSERT_EQ(r, CUBEB_OK);
  }

  cubeb_stream_start(stream);
  delay(500);
  cubeb_stream_stop(stream);

  cubeb_stream_destroy(stream);
  cubeb_destroy(ctx);

#ifdef __linux__
  // user callback does not arrive in Linux, silence the error
  printf("Check is disabled in Linux\n");
#else
  ASSERT_TRUE(stream_state.seen_audio);
#endif
}
示例#10
0
void
AudioStream::Shutdown()
{
    MonitorAutoLock mon(mMonitor);
    LOG(("AudioStream: Shutdown %p, state %d", this, mState));

    if (mCubebStream) {
        MonitorAutoUnlock mon(mMonitor);
        // Force stop to put the cubeb stream in a stable state before deletion.
        cubeb_stream_stop(mCubebStream.get());
        // Must not try to shut down cubeb from within the lock!  wasapi may still
        // call our callback after Pause()/stop()!?! Bug 996162
        mCubebStream.reset();
    }

    mState = SHUTDOWN;
}
void
BufferedAudioStream::Pause()
{
  MonitorAutoLock mon(mMonitor);
  if (!mCubebStream || mState != STARTED) {
    return;
  }

  int r;
  {
    MonitorAutoUnlock mon(mMonitor);
    r = cubeb_stream_stop(mCubebStream);
  }
  if (mState != ERRORED && r == CUBEB_OK) {
    mState = STOPPED;
  }
}
示例#12
0
int main(int argc, char *argv[])
{
#ifdef CUBEB_GECKO_BUILD
  ScopedXPCOM xpcom("test_record");
#endif

  cubeb *ctx;
  cubeb_stream *stream;
  cubeb_stream_params params;
  int r;
  user_state stream_state = { false };

  r = cubeb_init(&ctx, "Cubeb record example");
  if (r != CUBEB_OK) {
    fprintf(stderr, "Error initializing cubeb library\n");
    return r;
  }

  /* This test needs an available input device, skip it if this host does not
   * have one. */
  if (!has_available_input_device(ctx)) {
    return 0;
  }

  params.format = STREAM_FORMAT;
  params.rate = SAMPLE_FREQUENCY;
  params.channels = 1;

  r = cubeb_stream_init(ctx, &stream, "Cubeb record (mono)", NULL, &params, NULL, nullptr,
                        250, data_cb, state_cb, &stream_state);
  if (r != CUBEB_OK) {
    fprintf(stderr, "Error initializing cubeb stream\n");
    return r;
  }

  cubeb_stream_start(stream);
  delay(500);
  cubeb_stream_stop(stream);

  cubeb_stream_destroy(stream);
  cubeb_destroy(ctx);

  assert(stream_state.seen_noise);

  return CUBEB_OK;
}
示例#13
0
static void
test_basic_stream_operations(void)
{
  int r;
  cubeb * ctx;
  cubeb_stream * stream;
  cubeb_stream_params params;
  uint64_t position;

  BEGIN_TEST

  r = cubeb_init(&ctx, "test_sanity");
  assert(r == 0 && ctx);

  params.format = STREAM_FORMAT;
  params.rate = STREAM_RATE;
  params.channels = STREAM_CHANNELS;

  r = cubeb_stream_init(ctx, &stream, "test", params, STREAM_LATENCY,
                        test_data_callback, test_state_callback, &dummy);
  assert(r == 0 && stream);

  /* position and volume before stream has started */
  r = cubeb_stream_get_position(stream, &position);
  assert(r == 0 && position == 0);

  r = cubeb_stream_start(stream);
  assert(r == 0);

  /* position and volume after while stream running */
  r = cubeb_stream_get_position(stream, &position);
  assert(r == 0);

  r = cubeb_stream_stop(stream);
  assert(r == 0);

  /* position and volume after stream has stopped */
  r = cubeb_stream_get_position(stream, &position);
  assert(r == 0);

  cubeb_stream_destroy(stream);
  cubeb_destroy(ctx);

  END_TEST
}
示例#14
0
TEST(cubeb, basic_stream_operations)
{
  int r;
  cubeb * ctx;
  cubeb_stream * stream;
  cubeb_stream_params params;
  uint64_t position;

  r = common_init(&ctx, "test_sanity");
  ASSERT_EQ(r, CUBEB_OK);
  ASSERT_NE(ctx, nullptr);

  params.format = STREAM_FORMAT;
  params.rate = STREAM_RATE;
  params.channels = STREAM_CHANNELS;
  params.layout = STREAM_LAYOUT;

  r = cubeb_stream_init(ctx, &stream, "test", NULL, NULL, NULL, &params, STREAM_LATENCY,
                        test_data_callback, test_state_callback, &dummy);
  ASSERT_EQ(r, CUBEB_OK);
  ASSERT_NE(stream, nullptr);

  /* position and volume before stream has started */
  r = cubeb_stream_get_position(stream, &position);
  ASSERT_EQ(r, CUBEB_OK);
  ASSERT_EQ(position, 0u);

  r = cubeb_stream_start(stream);
  ASSERT_EQ(r, CUBEB_OK);

  /* position and volume after while stream running */
  r = cubeb_stream_get_position(stream, &position);
  ASSERT_EQ(r, CUBEB_OK);

  r = cubeb_stream_stop(stream);
  ASSERT_EQ(r, CUBEB_OK);

  /* position and volume after stream has stopped */
  r = cubeb_stream_get_position(stream, &position);
  ASSERT_EQ(r, CUBEB_OK);

  cubeb_stream_destroy(stream);
  cubeb_destroy(ctx);
}
示例#15
0
void
AudioStream::Pause()
{
  MonitorAutoLock mon(mMonitor);
  if (!mCubebStream || (mState != STARTED && mState != RUNNING)) {
    mNeedsStart = false;
    mState = STOPPED; // which also tells async OpenCubeb not to start, just init
    return;
  }

  int r;
  {
    MonitorAutoUnlock mon(mMonitor);
    r = cubeb_stream_stop(mCubebStream);
  }
  if (mState != ERRORED && r == CUBEB_OK) {
    mState = STOPPED;
  }
}
示例#16
0
TEST(cubeb, record)
{
  cubeb *ctx;
  cubeb_stream *stream;
  cubeb_stream_params params;
  int r;
  user_state_record stream_state = { false };

  r = cubeb_init(&ctx, "Cubeb record example");
  if (r != CUBEB_OK) {
    fprintf(stderr, "Error initializing cubeb library\n");
    ASSERT_EQ(r, CUBEB_OK);
  }

  /* This test needs an available input device, skip it if this host does not
   * have one. */
  if (!has_available_input_device(ctx)) {
    return;
  }

  params.format = STREAM_FORMAT;
  params.rate = SAMPLE_FREQUENCY;
  params.channels = 1;

  r = cubeb_stream_init(ctx, &stream, "Cubeb record (mono)", NULL, &params, NULL, nullptr,
                        4096, data_cb_record, state_cb_record, &stream_state);
  if (r != CUBEB_OK) {
    fprintf(stderr, "Error initializing cubeb stream\n");
    ASSERT_EQ(r, CUBEB_OK);
  }

  cubeb_stream_start(stream);
  delay(500);
  cubeb_stream_stop(stream);

  cubeb_stream_destroy(stream);
  cubeb_destroy(ctx);

  ASSERT_TRUE(stream_state.seen_noise);
}
示例#17
0
static void
test_stream_position(void)
{
  int i;
  int r;
  cubeb * ctx;
  cubeb_stream * stream;
  cubeb_stream_params params;
  uint64_t position, last_position;

  BEGIN_TEST

  total_frames_written = 0;

  r = cubeb_init(&ctx, "test_sanity");
  assert(r == 0 && ctx);

  params.format = STREAM_FORMAT;
  params.rate = STREAM_RATE;
  params.channels = STREAM_CHANNELS;

  r = cubeb_stream_init(ctx, &stream, "test", params, STREAM_LATENCY,
                        test_data_callback, test_state_callback, &dummy);
  assert(r == 0 && stream);

  /* stream position should not advance before starting playback */
  r = cubeb_stream_get_position(stream, &position);
  assert(r == 0 && position == 0);

  delay(500);

  r = cubeb_stream_get_position(stream, &position);
  assert(r == 0 && position == 0);

  /* stream position should advance during playback */
  r = cubeb_stream_start(stream);
  assert(r == 0);

  /* XXX let start happen */
  delay(500);

  /* stream should have prefilled */
  assert(total_frames_written > 0);

  r = cubeb_stream_get_position(stream, &position);
  assert(r == 0);
  last_position = position;

  delay(500);

  r = cubeb_stream_get_position(stream, &position);
  assert(r == 0);
  assert(position >= last_position);
  last_position = position;

  /* stream position should not exceed total frames written */
  for (i = 0; i < 5; ++i) {
    r = cubeb_stream_get_position(stream, &position);
    assert(r == 0);
    assert(position >= last_position);
    assert(position <= total_frames_written);
    last_position = position;
    delay(500);
  }

  assert(last_position != 0);

  /* stream position should not advance after stopping playback */
  r = cubeb_stream_stop(stream);
  assert(r == 0);

  /* XXX allow stream to settle */
  delay(500);

  r = cubeb_stream_get_position(stream, &position);
  assert(r == 0);
  last_position = position;

  delay(500);

  r = cubeb_stream_get_position(stream, &position);
  assert(r == 0);
  assert(position == last_position);

  cubeb_stream_destroy(stream);
  cubeb_destroy(ctx);

  END_TEST
}
示例#18
0
TEST(cubeb, stream_position)
{
  size_t i;
  int r;
  cubeb * ctx;
  cubeb_stream * stream;
  cubeb_stream_params params;
  uint64_t position, last_position;

  total_frames_written = 0;

  r = common_init(&ctx, "test_sanity");
  ASSERT_EQ(r, CUBEB_OK);
  ASSERT_NE(ctx, nullptr);

  params.format = STREAM_FORMAT;
  params.rate = STREAM_RATE;
  params.channels = STREAM_CHANNELS;
  params.layout = STREAM_LAYOUT;

  r = cubeb_stream_init(ctx, &stream, "test", NULL, NULL, NULL, &params, STREAM_LATENCY,
                        test_data_callback, test_state_callback, &dummy);
  ASSERT_EQ(r, CUBEB_OK);
  ASSERT_NE(stream, nullptr);

  /* stream position should not advance before starting playback */
  r = cubeb_stream_get_position(stream, &position);
  ASSERT_EQ(r, CUBEB_OK);
  ASSERT_EQ(position, 0u);

  delay(500);

  r = cubeb_stream_get_position(stream, &position);
  ASSERT_EQ(r, CUBEB_OK);
  ASSERT_EQ(position, 0u);

  /* stream position should advance during playback */
  r = cubeb_stream_start(stream);
  ASSERT_EQ(r, CUBEB_OK);

  /* XXX let start happen */
  delay(500);

  /* stream should have prefilled */
  ASSERT_TRUE(total_frames_written.load() > 0);

  r = cubeb_stream_get_position(stream, &position);
  ASSERT_EQ(r, CUBEB_OK);
  last_position = position;

  delay(500);

  r = cubeb_stream_get_position(stream, &position);
  ASSERT_EQ(r, CUBEB_OK);
  ASSERT_GE(position, last_position);
  last_position = position;

  /* stream position should not exceed total frames written */
  for (i = 0; i < 5; ++i) {
    r = cubeb_stream_get_position(stream, &position);
    ASSERT_EQ(r, CUBEB_OK);
    ASSERT_GE(position, last_position);
    ASSERT_LE(position, total_frames_written.load());
    last_position = position;
    delay(500);
  }

  /* test that the position is valid even when starting and
   * stopping the stream.  */
  for (i = 0; i < 5; ++i) {
    r = cubeb_stream_stop(stream);
    ASSERT_EQ(r, CUBEB_OK);
    r = cubeb_stream_get_position(stream, &position);
    ASSERT_EQ(r, CUBEB_OK);
    ASSERT_TRUE(last_position < position);
    last_position = position;
    delay(500);
    r = cubeb_stream_start(stream);
    ASSERT_EQ(r, CUBEB_OK);
    delay(500);
  }

  ASSERT_NE(last_position, 0u);

  /* stream position should not advance after stopping playback */
  r = cubeb_stream_stop(stream);
  ASSERT_EQ(r, CUBEB_OK);

  /* XXX allow stream to settle */
  delay(500);

  r = cubeb_stream_get_position(stream, &position);
  ASSERT_EQ(r, CUBEB_OK);
  last_position = position;

  delay(500);

  r = cubeb_stream_get_position(stream, &position);
  ASSERT_EQ(r, CUBEB_OK);
  ASSERT_EQ(position, last_position);

  cubeb_stream_destroy(stream);
  cubeb_destroy(ctx);
}
示例#19
0
int run_panning_volume_test(int is_float)
{
  int r = CUBEB_OK;

  cubeb *ctx = NULL;
  synth_state* synth = NULL;
  cubeb_stream *stream = NULL;
  const char * backend_id = NULL;

  r = cubeb_init(&ctx, "Cubeb audio test");
  if (r != CUBEB_OK) {
    fprintf(stderr, "Error initializing cubeb library\n");
    goto cleanup;
  }
  backend_id = cubeb_get_backend_id(ctx);

  if ((is_float && !supports_float32(backend_id)) ||
      (!is_float && !supports_int16(backend_id))) {
    /* don't treat this as a test failure. */
    goto cleanup;
  }

  cubeb_stream_params params;
  params.format = is_float ? CUBEB_SAMPLE_FLOAT32NE : CUBEB_SAMPLE_S16NE;
  params.rate = 44100;
  params.channels = 2;

  synth = synth_create(params.channels, params.rate);
  if (synth == NULL) {
    fprintf(stderr, "Out of memory\n");
    goto cleanup;
  }

  r = cubeb_stream_init(ctx, &stream, "test tone", NULL, NULL, NULL, &params,
                        4096, is_float ? data_cb_float : data_cb_short,
                        state_cb_audio, synth);
  if (r != CUBEB_OK) {
    fprintf(stderr, "Error initializing cubeb stream: %d\n", r);
    goto cleanup;
  }

  fprintf(stderr, "Testing: volume\n");
  for(int i=0;i <= 4; ++i)
  {
    fprintf(stderr, "Volume: %d%%\n", i*25);

    cubeb_stream_set_volume(stream, i/4.0f);
    cubeb_stream_start(stream);
    delay(400);
    cubeb_stream_stop(stream);
    delay(100);
  }

  fprintf(stderr, "Testing: panning\n");
  for(int i=-4;i <= 4; ++i)
  {
    fprintf(stderr, "Panning: %.2f%%\n", i/4.0f);

    cubeb_stream_set_panning(stream, i/4.0f);
    cubeb_stream_start(stream);
    delay(400);
    cubeb_stream_stop(stream);
    delay(100);
  }

cleanup:
  cubeb_stream_destroy(stream);
  cubeb_destroy(ctx);
  synth_destroy(synth);

  return r;
}