Skip to content

Commit

Permalink
Generate compile_commands.json while building
Browse files Browse the repository at this point in the history
  • Loading branch information
padenot committed Aug 25, 2023
1 parent 655631c commit 54f27be
Show file tree
Hide file tree
Showing 2 changed files with 169 additions and 135 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ endif()
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

if(USE_SANITIZERS)
if(NOT COMMAND add_sanitizers)
Expand Down
303 changes: 168 additions & 135 deletions src/cubeb_opensl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* This program is made available under an ISC-style license. See the
* accompanying file LICENSE for details.
*/
#include <functional>
#undef NDEBUG
#include <SLES/OpenSLES.h>
#include <assert.h>
Expand Down Expand Up @@ -330,6 +331,7 @@ bufferqueue_callback(SLBufferQueueItf caller, void * user_ptr)
ALOGV("bufferqueue_callback: resampler fill returned %ld frames", written);
if (written < 0 ||
written * stm->framesize > static_cast<uint32_t>(stm->queuebuf_len)) {
ALOGV("bufferqueue_callback: error, shutting down", written);
r = pthread_mutex_lock(&stm->mutex);
assert(r == 0);
opensl_set_shutdown(stm, 1);
Expand Down Expand Up @@ -432,7 +434,7 @@ convert_input_buffer_if_needed(cubeb_stream * stm, void * input_buffer,
}
int16_t * int16_buf = reinterpret_cast<int16_t *>(input_buffer);
for (uint32_t i = 0; i < sample_count; i++) {
stm->conversion_buffer_input[i] = int16_buf[i] / 32768.f;
stm->conversion_buffer_input[i] = static_cast<float>(int16_buf[i]) / 32768.f;
}
return stm->conversion_buffer_input.data();
}
Expand Down Expand Up @@ -950,14 +952,13 @@ opensl_set_format(SLDataFormat_PCM * format, cubeb_stream_params * params)
return CUBEB_OK;
}

