Bug 1803765 - Update libcubeb to revision b8765e13. r=cubeb-reviewers,kinetik

Differential Revision: https://phabricator.services.mozilla.com/D163720
This commit is contained in:
Paul Adenot 2022-12-06 10:30:34 +00:00
Родитель 5c9197d6a9
Коммит 41f19649c9
15 изменённых файлов: 271 добавлений и 39 удалений

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

@ -9,8 +9,8 @@ origin:
description: "Cross platform audio library"
url: https://github.com/mozilla/cubeb
license: ISC
release: 93d1fa3fccdc22da37aa59f67b213591797db369 (2022-09-22T21:52:54Z).
revision: 93d1fa3fccdc22da37aa59f67b213591797db369
release: cfc5692bf7c556d5c9f66f782fa15d1e8b80e761 (2022-12-05T16:27:36Z).
revision: cfc5692bf7c556d5c9f66f782fa15d1e8b80e761
vendoring:
url: https://github.com/mozilla/cubeb

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

@ -351,6 +351,8 @@ cubeb_destroy(cubeb * context)
}
context->ops->destroy(context);
cubeb_set_log_callback(CUBEB_LOG_DISABLED, NULL);
}
int

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

@ -65,47 +65,67 @@ public:
void push(char const str[CUBEB_LOG_MESSAGE_MAX_SIZE])
{
cubeb_log_message msg(str);
msg_queue.enqueue(msg);
msg_queue->enqueue(msg);
}
void run()
{
std::thread([this]() {
assert(logging_thread.get_id() == std::thread::id());
assert(msg_queue);
logging_thread = std::thread([this]() {
CUBEB_REGISTER_THREAD("cubeb_log");
while (true) {
while (!shutdown_thread) {
cubeb_log_message msg;
while (msg_queue.dequeue(&msg, 1)) {
while (msg_queue->dequeue(&msg, 1)) {
cubeb_log_internal_no_format(msg.get());
}
#ifdef _WIN32
Sleep(CUBEB_LOG_BATCH_PRINT_INTERVAL_MS);
#else
timespec sleep_duration = sleep_for;
timespec remainder;
do {
if (nanosleep(&sleep_duration, &remainder) == 0 || errno != EINTR) {
break;
}
sleep_duration = remainder;
} while (remainder.tv_sec || remainder.tv_nsec);
#endif
std::this_thread::sleep_for(
std::chrono::milliseconds(CUBEB_LOG_BATCH_PRINT_INTERVAL_MS));
}
CUBEB_UNREGISTER_THREAD();
}).detach();
});
}
// Tell the underlying queue the producer thread has changed, so it does not
// assert in debug. This should be called with the thread stopped.
void reset_producer_thread() { msg_queue.reset_thread_ids(); }
void reset_producer_thread() { msg_queue->reset_thread_ids(); }
void start()
{
msg_queue.reset(
new lock_free_queue<cubeb_log_message>(CUBEB_LOG_MESSAGE_QUEUE_DEPTH));
shutdown_thread = false;
run();
}
void stop()
{
shutdown_thread = true;
if (logging_thread.get_id() != std::thread::id()) {
logging_thread.join();
logging_thread = std::thread();
// This is OK, because at this point, we know the consumer has stopped
// consuming.
msg_queue->reset_thread_ids();
purge_queue();
msg_queue.reset(nullptr);
}
}
void purge_queue()
{
assert(logging_thread.get_id() == std::thread::id() &&
"Only purge the async logger queue when the thread is stopped");
if (!msg_queue) {
return;
}
cubeb_log_message msg;
while (msg_queue->dequeue(&msg, 1)) { /* nothing */
}
}
private:
#ifndef _WIN32
const struct timespec sleep_for = {
CUBEB_LOG_BATCH_PRINT_INTERVAL_MS / 1000,
(CUBEB_LOG_BATCH_PRINT_INTERVAL_MS % 1000) * 1000 * 1000};
#endif
cubeb_async_logger() : msg_queue(CUBEB_LOG_MESSAGE_QUEUE_DEPTH) { run(); }
cubeb_async_logger() {}
/** This is quite a big data structure, but is only instantiated if the
* asynchronous logger is used.*/
lock_free_queue<cubeb_log_message> msg_queue;
std::unique_ptr<lock_free_queue<cubeb_log_message>> msg_queue;
std::atomic<bool> shutdown_thread = {false};
std::thread logging_thread;
};
void
@ -115,8 +135,8 @@ cubeb_log_internal(char const * file, uint32_t line, char const * fmt, ...)
va_start(args, fmt);
char msg[CUBEB_LOG_MESSAGE_MAX_SIZE];
vsnprintf(msg, CUBEB_LOG_MESSAGE_MAX_SIZE, fmt, args);
g_cubeb_log_callback.load()("%s:%d:%s", file, line, msg);
va_end(args);
g_cubeb_log_callback.load()("%s:%d:%s", file, line, msg);
}
void
@ -148,11 +168,28 @@ cubeb_async_log_reset_threads(void)
cubeb_async_logger::get().reset_producer_thread();
}
void
cubeb_noop_log_callback(char const * /* fmt */, ...)
{
}
void
cubeb_log_set(cubeb_log_level log_level, cubeb_log_callback log_callback)
{
g_cubeb_log_level = log_level;
g_cubeb_log_callback = log_callback;
// Once a callback has a been set, `g_cubeb_log_callback` is never set back to
// nullptr, to prevent a TOCTOU race between checking the pointer
if (log_callback && log_level != CUBEB_LOG_DISABLED) {
g_cubeb_log_callback = log_callback;
cubeb_async_logger::get().start();
} else if (!log_callback || CUBEB_LOG_DISABLED) {
// This returns once the thread has joined.
cubeb_async_logger::get().stop();
g_cubeb_log_callback = cubeb_noop_log_callback;
cubeb_async_logger::get().purge_queue();
} else {
assert(false && "Incorrect parameters passed to cubeb_log_set");
}
}
cubeb_log_level
@ -164,5 +201,8 @@ cubeb_log_get_level()
cubeb_log_callback
cubeb_log_get_callback()
{
if (g_cubeb_log_callback == cubeb_noop_log_callback) {
return nullptr;
}
return g_cubeb_log_callback;
}

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

