aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorPaul Adenot <[email protected]>2023-07-25 16:58:49 +0200
committerPaul Adenot <[email protected]>2023-07-26 14:02:22 +0200
commit29d266e628eef31e27820c9f2c697ab53d91f275 (patch)
treeaea9a6a6e099817b7db1fcb68056f44a4c96d502
parent8ee7b799e26cf36fab28c93cc12f12673a9a6d23 (diff)
downloadcubeb-29d266e628eef31e27820c9f2c697ab53d91f275.tar.gz
cubeb-29d266e628eef31e27820c9f2c697ab53d91f275.zip
AAudio: Split init/destroy/start functions into an internal and external interface
This will allow calling those functions properly from an internal thread, and simplify lock management. This will happen in a subsequent patch. The initial parameter passed to cubeb_stream_init are now stored on the cubeb_stream struct to be able to reinitialized properly (again in a subsequent patch). Since all those calls need have a lock held, the lock is passed as argument to ensure thread safety. This ensures the caller of the internal functions has taken the lock, and at the same time allows not unlocking/relocking the mutex if a series of call is performed (that will be the case in a subsequent patch, during reinitialization). The boolean that marks that a stream is in use is modified in the external interface, called by the user. A stream is marked as being in use when the user initialize it, and is marked as not being in use when the user destroys it.
-rw-r--r--src/cubeb_aaudio.cpp106
1 files changed, 71 insertions, 35 deletions
diff --git a/src/cubeb_aaudio.cpp b/src/cubeb_aaudio.cpp
index 83ca854..e8424a0 100644
--- a/src/cubeb_aaudio.cpp
+++ b/src/cubeb_aaudio.cpp
@@ -25,6 +25,8 @@
#include <thread>
#include <time.h>
+using namespace std;
+
#ifdef DISABLE_LIBAAUDIO_DLOPEN
#define WRAP(x) x
#else
@@ -92,8 +94,14 @@ LIBAAUDIO_API_VISIT(MAKE_TYPEDEF)
const uint8_t MAX_STREAMS = 16;
const int64_t NS_PER_S = static_cast<int64_t>(1e9);
-using unique_lock = std::unique_lock<std::mutex>;
-using lock_guard = std::lock_guard<std::mutex>;
+static int
+aaudio_stream_init_impl(cubeb_stream * stm, lock_guard<mutex> & lock);
+static int
+aaudio_stream_stop_locked(cubeb_stream * stm, lock_guard<mutex> & lock);
+static void
+aaudio_stream_destroy_locked(cubeb_stream * stm, lock_guard<mutex>& lock);
+static int
+aaudio_stream_start_locked(cubeb_stream * stm, lock_guard<mutex>& lock);
enum class stream_state {
INIT = 0,
@@ -142,6 +150,9 @@ struct cubeb_stream {
std::unique_ptr<char[]> in_buf;
unsigned in_frame_size{}; // size of one input frame
+ unique_ptr<cubeb_stream_params> output_stream_params;
+ unique_ptr<cubeb_stream_params> input_stream_params;
+ uint32_t latency_frames{};
cubeb_sample_format out_format{};
uint32_t sample_rate{};
std::atomic<float> volume{1.f};
@@ -902,6 +913,13 @@ static void
aaudio_stream_destroy(cubeb_stream * stm)
{
lock_guard lock(stm->mutex);
+ stm->in_use.store(false);
+ aaudio_stream_destroy_locked(stm, lock);
+}
+
+static void
+aaudio_stream_destroy_locked(cubeb_stream * stm, lock_guard<mutex>& lock)
+{
assert(stm->state == stream_state::STOPPED ||
stm->state == stream_state::STOPPING ||
stm->state == stream_state::INIT ||
@@ -956,18 +974,12 @@ aaudio_stream_destroy(cubeb_stream * stm)
stm->out_frame_size = {};
stm->state.store(stream_state::INIT);
- stm->in_use.store(false);
}
static int
-aaudio_stream_init_impl(cubeb_stream * stm, cubeb_devid input_device,
- cubeb_stream_params * input_stream_params,
- cubeb_devid output_device,
- cubeb_stream_params * output_stream_params,
- unsigned int latency_frames)
+aaudio_stream_init_impl(cubeb_stream * stm, lock_guard<mutex>& lock)
{
assert(stm->state.load() == stream_state::INIT);
- stm->in_use.store(true);
aaudio_result_t res;
AAudioStreamBuilder * sb;
@@ -989,16 +1001,16 @@ aaudio_stream_init_impl(cubeb_stream * stm, cubeb_devid input_device,
std::unique_ptr<AAudioStreamBuilder, StreamBuilderDestructor> sbPtr(sb);
WRAP(AAudioStreamBuilder_setErrorCallback)(sb, aaudio_error_cb, stm);
- WRAP(AAudioStreamBuilder_setBufferCapacityInFrames)(sb, static_cast<int32_t>(latency_frames));
+ WRAP(AAudioStreamBuilder_setBufferCapacityInFrames)(sb, static_cast<int32_t>(stm->latency_frames));
AAudioStream_dataCallback in_data_callback{};
AAudioStream_dataCallback out_data_callback{};
- if (output_stream_params && input_stream_params) {
+ if (stm->output_stream_params && stm->input_stream_params) {
out_data_callback = aaudio_duplex_data_cb;
in_data_callback = nullptr;
- } else if (input_stream_params) {
+ } else if (stm->input_stream_params) {
in_data_callback = aaudio_input_data_cb;
- } else if (output_stream_params) {
+ } else if (stm->output_stream_params) {
out_data_callback = aaudio_output_data_cb;
} else {
LOG("Tried to open stream without input or output parameters");
@@ -1010,7 +1022,7 @@ aaudio_stream_init_impl(cubeb_stream * stm, cubeb_devid input_device,
WRAP(AAudioStreamBuilder_setSharingMode)(sb, AAUDIO_SHARING_MODE_EXCLUSIVE);
#endif
- if (latency_frames <= POWERSAVE_LATENCY_FRAMES_THRESHOLD) {
+ if (stm->latency_frames <= POWERSAVE_LATENCY_FRAMES_THRESHOLD) {
LOG("AAudio setting low latency mode for stream");
WRAP(AAudioStreamBuilder_setPerformanceMode)
(sb, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
@@ -1025,14 +1037,14 @@ aaudio_stream_init_impl(cubeb_stream * stm, cubeb_devid input_device,
// initialize streams
// output
cubeb_stream_params out_params;
- if (output_stream_params) {
+ if (stm->output_stream_params) {
int output_preset = stm->voice_output ? AAUDIO_USAGE_VOICE_COMMUNICATION
: AAUDIO_USAGE_MEDIA;
WRAP(AAudioStreamBuilder_setUsage)(sb, output_preset);
WRAP(AAudioStreamBuilder_setDirection)(sb, AAUDIO_DIRECTION_OUTPUT);
WRAP(AAudioStreamBuilder_setDataCallback)(sb, out_data_callback, stm);
int res_err =
- realize_stream(sb, output_stream_params, &stm->ostream, &frame_size);
+ realize_stream(sb, stm->output_stream_params.get(), &stm->ostream, &frame_size);
if (res_err) {
return res_err;
}
@@ -1048,19 +1060,19 @@ aaudio_stream_init_impl(cubeb_stream * stm, cubeb_devid input_device,
WRAP(AAudioStream_getBufferSizeInFrames)(stm->ostream));
LOG("AAudio output stream sample-rate: %d", rate);
- stm->sample_rate = output_stream_params->rate;
- out_params = *output_stream_params;
+ stm->sample_rate = stm->output_stream_params->rate;
+ out_params = *stm->output_stream_params;
out_params.rate = rate;
- stm->out_channels = output_stream_params->channels;
- stm->out_format = output_stream_params->format;
+ stm->out_channels = stm->output_stream_params->channels;
+ stm->out_format = stm->output_stream_params->format;
stm->out_frame_size = frame_size;
stm->volume.store(1.f);
}
// input
cubeb_stream_params in_params;
- if (input_stream_params) {
+ if (stm->input_stream_params) {
// Match what the OpenSL backend does for now, we could use UNPROCESSED and
// VOICE_COMMUNICATION here, but we'd need to make it clear that
// application-level AEC and other voice processing should be disabled
@@ -1071,7 +1083,7 @@ aaudio_stream_init_impl(cubeb_stream * stm, cubeb_devid input_device,
WRAP(AAudioStreamBuilder_setDirection)(sb, AAUDIO_DIRECTION_INPUT);
WRAP(AAudioStreamBuilder_setDataCallback)(sb, in_data_callback, stm);
int res_err =
- realize_stream(sb, input_stream_params, &stm->istream, &frame_size);
+ realize_stream(sb, stm->input_stream_params.get(), &stm->istream, &frame_size);
if (res_err) {
return res_err;
}
@@ -1088,18 +1100,18 @@ aaudio_stream_init_impl(cubeb_stream * stm, cubeb_devid input_device,
LOG("AAudio input stream buffer rate: %d", rate);
stm->in_buf.reset(new char[bcap * frame_size]());
- assert(!stm->sample_rate || stm->sample_rate == input_stream_params->rate);
+ assert(!stm->sample_rate || stm->sample_rate == stm->input_stream_params->rate);
- stm->sample_rate = input_stream_params->rate;
- in_params = *input_stream_params;
+ stm->sample_rate = stm->input_stream_params->rate;
+ in_params = *stm->input_stream_params;
in_params.rate = rate;
stm->in_frame_size = frame_size;
}
// initialize resampler
stm->resampler = cubeb_resampler_create(
- stm, input_stream_params ? &in_params : nullptr,
- output_stream_params ? &out_params : nullptr, stm->sample_rate,
+ stm, stm->input_stream_params ? &in_params : nullptr,
+ stm->output_stream_params ? &out_params : nullptr, stm->sample_rate,
stm->data_callback, stm->user_ptr, CUBEB_RESAMPLER_QUALITY_DEFAULT,
CUBEB_RESAMPLER_RECLOCK_NONE);
@@ -1131,7 +1143,7 @@ aaudio_stream_init(cubeb * ctx, cubeb_stream ** stream,
// atomically find a free stream.
cubeb_stream * stm = nullptr;
- unique_lock lock;
+ unique_lock<mutex> lock;
for (auto & stream : ctx->streams) {
// This check is only an optimization, we don't strictly need it
// since we check again after locking the mutex.
@@ -1155,6 +1167,8 @@ aaudio_stream_init(cubeb * ctx, cubeb_stream ** stream,
break;
}
+ stm->in_use.store(true);
+
if (!stm) {
LOG("Error: maximum number of streams reached");
return CUBEB_ERROR;
@@ -1169,18 +1183,29 @@ aaudio_stream_init(cubeb * ctx, cubeb_stream ** stream,
stm->voice_output = output_stream_params &&
!!(output_stream_params->prefs & CUBEB_STREAM_PREF_VOICE);
stm->previous_clock = 0;
+ stm->latency_frames = latency_frames;
+ if (output_stream_params) {
+ stm->output_stream_params = std::make_unique<cubeb_stream_params>();
+ *(stm->output_stream_params) = *output_stream_params;
+ }
+ if (input_stream_params) {
+ stm->input_stream_params = std::make_unique<cubeb_stream_params>();
+ *(stm->input_stream_params) = *input_stream_params;
+ }
LOG("cubeb stream prefs: voice_input: %s voice_output: %s",
stm->voice_input ? "true" : "false",
stm->voice_output ? "true" : "false");
- int err = aaudio_stream_init_impl(stm, input_device, input_stream_params,
- output_device, output_stream_params,
- latency_frames);
+ // This is ok: the thread is marked as being in use
+ lock.unlock();
+ lock_guard guard(stm->mutex);
+
+ int err = aaudio_stream_init_impl(stm, guard);
if (err != CUBEB_OK) {
// This is needed since aaudio_stream_destroy will lock the mutex again.
// It's no problem that there is a gap in between as the stream isn't
- // actually in u se.
+ // actually in use.
lock.unlock();
aaudio_stream_destroy(stm);
return err;
@@ -1191,11 +1216,15 @@ aaudio_stream_init(cubeb * ctx, cubeb_stream ** stream,
}
static int
-aaudio_stream_start(cubeb_stream * stm)
-{
- assert(stm && stm->in_use.load());
+aaudio_stream_start(cubeb_stream * stm) {
lock_guard lock(stm->mutex);
+ return aaudio_stream_start_locked(stm, lock);
+}
+static int
+aaudio_stream_start_locked(cubeb_stream * stm, lock_guard<mutex>& lock)
+{
+ assert(stm && stm->in_use.load());
stream_state state = stm->state.load();
int istate = stm->istream ? WRAP(AAudioStream_getState)(stm->istream) : 0;
int ostate = stm->ostream ? WRAP(AAudioStream_getState)(stm->ostream) : 0;
@@ -1295,6 +1324,13 @@ aaudio_stream_stop(cubeb_stream * stm)
{
assert(stm && stm->in_use.load());
lock_guard lock(stm->mutex);
+ return aaudio_stream_stop_locked(stm, lock);
+}
+
+static int
+aaudio_stream_stop_locked(cubeb_stream * stm, lock_guard<mutex>& lock)
+{
+ assert(stm && stm->in_use.load());
stream_state state = stm->state.load();
int istate = stm->istream ? WRAP(AAudioStream_getState)(stm->istream) : 0;