@@ -286,6 +286,11 @@ void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters,
286
286
userData, options, errorCallback );
287
287
}
288
288
289
+ RtAudioClientHandle *RtAudio :: getClientHandle( void )
290
+ {
291
+ return rtapi_->getClientHandle ();
292
+ }
293
+
289
294
// *************************************************** //
290
295
//
291
296
// Public RtApi definitions (see end of file for
@@ -497,6 +502,9 @@ unsigned int RtApi :: getStreamSampleRate( void )
497
502
return stream_.sampleRate ;
498
503
}
499
504
505
+ // Re-include RtAudio.h to get API-specific structs
506
+ #define RTAUDIO_API_SPECIFIC
507
+ #include " RtAudio.h"
500
508
501
509
// *************************************************** //
502
510
//
@@ -2013,19 +2021,28 @@ const char* RtApiCore :: getErrorCode( OSStatus code )
2013
2021
#include < unistd.h>
2014
2022
#include < cstdio>
2015
2023
2024
+ // A structure to hold various information related to the Jack API
2025
+ // implementation that can be exposed to caller. Same struct is
2026
+ // defined in RtAudio.h if RTAUDIO_API_SPECIFIC is defined.
2027
+ struct RtAudioClientHandleJack : public RtAudioClientHandle
2028
+ {
2029
+ jack_client_t *client = 0 ;
2030
+ jack_port_t **ports[2 ] = {0 ,0 };
2031
+ };
2032
+
2016
2033
// A structure to hold various information related to the Jack API
2017
2034
// implementation.
2018
2035
struct JackHandle {
2019
- jack_client_t *client;
2020
- jack_port_t **ports[2 ];
2036
+ RtAudioClientHandleJack ch;
2021
2037
std::string deviceName[2 ];
2022
2038
bool xrun[2 ];
2023
2039
pthread_cond_t condition;
2024
2040
int drainCounter; // Tracks callback counts when draining
2025
2041
bool internalDrain; // Indicates if stop is initiated from callback or not.
2026
2042
2027
2043
JackHandle ()
2028
- :client(0 ), drainCounter(0 ), internalDrain(false ) { ports[0 ] = 0 ; ports[1 ] = 0 ; xrun[0 ] = false ; xrun[1 ] = false ; }
2044
+ : drainCounter(0 ), internalDrain(false )
2045
+ { xrun[0 ] = false ; xrun[1 ] = false ; }
2029
2046
};
2030
2047
2031
2048
#if !defined(__RTAUDIO_DEBUG__)
@@ -2172,6 +2189,13 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
2172
2189
return info;
2173
2190
}
2174
2191
2192
+ RtAudioClientHandle *RtApiJack :: getClientHandle()
2193
+ {
2194
+ JackHandle *handle = (JackHandle *) stream_.apiHandle ;
2195
+
2196
+ return &handle->ch ;
2197
+ }
2198
+
2175
2199
static int jackCallbackHandler ( jack_nframes_t nframes, void *infoPointer )
2176
2200
{
2177
2201
CallbackInfo *info = (CallbackInfo *) infoPointer;
@@ -2216,8 +2240,8 @@ static int jackXrun( void *infoPointer )
2216
2240
{
2217
2241
JackHandle *handle = *((JackHandle **) infoPointer);
2218
2242
2219
- if ( handle->ports [0 ] ) handle->xrun [0 ] = true ;
2220
- if ( handle->ports [1 ] ) handle->xrun [1 ] = true ;
2243
+ if ( handle->ch . ports [0 ] ) handle->xrun [0 ] = true ;
2244
+ if ( handle->ch . ports [1 ] ) handle->xrun [1 ] = true ;
2221
2245
2222
2246
return 0 ;
2223
2247
}
@@ -2246,7 +2270,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
2246
2270
}
2247
2271
else {
2248
2272
// The handle must have been created on an earlier pass.
2249
- client = handle->client ;
2273
+ client = handle->ch . client ;
2250
2274
}
2251
2275
2252
2276
const char **ports;
@@ -2365,7 +2389,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
2365
2389
goto error;
2366
2390
}
2367
2391
stream_.apiHandle = (void *) handle;
2368
- handle->client = client;
2392
+ handle->ch . client = client;
2369
2393
}
2370
2394
handle->deviceName [mode] = deviceName;
2371
2395
@@ -2403,8 +2427,8 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
2403
2427
}
2404
2428
2405
2429
// Allocate memory for the Jack ports (channels) identifiers.
2406
- handle->ports [mode] = (jack_port_t **) malloc ( sizeof (jack_port_t *) * channels );
2407
- if ( handle->ports [mode] == NULL ) {
2430
+ handle->ch . ports [mode] = (jack_port_t **) malloc ( sizeof (jack_port_t *) * channels );
2431
+ if ( handle->ch . ports [mode] == NULL ) {
2408
2432
errorText_ = " RtApiJack::probeDeviceOpen: error allocating port memory." ;
2409
2433
goto error;
2410
2434
}
@@ -2419,25 +2443,26 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
2419
2443
stream_.mode = DUPLEX;
2420
2444
else {
2421
2445
stream_.mode = mode;
2422
- jack_set_process_callback ( handle->client , jackCallbackHandler, (void *) &stream_.callbackInfo );
2423
- jack_set_xrun_callback ( handle->client , jackXrun, (void *) &stream_.apiHandle );
2424
- jack_on_shutdown ( handle->client , jackShutdown, (void *) &stream_.callbackInfo );
2446
+ jack_set_process_callback ( handle->ch .client , jackCallbackHandler,
2447
+ (void *) &stream_.callbackInfo );
2448
+ jack_set_xrun_callback ( handle->ch .client , jackXrun, (void *) &stream_.apiHandle );
2449
+ jack_on_shutdown ( handle->ch .client , jackShutdown, (void *) &stream_.callbackInfo );
2425
2450
}
2426
2451
2427
2452
// Register our ports.
2428
2453
char label[64 ];
2429
2454
if ( mode == OUTPUT ) {
2430
2455
for ( unsigned int i=0 ; i<stream_.nUserChannels [0 ]; i++ ) {
2431
2456
snprintf ( label, 64 , " outport %d" , i );
2432
- handle->ports [0 ][i] = jack_port_register ( handle->client , (const char *)label,
2433
- JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );
2457
+ handle->ch . ports [0 ][i] = jack_port_register ( handle->ch . client , (const char *)label,
2458
+ JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );
2434
2459
}
2435
2460
}
2436
2461
else {
2437
2462
for ( unsigned int i=0 ; i<stream_.nUserChannels [1 ]; i++ ) {
2438
2463
snprintf ( label, 64 , " inport %d" , i );
2439
- handle->ports [1 ][i] = jack_port_register ( handle->client , (const char *)label,
2440
- JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 );
2464
+ handle->ch . ports [1 ][i] = jack_port_register ( handle->ch . client , (const char *)label,
2465
+ JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 );
2441
2466
}
2442
2467
}
2443
2468
@@ -2453,10 +2478,10 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
2453
2478
error:
2454
2479
if ( handle ) {
2455
2480
pthread_cond_destroy ( &handle->condition );
2456
- jack_client_close ( handle->client );
2481
+ jack_client_close ( handle->ch . client );
2457
2482
2458
- if ( handle->ports [0 ] ) free ( handle->ports [0 ] );
2459
- if ( handle->ports [1 ] ) free ( handle->ports [1 ] );
2483
+ if ( handle->ch . ports [0 ] ) free ( handle->ch . ports [0 ] );
2484
+ if ( handle->ch . ports [1 ] ) free ( handle->ch . ports [1 ] );
2460
2485
2461
2486
delete handle;
2462
2487
stream_.apiHandle = 0 ;
@@ -2489,14 +2514,14 @@ void RtApiJack :: closeStream( void )
2489
2514
if ( handle ) {
2490
2515
2491
2516
if ( stream_.state == STREAM_RUNNING )
2492
- jack_deactivate ( handle->client );
2517
+ jack_deactivate ( handle->ch . client );
2493
2518
2494
- jack_client_close ( handle->client );
2519
+ jack_client_close ( handle->ch . client );
2495
2520
}
2496
2521
2497
2522
if ( handle ) {
2498
- if ( handle->ports [0 ] ) free ( handle->ports [0 ] );
2499
- if ( handle->ports [1 ] ) free ( handle->ports [1 ] );
2523
+ if ( handle->ch . ports [0 ] ) free ( handle->ch . ports [0 ] );
2524
+ if ( handle->ch . ports [1 ] ) free ( handle->ch . ports [1 ] );
2500
2525
pthread_cond_destroy ( &handle->condition );
2501
2526
delete handle;
2502
2527
stream_.apiHandle = 0 ;
@@ -2532,7 +2557,7 @@ void RtApiJack :: startStream( void )
2532
2557
#endif
2533
2558
2534
2559
JackHandle *handle = (JackHandle *) stream_.apiHandle ;
2535
- int result = jack_activate ( handle->client );
2560
+ int result = jack_activate ( handle->ch . client );
2536
2561
if ( result ) {
2537
2562
errorText_ = " RtApiJack::startStream(): unable to activate JACK client!" ;
2538
2563
goto unlock;
@@ -2543,7 +2568,8 @@ void RtApiJack :: startStream( void )
2543
2568
// Get the list of available ports.
2544
2569
if ( shouldAutoconnect_ && (stream_.mode == OUTPUT || stream_.mode == DUPLEX) ) {
2545
2570
result = 1 ;
2546
- ports = jack_get_ports ( handle->client , handle->deviceName [0 ].c_str (), JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput);
2571
+ ports = jack_get_ports ( handle->ch .client , handle->deviceName [0 ].c_str (),
2572
+ JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput);
2547
2573
if ( ports == NULL ) {
2548
2574
errorText_ = " RtApiJack::startStream(): error determining available JACK input ports!" ;
2549
2575
goto unlock;
@@ -2555,7 +2581,8 @@ void RtApiJack :: startStream( void )
2555
2581
for ( unsigned int i=0 ; i<stream_.nUserChannels [0 ]; i++ ) {
2556
2582
result = 1 ;
2557
2583
if ( ports[ stream_.channelOffset [0 ] + i ] )
2558
- result = jack_connect ( handle->client , jack_port_name ( handle->ports [0 ][i] ), ports[ stream_.channelOffset [0 ] + i ] );
2584
+ result = jack_connect ( handle->ch .client , jack_port_name ( handle->ch .ports [0 ][i] ),
2585
+ ports[ stream_.channelOffset [0 ] + i ] );
2559
2586
if ( result ) {
2560
2587
free ( ports );
2561
2588
errorText_ = " RtApiJack::startStream(): error connecting output ports!" ;
@@ -2567,7 +2594,8 @@ void RtApiJack :: startStream( void )
2567
2594
2568
2595
if ( shouldAutoconnect_ && (stream_.mode == INPUT || stream_.mode == DUPLEX) ) {
2569
2596
result = 1 ;
2570
- ports = jack_get_ports ( handle->client , handle->deviceName [1 ].c_str (), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput );
2597
+ ports = jack_get_ports ( handle->ch .client , handle->deviceName [1 ].c_str (),
2598
+ JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput );
2571
2599
if ( ports == NULL ) {
2572
2600
errorText_ = " RtApiJack::startStream(): error determining available JACK output ports!" ;
2573
2601
goto unlock;
@@ -2577,7 +2605,8 @@ void RtApiJack :: startStream( void )
2577
2605
for ( unsigned int i=0 ; i<stream_.nUserChannels [1 ]; i++ ) {
2578
2606
result = 1 ;
2579
2607
if ( ports[ stream_.channelOffset [1 ] + i ] )
2580
- result = jack_connect ( handle->client , ports[ stream_.channelOffset [1 ] + i ], jack_port_name ( handle->ports [1 ][i] ) );
2608
+ result = jack_connect ( handle->ch .client , ports[ stream_.channelOffset [1 ] + i ],
2609
+ jack_port_name ( handle->ch .ports [1 ][i] ) );
2581
2610
if ( result ) {
2582
2611
free ( ports );
2583
2612
errorText_ = " RtApiJack::startStream(): error connecting input ports!" ;
@@ -2614,7 +2643,7 @@ void RtApiJack :: stopStream( void )
2614
2643
}
2615
2644
}
2616
2645
2617
- jack_deactivate ( handle->client );
2646
+ jack_deactivate ( handle->ch . client );
2618
2647
stream_.state = STREAM_STOPPED;
2619
2648
}
2620
2649
@@ -2711,7 +2740,8 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
2711
2740
if ( handle->drainCounter > 1 ) { // write zeros to the output stream
2712
2741
2713
2742
for ( unsigned int i=0 ; i<stream_.nDeviceChannels [0 ]; i++ ) {
2714
- jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer ( handle->ports [0 ][i], (jack_nframes_t ) nframes );
2743
+ jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer (
2744
+ handle->ch .ports [0 ][i], (jack_nframes_t ) nframes );
2715
2745
memset ( jackbuffer, 0 , bufferBytes );
2716
2746
}
2717
2747
@@ -2721,13 +2751,15 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
2721
2751
convertBuffer ( stream_.deviceBuffer , stream_.userBuffer [0 ], stream_.convertInfo [0 ] );
2722
2752
2723
2753
for ( unsigned int i=0 ; i<stream_.nDeviceChannels [0 ]; i++ ) {
2724
- jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer ( handle->ports [0 ][i], (jack_nframes_t ) nframes );
2754
+ jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer (
2755
+ handle->ch .ports [0 ][i], (jack_nframes_t ) nframes );
2725
2756
memcpy ( jackbuffer, &stream_.deviceBuffer [i*bufferBytes], bufferBytes );
2726
2757
}
2727
2758
}
2728
2759
else { // no buffer conversion
2729
2760
for ( unsigned int i=0 ; i<stream_.nUserChannels [0 ]; i++ ) {
2730
- jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer ( handle->ports [0 ][i], (jack_nframes_t ) nframes );
2761
+ jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer (
2762
+ handle->ch .ports [0 ][i], (jack_nframes_t ) nframes );
2731
2763
memcpy ( jackbuffer, &stream_.userBuffer [0 ][i*bufferBytes], bufferBytes );
2732
2764
}
2733
2765
}
@@ -2743,14 +2775,16 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
2743
2775
2744
2776
if ( stream_.doConvertBuffer [1 ] ) {
2745
2777
for ( unsigned int i=0 ; i<stream_.nDeviceChannels [1 ]; i++ ) {
2746
- jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer ( handle->ports [1 ][i], (jack_nframes_t ) nframes );
2778
+ jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer (
2779
+ handle->ch .ports [1 ][i], (jack_nframes_t ) nframes );
2747
2780
memcpy ( &stream_.deviceBuffer [i*bufferBytes], jackbuffer, bufferBytes );
2748
2781
}
2749
2782
convertBuffer ( stream_.userBuffer [1 ], stream_.deviceBuffer , stream_.convertInfo [1 ] );
2750
2783
}
2751
2784
else { // no buffer conversion
2752
2785
for ( unsigned int i=0 ; i<stream_.nUserChannels [1 ]; i++ ) {
2753
- jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer ( handle->ports [1 ][i], (jack_nframes_t ) nframes );
2786
+ jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer (
2787
+ handle->ch .ports [1 ][i], (jack_nframes_t ) nframes );
2754
2788
memcpy ( &stream_.userBuffer [1 ][i*bufferBytes], jackbuffer, bufferBytes );
2755
2789
}
2756
2790
}
@@ -8489,13 +8523,17 @@ static const rtaudio_pa_format_mapping_t supported_sampleformats[] = {
8489
8523
{RTAUDIO_FLOAT32, PA_SAMPLE_FLOAT32LE},
8490
8524
{0 , PA_SAMPLE_INVALID}};
8491
8525
8526
+ struct RtAudioClientHandlePulse : public RtAudioClientHandle
8527
+ {
8528
+ pa_simple *s_play = nullptr ;
8529
+ pa_simple *s_rec = nullptr ;
8530
+ };
8531
+
8492
8532
struct PulseAudioHandle {
8493
- pa_simple *s_play;
8494
- pa_simple *s_rec;
8533
+ RtAudioClientHandlePulse ch;
8495
8534
pthread_t thread;
8496
8535
pthread_cond_t runnable_cv;
8497
- bool runnable;
8498
- PulseAudioHandle () : s_play(0 ), s_rec(0 ), runnable(false ) { }
8536
+ bool runnable = false ;
8499
8537
};
8500
8538
8501
8539
static void rt_pa_mainloop_api_quit (int ret) {
@@ -8737,12 +8775,12 @@ void RtApiPulse::closeStream( void )
8737
8775
MUTEX_UNLOCK ( &stream_.mutex );
8738
8776
8739
8777
pthread_join ( pah->thread , 0 );
8740
- if ( pah->s_play ) {
8741
- pa_simple_flush ( pah->s_play , NULL );
8742
- pa_simple_free ( pah->s_play );
8778
+ if ( pah->ch . s_play ) {
8779
+ pa_simple_flush ( pah->ch . s_play , NULL );
8780
+ pa_simple_free ( pah->ch . s_play );
8743
8781
}
8744
- if ( pah->s_rec )
8745
- pa_simple_free ( pah->s_rec );
8782
+ if ( pah->ch . s_rec )
8783
+ pa_simple_free ( pah->ch . s_rec );
8746
8784
8747
8785
pthread_cond_destroy ( &pah->runnable_cv );
8748
8786
delete pah;
@@ -8817,7 +8855,7 @@ void RtApiPulse::callbackEvent( void )
8817
8855
bytes = stream_.nUserChannels [OUTPUT] * stream_.bufferSize *
8818
8856
formatBytes ( stream_.userFormat );
8819
8857
8820
- if ( pa_simple_write ( pah->s_play , pulse_out, bytes, &pa_error ) < 0 ) {
8858
+ if ( pa_simple_write ( pah->ch . s_play , pulse_out, bytes, &pa_error ) < 0 ) {
8821
8859
errorStream_ << " RtApiPulse::callbackEvent: audio write error, " <<
8822
8860
pa_strerror ( pa_error ) << " ." ;
8823
8861
errorText_ = errorStream_.str ();
@@ -8833,7 +8871,7 @@ void RtApiPulse::callbackEvent( void )
8833
8871
bytes = stream_.nUserChannels [INPUT] * stream_.bufferSize *
8834
8872
formatBytes ( stream_.userFormat );
8835
8873
8836
- if ( pa_simple_read ( pah->s_rec , pulse_in, bytes, &pa_error ) < 0 ) {
8874
+ if ( pa_simple_read ( pah->ch . s_rec , pulse_in, bytes, &pa_error ) < 0 ) {
8837
8875
errorStream_ << " RtApiPulse::callbackEvent: audio read error, " <<
8838
8876
pa_strerror ( pa_error ) << " ." ;
8839
8877
errorText_ = errorStream_.str ();
@@ -8902,9 +8940,9 @@ void RtApiPulse::stopStream( void )
8902
8940
8903
8941
if ( pah ) {
8904
8942
pah->runnable = false ;
8905
- if ( pah->s_play ) {
8943
+ if ( pah->ch . s_play ) {
8906
8944
int pa_error;
8907
- if ( pa_simple_drain ( pah->s_play , &pa_error ) < 0 ) {
8945
+ if ( pa_simple_drain ( pah->ch . s_play , &pa_error ) < 0 ) {
8908
8946
errorStream_ << " RtApiPulse::stopStream: error draining output device, " <<
8909
8947
pa_strerror ( pa_error ) << " ." ;
8910
8948
errorText_ = errorStream_.str ();
@@ -8939,9 +8977,9 @@ void RtApiPulse::abortStream( void )
8939
8977
8940
8978
if ( pah ) {
8941
8979
pah->runnable = false ;
8942
- if ( pah->s_play ) {
8980
+ if ( pah->ch . s_play ) {
8943
8981
int pa_error;
8944
- if ( pa_simple_flush ( pah->s_play , &pa_error ) < 0 ) {
8982
+ if ( pa_simple_flush ( pah->ch . s_play , &pa_error ) < 0 ) {
8945
8983
errorStream_ << " RtApiPulse::abortStream: error flushing output device, " <<
8946
8984
pa_strerror ( pa_error ) << " ." ;
8947
8985
errorText_ = errorStream_.str ();
@@ -9121,17 +9159,17 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
9121
9159
buffer_attr.fragsize = bufferBytes;
9122
9160
buffer_attr.maxlength = -1 ;
9123
9161
9124
- pah->s_rec = pa_simple_new ( NULL , streamName.c_str (), PA_STREAM_RECORD,
9162
+ pah->ch . s_rec = pa_simple_new ( NULL , streamName.c_str (), PA_STREAM_RECORD,
9125
9163
dev_input, " Record" , &ss, NULL , &buffer_attr, &error );
9126
- if ( !pah->s_rec ) {
9164
+ if ( !pah->ch . s_rec ) {
9127
9165
errorText_ = " RtApiPulse::probeDeviceOpen: error connecting input to PulseAudio server." ;
9128
9166
goto error;
9129
9167
}
9130
9168
break ;
9131
9169
case OUTPUT:
9132
- pah->s_play = pa_simple_new ( NULL , streamName.c_str (), PA_STREAM_PLAYBACK,
9170
+ pah->ch . s_play = pa_simple_new ( NULL , streamName.c_str (), PA_STREAM_PLAYBACK,
9133
9171
dev_output, " Playback" , &ss, NULL , NULL , &error );
9134
- if ( !pah->s_play ) {
9172
+ if ( !pah->ch . s_play ) {
9135
9173
errorText_ = " RtApiPulse::probeDeviceOpen: error connecting output to PulseAudio server." ;
9136
9174
goto error;
9137
9175
}
@@ -9229,6 +9267,12 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
9229
9267
return FAILURE;
9230
9268
}
9231
9269
9270
+ RtAudioClientHandle* RtApiPulse :: getClientHandle( void )
9271
+ {
9272
+ PulseAudioHandle *pah = static_cast <PulseAudioHandle *>( stream_.apiHandle );
9273
+ return &pah->ch ;
9274
+ }
9275
+
9232
9276
// ******************** End of __LINUX_PULSE__ *********************//
9233
9277
#endif
9234
9278
0 commit comments