@ -33,9 +33,9 @@ extern "C" {
void
cubeb_log_set(cubeb_log_level log_level, cubeb_log_callback log_callback);
cubeb_log_level
cubeb_log_get_level();
cubeb_log_get_level(void);
cubeb_log_callback
cubeb_log_get_callback();
cubeb_log_get_callback(void);
void
cubeb_log_internal_no_format(const char * msg);
void
@ -54,14 +54,14 @@ cubeb_async_log_reset_threads(void);
#define LOG_INTERNAL(level, fmt, ...) \
do { \
if (cubeb_log_get_level() <= level && cubeb_log_get_callback()) { \
if (cubeb_log_get_level() >= level && cubeb_log_get_callback()) { \
cubeb_log_internal(__FILENAME__, __LINE__, fmt, ##__VA_ARGS__); \
} \
} while (0)
#define ALOG_INTERNAL(level, fmt, ...) \
do { \
if (cubeb_log_get_level() <= level && cubeb_log_get_callback()) { \
if (cubeb_log_get_level() >= level && cubeb_log_get_callback()) { \
cubeb_async_log(fmt, ##__VA_ARGS__); \
} \
} while (0)

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

@ -26,11 +26,6 @@
using namespace std;
#define MAX_NUM_CHANNELS 32
#if !defined(M_PI)
#define M_PI 3.14159265358979323846
#endif
#define VOLUME 0.2
float get_frequency(int channel_index)
@ -242,3 +237,7 @@ TEST(cubeb, run_channel_rate_test)
}
}
}
#undef MAX_NUM_CHANNELS
#undef VOLUME

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

@ -258,3 +258,5 @@ TEST(cubeb, run_deadlock_test)
cubeb_stream_stop(stream);
}
#undef CALL_THREAD_KILLER

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

@ -107,3 +107,10 @@ TEST(cubeb, device_changed_callbacks)
cubeb_stream_destroy(stream);
}
#undef SAMPLE_FREQUENCY
#undef STREAM_FORMAT
#undef INPUT_CHANNELS
#undef INPUT_LAYOUT
#undef OUTPUT_CHANNELS
#undef OUTPUT_LAYOUT

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

@ -337,3 +337,10 @@ TEST(cubeb, one_duplex_one_input)
ASSERT_FALSE(duplex_stream_state.invalid_audio_value.load());
}
#undef SAMPLE_FREQUENCY
#undef STREAM_FORMAT
#undef INPUT_CHANNELS
#undef INPUT_LAYOUT
#undef OUTPUT_CHANNELS
#undef OUTPUT_LAYOUT

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

