Bug 1830060 - Update libcubeb to revision 1ba9237. r=cubeb-reviewers,kinetik

Differential Revision: https://phabricator.services.mozilla.com/D176530
This commit is contained in:
Paul Adenot 2023-04-27 08:59:39 +00:00
Родитель 81d78e645f
Коммит 45df9ca377
11 изменённых файлов: 148 добавлений и 27 удалений

Просмотреть файл

@ -9,8 +9,8 @@ origin:
description: "Cross platform audio library"
url: https://github.com/mozilla/cubeb
license: ISC
release: 3ecf0c8f83a91d0966aa1a1916c3e545b041be4f (2023-04-20T12:07:44Z).
revision: 3ecf0c8f83a91d0966aa1a1916c3e545b041be4f
release: 1ba923736487443f5c7be09bdb6bb894f9ee9d06 (2023-04-26T12:28:46Z).
revision: 1ba923736487443f5c7be09bdb6bb894f9ee9d06
vendoring:
url: https://github.com/mozilla/cubeb

Просмотреть файл

@ -11,7 +11,6 @@
#include "cubeb_resampler.h"
#include "cubeb_triple_buffer.h"
#include <aaudio/AAudio.h>
#include <android/api-level.h>
#include <atomic>
#include <cassert>
#include <chrono>
@ -1606,9 +1605,6 @@ const static struct cubeb_ops aaudio_ops = {
extern "C" /*static*/ int
aaudio_init(cubeb ** context, char const * /* context_name */)
{
if (android_get_device_api_level() <= 30) {
return CUBEB_ERROR;
}
// load api
void * libaaudio = NULL;
#ifndef DISABLE_LIBAAUDIO_DLOPEN

Просмотреть файл

@ -105,10 +105,13 @@ struct cubeb_stream {
int free_buffers;
int shutdown;
int draining;
int error;
HANDLE event;
HWAVEOUT waveout;
CRITICAL_SECTION lock;
uint64_t written;
/* number of frames written during preroll */
uint64_t position_base;
float soft_volume;
/* For position wrap-around handling: */
size_t frame_size;
@ -150,6 +153,14 @@ winmm_get_next_buffer(cubeb_stream * stm)
return hdr;
}
static long
preroll_callback(cubeb_stream * stream, void * user, const void * inputbuffer,
void * outputbuffer, long nframes)
{
memset((uint8_t *)outputbuffer, 0, nframes * bytes_per_frame(stream->params));
return nframes;
}
static void
winmm_refill_stream(cubeb_stream * stm)
{
@ -158,13 +169,20 @@ winmm_refill_stream(cubeb_stream * stm)
long wanted;
MMRESULT r;
ALOG("winmm_refill_stream");
EnterCriticalSection(&stm->lock);
if (stm->error) {
LeaveCriticalSection(&stm->lock);
return;
}
stm->free_buffers += 1;
XASSERT(stm->free_buffers > 0 && stm->free_buffers <= NBUFS);
if (stm->draining) {
LeaveCriticalSection(&stm->lock);
if (stm->free_buffers == NBUFS) {
ALOG("winmm_refill_stream draining");
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
}
SetEvent(stm->event);
@ -187,9 +205,10 @@ winmm_refill_stream(cubeb_stream * stm)
got = stm->data_callback(stm, stm->user_ptr, NULL, hdr->lpData, wanted);
EnterCriticalSection(&stm->lock);
if (got < 0) {
stm->error = 1;
LeaveCriticalSection(&stm->lock);
/* XXX handle this case */
XASSERT(0);
SetEvent(stm->event);
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
return;
} else if (got < wanted) {
stm->draining = 1;
@ -224,6 +243,8 @@ winmm_refill_stream(cubeb_stream * stm)
return;
}
ALOG("winmm_refill_stream %ld frames", got);
LeaveCriticalSection(&stm->lock);
}
@ -486,7 +507,11 @@ winmm_stream_init(cubeb * context, cubeb_stream ** stream,
stm->params = *output_stream_params;
stm->data_callback = data_callback;
// Data callback is set to the user-provided data callback after
// the initialization and potential preroll callback calls are done, because
// cubeb users don't expect the data callback to be called during
// initialization.
stm->data_callback = preroll_callback;
stm->state_callback = state_callback;
stm->user_ptr = user_ptr;
stm->written = 0;
@ -553,9 +578,18 @@ winmm_stream_init(cubeb * context, cubeb_stream ** stream,
stm->frame_size = bytes_per_frame(stm->params);
stm->prev_pos_lo_dword = 0;
stm->pos_hi_dword = 0;
// Set the user data callback now that preroll has finished.
stm->data_callback = data_callback;
stm->position_base = 0;
// Offset the position by the number of frames written during preroll.
stm->position_base = stm->written;
stm->written = 0;
*stream = stm;
LOG("winmm_stream_init OK");
return CUBEB_OK;
}
@ -585,7 +619,7 @@ winmm_stream_destroy(cubeb_stream * stm)
LeaveCriticalSection(&stm->lock);
/* Wait for all blocks to complete. */
while (device_valid && enqueued > 0) {
while (device_valid && enqueued > 0 && !stm->error) {
DWORD rv = WaitForSingleObject(stm->event, INFINITE);
XASSERT(rv == WAIT_OBJECT_0);
@ -774,7 +808,17 @@ winmm_stream_get_position(cubeb_stream * stm, uint64_t * position)
return CUBEB_ERROR;
}
*position = update_64bit_position(stm, time.u.cb) / stm->frame_size;
uint64_t position_not_adjusted =
update_64bit_position(stm, time.u.cb) / stm->frame_size;
// Subtract the number of frames that were written while prerolling, during
// initialization.
if (position_not_adjusted < stm->position_base) {
*position = 0;
} else {
*position = position_not_adjusted - stm->position_base;
}
LeaveCriticalSection(&stm->lock);
return CUBEB_OK;
@ -787,17 +831,12 @@ winmm_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
MMTIME time;
uint64_t written, position;
EnterCriticalSection(&stm->lock);
/* See the long comment above for why not just use TIME_SAMPLES here. */
time.wType = TIME_BYTES;
r = waveOutGetPosition(stm->waveout, &time, sizeof(time));
if (r != MMSYSERR_NOERROR || time.wType != TIME_BYTES) {
LeaveCriticalSection(&stm->lock);
return CUBEB_ERROR;
int rv = winmm_stream_get_position(stm, &position);
if (rv != CUBEB_OK) {
return rv;
}
position = update_64bit_position(stm, time.u.cb);
EnterCriticalSection(&stm->lock);
written = stm->written;
LeaveCriticalSection(&stm->lock);

Просмотреть файл

@ -48,7 +48,34 @@ typedef struct {
uint32_t const layout;
} layout_info;
inline int has_available_input_device(cubeb * ctx)
struct backend_caps {
const char* id;
const int input_capabilities;
};
// This static table allows knowing if a backend has audio input capabilities.
// We don't rely on opening a stream and checking if it works, because this
// would make the test skip the tests that make use of audio input, if a
// particular backend has a bug that causes a failure during audio input stream
// creation
static backend_caps backend_capabilities[] = {
{"sun", 1},
{"wasapi", 1},
{"kai", 1},
{"audiounit", 1},
{"audiotrack", 0},
{"opensl", 1},
{"aaudio", 1},
{"jack", 1},
{"pulse", 1},
{"sndio", 1},
{"oss", 1},
{"winmm", 0},
{"alsa", 1},
};
inline int can_run_audio_input_test(cubeb * ctx)
{
cubeb_device_collection devices;
int input_device_available = 0;
@ -77,7 +104,16 @@ inline int has_available_input_device(cubeb * ctx)
}
cubeb_device_collection_destroy(ctx, &devices);
return !!input_device_available;
int backend_has_input_capabilities;
const char * backend_id = cubeb_get_backend_id(ctx);
for (uint32_t i = 0; i < sizeof(backend_capabilities) / sizeof(backend_caps); i++) {
if (strcmp(backend_capabilities[i].id, backend_id) == 0) {
backend_has_input_capabilities = backend_capabilities[i].input_capabilities;
}
}
return !!input_device_available && !!backend_has_input_capabilities;
}
inline void print_log(const char * msg, ...)

Просмотреть файл

@ -158,9 +158,9 @@ void run_test_callback(test_direction direction,
cleanup_cubeb_at_exit(ctx, cubeb_destroy);
if ((direction == INPUT_ONLY || direction == DUPLEX) &&
!has_available_input_device(ctx)) {
!can_run_audio_input_test(ctx)) {
/* This test needs an available input device, skip it if this host does not
* have one. */
* have one or if the backend doesn't implement input. */
return;
}

Просмотреть файл

@ -75,9 +75,14 @@ TEST(cubeb, device_changed_callbacks)
int r = CUBEB_OK;
uint32_t latency_frames = 0;
r = common_init(&ctx, "Cubeb duplex example with device change");
ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb library";
if (!can_run_audio_input_test(ctx)) {
return;
}
std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
cleanup_cubeb_at_exit(ctx, cubeb_destroy);

Просмотреть файл

@ -185,6 +185,9 @@ TEST(cubeb, enumerate_devices)
count_before_creating_duplex_stream = collection.count;
cubeb_device_collection_destroy(ctx, &collection);
if (!can_run_audio_input_test(ctx)) {
return;
}
cubeb_stream * stream;
cubeb_stream_params input_params;
cubeb_stream_params output_params;
@ -221,6 +224,10 @@ TEST(cubeb, stream_get_current_device)
fprintf(stdout, "Getting current devices for backend %s\n",
cubeb_get_backend_id(ctx));
if (!can_run_audio_input_test(ctx)) {
return;
}
cubeb_stream * stream = NULL;
cubeb_stream_params input_params;
cubeb_stream_params output_params;
@ -252,4 +259,4 @@ TEST(cubeb, stream_get_current_device)
r = cubeb_stream_device_destroy(stream, device);
ASSERT_EQ(r, CUBEB_OK) << "Error destroying current devices";
}
}

Просмотреть файл

@ -96,7 +96,7 @@ TEST(cubeb, duplex)
/* This test needs an available input device, skip it if this host does not
* have one. */
if (!has_available_input_device(ctx)) {
if (!can_run_audio_input_test(ctx)) {
return;
}
@ -184,6 +184,12 @@ TEST(cubeb, duplex_collection_change)
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 (!can_run_audio_input_test(ctx)) {
return;
}
duplex_collection_change_impl(ctx);
r = cubeb_register_device_collection_changed(
ctx, static_cast<cubeb_device_type>(CUBEB_DEVICE_TYPE_INPUT), nullptr,
@ -198,6 +204,14 @@ TEST(cubeb, duplex_collection_change_no_unregister)
r = common_init(&ctx, "Cubeb duplex example with collection change");
ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb library";
/* This test needs an available input device, skip it if this host does not
* have one. */
if (!can_run_audio_input_test(ctx)) {
cubeb_destroy(ctx);
return;
}
std::unique_ptr<cubeb, decltype(&cubeb_destroy)> cleanup_cubeb_at_exit(
ctx, [](cubeb * p) noexcept { EXPECT_DEATH(cubeb_destroy(p), ""); });

Просмотреть файл

@ -267,6 +267,12 @@ void run_loopback_duplex_test(bool is_float)
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 (!can_run_audio_input_test(ctx)) {
return;
}
input_params.format = is_float ? CUBEB_SAMPLE_FLOAT32NE : CUBEB_SAMPLE_S16LE;
input_params.rate = SAMPLE_FREQUENCY;
input_params.channels = 1;
@ -340,6 +346,10 @@ void run_loopback_separate_streams_test(bool is_float)
std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
cleanup_cubeb_at_exit(ctx, cubeb_destroy);
if (!can_run_audio_input_test(ctx)) {
return;
}
input_params.format = is_float ? CUBEB_SAMPLE_FLOAT32NE : CUBEB_SAMPLE_S16LE;
input_params.rate = SAMPLE_FREQUENCY;
input_params.channels = 1;
@ -423,6 +433,10 @@ void run_loopback_silence_test(bool is_float)
std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
cleanup_cubeb_at_exit(ctx, cubeb_destroy);
if (!can_run_audio_input_test(ctx)) {
return;
}
input_params.format = is_float ? CUBEB_SAMPLE_FLOAT32NE : CUBEB_SAMPLE_S16LE;
input_params.rate = SAMPLE_FREQUENCY;
input_params.channels = 1;
@ -486,6 +500,10 @@ void run_loopback_device_selection_test(bool is_float)
std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
cleanup_cubeb_at_exit(ctx, cubeb_destroy);
if (!can_run_audio_input_test(ctx)) {
return;
}
r = cubeb_enumerate_devices(ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection);
if (r == CUBEB_ERROR_NOT_SUPPORTED) {
fprintf(stderr, "Device enumeration not supported"

Просмотреть файл

@ -66,6 +66,12 @@ TEST(cubeb, overload_callback)
std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
cleanup_cubeb_at_exit(ctx, cubeb_destroy);
// This test is specifically designed to test a behaviour of the WASAPI
// backend in a specific scenario.
if (strcmp(cubeb_get_backend_id(ctx), "wasapi") != 0) {
return;
}
output_params.format = STREAM_FORMAT;
output_params.rate = 48000;
output_params.channels = 2;

Просмотреть файл

@ -86,7 +86,7 @@ TEST(cubeb, record)
/* This test needs an available input device, skip it if this host does not
* have one. */
if (!has_available_input_device(ctx)) {
if (!can_run_audio_input_test(ctx)) {
return;
}