aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/cubeb_aaudio.c
diff options
context:
space:
mode:
authornyorain <[email protected]>2019-12-10 20:29:01 +0100
committerPaul Adenot <[email protected]>2020-10-28 16:55:14 +0000
commitefae368bcf1933316586a4669d1f7b70a45aa64a (patch)
treef6d64999ba282bc906009ae1738c9c6d814d8a05 /src/cubeb_aaudio.c
parent3c316f4ed2ca31c454747513dceb1f58373bc898 (diff)
downloadcubeb-efae368bcf1933316586a4669d1f7b70a45aa64a.tar.gz
cubeb-efae368bcf1933316586a4669d1f7b70a45aa64a.zip
AAudio: Implement stream_set_volume
Diffstat (limited to 'src/cubeb_aaudio.c')
-rw-r--r--src/cubeb_aaudio.c61
1 files changed, 54 insertions, 7 deletions
diff --git a/src/cubeb_aaudio.c b/src/cubeb_aaudio.c
index f564742..a301aa9 100644
--- a/src/cubeb_aaudio.c
+++ b/src/cubeb_aaudio.c
@@ -115,6 +115,10 @@ struct cubeb_stream {
pthread_mutex_t mutex;
unsigned in_frame_size;
+
+ cubeb_sample_format out_format;
+ _Atomic float volume;
+ unsigned out_channels;
unsigned out_frame_size;
};
@@ -397,6 +401,30 @@ aaudio_init(cubeb ** context, char const * context_name) {
return CUBEB_OK;
}
+static void
+apply_volume(cubeb_stream * stm, void * audio_data, uint32_t num_frames) {
+ // optimization: we don't have to change anything in this case
+ float volume = atomic_load(&stm->volume);
+ if(volume == 1.f) {
+ return;
+ }
+
+ switch(stm->out_format) {
+ case CUBEB_SAMPLE_S16NE:
+ for(uint32_t i = 0u; i < num_frames * stm->out_channels; ++i) {
+ ((int16_t*)audio_data)[i] *= volume;
+ }
+ break;
+ case CUBEB_SAMPLE_FLOAT32NE:
+ for(uint32_t i = 0u; i < num_frames * stm->out_channels; ++i) {
+ ((float*)audio_data)[i] *= volume;
+ }
+ break;
+ default:
+ assert(false && "Unreachable: invalid stream out_format");
+ }
+}
+
// Returning AAUDIO_CALLBACK_RESULT_STOP seems to put the stream in
// an invalid state. Seems like an AAudio bug/bad documentation.
// We therefore only return it on error.
@@ -408,6 +436,7 @@ aaudio_duplex_data_cb(AAudioStream * astream, void * user_data,
cubeb_stream * stm = (cubeb_stream*) user_data;
assert(stm->ostream == astream);
assert(stm->istream);
+ assert(num_frames >= 0);
enum stream_state state = atomic_load(&stm->state);
int istate = WRAP(AAudioStream_getState)(stm->istream);
@@ -458,12 +487,12 @@ aaudio_duplex_data_cb(AAudioStream * astream, void * user_data,
return AAUDIO_CALLBACK_RESULT_STOP;
} else if (done_frames < num_frames) {
atomic_store(&stm->state, STREAM_STATE_DRAINING);
- // RESULT_STOP would make more sense here but leads to errors.
- // Restarting the stream would not be possible
- return AAUDIO_CALLBACK_RESULT_CONTINUE;
+
+ char* begin = ((char*)audio_data) + done_frames * stm->out_frame_size;
+ memset(begin, 0x0, (num_frames - done_frames) * stm->out_frame_size);
}
- assert(in_num_frames == num_frames);
+ apply_volume(stm, audio_data, done_frames);
return AAUDIO_CALLBACK_RESULT_CONTINUE;
}
@@ -474,6 +503,7 @@ aaudio_output_data_cb(AAudioStream * astream, void * user_data,
cubeb_stream * stm = (cubeb_stream*) user_data;
assert(stm->ostream == astream);
assert(!stm->istream);
+ assert(num_frames >= 0);
enum stream_state state = atomic_load(&stm->state);
int ostate = WRAP(AAudioStream_getState)(stm->ostream);
@@ -499,9 +529,12 @@ aaudio_output_data_cb(AAudioStream * astream, void * user_data,
return AAUDIO_CALLBACK_RESULT_STOP;
} else if (done_frames < num_frames) {
atomic_store(&stm->state, STREAM_STATE_DRAINING);
- return AAUDIO_CALLBACK_RESULT_CONTINUE;
+
+ char* begin = ((char*)audio_data) + done_frames * stm->out_frame_size;
+ memset(begin, 0x0, (num_frames - done_frames) * stm->out_frame_size);
}
+ apply_volume(stm, audio_data, done_frames);
return AAUDIO_CALLBACK_RESULT_CONTINUE;
}
@@ -512,6 +545,7 @@ aaudio_input_data_cb(AAudioStream * astream, void * user_data,
cubeb_stream * stm = (cubeb_stream*) user_data;
assert(stm->istream == astream);
assert(!stm->ostream);
+ assert(num_frames >= 0);
enum stream_state state = atomic_load(&stm->state);
int istate = WRAP(AAudioStream_getState)(stm->istream);
@@ -540,7 +574,6 @@ aaudio_input_data_cb(AAudioStream * astream, void * user_data,
// stop it from the state thread. That is signaled via the
// DRAINING state.
atomic_store(&stm->state, STREAM_STATE_DRAINING);
- return AAUDIO_CALLBACK_RESULT_CONTINUE;
}
return AAUDIO_CALLBACK_RESULT_CONTINUE;
@@ -629,6 +662,7 @@ aaudio_stream_destroy(cubeb_stream * stm)
}
WRAP(AAudioStream_close)(stm->ostream);
+ stm->ostream = NULL;
}
if (stm->istream) {
@@ -642,6 +676,7 @@ aaudio_stream_destroy(cubeb_stream * stm)
}
WRAP(AAudioStream_close)(stm->istream);
+ stm->istream = NULL;
}
if (stm->resampler) {
@@ -769,7 +804,11 @@ aaudio_stream_init(cubeb * ctx,
target_sample_rate = output_stream_params->rate;
out_params = *output_stream_params;
out_params.rate = rate;
+
+ stm->out_channels = output_stream_params->channels;
+ stm->out_format = output_stream_params->format;
stm->out_frame_size = frame_size;
+ atomic_store(&stm->volume, 1.f);
}
// input
@@ -1113,6 +1152,14 @@ aaudio_stream_get_position(cubeb_stream * stm, uint64_t * position)
return CUBEB_OK;
}
+static int
+aaudio_stream_set_volume(cubeb_stream * stm, float volume)
+{
+ assert(stm && stm->ostream);
+ atomic_store(&stm->volume, volume);
+ return CUBEB_OK;
+}
+
static const struct cubeb_ops aaudio_ops = {
.init = aaudio_init,
.get_backend_id = aaudio_get_backend_id,
@@ -1132,7 +1179,7 @@ static const struct cubeb_ops aaudio_ops = {
.stream_reset_default_device = NULL,
.stream_get_position = aaudio_stream_get_position,
.stream_get_latency = NULL,
- .stream_set_volume = NULL,
+ .stream_set_volume = aaudio_stream_set_volume,
.stream_get_current_device = NULL,
.stream_device_destroy = NULL,
.stream_register_device_changed_callback = NULL,