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; }
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(), ¶ms, &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, ¶ms, std::max(BUFFER_SAMPLES, minimum_latency), DataCallback, StateCallback, this) == CUBEB_OK; }
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; }
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 }
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; }
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 }
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, ¶ms, 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); }
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, ¶ms, 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); }
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, ¶ms, 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); }
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; }
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; }
// 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; }
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, ¶ms, 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; }
// 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; }
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, ¶ms, 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; }
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; }
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.")); }
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, ¶ms, 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 }
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); }
// 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; }
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, ¶ms, 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; }
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; }
// 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; }
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, ¶ms, 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); }
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, ¶ms, 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]); } }
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, ¶ms, 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); }
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; }
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 }