diff options
author | Paul Adenot <[email protected]> | 2023-08-25 10:31:07 -0400 |
---|---|---|
committer | Paul Adenot <[email protected]> | 2023-08-25 20:09:58 +0200 |
commit | 46f10c2eeaeef949a139f1e2b672989895cec98e (patch) | |
tree | 98ec47cc8e604ec344b3d8118f4a554f7688d3e4 | |
parent | ed468c2a472c362b7fb9c80c25ed35ca987f0d76 (diff) | |
download | cubeb-46f10c2eeaeef949a139f1e2b672989895cec98e.tar.gz cubeb-46f10c2eeaeef949a139f1e2b672989895cec98e.zip |
Handle input side
-rw-r--r-- | src/cubeb_opensl.cpp | 196 |
1 files changed, 131 insertions, 65 deletions
diff --git a/src/cubeb_opensl.cpp b/src/cubeb_opensl.cpp index c5a2543..6a0f43a 100644 --- a/src/cubeb_opensl.cpp +++ b/src/cubeb_opensl.cpp @@ -141,6 +141,7 @@ struct cubeb_stream { std::unique_ptr<cubeb_stream_params> output_params; // A non-empty buffer means that f32 -> int16 conversion need to happen std::vector<float> conversion_buffer_output; + std::vector<float> conversion_buffer_input; }; /* Forward declaration. */ @@ -417,6 +418,27 @@ opensl_enqueue_recorder(cubeb_stream * stm, void ** last_filled_buffer) return CUBEB_OK; } +// If necessary, convert and returns an input buffer. +// Otherwise, just returns the pointer that has been passed in. +void * +convert_input_buffer_if_needed(cubeb_stream * stm, void * input_buffer, + uint32_t sample_count) +{ + // Perform conversion if needed + if (stm->conversion_buffer_input.empty()) { + return input_buffer; + } + if (stm->conversion_buffer_input.size() < sample_count) { + stm->conversion_buffer_input.resize(sample_count); + } + int16_t * int16_buf = reinterpret_cast<int16_t *>(input_buffer); + for (uint32_t i = 0; i < sample_count; i++) { + stm->conversion_buffer_input[i] = + static_cast<float>(int16_buf[i]) / 32768.f; + } + return stm->conversion_buffer_input.data(); +} + // input data callback void recorder_callback(SLAndroidSimpleBufferQueueItf bq, void * context) @@ -447,8 +469,14 @@ recorder_callback(SLAndroidSimpleBufferQueueItf bq, void * context) r = opensl_enqueue_recorder(stm, &input_buffer); assert(r == CUBEB_OK); assert(input_buffer); - // Fill resampler with last input + long input_frame_count = stm->input_buffer_length / stm->input_frame_size; + uint32_t sample_count = input_frame_count * stm->input_params->channels; + + input_buffer = + convert_input_buffer_if_needed(stm, input_buffer, sample_count); + + // Fill resampler with last input long got = cubeb_resampler_fill(stm->resampler, input_buffer, &input_frame_count, nullptr, 0); // Error case @@ -542,6 +570,7 @@ player_fullduplex_callback(SLBufferQueueItf caller, void * user_ptr) r = pthread_mutex_lock(&stm->mutex); assert(r == 0); output_buffer = stm->queuebuf[stm->queuebuf_idx]; + void * output_buffer_original_ptr = output_buffer; // Advance the output buffer queue index stm->queuebuf_idx = (stm->queuebuf_idx + 1) % stm->queuebuf_capacity; r = pthread_mutex_unlock(&stm->mutex); @@ -561,18 +590,28 @@ player_fullduplex_callback(SLBufferQueueItf caller, void * user_ptr) // Get input. void * input_buffer = array_queue_pop(stm->input_queue); long input_frame_count = stm->input_buffer_length / stm->input_frame_size; + long sample_count = input_frame_count * stm->input_params->channels; long frames_needed = stm->queuebuf_len / stm->framesize; + if (!input_buffer) { LOG("Input hole set silent input buffer"); input_buffer = stm->input_silent_buffer; } + input_buffer = + convert_input_buffer_if_needed(stm, input_buffer, sample_count); + + output_buffer = get_output_buffer(stm, output_buffer, sample_count); + long written = 0; // Trigger user callback through resampler written = cubeb_resampler_fill(stm->resampler, input_buffer, &input_frame_count, output_buffer, frames_needed); + output_buffer = + release_output_buffer(stm, output_buffer_original_ptr, sample_count); + LOG("Fill: written %ld, frames_needed %ld, input array size %zu", written, frames_needed, array_queue_get_size(stm->input_queue)); @@ -804,8 +843,8 @@ opensl_get_max_channel_count(cubeb * ctx, uint32_t * max_channels) { assert(ctx && max_channels); /* The android mixer handles up to two channels, see - http://androidxref.com/4.2.2_r1/xref/frameworks/av/services/audioflinger/AudioFlinger.h#67 - */ + http://androidxref.com/4.2.2_r1/xref/frameworks/av/services/audioflinger/AudioFlinger.h#67 + */ *max_channels = 2; return CUBEB_OK; @@ -957,70 +996,90 @@ 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; - - SLDataFormat_PCM lDataFormat; - int r = opensl_set_format(&lDataFormat, params); - if (r != CUBEB_OK) { - return CUBEB_ERROR_INVALID_FORMAT; - } - /* For now set device rate to params rate. */ stm->input_device_rate = params->rate; - SLDataSink lDataSink; - lDataSink.pLocator = &lDataLocatorOut; - lDataSink.pFormat = &lDataFormat; - - 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; - } - lDataFormat.samplesPerSec = 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) @@ -1112,7 +1171,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 @@ -1141,9 +1207,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"); |