@ -0,0 +1,155 @@
/*
* Copyright © 2016 Mozilla Foundation
*
* This program is made available under an ISC-style license. See the
* accompanying file LICENSE for details.
*/
/* cubeb_logging test */
#include "gtest/gtest.h"
#if !defined(_XOPEN_SOURCE)
#define _XOPEN_SOURCE 600
#endif
#include "cubeb/cubeb.h"
#include <atomic>
#include <math.h>
#include <memory>
#include <stdio.h>
#include <stdlib.h>
#include "common.h"
#define PRINT_LOGS_TO_STDERR 0
std::atomic<uint32_t> log_statements_received = {0};
std::atomic<uint32_t> data_callback_call_count = {0};
void
test_logging_callback(char const * fmt, ...)
{
log_statements_received++;
#if PRINT_LOGS_TO_STDERR == 1
char buf[1024];
va_list argslist;
va_start(argslist, fmt);
vsnprintf(buf, 1024, fmt, argslist);
fprintf(stderr, "%s\n", buf);
va_end(argslist);
#endif // PRINT_LOGS_TO_STDERR
}
long
data_cb_load(cubeb_stream * stream, void * user, const void * inputbuffer,
void * outputbuffer, long nframes)
{
data_callback_call_count++;
return nframes;
}
void
state_cb(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;
default:
fprintf(stderr, "unknown stream state %d\n", state);
}
return;
}
// Waits for at least one audio callback to have occured.
void wait_for_audio_callback() {
uint32_t audio_callback_index =
data_callback_call_count.load(std::memory_order_acquire);
while (audio_callback_index ==
data_callback_call_count.load(std::memory_order_acquire)) {
delay(100);
}
}
TEST(cubeb, logging)
{
cubeb * ctx;
cubeb_stream * stream;
cubeb_stream_params output_params;
int r;
uint32_t latency_frames = 0;
cubeb_set_log_callback(CUBEB_LOG_NORMAL, test_logging_callback);
r = common_init(&ctx, "Cubeb logging test");
ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb library";
std::unique_ptr<cubeb, decltype(&cubeb_destroy)> cleanup_cubeb_at_exit(
ctx, cubeb_destroy);
output_params.format = CUBEB_SAMPLE_FLOAT32LE;
output_params.rate = 48000;
output_params.channels = 2;
output_params.layout = CUBEB_LAYOUT_STEREO;
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, &stream, "Cubeb logging", NULL, NULL, NULL,
&output_params, latency_frames, data_cb_load, state_cb,
NULL);
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);
ASSERT_NE(log_statements_received.load(std::memory_order_acquire), 0u);
cubeb_set_log_callback(CUBEB_LOG_DISABLED, nullptr);
log_statements_received.store(0, std::memory_order_release);
// This is synchronous and we'll receive log messages on all backends that we
// test
cubeb_stream_start(stream);
ASSERT_EQ(log_statements_received.load(std::memory_order_acquire), 0u);
cubeb_set_log_callback(CUBEB_LOG_VERBOSE, test_logging_callback);
wait_for_audio_callback();
ASSERT_NE(log_statements_received.load(std::memory_order_acquire), 0u);
bool log_callback_set = true;
uint32_t iterations = 100;
while (iterations--) {
wait_for_audio_callback();
if (!log_callback_set) {
ASSERT_EQ(log_statements_received.load(std::memory_order_acquire), 0u);
// Set a logging callback, start logging
cubeb_set_log_callback(CUBEB_LOG_VERBOSE, test_logging_callback);
log_callback_set = true;
} else {
// Disable the logging callback, stop logging.
ASSERT_NE(log_statements_received.load(std::memory_order_acquire), 0u);
cubeb_set_log_callback(CUBEB_LOG_DISABLED, nullptr);
log_statements_received.store(0, std::memory_order_release);
// Disabling logging should flush any log message -- wait a bit and check
// that this is true.
ASSERT_EQ(log_statements_received.load(std::memory_order_acquire), 0u);
log_callback_set = false;
}
}
cubeb_stream_stop(stream);
}

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

@ -90,3 +90,6 @@ TEST(cubeb, overload_callback)
delay(500);
cubeb_stream_stop(stream);
}
#undef SAMPLE_FREQUENCY
#undef STREAM_FORMAT

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

@ -114,3 +114,6 @@ TEST(cubeb, record)
ASSERT_FALSE(stream_state.invalid_audio_value.load());
#endif
}
#undef SAMPLE_FREQUENCY
#undef STREAM_FORMAT

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

@ -53,7 +53,7 @@ const uint32_t max_chunks = 30; /* ms */
const uint32_t chunk_increment = 10;
#endif
#define DUMP_ARRAYS
// #define DUMP_ARRAYS
#ifdef DUMP_ARRAYS
/**
* Files produced by dump(...) can be converted to .wave files using:
@ -1084,3 +1084,6 @@ TEST(cubeb, individual_methods) {
ASSERT_EQ(frames_needed2, 0u);
}
#undef NOMINMAX
#undef DUMP_ARRAYS

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

@ -225,3 +225,5 @@ TEST(cubeb, ring_buffer)
test_reset_api();
}
#undef NOMINMAX

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

@ -690,3 +690,9 @@ TEST(cubeb, stable_devid)
ASSERT_EQ(r, CUBEB_OK);
cubeb_destroy(ctx);
}
#undef STREAM_RATE
#undef STREAM_LATENCY
#undef STREAM_CHANNELS
#undef STREAM_LAYOUT
#undef STREAM_FORMAT

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

@ -119,3 +119,6 @@ TEST(cubeb, tone)
ASSERT_TRUE(user_data->position.load());
}
#undef SAMPLE_FREQUENCY
#undef STREAM_FORMAT