template <typename T>
template <typename Function>
int
get_source_or_sink_with_format(cubeb_stream * stm, cubeb_stream_params * params,
T & source_or_sink,
uint32_t *& format_sample_rate)
initialize_with_format(cubeb_stream * stm, cubeb_stream_params * params, Function func)
{
void * format = nullptr;
bool using_floats = false;
uint32_t * format_sample_rate;
#if defined(__ANDROID__) && (__ANDROID_API__ >= ANDROID_VERSION_LOLLIPOP)
SLAndroidDataFormat_PCM_EX pcm_ext_format;
if (get_android_version() >= ANDROID_VERSION_LOLLIPOP) {
Expand All @@ -982,26 +983,7 @@ get_source_or_sink_with_format(cubeb_stream * stm, cubeb_stream_params * params,
format_sample_rate = &pcm_format.samplesPerSec;
}

// It's always possible to use int16 regardless of the Android version.
// However if compiling for older Android version, it's possible to request
// f32 audio, but Android only supports int16, in which case a conversion need
// to happen.
if ((params->format == CUBEB_SAMPLE_FLOAT32NE ||
params->format == CUBEB_SAMPLE_FLOAT32BE) &&
!using_floats) {
// setup conversion from f32 to int16
LOG("Input stream configured for using float, but not supported: a "
"conversion will be performed");
stm->conversion_buffer_input.resize(1);
}

if (!using_floats) {
stm->framesize = params->channels * sizeof(int16_t);
} else {
stm->framesize = params->channels * sizeof(float);
}

source_or_sink.pFormat = format;
func(format, format_sample_rate, using_floats);

return CUBEB_OK;
}
Expand All @@ -1012,69 +994,88 @@ opensl_configure_capture(cubeb_stream * stm, cubeb_stream_params * params)
assert(stm);
assert(params);

SLDataLocator_AndroidSimpleBufferQueue lDataLocatorOut;
lDataLocatorOut.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
lDataLocatorOut.numBuffers = NBUFS;

SLDataSink lDataSink;
lDataSink.pLocator = &lDataLocatorOut;
uint32_t * format_sample_rate;
int rv = get_source_or_sink_with_format(stm, params, lDataSink, format_sample_rate);
if (rv != CUBEB_OK) {
LOG("Couldn't set format on sink or source");
return rv;
}

/* For now set device rate to params rate. */
stm->input_device_rate = params->rate;

SLDataLocator_IODevice lDataLocatorIn;
lDataLocatorIn.locatorType = SL_DATALOCATOR_IODEVICE;
lDataLocatorIn.deviceType = SL_IODEVICE_AUDIOINPUT;
lDataLocatorIn.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
lDataLocatorIn.device = NULL;

SLDataSource lDataSource;
lDataSource.pLocator = &lDataLocatorIn;
lDataSource.pFormat = NULL;

const SLInterfaceID lSoundRecorderIIDs[] = {
stm->context->SL_IID_RECORD,
stm->context->SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
stm->context->SL_IID_ANDROIDCONFIGURATION};

const SLboolean lSoundRecorderReqs[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE,
SL_BOOLEAN_TRUE};
// create the audio recorder abstract object
SLresult res = (*stm->context->eng)
->CreateAudioRecorder(
stm->context->eng, &stm->recorderObj, &lDataSource,
&lDataSink, NELEMS(lSoundRecorderIIDs),
lSoundRecorderIIDs, lSoundRecorderReqs);
// Sample rate not supported. Try again with default sample rate!
if (res == SL_RESULT_CONTENT_UNSUPPORTED) {
if (stm->output_enabled && stm->output_configured_rate != 0) {
// Set the same with the player. Since there is no
// api for input device this is a safe choice.
stm->input_device_rate = stm->output_configured_rate;
} else {
// The output preferred rate is used for an input only scenario.
// The default rate expected to be supported from all android devices.
stm->input_device_rate = DEFAULT_SAMPLE_RATE;
}
*format_sample_rate = stm->input_device_rate * 1000;
res = (*stm->context->eng)
->CreateAudioRecorder(stm->context->eng, &stm->recorderObj,
&lDataSource, &lDataSink,
NELEMS(lSoundRecorderIIDs),
lSoundRecorderIIDs, lSoundRecorderReqs);
int rv = initialize_with_format(
stm, params, [=](void* format, uint32_t* format_sample_rate, bool using_floats) -> int {
SLDataLocator_AndroidSimpleBufferQueue lDataLocatorOut;
lDataLocatorOut.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
lDataLocatorOut.numBuffers = NBUFS;

SLDataSink dataSink;
dataSink.pLocator = &lDataLocatorOut;
dataSink.pFormat = format;

SLDataLocator_IODevice dataLocatorIn;
dataLocatorIn.locatorType = SL_DATALOCATOR_IODEVICE;
dataLocatorIn.deviceType = SL_IODEVICE_AUDIOINPUT;
dataLocatorIn.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
dataLocatorIn.device = nullptr;

SLDataSource dataSource;
dataSource.pLocator = &dataLocatorIn;
dataSource.pFormat = nullptr;

const SLInterfaceID lSoundRecorderIIDs[] = {
stm->context->SL_IID_RECORD,
stm->context->SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
stm->context->SL_IID_ANDROIDCONFIGURATION};

const SLboolean lSoundRecorderReqs[] = {
SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
// create the audio recorder abstract object
SLresult res =
(*stm->context->eng)
->CreateAudioRecorder(stm->context->eng, &stm->recorderObj,
&dataSource, &dataSink,
NELEMS(lSoundRecorderIIDs),
lSoundRecorderIIDs, lSoundRecorderReqs);
// Sample rate not supported. Try again with default sample rate!
if (res == SL_RESULT_CONTENT_UNSUPPORTED) {
if (stm->output_enabled && stm->output_configured_rate != 0) {
// Set the same with the player. Since there is no
// api for input device this is a safe choice.
stm->input_device_rate = stm->output_configured_rate;
} else {
// The output preferred rate is used for an input only scenario.
// The default rate expected to be supported from all android
// devices.
stm->input_device_rate = DEFAULT_SAMPLE_RATE;
}
*format_sample_rate = stm->input_device_rate * 1000;
res = (*stm->context->eng)
->CreateAudioRecorder(
stm->context->eng, &stm->recorderObj, &dataSource,
&dataSink, NELEMS(lSoundRecorderIIDs),
lSoundRecorderIIDs, lSoundRecorderReqs);

if (res != SL_RESULT_SUCCESS) {
LOG("Failed to create recorder. Error code: %lu", res);
return CUBEB_ERROR;
}
}
// It's always possible to use int16 regardless of the Android version.
// However if compiling for older Android version, it's possible to request
// f32 audio, but Android only supports int16, in which case a conversion need
// to happen.
if ((params->format == CUBEB_SAMPLE_FLOAT32NE ||
params->format == CUBEB_SAMPLE_FLOAT32BE) &&
!using_floats) {
// setup conversion from f32 to int16
LOG("Input stream configured for using float, but not supported: a "
"conversion will be performed");
stm->conversion_buffer_input.resize(1);
}
return CUBEB_OK;
});

if (res != SL_RESULT_SUCCESS) {
LOG("Failed to create recorder. Error code: %lu", res);
return CUBEB_ERROR;
}
if (rv != CUBEB_OK) {
LOG("Could not initialize recorder.");
return rv;
}

SLresult res;
if (get_android_version() > ANDROID_VERSION_JELLY_BEAN) {
SLAndroidConfigurationItf recorderConfig;
res = (*stm->recorderObj)
Expand Down Expand Up @@ -1166,7 +1167,14 @@ opensl_configure_capture(cubeb_stream * stm, cubeb_stream_params * params)
}

// Calculate length of input buffer according to requested latency
stm->input_frame_size = params->channels * sizeof(int16_t);
uint32_t sample_size = 0;
if (params->format == CUBEB_SAMPLE_FLOAT32BE ||
params->format == CUBEB_SAMPLE_FLOAT32NE) {
sample_size = sizeof(float);
} else {
sample_size = sizeof(int16_t);
}
stm->input_frame_size = params->channels * sample_size;
stm->input_buffer_length = (stm->input_frame_size * stm->buffer_size_frames);

// Calculate the capacity of input array
Expand Down Expand Up @@ -1195,9 +1203,9 @@ opensl_configure_capture(cubeb_stream * stm, cubeb_stream_params * params)
}

// Enqueue buffer to start rolling once recorder started
res = opensl_enqueue_recorder(stm, NULL);
if (res != CUBEB_OK) {
return res;
rv = opensl_enqueue_recorder(stm, nullptr);
if (rv != CUBEB_OK) {
return rv;
}

LOG("Cubeb stream init recorder success");
Expand All @@ -1216,62 +1224,86 @@ opensl_configure_playback(cubeb_stream * stm, cubeb_stream_params * params)
stm->lastPositionTimeStamp = 0;
stm->lastCompensativePosition = -1;

SLDataLocator_BufferQueue loc_bufq;
loc_bufq.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
loc_bufq.numBuffers = NBUFS;

uint32_t * format_sample_rate = nullptr;

SLDataSource source;
source.pLocator = &loc_bufq;
int rv = get_source_or_sink_with_format(stm, params, source, format_sample_rate);
if (rv != CUBEB_OK) {
LOG("Couldn't set format on sink or source");
return rv;
}

SLDataLocator_OutputMix loc_outmix;
loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
loc_outmix.outputMix = stm->context->outmixObj;
SLDataSink sink;
sink.pLocator = &loc_outmix;
sink.pFormat = nullptr;
int rv = initialize_with_format(
stm, params,
[=](void* format, uint32_t* format_sample_rate, bool using_floats) {
SLDataLocator_BufferQueue loc_bufq;
loc_bufq.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
loc_bufq.numBuffers = NBUFS;
SLDataSource source;
source.pLocator = &loc_bufq;
source.pFormat = format;
SLDataLocator_OutputMix loc_outmix;
loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
loc_outmix.outputMix = stm->context->outmixObj;

SLDataSink sink;
sink.pLocator = &loc_outmix;
sink.pFormat = nullptr;

#if defined(__ANDROID__)
const SLInterfaceID ids[] = {stm->context->SL_IID_BUFFERQUEUE,
stm->context->SL_IID_VOLUME,
stm->context->SL_IID_ANDROIDCONFIGURATION};
const SLboolean req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
const SLInterfaceID ids[] = {stm->context->SL_IID_BUFFERQUEUE,
stm->context->SL_IID_VOLUME,
stm->context->SL_IID_ANDROIDCONFIGURATION};
const SLboolean req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE,
SL_BOOLEAN_TRUE};
#else
const SLInterfaceID ids[] = {ctx->SL_IID_BUFFERQUEUE, ctx->SL_IID_VOLUME};
const SLboolean req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
const SLInterfaceID ids[] = {ctx->SL_IID_BUFFERQUEUE,
ctx->SL_IID_VOLUME};
const SLboolean req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
#endif
assert(NELEMS(ids) == NELEMS(req));
assert(NELEMS(ids) == NELEMS(req));

uint32_t preferred_sampling_rate = stm->user_output_rate;
SLresult res = SL_RESULT_CONTENT_UNSUPPORTED;
if (preferred_sampling_rate) {
res = (*stm->context->eng)
->CreateAudioPlayer(stm->context->eng, &stm->playerObj,
&source, &sink, NELEMS(ids), ids, req);
}

// Sample rate not supported? Try again with primary sample rate!
if (res == SL_RESULT_CONTENT_UNSUPPORTED &&
preferred_sampling_rate != DEFAULT_SAMPLE_RATE) {
preferred_sampling_rate = DEFAULT_SAMPLE_RATE;
*format_sample_rate = preferred_sampling_rate * 1000;
res = (*stm->context->eng)
->CreateAudioPlayer(stm->context->eng, &stm->playerObj,
&source, &sink, NELEMS(ids), ids, req);
}

if (res != SL_RESULT_SUCCESS) {
LOG("Failed to create audio player. Error code: %lu", res);
return CUBEB_ERROR;
}
stm->output_configured_rate = preferred_sampling_rate;

// It's always possible to use int16 regardless of the Android version.
// However if compiling for older Android version, it's possible to
// request f32 audio, but Android only supports int16, in which case a
// conversion need to happen.
if ((params->format == CUBEB_SAMPLE_FLOAT32NE ||
params->format == CUBEB_SAMPLE_FLOAT32BE) &&
!using_floats) {
// setup conversion from f32 to int16
LOG("Input stream configured for using float, but not supported: a "
"conversion will be performed");
stm->conversion_buffer_output.resize(1);
}

if (!using_floats) {
stm->framesize = params->channels * sizeof(int16_t);
} else {
stm->framesize = params->channels * sizeof(float);
}
return CUBEB_OK;
});

uint32_t preferred_sampling_rate = stm->user_output_rate;
SLresult res = SL_RESULT_CONTENT_UNSUPPORTED;
if (preferred_sampling_rate) {
res = (*stm->context->eng)
->CreateAudioPlayer(stm->context->eng, &stm->playerObj, &source,
&sink, NELEMS(ids), ids, req);
}

// Sample rate not supported? Try again with primary sample rate!
if (res == SL_RESULT_CONTENT_UNSUPPORTED &&
preferred_sampling_rate != DEFAULT_SAMPLE_RATE) {
preferred_sampling_rate = DEFAULT_SAMPLE_RATE;
*format_sample_rate = preferred_sampling_rate * 1000;
res = (*stm->context->eng)
->CreateAudioPlayer(stm->context->eng, &stm->playerObj, &source,
&sink, NELEMS(ids), ids, req);
}

if (res != SL_RESULT_SUCCESS) {
LOG("Failed to create audio player. Error code: %lu", res);
return CUBEB_ERROR;
if (rv != CUBEB_OK) {
LOG("Couldn't set format on sink or source");
return rv;
}

stm->output_configured_rate = preferred_sampling_rate;
stm->bytespersec = stm->output_configured_rate * stm->framesize;
stm->queuebuf_len = stm->framesize * stm->buffer_size_frames;

Expand All @@ -1286,6 +1318,7 @@ opensl_configure_playback(cubeb_stream * stm, cubeb_stream_params * params)

SLAndroidConfigurationItf playerConfig = nullptr;

SLresult res;
if (get_android_version() >= ANDROID_VERSION_N_MR1) {
res = (*stm->playerObj)
->GetInterface(stm->playerObj,
Expand Down

0 comments on commit 54f27be

Please sign in to comment.