mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-22 00:06:59 +02:00
Convert the SDL2 backend to the new backend architecture.
This commit is contained in:
@@ -119,17 +119,14 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ma_device_state_async async;
|
||||
struct
|
||||
{
|
||||
int deviceID;
|
||||
ma_format format;
|
||||
ma_uint32 channels;
|
||||
} capture;
|
||||
struct
|
||||
{
|
||||
int deviceID;
|
||||
ma_format format;
|
||||
ma_uint32 channels;
|
||||
} playback;
|
||||
} ma_device_state_sdl;
|
||||
|
||||
@@ -172,6 +169,9 @@ static ma_device_state_sdl* ma_device_get_backend_state__sdl(ma_device* pDevice)
|
||||
}
|
||||
|
||||
|
||||
static void ma_device_step__sdl(ma_device* pDevice);
|
||||
|
||||
|
||||
static void ma_backend_info__sdl(ma_device_backend_info* pBackendInfo)
|
||||
{
|
||||
MA_SDL_ASSERT(pBackendInfo != NULL);
|
||||
@@ -384,14 +384,14 @@ void ma_audio_callback_capture__sdl(void* pUserData, ma_uint8* pBuffer, int buff
|
||||
{
|
||||
ma_device* pDevice = (ma_device*)pUserData;
|
||||
ma_device_state_sdl* pDeviceStateSDL = ma_device_get_backend_state__sdl(pDevice);
|
||||
ma_device_handle_backend_data_callback(pDevice, NULL, pBuffer, (ma_uint32)bufferSizeInBytes / ma_get_bytes_per_frame(pDeviceStateSDL->capture.format, pDeviceStateSDL->capture.channels));
|
||||
ma_device_state_async_process(&pDeviceStateSDL->async, pDevice, NULL, pBuffer, (ma_uint32)bufferSizeInBytes / ma_get_bytes_per_frame(pDeviceStateSDL->async.capture.format, pDeviceStateSDL->async.capture.channels));
|
||||
}
|
||||
|
||||
void ma_audio_callback_playback__sdl(void* pUserData, ma_uint8* pBuffer, int bufferSizeInBytes)
|
||||
{
|
||||
ma_device* pDevice = (ma_device*)pUserData;
|
||||
ma_device_state_sdl* pDeviceStateSDL = ma_device_get_backend_state__sdl(pDevice);
|
||||
ma_device_handle_backend_data_callback(pDevice, pBuffer, NULL, (ma_uint32)bufferSizeInBytes / ma_get_bytes_per_frame(pDeviceStateSDL->playback.format, pDeviceStateSDL->playback.channels));
|
||||
ma_device_state_async_process(&pDeviceStateSDL->async, pDevice, pBuffer, NULL, (ma_uint32)bufferSizeInBytes / ma_get_bytes_per_frame(pDeviceStateSDL->async.playback.format, pDeviceStateSDL->async.playback.channels));
|
||||
}
|
||||
|
||||
static ma_result ma_device_init_internal__sdl(ma_device* pDevice, ma_context_state_sdl* pContextStateSDL, ma_device_state_sdl* pDeviceStateSDL, const ma_device_config_sdl* pDeviceConfigSDL, ma_device_type deviceType, ma_device_descriptor* pDescriptor)
|
||||
@@ -472,12 +472,8 @@ static ma_result ma_device_init_internal__sdl(ma_device* pDevice, ma_context_sta
|
||||
|
||||
if (deviceType == ma_device_type_playback) {
|
||||
pDeviceStateSDL->playback.deviceID = deviceID;
|
||||
pDeviceStateSDL->playback.format = pDescriptor->format;
|
||||
pDeviceStateSDL->playback.channels = pDescriptor->channels;
|
||||
} else {
|
||||
pDeviceStateSDL->capture.deviceID = deviceID;
|
||||
pDeviceStateSDL->capture.format = pDescriptor->format;
|
||||
pDeviceStateSDL->capture.channels = pDescriptor->channels;
|
||||
pDeviceStateSDL->capture.deviceID = deviceID;
|
||||
}
|
||||
|
||||
return MA_SUCCESS;
|
||||
@@ -522,6 +518,19 @@ static ma_result ma_device_init__sdl(ma_device* pDevice, const void* pDeviceBack
|
||||
}
|
||||
}
|
||||
|
||||
result = ma_device_state_async_init(deviceType, pDescriptorPlayback, pDescriptorCapture, ma_device_get_allocation_callbacks(pDevice), &pDeviceStateSDL->async);
|
||||
if (result != MA_SUCCESS) {
|
||||
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
|
||||
pContextStateSDL->SDL_CloseAudioDevice(pDeviceStateSDL->capture.deviceID);
|
||||
}
|
||||
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
|
||||
pContextStateSDL->SDL_CloseAudioDevice(pDeviceStateSDL->playback.deviceID);
|
||||
}
|
||||
|
||||
ma_free(pDeviceStateSDL, ma_device_get_allocation_callbacks(pDevice));
|
||||
return result;
|
||||
}
|
||||
|
||||
*ppDeviceState = pDeviceStateSDL;
|
||||
|
||||
return MA_SUCCESS;
|
||||
@@ -541,6 +550,8 @@ static void ma_device_uninit__sdl(ma_device* pDevice)
|
||||
pContextStateSDL->SDL_CloseAudioDevice(pDeviceStateSDL->playback.deviceID);
|
||||
}
|
||||
|
||||
ma_device_state_async_uninit(&pDeviceStateSDL->async, ma_device_get_allocation_callbacks(pDevice));
|
||||
|
||||
ma_free(pDeviceStateSDL, ma_device_get_allocation_callbacks(pDevice));
|
||||
}
|
||||
|
||||
@@ -550,6 +561,9 @@ static ma_result ma_device_start__sdl(ma_device* pDevice)
|
||||
ma_context_state_sdl* pContextStateSDL = ma_context_get_backend_state__sdl(ma_device_get_context(pDevice));
|
||||
ma_device_type deviceType = ma_device_get_type(pDevice);
|
||||
|
||||
/* Step the device once to ensure buffers are pre-filled before starting. */
|
||||
ma_device_step__sdl(pDevice);
|
||||
|
||||
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
|
||||
pContextStateSDL->SDL_PauseAudioDevice(pDeviceStateSDL->capture.deviceID, 0);
|
||||
}
|
||||
@@ -579,6 +593,33 @@ static ma_result ma_device_stop__sdl(ma_device* pDevice)
|
||||
}
|
||||
|
||||
|
||||
static void ma_device_wait__sdl(ma_device* pDevice)
|
||||
{
|
||||
ma_device_state_sdl* pDeviceStateSDL = ma_device_get_backend_state__sdl(pDevice);
|
||||
ma_device_state_async_wait(&pDeviceStateSDL->async);
|
||||
}
|
||||
|
||||
static void ma_device_step__sdl(ma_device* pDevice)
|
||||
{
|
||||
ma_device_state_sdl* pDeviceStateSDL = ma_device_get_backend_state__sdl(pDevice);
|
||||
ma_device_state_async_step(&pDeviceStateSDL->async, pDevice);
|
||||
}
|
||||
|
||||
static void ma_device_loop__sdl(ma_device* pDevice)
|
||||
{
|
||||
for (;;) {
|
||||
ma_device_wait__sdl(pDevice);
|
||||
|
||||
/* If the wait terminated due to the device being stopped, abort now. */
|
||||
if (!ma_device_is_started(pDevice)) {
|
||||
break;
|
||||
}
|
||||
|
||||
ma_device_step__sdl(pDevice);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ma_device_backend_vtable ma_gDeviceBackendVTable_SDL =
|
||||
{
|
||||
ma_backend_info__sdl,
|
||||
@@ -591,7 +632,7 @@ static ma_device_backend_vtable ma_gDeviceBackendVTable_SDL =
|
||||
ma_device_stop__sdl,
|
||||
NULL, /* onDeviceRead */
|
||||
NULL, /* onDeviceWrite */
|
||||
NULL, /* onDeviceLoop */
|
||||
ma_device_loop__sdl,
|
||||
NULL /* onDeviceWakeup */
|
||||
};
|
||||
|
||||
|
||||
+244
@@ -9489,6 +9489,34 @@ is also zero, `MA_DEFAULT_SAMPLE_RATE` will be used instead.
|
||||
*/
|
||||
MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_descriptor(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate);
|
||||
|
||||
|
||||
/* BEG ma_device_state_async.h */
|
||||
typedef struct ma_device_state_async
|
||||
{
|
||||
ma_device_type deviceType;
|
||||
struct
|
||||
{
|
||||
ma_semaphore semaphore;
|
||||
ma_spinlock lock;
|
||||
ma_format format;
|
||||
ma_uint32 channels;
|
||||
ma_uint32 frameCap;
|
||||
ma_uint32 frameCount;
|
||||
void* pBuffer; /* An offset of internal.pBuffer. */
|
||||
} playback, capture;
|
||||
struct
|
||||
{
|
||||
void* pBuffer; /* One buffer allocation for both playback and capture. */
|
||||
} internal;
|
||||
} ma_device_state_async;
|
||||
|
||||
MA_API ma_result ma_device_state_async_init(ma_device_type deviceType, const ma_device_descriptor* pDescriptorPlayback, const ma_device_descriptor* pDescriptorCapture, const ma_allocation_callbacks* pAllocationCallbacks, ma_device_state_async* pAsyncDeviceState);
|
||||
MA_API void ma_device_state_async_uninit(ma_device_state_async* pAsyncDeviceState, const ma_allocation_callbacks* pAllocationCallbacks);
|
||||
MA_API void ma_device_state_async_wait(ma_device_state_async* pAsyncDeviceState);
|
||||
MA_API void ma_device_state_async_step(ma_device_state_async* pAsyncDeviceState, ma_device* pDevice);
|
||||
MA_API void ma_device_state_async_process(ma_device_state_async* pAsyncDeviceState, ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
|
||||
/* END ma_device_state_async.h */
|
||||
|
||||
#endif /* MA_NO_DEVICE_IO */
|
||||
|
||||
|
||||
@@ -45930,6 +45958,222 @@ MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_descriptor(const ma_dev
|
||||
return pDescriptor->periodSizeInFrames;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* BEG ma_device_state_async.c */
|
||||
MA_API ma_result ma_device_state_async_init(ma_device_type deviceType, const ma_device_descriptor* pDescriptorPlayback, const ma_device_descriptor* pDescriptorCapture, const ma_allocation_callbacks* pAllocationCallbacks, ma_device_state_async* pAsyncDeviceState)
|
||||
{
|
||||
ma_result result;
|
||||
size_t bufferAllocSizeInBytesCapture = 0;
|
||||
size_t bufferAllocSizeInBytesPlayback = 0;
|
||||
|
||||
if (pAsyncDeviceState == NULL) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
MA_ZERO_OBJECT(pAsyncDeviceState);
|
||||
pAsyncDeviceState->deviceType = deviceType;
|
||||
|
||||
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
|
||||
if (pDescriptorCapture == NULL) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
result = ma_semaphore_init(0, &pAsyncDeviceState->capture.semaphore);
|
||||
if (result != MA_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
pAsyncDeviceState->capture.format = pDescriptorCapture->format;
|
||||
pAsyncDeviceState->capture.channels = pDescriptorCapture->channels;
|
||||
pAsyncDeviceState->capture.frameCap = pDescriptorCapture->periodSizeInFrames;
|
||||
|
||||
bufferAllocSizeInBytesCapture = ma_align_64(ma_get_bytes_per_frame(pAsyncDeviceState->capture.format, pAsyncDeviceState->capture.channels) * pAsyncDeviceState->capture.frameCap);
|
||||
}
|
||||
|
||||
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
|
||||
if (pDescriptorPlayback == NULL) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
result = ma_semaphore_init(0, &pAsyncDeviceState->playback.semaphore);
|
||||
if (result != MA_SUCCESS) {
|
||||
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
|
||||
ma_semaphore_uninit(&pAsyncDeviceState->capture.semaphore);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
pAsyncDeviceState->playback.format = pDescriptorPlayback->format;
|
||||
pAsyncDeviceState->playback.channels = pDescriptorPlayback->channels;
|
||||
pAsyncDeviceState->playback.frameCap = pDescriptorPlayback->periodSizeInFrames;
|
||||
|
||||
bufferAllocSizeInBytesPlayback = ma_align_64(ma_get_bytes_per_frame(pAsyncDeviceState->playback.format, pAsyncDeviceState->playback.channels) * pAsyncDeviceState->playback.frameCap);
|
||||
}
|
||||
|
||||
pAsyncDeviceState->internal.pBuffer = ma_malloc(bufferAllocSizeInBytesCapture + bufferAllocSizeInBytesPlayback, pAllocationCallbacks);
|
||||
if (pAsyncDeviceState->internal.pBuffer == NULL) {
|
||||
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
|
||||
ma_semaphore_uninit(&pAsyncDeviceState->capture.semaphore);
|
||||
}
|
||||
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
|
||||
ma_semaphore_uninit(&pAsyncDeviceState->playback.semaphore);
|
||||
}
|
||||
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
|
||||
pAsyncDeviceState->capture.pBuffer = pAsyncDeviceState->internal.pBuffer;
|
||||
}
|
||||
|
||||
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
|
||||
pAsyncDeviceState->playback.pBuffer = ma_offset_ptr(pAsyncDeviceState->internal.pBuffer, bufferAllocSizeInBytesCapture);
|
||||
}
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
MA_API void ma_device_state_async_uninit(ma_device_state_async* pAsyncDeviceState, const ma_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
if (pAsyncDeviceState == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ma_free(pAsyncDeviceState->internal.pBuffer, pAllocationCallbacks);
|
||||
pAsyncDeviceState->internal.pBuffer = NULL;
|
||||
|
||||
if (pAsyncDeviceState->deviceType == ma_device_type_capture || pAsyncDeviceState->deviceType == ma_device_type_duplex) {
|
||||
ma_semaphore_uninit(&pAsyncDeviceState->capture.semaphore);
|
||||
}
|
||||
|
||||
if (pAsyncDeviceState->deviceType == ma_device_type_playback || pAsyncDeviceState->deviceType == ma_device_type_duplex) {
|
||||
ma_semaphore_uninit(&pAsyncDeviceState->playback.semaphore);
|
||||
}
|
||||
}
|
||||
|
||||
MA_API void ma_device_state_async_wait(ma_device_state_async* pAsyncDeviceState)
|
||||
{
|
||||
if (pAsyncDeviceState == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pAsyncDeviceState->deviceType == ma_device_type_capture || pAsyncDeviceState->deviceType == ma_device_type_duplex) {
|
||||
ma_semaphore_wait(&pAsyncDeviceState->capture.semaphore);
|
||||
}
|
||||
|
||||
if (pAsyncDeviceState->deviceType == ma_device_type_playback || pAsyncDeviceState->deviceType == ma_device_type_duplex) {
|
||||
ma_semaphore_wait(&pAsyncDeviceState->playback.semaphore);
|
||||
}
|
||||
}
|
||||
|
||||
MA_API void ma_device_state_async_step(ma_device_state_async* pAsyncDeviceState, ma_device* pDevice)
|
||||
{
|
||||
if (pAsyncDeviceState == NULL || pDevice == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pAsyncDeviceState->deviceType == ma_device_type_capture || pAsyncDeviceState->deviceType == ma_device_type_duplex) {
|
||||
ma_spinlock_lock(&pAsyncDeviceState->capture.lock);
|
||||
{
|
||||
if (pAsyncDeviceState->capture.frameCount > 0) {
|
||||
ma_device_handle_backend_data_callback(pDevice, NULL, pAsyncDeviceState->capture.pBuffer, pAsyncDeviceState->capture.frameCount);
|
||||
pAsyncDeviceState->capture.frameCount = 0;
|
||||
}
|
||||
}
|
||||
ma_spinlock_unlock(&pAsyncDeviceState->capture.lock);
|
||||
}
|
||||
|
||||
if (pAsyncDeviceState->deviceType == ma_device_type_playback || pAsyncDeviceState->deviceType == ma_device_type_duplex) {
|
||||
ma_uint32 bytesPerFrame = ma_get_bytes_per_frame(pAsyncDeviceState->playback.format, pAsyncDeviceState->playback.channels);
|
||||
|
||||
ma_spinlock_lock(&pAsyncDeviceState->playback.lock);
|
||||
{
|
||||
if (pAsyncDeviceState->playback.frameCount < pAsyncDeviceState->playback.frameCap) {
|
||||
ma_device_handle_backend_data_callback(pDevice, ma_offset_ptr(pAsyncDeviceState->playback.pBuffer, bytesPerFrame * pAsyncDeviceState->playback.frameCount), NULL, (pAsyncDeviceState->playback.frameCap - pAsyncDeviceState->playback.frameCount));
|
||||
pAsyncDeviceState->playback.frameCount = pAsyncDeviceState->playback.frameCap;
|
||||
}
|
||||
}
|
||||
ma_spinlock_unlock(&pAsyncDeviceState->playback.lock);
|
||||
}
|
||||
}
|
||||
|
||||
MA_API void ma_device_state_async_process(ma_device_state_async* pAsyncDeviceState, ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
|
||||
{
|
||||
if (pAsyncDeviceState == NULL || pDevice == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pInput != NULL) {
|
||||
if (pAsyncDeviceState->deviceType == ma_device_type_capture || pAsyncDeviceState->deviceType == ma_device_type_duplex) {
|
||||
ma_spinlock_lock(&pAsyncDeviceState->capture.lock);
|
||||
{
|
||||
ma_uint32 framesToCopy;
|
||||
ma_uint32 framesAvailable;
|
||||
|
||||
MA_ASSERT(pAsyncDeviceState->capture.frameCap >= pAsyncDeviceState->capture.frameCount);
|
||||
framesAvailable = pAsyncDeviceState->capture.frameCap - pAsyncDeviceState->capture.frameCount;
|
||||
|
||||
framesToCopy = frameCount;
|
||||
if (framesToCopy > framesAvailable) {
|
||||
framesToCopy = framesAvailable;
|
||||
}
|
||||
|
||||
if (framesToCopy > 0) {
|
||||
ma_uint32 bytesPerFrame = ma_get_bytes_per_frame(pAsyncDeviceState->capture.format, pAsyncDeviceState->capture.channels);
|
||||
|
||||
MA_COPY_MEMORY(ma_offset_ptr(pAsyncDeviceState->capture.pBuffer, bytesPerFrame * pAsyncDeviceState->capture.frameCount), pInput, bytesPerFrame * framesToCopy);
|
||||
pAsyncDeviceState->capture.frameCount += framesToCopy;
|
||||
|
||||
/* If we just filled up the buffer with data, it's time to release the semaphore. */
|
||||
if (pAsyncDeviceState->capture.frameCount == pAsyncDeviceState->capture.frameCap) {
|
||||
ma_semaphore_release(&pAsyncDeviceState->capture.semaphore);
|
||||
}
|
||||
}
|
||||
}
|
||||
ma_spinlock_unlock(&pAsyncDeviceState->capture.lock);
|
||||
} else {
|
||||
MA_ASSERT(MA_FALSE); /* Should never get here. */
|
||||
}
|
||||
}
|
||||
|
||||
if (pOutput != NULL) {
|
||||
if (pAsyncDeviceState->deviceType == ma_device_type_playback || pAsyncDeviceState->deviceType == ma_device_type_duplex) {
|
||||
ma_spinlock_lock(&pAsyncDeviceState->playback.lock);
|
||||
{
|
||||
ma_uint32 framesToCopy;
|
||||
|
||||
framesToCopy = frameCount;
|
||||
if (framesToCopy > pAsyncDeviceState->playback.frameCount) {
|
||||
framesToCopy = pAsyncDeviceState->playback.frameCount;
|
||||
}
|
||||
|
||||
if (framesToCopy > 0) {
|
||||
ma_uint32 bytesPerFrame = ma_get_bytes_per_frame(pAsyncDeviceState->playback.format, pAsyncDeviceState->playback.channels);
|
||||
MA_COPY_MEMORY(pOutput, pAsyncDeviceState->playback.pBuffer, bytesPerFrame * framesToCopy);
|
||||
|
||||
/* Move any remaining data to the front of the buffer. */
|
||||
if (framesToCopy < pAsyncDeviceState->playback.frameCount) {
|
||||
MA_COPY_MEMORY(pAsyncDeviceState->playback.pBuffer, ma_offset_ptr(pAsyncDeviceState->playback.pBuffer, bytesPerFrame * framesToCopy), bytesPerFrame * (pAsyncDeviceState->playback.frameCount - framesToCopy));
|
||||
}
|
||||
|
||||
pAsyncDeviceState->playback.frameCount -= framesToCopy;
|
||||
}
|
||||
|
||||
/* If we just emptied the buffer, it's time to release the semaphore. */
|
||||
if (pAsyncDeviceState->playback.frameCount == 0) {
|
||||
ma_semaphore_release(&pAsyncDeviceState->playback.semaphore);
|
||||
}
|
||||
}
|
||||
ma_spinlock_unlock(&pAsyncDeviceState->playback.lock);
|
||||
} else {
|
||||
MA_ASSERT(MA_FALSE); /* Should never get here. */
|
||||
}
|
||||
}
|
||||
}
|
||||
/* END ma_device_state_async.c */
|
||||
|
||||
#endif /* MA_NO_DEVICE_IO */
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user