Commit 5276057d authored by David Reid's avatar David Reid

Minor refactoring to the PulseAudio backend.

parent 34c9a4ea
......@@ -15567,7 +15567,7 @@ ma_result ma_device_stop__pulse(ma_device* pDevice)
return MA_SUCCESS;
}
ma_result ma_device_write__pulse(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount)
ma_result ma_device_write__pulse(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
{
ma_uint32 totalFramesWritten;
......@@ -15575,16 +15575,16 @@ ma_result ma_device_write__pulse(ma_device* pDevice, const void* pPCMFrames, ma_
ma_assert(pPCMFrames != NULL);
ma_assert(frameCount > 0);
/* The stream needs to be uncorked first. */
if (((ma_pa_stream_is_corked_proc)pDevice->pContext->pulse.pa_stream_is_corked)((ma_pa_stream*)pDevice->pulse.pStreamPlayback)) {
ma_result result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 0);
if (result != MA_SUCCESS) {
return result;
}
if (pFramesWritten != NULL) {
*pFramesWritten = 0;
}
totalFramesWritten = 0;
while (totalFramesWritten < frameCount) {
if (ma_device__get_state(pDevice) != MA_STATE_STARTED) {
return MA_DEVICE_NOT_STARTED;
}
/* Place the data into the mapped buffer if we have one. */
if (pDevice->pulse.pMappedBufferPlayback != NULL && pDevice->pulse.mappedBufferFramesRemainingPlayback > 0) {
ma_uint32 bpf = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
......@@ -15660,10 +15660,14 @@ ma_result ma_device_write__pulse(ma_device* pDevice, const void* pPCMFrames, ma_
}
}
if (pFramesWritten != NULL) {
*pFramesWritten = totalFramesWritten;
}
return MA_SUCCESS;
}
ma_result ma_device_read__pulse(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount)
ma_result ma_device_read__pulse(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead)
{
ma_uint32 totalFramesRead;
......@@ -15671,18 +15675,14 @@ ma_result ma_device_read__pulse(ma_device* pDevice, void* pPCMFrames, ma_uint32
ma_assert(pPCMFrames != NULL);
ma_assert(frameCount > 0);
/* The stream needs to be uncorked first. */
if (((ma_pa_stream_is_corked_proc)pDevice->pContext->pulse.pa_stream_is_corked)((ma_pa_stream*)pDevice->pulse.pStreamCapture)) {
ma_result result = ma_device__cork_stream__pulse(pDevice, ma_device_type_capture, 0);
if (result != MA_SUCCESS) {
return result;
}
if (pFramesRead != NULL) {
*pFramesRead = 0;
}
totalFramesRead = 0;
while (totalFramesRead < frameCount) {
if (ma_device__get_state(pDevice) != MA_STATE_STARTED) {
break;
return MA_DEVICE_NOT_STARTED;
}
/* If a buffer is mapped we need to write to that first. Once it's consumed we reset the event and unmap it. */
......@@ -15787,9 +15787,183 @@ ma_result ma_device_read__pulse(ma_device* pDevice, void* pPCMFrames, ma_uint32
}
}
if (pFramesRead != NULL) {
*pFramesRead = totalFramesRead;
}
return MA_SUCCESS;
}
ma_result ma_device_main_loop__pulse(ma_device* pDevice)
{
ma_result result = MA_SUCCESS;
ma_bool32 exitLoop = MA_FALSE;
ma_assert(pDevice != NULL);
/* The stream needs to be uncorked first. We do this at the top for both capture and playback for PulseAudio. */
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
result = ma_device__cork_stream__pulse(pDevice, ma_device_type_capture, 0);
if (result != MA_SUCCESS) {
return result;
}
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 0);
if (result != MA_SUCCESS) {
return result;
}
}
while (ma_device__get_state(pDevice) == MA_STATE_STARTED && !exitLoop) {
switch (pDevice->type)
{
case ma_device_type_duplex:
{
/* The process is: device_read -> convert -> callback -> convert -> device_write */
ma_uint8 capturedDeviceData[8192];
ma_uint8 playbackDeviceData[8192];
ma_uint32 capturedDeviceDataCapInFrames = sizeof(capturedDeviceData) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
ma_uint32 playbackDeviceDataCapInFrames = sizeof(playbackDeviceData) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
ma_uint32 totalFramesProcessed = 0;
ma_uint32 periodSizeInFrames = ma_min(pDevice->capture.internalBufferSizeInFrames/pDevice->capture.internalPeriods, pDevice->playback.internalBufferSizeInFrames/pDevice->playback.internalPeriods);
while (totalFramesProcessed < periodSizeInFrames) {
ma_device_callback_proc onData;
ma_uint32 framesRemaining = periodSizeInFrames - totalFramesProcessed;
ma_uint32 framesProcessed;
ma_uint32 framesToProcess = framesRemaining;
if (framesToProcess > capturedDeviceDataCapInFrames) {
framesToProcess = capturedDeviceDataCapInFrames;
}
result = ma_device_read__pulse(pDevice, capturedDeviceData, framesToProcess, &framesProcessed);
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
}
onData = pDevice->onData;
if (onData != NULL) {
pDevice->capture._dspFrameCount = framesToProcess;
pDevice->capture._dspFrames = capturedDeviceData;
for (;;) {
ma_uint8 capturedData[8192];
ma_uint8 playbackData[8192];
ma_uint32 capturedDataCapInFrames = sizeof(capturedData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
ma_uint32 playbackDataCapInFrames = sizeof(playbackData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
ma_uint32 capturedFramesToTryProcessing = ma_min(capturedDataCapInFrames, playbackDataCapInFrames);
ma_uint32 capturedFramesToProcess = (ma_uint32)ma_pcm_converter_read(&pDevice->capture.converter, capturedData, capturedFramesToTryProcessing);
if (capturedFramesToProcess == 0) {
break; /* Don't fire the data callback with zero frames. */
}
onData(pDevice, playbackData, capturedData, capturedFramesToProcess);
/* At this point the playbackData buffer should be holding data that needs to be written to the device. */
pDevice->playback._dspFrameCount = capturedFramesToProcess;
pDevice->playback._dspFrames = playbackData;
for (;;) {
ma_uint32 playbackDeviceFramesCount = (ma_uint32)ma_pcm_converter_read(&pDevice->playback.converter, playbackDeviceData, playbackDeviceDataCapInFrames);
if (playbackDeviceFramesCount == 0) {
break;
}
result = ma_device_write__pulse(pDevice, playbackDeviceData, playbackDeviceFramesCount, NULL);
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
}
if (playbackDeviceFramesCount < playbackDeviceDataCapInFrames) {
break;
}
}
if (capturedFramesToProcess < capturedFramesToTryProcessing) {
break;
}
/* In case an error happened from ma_device_write2__alsa()... */
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
}
}
}
totalFramesProcessed += framesProcessed;
}
} break;
case ma_device_type_capture:
{
ma_uint8 intermediaryBuffer[8192];
ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
ma_uint32 periodSizeInFrames = pDevice->capture.internalBufferSizeInFrames / pDevice->capture.internalPeriods;
ma_uint32 framesReadThisPeriod = 0;
while (framesReadThisPeriod < periodSizeInFrames) {
ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesReadThisPeriod;
ma_uint32 framesProcessed;
ma_uint32 framesToReadThisIteration = framesRemainingInPeriod;
if (framesToReadThisIteration > intermediaryBufferSizeInFrames) {
framesToReadThisIteration = intermediaryBufferSizeInFrames;
}
result = ma_device_read__pulse(pDevice, intermediaryBuffer, framesToReadThisIteration, &framesProcessed);
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
}
ma_device__send_frames_to_client(pDevice, framesProcessed, intermediaryBuffer);
framesReadThisPeriod += framesProcessed;
}
} break;
case ma_device_type_playback:
{
ma_uint8 intermediaryBuffer[8192];
ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
ma_uint32 periodSizeInFrames = pDevice->playback.internalBufferSizeInFrames / pDevice->playback.internalPeriods;
ma_uint32 framesWrittenThisPeriod = 0;
while (framesWrittenThisPeriod < periodSizeInFrames) {
ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesWrittenThisPeriod;
ma_uint32 framesProcessed;
ma_uint32 framesToWriteThisIteration = framesRemainingInPeriod;
if (framesToWriteThisIteration > intermediaryBufferSizeInFrames) {
framesToWriteThisIteration = intermediaryBufferSizeInFrames;
}
ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, intermediaryBuffer);
result = ma_device_write__pulse(pDevice, intermediaryBuffer, framesToWriteThisIteration, &framesProcessed);
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
}
framesWrittenThisPeriod += framesProcessed;
}
} break;
/* To silence a warning. Will never hit this. */
case ma_device_type_loopback:
default: break;
}
}
/* Here is where the device needs to be stopped. */
ma_device_stop__pulse(pDevice);
return result;
}
ma_result ma_context_uninit__pulse(ma_context* pContext)
{
......@@ -15973,9 +16147,10 @@ ma_result ma_context_init__pulse(const ma_context_config* pConfig, ma_context* p
pContext->onDeviceInit = ma_device_init__pulse;
pContext->onDeviceUninit = ma_device_uninit__pulse;
pContext->onDeviceStart = NULL;
pContext->onDeviceStop = ma_device_stop__pulse;
pContext->onDeviceWrite = ma_device_write__pulse;
pContext->onDeviceRead = ma_device_read__pulse;
pContext->onDeviceStop = NULL;
pContext->onDeviceWrite = NULL;
pContext->onDeviceRead = NULL;
pContext->onDeviceMainLoop = ma_device_main_loop__pulse;
if (pConfig->pulse.pApplicationName) {
pContext->pulse.pApplicationName = ma_copy_string(pConfig->pulse.pApplicationName);
......@@ -33568,7 +33743,7 @@ v0.9.7 - 2019-xx-xx
- If you need to capture from a specific output device, set the capture device ID to that of a playback device.
- Fix a crash when an error is posted in ma_device_init().
- Fix a compilation error when compiling for ARM architectures.
- Minor refactoring to the ALSA backend.
- Minor refactoring to the ALSA and PulseAudio backends.
v0.9.6 - 2019-08-04
- Add support for loading decoders using a wchar_t string for file paths.
......@@ -63,7 +63,7 @@ int main(int argc, char** argv)
#endif
ma_backend backend = ma_backend_alsa;
ma_backend backend = ma_backend_pulseaudio;
ma_context_config contextConfig = ma_context_config_init();
contextConfig.logCallback = log_callback;
......@@ -100,11 +100,11 @@ int main(int argc, char** argv)
deviceConfig.capture.pDeviceID = NULL;
deviceConfig.capture.format = ma_format_s16;
deviceConfig.capture.channels = 2;
deviceConfig.capture.shareMode = ma_share_mode_exclusive;
deviceConfig.capture.shareMode = ma_share_mode_shared;
deviceConfig.playback.pDeviceID = NULL;
deviceConfig.playback.format = ma_format_s16;
deviceConfig.playback.channels = 2;
deviceConfig.playback.shareMode = ma_share_mode_exclusive;
deviceConfig.playback.shareMode = ma_share_mode_shared;
deviceConfig.sampleRate = 50000;
//deviceConfig.bufferSizeInMilliseconds = 60;
deviceConfig.bufferSizeInFrames = 4096;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment