Example #1
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;
}
Example #2
0
bool CubebStream::Init()
{
  m_ctx = CubebUtils::GetContext();
  if (!m_ctx)
    return false;

  m_stereo = !SConfig::GetInstance().bDPL2Decoder;

  cubeb_stream_params params;
  params.rate = m_mixer->GetSampleRate();
  if (m_stereo)
  {
    params.channels = 2;
    params.format = CUBEB_SAMPLE_S16NE;
    params.layout = CUBEB_LAYOUT_STEREO;
  }
  else
  {
    params.channels = 6;
    params.format = CUBEB_SAMPLE_FLOAT32NE;
    params.layout = CUBEB_LAYOUT_3F2_LFE;
  }

  u32 minimum_latency = 0;
  if (cubeb_get_min_latency(m_ctx.get(), &params, &minimum_latency) != CUBEB_OK)
    ERROR_LOG(AUDIO, "Error getting minimum latency");
  INFO_LOG(AUDIO, "Minimum latency: %i frames", minimum_latency);

  return cubeb_stream_init(m_ctx.get(), &m_stream, "Dolphin Audio Output", nullptr, nullptr,
                           nullptr, &params, std::max(BUFFER_SAMPLES, minimum_latency),
                           DataCallback, StateCallback, this) == CUBEB_OK;
}
Example #3
0
static void
test_configure_stream(void)
{
  int r;
  cubeb * ctx;
  cubeb_stream * stream;
  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 = 2; // panning

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

  r = cubeb_stream_set_volume(stream, 1.0f);
  assert(r == 0 || r == CUBEB_ERROR_NOT_SUPPORTED);

  r = cubeb_stream_set_panning(stream, 0.0f);
  assert(r == 0 || r == CUBEB_ERROR_NOT_SUPPORTED);

  cubeb_stream_destroy(stream);
  cubeb_destroy(ctx);
  END_TEST;
}
Example #4
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
}
Example #5
0
nsresult
AudioStream::OpenCubeb(cubeb* aContext, cubeb_stream_params& aParams,
                       TimeStamp aStartTime, bool aIsFirst)
{
  MOZ_ASSERT(aContext);

  cubeb_stream* stream = nullptr;
  /* Convert from milliseconds to frames. */
  uint32_t latency_frames =
    CubebUtils::GetCubebPlaybackLatencyInMilliseconds() * aParams.rate / 1000;
  cubeb_devid deviceID = nullptr;
  if (mSinkInfo && mSinkInfo->DeviceID()) {
    deviceID = mSinkInfo->DeviceID();
  }
  if (cubeb_stream_init(aContext, &stream, "AudioStream",
                        nullptr, nullptr, deviceID, &aParams,
                        latency_frames,
                        DataCallback_S, StateCallback_S, this) == CUBEB_OK) {
    mCubebStream.reset(stream);
    CubebUtils::ReportCubebBackendUsed();
  } else {
    LOGE("OpenCubeb() failed to init cubeb");
    CubebUtils::ReportCubebStreamInitFailure(aIsFirst);
    return NS_ERROR_FAILURE;
  }

  TimeDuration timeDelta = TimeStamp::Now() - aStartTime;
  LOG("creation time %sfirst: %u ms", aIsFirst ? "" : "not ",
      (uint32_t) timeDelta.ToMilliseconds());
  Telemetry::Accumulate(aIsFirst ? Telemetry::AUDIOSTREAM_FIRST_OPEN_MS :
      Telemetry::AUDIOSTREAM_LATER_OPEN_MS, timeDelta.ToMilliseconds());

  return NS_OK;
}
Example #6
0
static void
test_init_destroy_stream(void)
{
  int r;
  cubeb * ctx;
  cubeb_stream * stream;
  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;

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

  cubeb_stream_destroy(stream);
  cubeb_destroy(ctx);

  END_TEST
}
Example #7
0
TEST(cubeb, init_destroy_multiple_streams)
{
  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);
  }

  for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
    cubeb_stream_destroy(stream[i]);
  }

  cubeb_destroy(ctx);
}
Example #8
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);
}
Example #9
0
TEST(cubeb, configure_stream)
{
  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_STEREO;

  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_set_volume(stream, 1.0f);
  ASSERT_TRUE(r == 0 || r == CUBEB_ERROR_NOT_SUPPORTED);

  r = cubeb_stream_set_panning(stream, 0.0f);
  ASSERT_TRUE(r == 0 || r == CUBEB_ERROR_NOT_SUPPORTED);

  cubeb_stream_destroy(stream);
  cubeb_destroy(ctx);
}
Example #10
0
nsresult
AudioStream::OpenCubeb(cubeb_stream_params& aParams,
                       TimeStamp aStartTime, bool aIsFirst)
{
  cubeb* cubebContext = CubebUtils::GetCubebContext();
  if (!cubebContext) {
    NS_WARNING("Can't get cubeb context!");
    return NS_ERROR_FAILURE;
  }

  cubeb_stream* stream = nullptr;
  if (cubeb_stream_init(cubebContext, &stream, "AudioStream",
                        nullptr, nullptr, nullptr, &aParams,
                        CubebUtils::GetCubebLatency(),
                        DataCallback_S, StateCallback_S, this) == CUBEB_OK) {
    mCubebStream.reset(stream);
  } else {
    NS_WARNING(nsPrintfCString("AudioStream::OpenCubeb() %p failed to init cubeb", this).get());
    return NS_ERROR_FAILURE;
  }

  TimeDuration timeDelta = TimeStamp::Now() - aStartTime;
  LOG("creation time %sfirst: %u ms", aIsFirst ? "" : "not ",
      (uint32_t) timeDelta.ToMilliseconds());
  Telemetry::Accumulate(aIsFirst ? Telemetry::AUDIOSTREAM_FIRST_OPEN_MS :
      Telemetry::AUDIOSTREAM_LATER_OPEN_MS, timeDelta.ToMilliseconds());

  return NS_OK;
}
Example #11
0
static void
test_init_destroy_multiple_streams(void)
{
  size_t 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 < ARRAY_LENGTH(stream); ++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]);
  }

  for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
    cubeb_stream_destroy(stream[i]);
  }

  cubeb_destroy(ctx);

  END_TEST;
}
nsresult
BufferedAudioStream::Init(int32_t aNumChannels, int32_t aRate,
                            const dom::AudioChannelType aAudioChannelType)
{
  cubeb* cubebContext = GetCubebContext();

  if (!cubebContext || aNumChannels < 0 || aRate < 0) {
    return NS_ERROR_FAILURE;
  }

  mInRate = mOutRate = aRate;
  mChannels = aNumChannels;

  mDumpFile = OpenDumpFile(this);

  cubeb_stream_params params;
  params.rate = aRate;
  params.channels = aNumChannels;
#if defined(__ANDROID__)
#if defined(MOZ_B2G)
  params.stream_type = ConvertChannelToCubebType(aAudioChannelType);
#else
  params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
#endif

  if (params.stream_type == CUBEB_STREAM_TYPE_MAX) {
    return NS_ERROR_INVALID_ARG;
  }
#endif
  if (AUDIO_OUTPUT_FORMAT == AUDIO_FORMAT_S16) {
    params.format = CUBEB_SAMPLE_S16NE;
  } else {
    params.format = CUBEB_SAMPLE_FLOAT32NE;
  }
  mBytesPerFrame = sizeof(AudioDataValue) * aNumChannels;

  mAudioClock.Init();

  {
    cubeb_stream* stream;
    if (cubeb_stream_init(cubebContext, &stream, "BufferedAudioStream", params,
                          GetCubebLatency(), DataCallback_S, StateCallback_S, this) == CUBEB_OK) {
      mCubebStream.own(stream);
    }
  }

  if (!mCubebStream) {
    return NS_ERROR_FAILURE;
  }

  // Size mBuffer for one second of audio.  This value is arbitrary, and was
  // selected based on the observed behaviour of the existing AudioStream
  // implementations.
  uint32_t bufferLimit = FramesToBytes(aRate);
  NS_ABORT_IF_FALSE(bufferLimit % mBytesPerFrame == 0, "Must buffer complete frames");
  mBuffer.SetCapacity(bufferLimit);

  return NS_OK;
}
Example #13
0
// This code used to live inside AudioStream::Init(), but on Mac (others?)
// it has been known to take 300-800 (or even 8500) ms to execute(!)
nsresult
AudioStream::OpenCubeb(cubeb_stream_params &aParams,
                       LatencyRequest aLatencyRequest)
{
  cubeb* cubebContext = CubebUtils::GetCubebContext();
  if (!cubebContext) {
    NS_WARNING("Can't get cubeb context!");
    MonitorAutoLock mon(mMonitor);
    mState = AudioStream::ERRORED;
    return NS_ERROR_FAILURE;
  }

  // If the latency pref is set, use it. Otherwise, if this stream is intended
  // for low latency playback, try to get the lowest latency possible.
  // Otherwise, for normal streams, use 100ms.
  uint32_t latency;
  if (aLatencyRequest == LowLatency && !CubebUtils::CubebLatencyPrefSet()) {
    if (cubeb_get_min_latency(cubebContext, aParams, &latency) != CUBEB_OK) {
      latency = CubebUtils::GetCubebLatency();
    }
  } else {
    latency = CubebUtils::GetCubebLatency();
  }

  {
    cubeb_stream* stream;
    if (cubeb_stream_init(cubebContext, &stream, "AudioStream", aParams,
                          latency, DataCallback_S, StateCallback_S, this) == CUBEB_OK) {
      MonitorAutoLock mon(mMonitor);
      MOZ_ASSERT(mState != SHUTDOWN);
      mCubebStream.reset(stream);
      // We can't cubeb_stream_start() the thread from a transient thread due to
      // cubeb API requirements (init can be called from another thread, but
      // not start/stop/destroy/etc)
    } else {
      MonitorAutoLock mon(mMonitor);
      mState = ERRORED;
      NS_WARNING(nsPrintfCString("AudioStream::OpenCubeb() %p failed to init cubeb", this).get());
      return NS_ERROR_FAILURE;
    }
  }

  cubeb_stream_register_device_changed_callback(mCubebStream.get(),
                                                AudioStream::DeviceChangedCallback_s);

  mState = INITIALIZED;

  if (!mStartTime.IsNull()) {
    TimeDuration timeDelta = TimeStamp::Now() - mStartTime;
    LOG(("AudioStream creation time %sfirst: %u ms", mIsFirst ? "" : "not ",
          (uint32_t) timeDelta.ToMilliseconds()));
    Telemetry::Accumulate(mIsFirst ? Telemetry::AUDIOSTREAM_FIRST_OPEN_MS :
        Telemetry::AUDIOSTREAM_LATER_OPEN_MS, timeDelta.ToMilliseconds());
  }

  return NS_OK;
}
Example #14
0
TEST(cubeb, drain)
{
  int r;
  cubeb * ctx;
  cubeb_stream * stream;
  cubeb_stream_params params;
  uint64_t position;

  delay_callback = 0;
  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_drain_data_callback, test_drain_state_callback, &dummy);
  ASSERT_EQ(r, CUBEB_OK);
  ASSERT_NE(stream, nullptr);

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

  delay(500);

  do_drain = 1;

  for (;;) {
    r = cubeb_stream_get_position(stream, &position);
    ASSERT_EQ(r, CUBEB_OK);
    if (got_drain) {
      break;
    } else {
      ASSERT_LE(position, total_frames_written.load());
    }
    delay(500);
  }

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

  // Really, we should be able to rely on position reaching our final written frame, but
  // for now let's make sure it doesn't continue beyond that point.
  //ASSERT_LE(position, total_frames_written.load());

  cubeb_stream_destroy(stream);
  cubeb_destroy(ctx);

  got_drain = 0;
  do_drain = 0;
}
Example #15
0
// This code used to live inside AudioStream::Init(), but on Mac (others?)
// it has been known to take 300-800 (or even 8500) ms to execute(!)
nsresult
AudioStream::OpenCubeb(cubeb_stream_params &aParams,
                       LatencyRequest aLatencyRequest)
{
  cubeb* cubebContext = GetCubebContext();
  if (!cubebContext) {
    MonitorAutoLock mon(mMonitor);
    mState = AudioStream::ERRORED;
    return NS_ERROR_FAILURE;
  }

  // If the latency pref is set, use it. Otherwise, if this stream is intended
  // for low latency playback, try to get the lowest latency possible.
  // Otherwise, for normal streams, use 100ms.
  uint32_t latency;
  if (aLatencyRequest == LowLatency && !CubebLatencyPrefSet()) {
    if (cubeb_get_min_latency(cubebContext, aParams, &latency) != CUBEB_OK) {
      latency = GetCubebLatency();
    }
  } else {
    latency = GetCubebLatency();
  }

  {
    cubeb_stream* stream;
    if (cubeb_stream_init(cubebContext, &stream, "AudioStream", aParams,
                          latency, DataCallback_S, StateCallback_S, this) == CUBEB_OK) {
      MonitorAutoLock mon(mMonitor);
      mCubebStream.own(stream);
      // Make sure we weren't shut down while in flight!
      if (mState == SHUTDOWN) {
        mCubebStream.reset();
        LOG(("AudioStream::OpenCubeb() %p Shutdown while opening cubeb", this));
        return NS_ERROR_FAILURE;
      }

      // We can't cubeb_stream_start() the thread from a transient thread due to
      // cubeb API requirements (init can be called from another thread, but
      // not start/stop/destroy/etc)
    } else {
      MonitorAutoLock mon(mMonitor);
      mState = ERRORED;
      LOG(("AudioStream::OpenCubeb() %p failed to init cubeb", this));
      return NS_ERROR_FAILURE;
    }
  }

  if (!mStartTime.IsNull()) {
		TimeDuration timeDelta = TimeStamp::Now() - mStartTime;
    LOG(("AudioStream creation time %sfirst: %u ms", mIsFirst ? "" : "not ",
         (uint32_t) timeDelta.ToMilliseconds()));
		Telemetry::Accumulate(mIsFirst ? Telemetry::AUDIOSTREAM_FIRST_OPEN_MS :
                          Telemetry::AUDIOSTREAM_LATER_OPEN_MS, timeDelta.ToMilliseconds());
  }

  return NS_OK;
}
Example #16
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;
}
Example #17
0
static void
test_drain(void)
{
  int r;
  cubeb * ctx;
  cubeb_stream * stream;
  cubeb_stream_params params;
  uint64_t 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_drain_data_callback, test_drain_state_callback, &dummy);
  assert(r == 0 && stream);

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

  delay(500);

  do_drain = 1;

  for (;;) {
    r = cubeb_stream_get_position(stream, &position);
    assert(r == 0);
    if (got_drain) {
      break;
    } else {
      assert(position <= total_frames_written);
    }
    delay(500);
  }

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

  // Really, we should be able to rely on position reaching our final written frame, but
  // for now let's make sure it doesn't continue beyond that point.
  //assert(position <= total_frames_written);

  cubeb_stream_destroy(stream);
  cubeb_destroy(ctx);

  END_TEST;
}
Example #18
0
void
AudioCallbackDriver::Init()
{
  cubeb_stream_params params;
  uint32_t latency;

  MOZ_ASSERT(!NS_IsMainThread(),
      "This is blocking and should never run on the main thread.");

  mSampleRate = params.rate = CubebUtils::PreferredSampleRate();

#if defined(__ANDROID__)
#if defined(MOZ_B2G)
  params.stream_type = CubebUtils::ConvertChannelToCubebType(mAudioChannel);
#else
  params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
#endif
  if (params.stream_type == CUBEB_STREAM_TYPE_MAX) {
    NS_WARNING("Bad stream type");
    return;
  }
#else
  (void)mAudioChannel;
#endif

  params.channels = mGraphImpl->AudioChannelCount();
  if (AUDIO_OUTPUT_FORMAT == AUDIO_FORMAT_S16) {
    params.format = CUBEB_SAMPLE_S16NE;
  } else {
    params.format = CUBEB_SAMPLE_FLOAT32NE;
  }

  if (cubeb_get_min_latency(CubebUtils::GetCubebContext(), params, &latency) != CUBEB_OK) {
    NS_WARNING("Could not get minimal latency from cubeb.");
    return;
  }

  cubeb_stream* stream;
  if (cubeb_stream_init(CubebUtils::GetCubebContext(), &stream,
                        "AudioCallbackDriver", params, latency,
                        DataCallback_s, StateCallback_s, this) == CUBEB_OK) {
    mAudioStream.own(stream);
  } else {
    NS_WARNING("Could not create a cubeb stream for MediaStreamGraph.");
    return;
  }

  cubeb_stream_register_device_changed_callback(mAudioStream,
                                                AudioCallbackDriver::DeviceChangedCallback_s);

  StartStream();

  STREAM_LOG(PR_LOG_DEBUG, ("AudioCallbackDriver started."));
}
Example #19
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
}
Example #20
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);
}
Example #21
0
// This code used to live inside AudioStream::Init(), but on Mac (others?)
// it has been known to take 300-800 (or even 8500) ms to execute(!)
nsresult
AudioStream::OpenCubeb(cubeb_stream_params &aParams,
                       LatencyRequest aLatencyRequest)
{
  cubeb* cubebContext = GetCubebContext();
  if (!cubebContext) {
    MonitorAutoLock mon(mMonitor);
    mState = AudioStream::ERRORED;
    return NS_ERROR_FAILURE;
  }

  // If the latency pref is set, use it. Otherwise, if this stream is intended
  // for low latency playback, try to get the lowest latency possible.
  // Otherwise, for normal streams, use 100ms.
  uint32_t latency;
  if (aLatencyRequest == LowLatency && !CubebLatencyPrefSet()) {
    if (cubeb_get_min_latency(cubebContext, aParams, &latency) != CUBEB_OK) {
      latency = GetCubebLatency();
    }
  } else {
    latency = GetCubebLatency();
  }

  {
    cubeb_stream* stream;
    if (cubeb_stream_init(cubebContext, &stream, "AudioStream", aParams,
                          latency, DataCallback_S, StateCallback_S, this) == CUBEB_OK) {
      MonitorAutoLock mon(mMonitor);
      mCubebStream.own(stream);
      // Make sure we weren't shut down while in flight!
      if (mState == SHUTDOWN) {
        mCubebStream.reset();
        LOG(("AudioStream::OpenCubeb() %p Shutdown while opening cubeb", this));
        return NS_ERROR_FAILURE;
      }

      // We can't cubeb_stream_start() the thread from a transient thread due to
      // cubeb API requirements (init can be called from another thread, but
      // not start/stop/destroy/etc)
    } else {
      MonitorAutoLock mon(mMonitor);
      mState = ERRORED;
      LOG(("AudioStream::OpenCubeb() %p failed to init cubeb", this));
      return NS_ERROR_FAILURE;
    }
  }

  return NS_OK;
}
Example #22
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;
}
Example #23
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
}
nsresult
nsBufferedAudioStream::Init(int32_t aNumChannels, int32_t aRate,
                            const dom::AudioChannelType aAudioChannelType)
{
  cubeb* cubebContext = GetCubebContext();

  if (!cubebContext || aNumChannels < 0 || aRate < 0) {
    return NS_ERROR_FAILURE;
  }

  mRate = aRate;
  mChannels = aNumChannels;

  cubeb_stream_params params;
  params.rate = aRate;
  params.channels = aNumChannels;
  if (AUDIO_OUTPUT_FORMAT == AUDIO_FORMAT_S16) {
    params.format = CUBEB_SAMPLE_S16NE;
  } else {
    params.format = CUBEB_SAMPLE_FLOAT32NE;
  }
  mBytesPerFrame = sizeof(AudioDataValue) * aNumChannels;

  {
    cubeb_stream* stream;
    if (cubeb_stream_init(cubebContext, &stream, "nsBufferedAudioStream", params,
                          GetCubebLatency(), DataCallback_S, StateCallback_S, this) == CUBEB_OK) {
      mCubebStream.own(stream);
    }
  }

  if (!mCubebStream) {
    return NS_ERROR_FAILURE;
  }

  // Size mBuffer for one second of audio.  This value is arbitrary, and was
  // selected based on the observed behaviour of the existing AudioStream
  // implementations.
  uint32_t bufferLimit = aRate * mBytesPerFrame;
  NS_ABORT_IF_FALSE(bufferLimit % mBytesPerFrame == 0, "Must buffer complete frames");
  mBuffer.SetCapacity(bufferLimit);

  return NS_OK;
}
Example #25
0
// This code used to live inside AudioStream::Init(), but on Mac (others?)
// it has been known to take 300-800 (or even 8500) ms to execute(!)
nsresult
AudioStream::OpenCubeb(cubeb_stream_params &aParams)
{
    cubeb* cubebContext = CubebUtils::GetCubebContext();
    if (!cubebContext) {
        NS_WARNING("Can't get cubeb context!");
        MonitorAutoLock mon(mMonitor);
        mState = AudioStream::ERRORED;
        return NS_ERROR_FAILURE;
    }

    // If the latency pref is set, use it. Otherwise, if this stream is intended
    // for low latency playback, try to get the lowest latency possible.
    // Otherwise, for normal streams, use 100ms.
    uint32_t latency = CubebUtils::GetCubebLatency();

    {
        cubeb_stream* stream;
        if (cubeb_stream_init(cubebContext, &stream, "AudioStream",
                              nullptr, nullptr, nullptr, &aParams,
                              latency, DataCallback_S, StateCallback_S, this) == CUBEB_OK) {
            MonitorAutoLock mon(mMonitor);
            MOZ_ASSERT(mState != SHUTDOWN);
            mCubebStream.reset(stream);
        } else {
            MonitorAutoLock mon(mMonitor);
            mState = ERRORED;
            NS_WARNING(nsPrintfCString("AudioStream::OpenCubeb() %p failed to init cubeb", this).get());
            return NS_ERROR_FAILURE;
        }
    }

    mState = INITIALIZED;

    if (!mStartTime.IsNull()) {
        TimeDuration timeDelta = TimeStamp::Now() - mStartTime;
        LOG("creation time %sfirst: %u ms", mIsFirst ? "" : "not ",
            (uint32_t) timeDelta.ToMilliseconds());
        Telemetry::Accumulate(mIsFirst ? Telemetry::AUDIOSTREAM_FIRST_OPEN_MS :
                              Telemetry::AUDIOSTREAM_LATER_OPEN_MS, timeDelta.ToMilliseconds());
    }

    return NS_OK;
}
Example #26
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);
}
Example #27
0
TEST(cubeb, init_destroy_multiple_contexts_and_streams)
{
  size_t i, j;
  int r;
  cubeb * ctx[2];
  cubeb_stream * stream[8];
  cubeb_stream_params params;
  size_t streams_per_ctx = ARRAY_LENGTH(stream) / ARRAY_LENGTH(ctx);
  ASSERT_EQ(ARRAY_LENGTH(ctx) * streams_per_ctx, ARRAY_LENGTH(stream));

  /* Sometimes, when using WASAPI on windows 7 (vista and 8 are okay), and
   * calling Activate a lot on an AudioClient, 0x800700b7 is returned. This is
   * the HRESULT value for "Cannot create a file when that file already exists",
   * and is not documented as a possible return value for this call. Hence, we
   * try to limit the number of streams we create in this test. */
  if (is_windows_7())
    return;

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

  for (i = 0; i < ARRAY_LENGTH(ctx); ++i) {
    r = common_init(&ctx[i], "test_sanity");
    ASSERT_EQ(r, CUBEB_OK);
    ASSERT_NE(ctx[i], nullptr);

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

  for (i = 0; i < ARRAY_LENGTH(ctx); ++i) {
    for (j = 0; j < streams_per_ctx; ++j) {
      cubeb_stream_destroy(stream[i * streams_per_ctx + j]);
    }
    cubeb_destroy(ctx[i]);
  }
}
Example #28
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);
}
Example #29
0
static void
test_init_destroy_multiple_contexts_and_streams(void)
{
  size_t i, j;
  int r;
  cubeb * ctx[2];
  cubeb_stream * stream[8];
  cubeb_stream_params params;
  size_t streams_per_ctx = ARRAY_LENGTH(stream) / ARRAY_LENGTH(ctx);
  assert(ARRAY_LENGTH(ctx) * streams_per_ctx == ARRAY_LENGTH(stream));

  BEGIN_TEST;

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

  for (i = 0; i < ARRAY_LENGTH(ctx); ++i) {
    r = cubeb_init(&ctx[i], "test_sanity");
    assert(r == 0 && ctx[i]);

    for (j = 0; j < streams_per_ctx; ++j) {
      r = cubeb_stream_init(ctx[i], &stream[i * streams_per_ctx + j], "test", params, STREAM_LATENCY,
                            test_data_callback, test_state_callback, &dummy);
      assert(r == 0);
      assert(stream[i * streams_per_ctx + j]);
    }
  }

  for (i = 0; i < ARRAY_LENGTH(ctx); ++i) {
    for (j = 0; j < streams_per_ctx; ++j) {
      cubeb_stream_destroy(stream[i * streams_per_ctx + j]);
    }
    cubeb_destroy(ctx[i]);
  }

  END_TEST;
}
Example #30
0
static void
test_init_destroy_multiple_contexts_and_streams(void)
{
  int i, j;
  int r;
  cubeb * ctx[2];
  cubeb_stream * stream[8];
  cubeb_stream_params params;

  BEGIN_TEST

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

  for (i = 0; i < 2; ++i) {
    r = cubeb_init(&ctx[i], "test_sanity");
    assert(r == 0 && ctx[i]);

    for (j = 0; j < 4; ++j) {
      r = cubeb_stream_init(ctx[i], &stream[i * 4 + j], "test", params, STREAM_LATENCY,
                            test_data_callback, test_state_callback, &dummy);
      assert(r == 0);
      assert(stream[i * 4 + j]);
    }
  }

  for (i = 0; i < 2; ++i) {
    for (j = 0; j < 4; ++j) {
      cubeb_stream_destroy(stream[i * 4 + j]);
    }
    cubeb_destroy(ctx[i]);
  }

  END_TEST
}