From 1e1e8c0ba1663147d4dc68d28f2ad30af30ee56d Mon Sep 17 00:00:00 2001 From: David Reid Date: Sun, 24 Feb 2019 15:53:20 +1000 Subject: [PATCH] More full-duplex work on OpenSL and AAudio. --- mini_al.h | 47 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/mini_al.h b/mini_al.h index 166eaa3f..d534de3e 100644 --- a/mini_al.h +++ b/mini_al.h @@ -2308,6 +2308,7 @@ MAL_ALIGNED_STRUCT(MAL_SIMD_ALIGNMENT) mal_device { /*AAudioStream**/ mal_ptr pStreamPlayback; /*AAudioStream**/ mal_ptr pStreamCapture; + mal_pcm_rb duplexRB; } aaudio; #endif #ifdef MAL_SUPPORT_OPENSL @@ -2325,6 +2326,7 @@ MAL_ALIGNED_STRUCT(MAL_SIMD_ALIGNMENT) mal_device mal_uint32 currentBufferIndexCapture; mal_uint8* pBufferPlayback; // This is malloc()'d and is used for storing audio data. Typed as mal_uint8 for easy offsetting. mal_uint8* pBufferCapture; + mal_pcm_rb duplexRB; } opensl; #endif #ifdef MAL_SUPPORT_WEBAUDIO @@ -19532,10 +19534,9 @@ mal_aaudio_data_callback_result_t mal_stream_data_callback_capture__aaudio(mal_A mal_assert(pDevice != NULL); if (pDevice->type == mal_device_type_duplex) { - /* TODO: Write to ring buffer. The client callback will be called from AAudio's playback callback. */ + mal_device__handle_duplex_callback_capture(pDevice, frameCount, pAudioData, &pDevice->aaudio.duplexRB); } else { - /* Send directly to the client. */ - mal_device__send_frames_to_client(pDevice, frameCount, pAudioData); + mal_device__send_frames_to_client(pDevice, frameCount, pAudioData); /* Send directly to the client. */ } (void)pStream; @@ -19548,10 +19549,9 @@ mal_aaudio_data_callback_result_t mal_stream_data_callback_playback__aaudio(mal_ mal_assert(pDevice != NULL); if (pDevice->type == mal_device_type_duplex) { - /* TODO: Map input samples from the ring buffer and use that as the input buffer for the data callback. */ + mal_device__handle_duplex_callback_playback(pDevice, frameCount, pAudioData, &pDevice->aaudio.duplexRB); } else { - /* Read directly from the client. */ - mal_device__read_frames_from_client(pDevice, frameCount, pAudioData); + mal_device__read_frames_from_client(pDevice, frameCount, pAudioData); /* Read directly from the client. */ } (void)pStream; @@ -19774,6 +19774,10 @@ void mal_device_uninit__aaudio(mal_device* pDevice) mal_close_stream__aaudio(pDevice->pContext, (mal_AAudioStream*)pDevice->aaudio.pStreamPlayback); pDevice->aaudio.pStreamPlayback = NULL; } + + if (pDevice->type == mal_device_type_duplex) { + mal_pcm_rb_uninit(&pDevice->aaudio.duplexRB); + } } mal_result mal_device_init__aaudio(mal_context* pContext, const mal_device_config* pConfig, mal_device* pDevice) @@ -19833,6 +19837,20 @@ mal_result mal_device_init__aaudio(mal_context* pContext, const mal_device_confi } } + if (pConfig->deviceType == mal_device_type_duplex) { + mal_uint32 rbSizeInFrames = mal_calculate_frame_count_after_src(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalBufferSizeInFrames); + mal_result result = mal_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->aaudio.duplexRB); + if (result != MAL_SUCCESS) { + if (pDevice->type == mal_device_type_capture || pDevice->type == mal_device_type_duplex) { + mal_close_stream__aaudio(pDevice->pContext, (mal_AAudioStream*)pDevice->aaudio.pStreamCapture); + } + if (pDevice->type == mal_device_type_playback || pDevice->type == mal_device_type_duplex) { + mal_close_stream__aaudio(pDevice->pContext, (mal_AAudioStream*)pDevice->aaudio.pStreamPlayback); + } + return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[AAudio] Failed to initialize ring buffer.", result); + } + } + return MAL_SUCCESS; } @@ -20412,7 +20430,7 @@ void mal_buffer_queue_callback_capture__opensl_android(SLAndroidSimpleBufferQueu mal_uint8* pBuffer = pDevice->opensl.pBufferCapture + (pDevice->opensl.currentBufferIndexCapture * periodSizeInBytes); if (pDevice->type == mal_device_type_duplex) { - /* TODO: Write data to the ring buffer. */ + mal_device__handle_duplex_callback_capture(pDevice, (pDevice->capture.internalBufferSizeInFrames / pDevice->capture.internalPeriods), pBuffer, &pDevice->opensl.duplexRB); } else { mal_device__send_frames_to_client(pDevice, (pDevice->capture.internalBufferSizeInFrames / pDevice->capture.internalPeriods), pBuffer); } @@ -20441,7 +20459,7 @@ void mal_buffer_queue_callback_playback__opensl_android(SLAndroidSimpleBufferQue mal_uint8* pBuffer = pDevice->opensl.pBufferPlayback + (pDevice->opensl.currentBufferIndexPlayback * periodSizeInBytes); if (pDevice->type == mal_device_type_duplex) { - /* TOOD: Read from the ring buffer and fire the callback. */ + mal_device__handle_duplex_callback_playback(pDevice, (pDevice->playback.internalBufferSizeInFrames / pDevice->playback.internalPeriods), pBuffer, &pDevice->opensl.duplexRB); } else { mal_device__read_frames_from_client(pDevice, (pDevice->playback.internalBufferSizeInFrames / pDevice->playback.internalPeriods), pBuffer); } @@ -20482,6 +20500,10 @@ void mal_device_uninit__opensl(mal_device* pDevice) mal_free(pDevice->opensl.pBufferPlayback); } + + if (pDevice->type == mal_device_type_duplex) { + mal_pcm_rb_uninit(&pDevice->opensl.duplexRB); + } } #if defined(MAL_ANDROID) && __ANDROID_API__ >= 21 @@ -20787,6 +20809,15 @@ mal_result mal_device_init__opensl(mal_context* pContext, const mal_device_confi MAL_ZERO_MEMORY(pDevice->opensl.pBufferPlayback, bufferSizeInBytes); } + if (pConfig->deviceType == mal_device_type_duplex) { + mal_uint32 rbSizeInFrames = mal_calculate_frame_count_after_src(pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalBufferSizeInFrames); + mal_result result = mal_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->opensl.duplexRB); + if (result != MAL_SUCCESS) { + mal_device_uninit__opensl(pDevice); + return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[OpenSL] Failed to initialize ring buffer.", result); + } + } + return MAL_SUCCESS; }