diff --git a/media/libcubeb/gtest/test_duplex.cpp b/media/libcubeb/gtest/test_duplex.cpp index bc71431b99fc..3620bf0666e9 100644 --- a/media/libcubeb/gtest/test_duplex.cpp +++ b/media/libcubeb/gtest/test_duplex.cpp @@ -179,3 +179,137 @@ TEST(cubeb, duplex_collection_change) ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb stream"; cubeb_stream_destroy(stream); } + +long data_cb_input(cubeb_stream * stream, void * user, const void * inputbuffer, void * outputbuffer, long nframes) +{ + if (stream == NULL || inputbuffer == NULL || outputbuffer != NULL) { + return CUBEB_ERROR; + } + + return nframes; +} + +void state_cb_input(cubeb_stream * stream, void * /*user*/, cubeb_state state) +{ + if (stream == NULL) + return; + + switch (state) { + case CUBEB_STATE_STARTED: + fprintf(stderr, "stream started\n"); break; + case CUBEB_STATE_STOPPED: + fprintf(stderr, "stream stopped\n"); break; + case CUBEB_STATE_DRAINED: + fprintf(stderr, "stream drained\n"); break; + case CUBEB_STATE_ERROR: + fprintf(stderr, "stream runs into error state\n"); break; + default: + fprintf(stderr, "unknown stream state %d\n", state); + } + + return; +} + +std::vector get_devices(cubeb * ctx, cubeb_device_type type) { + std::vector devices; + + cubeb_device_collection collection; + int r = cubeb_enumerate_devices(ctx, type, &collection); + + if (r != CUBEB_OK) { + fprintf(stderr, "Failed to enumerate devices\n"); + return devices; + } + + for (uint32_t i = 0; i < collection.count; i++) { + if (collection.device[i].state == CUBEB_DEVICE_STATE_ENABLED) { + devices.emplace_back(collection.device[i].devid); + } + } + + cubeb_device_collection_destroy(ctx, &collection); + + return devices; +} + +TEST(cubeb, one_duplex_one_input) +{ + cubeb *ctx; + cubeb_stream *duplex_stream; + cubeb_stream_params input_params; + cubeb_stream_params output_params; + int r; + user_state_duplex duplex_stream_state; + uint32_t latency_frames = 0; + + r = common_init(&ctx, "Cubeb duplex example"); + ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb library"; + + std::unique_ptr + cleanup_cubeb_at_exit(ctx, cubeb_destroy); + + /* This test needs at least two available input devices. */ + std::vector input_devices = get_devices(ctx, CUBEB_DEVICE_TYPE_INPUT); + if (input_devices.size() < 2) { + return; + } + + /* This test needs at least one available output device. */ + std::vector output_devices = get_devices(ctx, CUBEB_DEVICE_TYPE_OUTPUT); + if (output_devices.size() < 1) { + return; + } + + cubeb_devid duplex_input = input_devices.front(); + cubeb_devid duplex_output = nullptr; // default device + cubeb_devid input_only = input_devices.back(); + + /* typical use-case: mono voice input, stereo output, low latency. */ + input_params.format = STREAM_FORMAT; + input_params.rate = SAMPLE_FREQUENCY; + input_params.channels = INPUT_CHANNELS; + input_params.layout = CUBEB_LAYOUT_UNDEFINED; + input_params.prefs = CUBEB_STREAM_PREF_VOICE; + + output_params.format = STREAM_FORMAT; + output_params.rate = SAMPLE_FREQUENCY; + output_params.channels = OUTPUT_CHANNELS; + output_params.layout = OUTPUT_LAYOUT; + output_params.prefs = CUBEB_STREAM_PREF_NONE; + + 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, &duplex_stream, "Cubeb duplex", + duplex_input, &input_params, duplex_output, &output_params, + latency_frames, data_cb_duplex, state_cb_duplex, &duplex_stream_state); + ASSERT_EQ(r, CUBEB_OK) << "Error initializing duplex cubeb stream"; + + std::unique_ptr + cleanup_stream_at_exit(duplex_stream, cubeb_stream_destroy); + + r = cubeb_stream_start(duplex_stream); + ASSERT_EQ(r, CUBEB_OK) << "Could not start duplex stream"; + delay(500); + + cubeb_stream *input_stream; + r = cubeb_stream_init(ctx, &input_stream, "Cubeb input", + input_only, &input_params, NULL, NULL, + latency_frames, data_cb_input, state_cb_input, nullptr); + ASSERT_EQ(r, CUBEB_OK) << "Error initializing input-only cubeb stream"; + + std::unique_ptr + cleanup_input_stream_at_exit(input_stream, cubeb_stream_destroy); + + r = cubeb_stream_start(input_stream); + ASSERT_EQ(r, CUBEB_OK) << "Could not start input stream"; + delay(500); + + r = cubeb_stream_stop(duplex_stream); + ASSERT_EQ(r, CUBEB_OK) << "Could not stop duplex stream"; + + r = cubeb_stream_stop(input_stream); + ASSERT_EQ(r, CUBEB_OK) << "Could not stop input stream"; + + ASSERT_FALSE(duplex_stream_state.invalid_audio_value.load()); +} diff --git a/media/libcubeb/include/cubeb.h b/media/libcubeb/include/cubeb.h index b678f737c235..0da5762b335e 100644 --- a/media/libcubeb/include/cubeb.h +++ b/media/libcubeb/include/cubeb.h @@ -240,9 +240,8 @@ typedef enum { except for always on APO, driver and hardware. */ CUBEB_STREAM_PREF_PERSIST = 0x10, /**< Request that the volume and mute settings should persist across restarts of the stream - and/or application. May not be honored for - all backends and platforms. */ - + and/or application. This is obsolete and ignored + by all backends. */ CUBEB_STREAM_PREF_JACK_NO_AUTO_CONNECT = 0x20 /**< Don't automatically try to connect ports. Only affects the jack backend. */ diff --git a/media/libcubeb/moz.yaml b/media/libcubeb/moz.yaml index fa43dab65f63..260104be50af 100644 --- a/media/libcubeb/moz.yaml +++ b/media/libcubeb/moz.yaml @@ -19,5 +19,5 @@ origin: license: "ISC" # update.sh will update this value - release: "b2f60c983df34f8cac0e061ef32da531c6d82536 (2021-07-13 13:51:30 +0200)" + release: "e1456788c48c5ed6b55bc107a7342d63f2a08413 (2021-07-27 16:11:10 +1200)" diff --git a/media/libcubeb/src/cubeb_wasapi.cpp b/media/libcubeb/src/cubeb_wasapi.cpp index da0fd98642e6..22a095a5abd0 100644 --- a/media/libcubeb/src/cubeb_wasapi.cpp +++ b/media/libcubeb/src/cubeb_wasapi.cpp @@ -1915,10 +1915,6 @@ initialize_iaudioclient3(com_ptr & audio_client, return false; } - // IAudioClient3 doesn't support AUDCLNT_STREAMFLAGS_NOPERSIST, and will return - // AUDCLNT_E_INVALID_STREAM_FLAG. This is undocumented. - flags = flags & ~AUDCLNT_STREAMFLAGS_NOPERSIST; - // Some people have reported glitches with capture streams: // http://blog.nirbheek.in/2018/03/low-latency-audio-on-windows-with.html if (direction == eCapture) { @@ -2134,11 +2130,6 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm, DWORD flags = 0; - bool is_persist = stream_params->prefs & CUBEB_STREAM_PREF_PERSIST; - if (!is_persist) { - flags |= AUDCLNT_STREAMFLAGS_NOPERSIST; - } - // Check if a loopback device should be requested. Note that event callbacks // do not work with loopback devices, so only request these if not looping. if (is_loopback) { @@ -2272,15 +2263,14 @@ void wasapi_find_matching_output_device(cubeb_stream * stm) { // Find the input device, and then find the output device with the same group // id and the same rate. for (uint32_t i = 0; i < collection.count; i++) { - cubeb_device_info dev = collection.device[i]; - if (dev.devid == input_device_id) { - input_device = &dev; + if (collection.device[i].devid == input_device_id) { + input_device = &collection.device[i]; break; } } for (uint32_t i = 0; i < collection.count; i++) { - cubeb_device_info dev = collection.device[i]; + cubeb_device_info & dev = collection.device[i]; if (dev.type == CUBEB_DEVICE_TYPE_OUTPUT && dev.group_id && input_device && !strcmp(dev.group_id, input_device->group_id) && dev.default_rate == input_device->default_rate) {