@@ -195,6 +195,8 @@ typedef int (* ma_pw_loop_set_name_proc )(struct
195195typedef void (* ma_pw_loop_enter_proc )(struct ma_pw_loop * loop );
196196typedef void (* ma_pw_loop_leave_proc )(struct ma_pw_loop * loop );
197197typedef int (* ma_pw_loop_iterate_proc )(struct ma_pw_loop * loop , int timeout );
198+ typedef struct spa_source * (* ma_pw_loop_add_event_proc )(struct ma_pw_loop * loop , void (* func )(void * data , ma_uint64 count ), void * data );
199+ typedef int (* ma_pw_loop_signal_event_proc )(struct ma_pw_loop * loop , struct spa_source * source );
198200typedef struct ma_pw_thread_loop * (* ma_pw_thread_loop_new_proc )(const char * name , const struct spa_dict * props );
199201typedef void (* ma_pw_thread_loop_destroy_proc )(struct ma_pw_thread_loop * loop );
200202typedef struct ma_pw_loop * (* ma_pw_thread_loop_get_loop_proc )(struct ma_pw_thread_loop * loop );
@@ -237,6 +239,8 @@ typedef struct
237239 ma_pw_loop_enter_proc pw_loop_enter ;
238240 ma_pw_loop_leave_proc pw_loop_leave ;
239241 ma_pw_loop_iterate_proc pw_loop_iterate ;
242+ ma_pw_loop_add_event_proc pw_loop_add_event ;
243+ ma_pw_loop_signal_event_proc pw_loop_signal_event ;
240244 ma_pw_thread_loop_new_proc pw_thread_loop_new ;
241245 ma_pw_thread_loop_destroy_proc pw_thread_loop_destroy ;
242246 ma_pw_thread_loop_get_loop_proc pw_thread_loop_get_loop ;
@@ -297,6 +301,7 @@ typedef struct
297301 struct ma_pw_loop * pLoop ;
298302 struct ma_pw_context * pContext ;
299303 struct ma_pw_core * pCore ;
304+ struct spa_source * pWakeup ; /* This is for waking up the loop which we need to do after each data processing callback and the miniaudio wakeup callback. */
300305 ma_pipewire_stream_state playback ;
301306 ma_pipewire_stream_state capture ;
302307 struct
@@ -463,7 +468,7 @@ static ma_device_state_pipewire* ma_device_get_backend_state__pipewire(ma_device
463468}
464469
465470
466- static ma_result ma_device_step__pipewire (ma_device * pDevice );
471+ static ma_result ma_device_step__pipewire (ma_device * pDevice , ma_blocking_mode blockingMode );
467472
468473
469474static void ma_backend_info__pipewire (ma_device_backend_info * pBackendInfo )
@@ -518,6 +523,8 @@ static ma_result ma_context_init__pipewire(ma_context* pContext, const void* pCo
518523 pContextStatePipeWire -> pw_loop_enter = (ma_pw_loop_enter_proc )ma_dlsym (pLog , hPipeWire , "pw_loop_enter" );
519524 pContextStatePipeWire -> pw_loop_leave = (ma_pw_loop_leave_proc )ma_dlsym (pLog , hPipeWire , "pw_loop_leave" );
520525 pContextStatePipeWire -> pw_loop_iterate = (ma_pw_loop_iterate_proc )ma_dlsym (pLog , hPipeWire , "pw_loop_iterate" );
526+ pContextStatePipeWire -> pw_loop_add_event = (ma_pw_loop_add_event_proc )ma_dlsym (pLog , hPipeWire , "pw_loop_add_event" );
527+ pContextStatePipeWire -> pw_loop_signal_event = (ma_pw_loop_signal_event_proc )ma_dlsym (pLog , hPipeWire , "pw_loop_signal_event" );
521528 pContextStatePipeWire -> pw_thread_loop_new = (ma_pw_thread_loop_new_proc )ma_dlsym (pLog , hPipeWire , "pw_thread_loop_new" );
522529 pContextStatePipeWire -> pw_thread_loop_destroy = (ma_pw_thread_loop_destroy_proc )ma_dlsym (pLog , hPipeWire , "pw_thread_loop_destroy" );
523530 pContextStatePipeWire -> pw_thread_loop_get_loop = (ma_pw_thread_loop_get_loop_proc )ma_dlsym (pLog , hPipeWire , "pw_thread_loop_get_loop" );
@@ -1252,6 +1259,9 @@ static void ma_stream_event_process__pipewire(void* pUserData, ma_device_type de
12521259 pBuffer -> buffer -> datas [0 ].chunk -> size = frameCount * bytesPerFrame ;
12531260
12541261 pContextStatePipeWire -> pw_stream_queue_buffer (pStreamState -> pStream , pBuffer );
1262+
1263+ /* We need to make sure the loop is woken up so we can refill the intermediary buffer in the step function. */
1264+ pContextStatePipeWire -> pw_loop_signal_event (pDeviceStatePipeWire -> pLoop , pDeviceStatePipeWire -> pWakeup );
12551265}
12561266
12571267
@@ -1419,6 +1429,13 @@ static ma_result ma_device_init_internal__pipewire(ma_device* pDevice, ma_contex
14191429 return MA_SUCCESS ;
14201430}
14211431
1432+ static void ma_device_on_wakupe__pipewire (void * pUserData , ma_uint64 count )
1433+ {
1434+ /* Nothing to do here. This is only used for waking up the loop. */
1435+ (void )pUserData ;
1436+ (void )count ;
1437+ }
1438+
14221439static ma_result ma_device_init__pipewire (ma_device * pDevice , const void * pDeviceBackendConfig , ma_device_descriptor * pDescriptorPlayback , ma_device_descriptor * pDescriptorCapture , void * * ppDeviceState )
14231440{
14241441 ma_result result ;
@@ -1503,6 +1520,17 @@ static ma_result ma_device_init__pipewire(ma_device* pDevice, const void* pDevic
15031520 return result ;
15041521 }
15051522
1523+ /* We need an event for waking up the loop. */
1524+ pDeviceStatePipeWire -> pWakeup = pContextStatePipeWire -> pw_loop_add_event (pLoop , ma_device_on_wakupe__pipewire , pDeviceStatePipeWire );
1525+ if (pDeviceStatePipeWire -> pWakeup == NULL ) {
1526+ ma_log_postf (ma_device_get_log (pDevice ), MA_LOG_LEVEL_ERROR , "Failed to create PipeWire loop wakeup event." );
1527+ pContextStatePipeWire -> pw_core_disconnect (pCore );
1528+ pContextStatePipeWire -> pw_context_destroy (pPipeWireContext );
1529+ pContextStatePipeWire -> pw_loop_destroy (pLoop );
1530+ ma_free (pDeviceStatePipeWire , ma_device_get_allocation_callbacks (pDevice ));
1531+ return MA_ERROR ;
1532+ }
1533+
15061534 * ppDeviceState = pDeviceStatePipeWire ;
15071535
15081536 return MA_SUCCESS ;
@@ -1540,7 +1568,7 @@ static ma_result ma_device_start__pipewire(ma_device* pDevice)
15401568 ma_context_state_pipewire * pContextStatePipeWire = ma_context_get_backend_state__pipewire (ma_device_get_context (pDevice ));
15411569
15421570 /* Prepare our buffers before starting the streams. To do this we just need to step. */
1543- ma_device_step__pipewire (pDevice );
1571+ ma_device_step__pipewire (pDevice , MA_BLOCKING_MODE_NON_BLOCKING );
15441572
15451573 if (pDeviceStatePipeWire -> capture .pStream != NULL ) {
15461574 pContextStatePipeWire -> pw_stream_set_active (pDeviceStatePipeWire -> capture .pStream , MA_TRUE );
@@ -1569,106 +1597,78 @@ static ma_result ma_device_stop__pipewire(ma_device* pDevice)
15691597 return MA_SUCCESS ;
15701598}
15711599
1572-
1573- static ma_result ma_device_wait__pipewire (ma_device * pDevice )
1600+ static ma_result ma_device_step__pipewire (ma_device * pDevice , ma_blocking_mode blockingMode )
15741601{
15751602 ma_device_state_pipewire * pDeviceStatePipeWire = ma_device_get_backend_state__pipewire (pDevice );
15761603 ma_context_state_pipewire * pContextStatePipeWire = ma_context_get_backend_state__pipewire (ma_device_get_context (pDevice ));
15771604 ma_device_type deviceType = ma_device_get_type (pDevice );
1605+ int timeout ;
1606+ ma_bool32 hasProcessedData = MA_FALSE ;
15781607
1579- for (;;) {
1580- int iterateResult ;
1581-
1582- if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex ) {
1583- if (ma_pcm_rb_available_read (& pDeviceStatePipeWire -> capture .rb ) > 0 ) {
1584- return MA_SUCCESS ;
1585- }
1586- }
1587- if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex ) {
1588- if (ma_pcm_rb_available_write (& pDeviceStatePipeWire -> playback .rb ) > 0 ) {
1589- return MA_SUCCESS ;
1590- }
1591- }
1592-
1593- iterateResult = pContextStatePipeWire -> pw_loop_iterate (pDeviceStatePipeWire -> pLoop , -1 );
1594- if (iterateResult < 0 ) {
1595- /*
1596- Getting here means the loop iteration failed. I've had this happen in cases where we really don't want to
1597- be stopping the device, one example being when I insert a breakpoint while debugging. I'm just going to
1598- break from the loop to ensure we don't get stuck.
1599- */
1600- ma_log_postf (ma_device_get_log (pDevice ), MA_LOG_LEVEL_WARNING , "PipeWire loop iterate failed." );
1601- break ;
1602- }
1608+ if (blockingMode == MA_BLOCKING_MODE_BLOCKING ) {
1609+ timeout = -1 ;
1610+ } else {
1611+ timeout = 0 ;
16031612 }
16041613
1605- return MA_SUCCESS ;
1606- }
1607-
1608- static ma_result ma_device_step__pipewire (ma_device * pDevice )
1609- {
1610- ma_device_state_pipewire * pDeviceStatePipeWire = ma_device_get_backend_state__pipewire (pDevice );
1611- ma_context_state_pipewire * pContextStatePipeWire = ma_context_get_backend_state__pipewire (ma_device_get_context (pDevice ));
1612- ma_device_type deviceType = ma_device_get_type (pDevice );
1613-
1614- pContextStatePipeWire -> pw_loop_iterate (pDeviceStatePipeWire -> pLoop , 0 );
1615-
1616- if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex ) {
1617- ma_uint32 framesAvailable ;
1614+ /* We will keep looping until we've processed some data. This should keep our stepping in time with data processing. */
1615+ for (;;) {
1616+ pContextStatePipeWire -> pw_loop_iterate (pDeviceStatePipeWire -> pLoop , timeout );
16181617
1619- framesAvailable = ma_pcm_rb_available_read (& pDeviceStatePipeWire -> capture .rb );
1620- if (framesAvailable > 0 ) {
1621- /*printf("framesAvailable (Capture): %d\n", (int)framesAvailable);*/
1618+ if (!ma_device_is_started (pDevice )) {
1619+ return MA_DEVICE_NOT_STARTED ;
16221620 }
16231621
1624- while (framesAvailable > 0 ) {
1625- void * pMappedBuffer ;
1626- ma_uint32 framesToRead = framesAvailable ;
1627- ma_result result ;
1622+ /* We want to handle both playback and capture in a single iteration for duplex mode. */
1623+ if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex ) {
1624+ ma_uint32 framesAvailable ;
16281625
1629- result = ma_pcm_rb_acquire_read (& pDeviceStatePipeWire -> capture .rb , & framesToRead , & pMappedBuffer );
1630- if (result == MA_SUCCESS ) {
1631- ma_device_handle_backend_data_callback (pDevice , NULL , pMappedBuffer , framesToRead );
1626+ framesAvailable = ma_pcm_rb_available_read (& pDeviceStatePipeWire -> capture .rb );
1627+ if (framesAvailable > 0 ) {
1628+ hasProcessedData = MA_TRUE ;
1629+ }
16321630
1633- result = ma_pcm_rb_commit_read (& pDeviceStatePipeWire -> capture .rb , framesToRead );
1634- framesAvailable -= framesToRead ;
1631+ while (framesAvailable > 0 ) {
1632+ void * pMappedBuffer ;
1633+ ma_uint32 framesToRead = framesAvailable ;
1634+ ma_result result ;
16351635
1636- if (result != MA_SUCCESS ) {
1637- ma_log_postf (ma_device_get_log (pDevice ), MA_LOG_LEVEL_ERROR , "(PipeWire) Failed to commit read to ring buffer." );
1636+ result = ma_pcm_rb_acquire_read (& pDeviceStatePipeWire -> capture .rb , & framesToRead , & pMappedBuffer );
1637+ if (result == MA_SUCCESS ) {
1638+ ma_device_handle_backend_data_callback (pDevice , NULL , pMappedBuffer , framesToRead );
1639+
1640+ result = ma_pcm_rb_commit_read (& pDeviceStatePipeWire -> capture .rb , framesToRead );
1641+ framesAvailable -= framesToRead ;
16381642 }
1639- } else {
1640- ma_log_postf (ma_device_get_log (pDevice ), MA_LOG_LEVEL_ERROR , "(PipeWire) Failed to acquire read to ring buffer." );
16411643 }
16421644 }
1643- }
1644-
1645- if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex ) {
1646- ma_uint32 framesAvailable ;
1647-
1648- framesAvailable = ma_pcm_rb_available_write (& pDeviceStatePipeWire -> playback .rb );
1649- if (framesAvailable > 0 ) {
1650- /*printf("framesAvailable (Playback): %d\n", (int)framesAvailable);*/
1651- }
1645+
1646+ if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex ) {
1647+ ma_uint32 framesAvailable ;
16521648
1653- while ( framesAvailable > 0 ) {
1654- void * pMappedBuffer ;
1655- ma_uint32 framesToWrite = framesAvailable ;
1656- ma_result result ;
1649+ framesAvailable = ma_pcm_rb_available_write ( & pDeviceStatePipeWire -> playback . rb );
1650+ if ( framesAvailable > 0 ) {
1651+ hasProcessedData = MA_TRUE ;
1652+ }
16571653
1658- result = ma_pcm_rb_acquire_write (& pDeviceStatePipeWire -> playback .rb , & framesToWrite , & pMappedBuffer );
1659- if (result == MA_SUCCESS ) {
1660- ma_device_handle_backend_data_callback (pDevice , pMappedBuffer , NULL , framesToWrite );
1654+ while (framesAvailable > 0 ) {
1655+ void * pMappedBuffer ;
1656+ ma_uint32 framesToWrite = framesAvailable ;
1657+ ma_result result ;
16611658
1662- result = ma_pcm_rb_commit_write (& pDeviceStatePipeWire -> playback .rb , framesToWrite );
1663- framesAvailable -= framesToWrite ;
1659+ result = ma_pcm_rb_acquire_write (& pDeviceStatePipeWire -> playback .rb , & framesToWrite , & pMappedBuffer );
1660+ if (result == MA_SUCCESS ) {
1661+ ma_device_handle_backend_data_callback (pDevice , pMappedBuffer , NULL , framesToWrite );
16641662
1665- if ( result != MA_SUCCESS ) {
1666- ma_log_postf ( ma_device_get_log ( pDevice ), MA_LOG_LEVEL_ERROR , "(PipeWire) Failed to commit write to ring buffer." ) ;
1663+ result = ma_pcm_rb_commit_write ( & pDeviceStatePipeWire -> playback . rb , framesToWrite );
1664+ framesAvailable -= framesToWrite ;
16671665 }
1668- } else {
1669- ma_log_postf (ma_device_get_log (pDevice ), MA_LOG_LEVEL_ERROR , "(PipeWire) Failed to acquire write to ring buffer." );
16701666 }
16711667 }
1668+
1669+ if (hasProcessedData ) {
1670+ break ;
1671+ }
16721672 }
16731673
16741674 return MA_SUCCESS ;
@@ -1677,21 +1677,19 @@ static ma_result ma_device_step__pipewire(ma_device* pDevice)
16771677static void ma_device_loop__pipewire (ma_device * pDevice )
16781678{
16791679 for (;;) {
1680- ma_result result = ma_device_wait__pipewire (pDevice );
1680+ ma_result result = ma_device_step__pipewire (pDevice , MA_BLOCKING_MODE_BLOCKING );
16811681 if (result != MA_SUCCESS ) {
16821682 break ;
16831683 }
1684+ }
1685+ }
16841686
1685- /* If the wait terminated due to the device being stopped, abort now. */
1686- if (! ma_device_is_started ( pDevice )) {
1687- break ;
1688- }
1687+ static void ma_device_wake__pipewire ( ma_device * pDevice )
1688+ {
1689+ ma_device_state_pipewire * pDeviceStatePipeWire = ma_device_get_backend_state__pipewire ( pDevice ) ;
1690+ ma_context_state_pipewire * pContextStatePipeWire = ma_context_get_backend_state__pipewire ( ma_device_get_context ( pDevice ));
16891691
1690- result = ma_device_step__pipewire (pDevice );
1691- if (result != MA_SUCCESS ) {
1692- break ;
1693- }
1694- }
1692+ pContextStatePipeWire -> pw_loop_signal_event (pDeviceStatePipeWire -> pLoop , pDeviceStatePipeWire -> pWakeup );
16951693}
16961694
16971695
@@ -1708,7 +1706,7 @@ static ma_device_backend_vtable ma_gDeviceBackendVTable_PipeWire =
17081706 NULL , /* onDeviceRead */
17091707 NULL , /* onDeviceWrite */
17101708 ma_device_loop__pipewire ,
1711- NULL /* onDeviceWakeup */
1709+ ma_device_wake__pipewire
17121710};
17131711
17141712ma_device_backend_vtable * ma_device_backend_pipewire = & ma_gDeviceBackendVTable_PipeWire ;
0 commit comments