/[pcsx2_0.9.7]/trunk/3rdparty/portaudio/src/hostapi/jack/pa_jack.c
ViewVC logotype

Contents of /trunk/3rdparty/portaudio/src/hostapi/jack/pa_jack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 273 - (show annotations) (download)
Fri Nov 12 01:10:22 2010 UTC (9 years, 2 months ago) by william
File MIME type: text/plain
File size: 63113 byte(s)
Auto Commited Import of: pcsx2-0.9.7-DEBUG (upstream: v0.9.7.4013 local: v0.9.7.197-latest) in ./trunk
1 /*
2 * $Id: pa_jack.c 1541 2010-09-22 06:33:47Z dmitrykos $
3 * PortAudio Portable Real-Time Audio Library
4 * Latest Version at: http://www.portaudio.com
5 * JACK Implementation by Joshua Haberman
6 *
7 * Copyright (c) 2004 Stefan Westerfeld <stefan@space.twc.de>
8 * Copyright (c) 2004 Arve Knudsen <aknuds-1@broadpark.no>
9 * Copyright (c) 2002 Joshua Haberman <joshua@haberman.com>
10 *
11 * Based on the Open Source API proposed by Ross Bencina
12 * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining
15 * a copy of this software and associated documentation files
16 * (the "Software"), to deal in the Software without restriction,
17 * including without limitation the rights to use, copy, modify, merge,
18 * publish, distribute, sublicense, and/or sell copies of the Software,
19 * and to permit persons to whom the Software is furnished to do so,
20 * subject to the following conditions:
21 *
22 * The above copyright notice and this permission notice shall be
23 * included in all copies or substantial portions of the Software.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
28 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
29 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
30 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 */
33
34 /*
35 * The text above constitutes the entire PortAudio license; however,
36 * the PortAudio community also makes the following non-binding requests:
37 *
38 * Any person wishing to distribute modifications to the Software is
39 * requested to send the modifications to the original developer so that
40 * they can be incorporated into the canonical version. It is also
41 * requested that these non-binding requests be included along with the
42 * license above.
43 */
44
45 /**
46 @file
47 @ingroup hostapi_src
48 */
49
50 #include <string.h>
51 #include <regex.h>
52 #include <stdlib.h>
53 #include <stdio.h>
54 #include <assert.h>
55 #include <sys/types.h>
56 #include <unistd.h>
57 #include <errno.h> /* EBUSY */
58 #include <signal.h> /* sig_atomic_t */
59 #include <math.h>
60 #include <semaphore.h>
61
62 #include <jack/types.h>
63 #include <jack/jack.h>
64
65 #include "pa_util.h"
66 #include "pa_hostapi.h"
67 #include "pa_stream.h"
68 #include "pa_process.h"
69 #include "pa_allocation.h"
70 #include "pa_cpuload.h"
71 #include "pa_ringbuffer.h"
72 #include "pa_debugprint.h"
73
74 static pthread_t mainThread_;
75 static char *jackErr_ = NULL;
76 static const char* clientName_ = "PortAudio";
77
78 #define STRINGIZE_HELPER(expr) #expr
79 #define STRINGIZE(expr) STRINGIZE_HELPER(expr)
80
81 /* Check PaError */
82 #define ENSURE_PA(expr) \
83 do { \
84 PaError paErr; \
85 if( (paErr = (expr)) < paNoError ) \
86 { \
87 if( (paErr) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \
88 { \
89 const char *err = jackErr_; \
90 if (! err ) err = "unknown error"; \
91 PaUtil_SetLastHostErrorInfo( paJACK, -1, err ); \
92 } \
93 PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
94 result = paErr; \
95 goto error; \
96 } \
97 } while( 0 )
98
99 #define UNLESS(expr, code) \
100 do { \
101 if( (expr) == 0 ) \
102 { \
103 if( (code) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \
104 { \
105 const char *err = jackErr_; \
106 if (!err) err = "unknown error"; \
107 PaUtil_SetLastHostErrorInfo( paJACK, -1, err ); \
108 } \
109 PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
110 result = (code); \
111 goto error; \
112 } \
113 } while( 0 )
114
115 #define ASSERT_CALL(expr, success) \
116 do { \
117 int err = (expr); \
118 assert( err == success ); \
119 } while( 0 )
120
121 /*
122 * Functions that directly map to the PortAudio stream interface
123 */
124
125 static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
126 static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
127 const PaStreamParameters *inputParameters,
128 const PaStreamParameters *outputParameters,
129 double sampleRate );
130 static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
131 PaStream** s,
132 const PaStreamParameters *inputParameters,
133 const PaStreamParameters *outputParameters,
134 double sampleRate,
135 unsigned long framesPerBuffer,
136 PaStreamFlags streamFlags,
137 PaStreamCallback *streamCallback,
138 void *userData );
139 static PaError CloseStream( PaStream* stream );
140 static PaError StartStream( PaStream *stream );
141 static PaError StopStream( PaStream *stream );
142 static PaError AbortStream( PaStream *stream );
143 static PaError IsStreamStopped( PaStream *s );
144 static PaError IsStreamActive( PaStream *stream );
145 /*static PaTime GetStreamInputLatency( PaStream *stream );*/
146 /*static PaTime GetStreamOutputLatency( PaStream *stream );*/
147 static PaTime GetStreamTime( PaStream *stream );
148 static double GetStreamCpuLoad( PaStream* stream );
149
150
151 /*
152 * Data specific to this API
153 */
154
155 struct PaJackStream;
156
157 typedef struct
158 {
159 PaUtilHostApiRepresentation commonHostApiRep;
160 PaUtilStreamInterface callbackStreamInterface;
161 PaUtilStreamInterface blockingStreamInterface;
162
163 PaUtilAllocationGroup *deviceInfoMemory;
164
165 jack_client_t *jack_client;
166 int jack_buffer_size;
167 PaHostApiIndex hostApiIndex;
168
169 pthread_mutex_t mtx;
170 pthread_cond_t cond;
171 unsigned long inputBase, outputBase;
172
173 /* For dealing with the process thread */
174 volatile int xrun; /* Received xrun notification from JACK? */
175 struct PaJackStream * volatile toAdd, * volatile toRemove;
176 struct PaJackStream *processQueue;
177 volatile sig_atomic_t jackIsDown;
178 }
179 PaJackHostApiRepresentation;
180
181 /* PaJackStream - a stream data structure specifically for this implementation */
182
183 typedef struct PaJackStream
184 {
185 PaUtilStreamRepresentation streamRepresentation;
186 PaUtilBufferProcessor bufferProcessor;
187 PaUtilCpuLoadMeasurer cpuLoadMeasurer;
188 PaJackHostApiRepresentation *hostApi;
189
190 /* our input and output ports */
191 jack_port_t **local_input_ports;
192 jack_port_t **local_output_ports;
193
194 /* the input and output ports of the client we are connecting to */
195 jack_port_t **remote_input_ports;
196 jack_port_t **remote_output_ports;
197
198 int num_incoming_connections;
199 int num_outgoing_connections;
200
201 jack_client_t *jack_client;
202
203 /* The stream is running if it's still producing samples.
204 * The stream is active if samples it produced are still being heard.
205 */
206 volatile sig_atomic_t is_running;
207 volatile sig_atomic_t is_active;
208 /* Used to signal processing thread that stream should start or stop, respectively */
209 volatile sig_atomic_t doStart, doStop, doAbort;
210
211 jack_nframes_t t0;
212
213 PaUtilAllocationGroup *stream_memory;
214
215 /* These are useful in the process callback */
216
217 int callbackResult;
218 int isSilenced;
219 int xrun;
220
221 /* These are useful for the blocking API */
222
223 int isBlockingStream;
224 PaUtilRingBuffer inFIFO;
225 PaUtilRingBuffer outFIFO;
226 volatile sig_atomic_t data_available;
227 sem_t data_semaphore;
228 int bytesPerFrame;
229 int samplesPerFrame;
230
231 struct PaJackStream *next;
232 }
233 PaJackStream;
234
235 #define TRUE 1
236 #define FALSE 0
237
238 /*
239 * Functions specific to this API
240 */
241
242 static int JackCallback( jack_nframes_t frames, void *userData );
243
244
245 /*
246 *
247 * Implementation
248 *
249 */
250
251 /* ---- blocking emulation layer ---- */
252
253 /* Allocate buffer. */
254 static PaError BlockingInitFIFO( PaUtilRingBuffer *rbuf, long numFrames, long bytesPerFrame )
255 {
256 long numBytes = numFrames * bytesPerFrame;
257 char *buffer = (char *) malloc( numBytes );
258 if( buffer == NULL ) return paInsufficientMemory;
259 memset( buffer, 0, numBytes );
260 return (PaError) PaUtil_InitializeRingBuffer( rbuf, 1, numBytes, buffer );
261 }
262
263 /* Free buffer. */
264 static PaError BlockingTermFIFO( PaUtilRingBuffer *rbuf )
265 {
266 if( rbuf->buffer ) free( rbuf->buffer );
267 rbuf->buffer = NULL;
268 return paNoError;
269 }
270
271 static int
272 BlockingCallback( const void *inputBuffer,
273 void *outputBuffer,
274 unsigned long framesPerBuffer,
275 const PaStreamCallbackTimeInfo* timeInfo,
276 PaStreamCallbackFlags statusFlags,
277 void *userData )
278 {
279 struct PaJackStream *stream = (PaJackStream *)userData;
280 long numBytes = stream->bytesPerFrame * framesPerBuffer;
281
282 /* This may get called with NULL inputBuffer during initial setup. */
283 if( inputBuffer != NULL )
284 {
285 PaUtil_WriteRingBuffer( &stream->inFIFO, inputBuffer, numBytes );
286 }
287 if( outputBuffer != NULL )
288 {
289 int numRead = PaUtil_ReadRingBuffer( &stream->outFIFO, outputBuffer, numBytes );
290 /* Zero out remainder of buffer if we run out of data. */
291 memset( (char *)outputBuffer + numRead, 0, numBytes - numRead );
292 }
293
294 if( !stream->data_available )
295 {
296 stream->data_available = 1;
297 sem_post( &stream->data_semaphore );
298 }
299 return paContinue;
300 }
301
302 static PaError
303 BlockingBegin( PaJackStream *stream, int minimum_buffer_size )
304 {
305 long doRead = 0;
306 long doWrite = 0;
307 PaError result = paNoError;
308 long numFrames;
309
310 doRead = stream->local_input_ports != NULL;
311 doWrite = stream->local_output_ports != NULL;
312 /* <FIXME> */
313 stream->samplesPerFrame = 2;
314 stream->bytesPerFrame = sizeof(float) * stream->samplesPerFrame;
315 /* </FIXME> */
316 numFrames = 32;
317 while (numFrames < minimum_buffer_size)
318 numFrames *= 2;
319
320 if( doRead )
321 {
322 ENSURE_PA( BlockingInitFIFO( &stream->inFIFO, numFrames, stream->bytesPerFrame ) );
323 }
324 if( doWrite )
325 {
326 long numBytes;
327
328 ENSURE_PA( BlockingInitFIFO( &stream->outFIFO, numFrames, stream->bytesPerFrame ) );
329
330 /* Make Write FIFO appear full initially. */
331 numBytes = PaUtil_GetRingBufferWriteAvailable( &stream->outFIFO );
332 PaUtil_AdvanceRingBufferWriteIndex( &stream->outFIFO, numBytes );
333 }
334
335 stream->data_available = 0;
336 sem_init( &stream->data_semaphore, 0, 0 );
337
338 error:
339 return result;
340 }
341
342 static void
343 BlockingEnd( PaJackStream *stream )
344 {
345 BlockingTermFIFO( &stream->inFIFO );
346 BlockingTermFIFO( &stream->outFIFO );
347
348 sem_destroy( &stream->data_semaphore );
349 }
350
351 static PaError BlockingReadStream( PaStream* s, void *data, unsigned long numFrames )
352 {
353 PaError result = paNoError;
354 PaJackStream *stream = (PaJackStream *)s;
355
356 long bytesRead;
357 char *p = (char *) data;
358 long numBytes = stream->bytesPerFrame * numFrames;
359 while( numBytes > 0 )
360 {
361 bytesRead = PaUtil_ReadRingBuffer( &stream->inFIFO, p, numBytes );
362 numBytes -= bytesRead;
363 p += bytesRead;
364 if( numBytes > 0 )
365 {
366 /* see write for an explanation */
367 if( stream->data_available )
368 stream->data_available = 0;
369 else
370 sem_wait( &stream->data_semaphore );
371 }
372 }
373
374 return result;
375 }
376
377 static PaError BlockingWriteStream( PaStream* s, const void *data, unsigned long numFrames )
378 {
379 PaError result = paNoError;
380 PaJackStream *stream = (PaJackStream *)s;
381 long bytesWritten;
382 char *p = (char *) data;
383 long numBytes = stream->bytesPerFrame * numFrames;
384 while( numBytes > 0 )
385 {
386 bytesWritten = PaUtil_WriteRingBuffer( &stream->outFIFO, p, numBytes );
387 numBytes -= bytesWritten;
388 p += bytesWritten;
389 if( numBytes > 0 )
390 {
391 /* we use the following algorithm:
392 * (1) write data
393 * (2) if some data didn't fit into the ringbuffer, set data_available to 0
394 * to indicate to the audio that if space becomes available, we want to know
395 * (3) retry to write data (because it might be that between (1) and (2)
396 * new space in the buffer became available)
397 * (4) if this failed, we are sure that the buffer is really empty and
398 * we will definitely receive a notification when it becomes available
399 * thus we can safely sleep
400 *
401 * if the algorithm bailed out in step (3) before, it leaks a count of 1
402 * on the semaphore; however, it doesn't matter, because if we block in (4),
403 * we also do it in a loop
404 */
405 if( stream->data_available )
406 stream->data_available = 0;
407 else
408 sem_wait( &stream->data_semaphore );
409 }
410 }
411
412 return result;
413 }
414
415 static signed long
416 BlockingGetStreamReadAvailable( PaStream* s )
417 {
418 PaJackStream *stream = (PaJackStream *)s;
419
420 int bytesFull = PaUtil_GetRingBufferReadAvailable( &stream->inFIFO );
421 return bytesFull / stream->bytesPerFrame;
422 }
423
424 static signed long
425 BlockingGetStreamWriteAvailable( PaStream* s )
426 {
427 PaJackStream *stream = (PaJackStream *)s;
428
429 int bytesEmpty = PaUtil_GetRingBufferWriteAvailable( &stream->outFIFO );
430 return bytesEmpty / stream->bytesPerFrame;
431 }
432
433 static PaError
434 BlockingWaitEmpty( PaStream *s )
435 {
436 PaJackStream *stream = (PaJackStream *)s;
437
438 while( PaUtil_GetRingBufferReadAvailable( &stream->outFIFO ) > 0 )
439 {
440 stream->data_available = 0;
441 sem_wait( &stream->data_semaphore );
442 }
443 return 0;
444 }
445
446 /* ---- jack driver ---- */
447
448 /* BuildDeviceList():
449 *
450 * The process of determining a list of PortAudio "devices" from
451 * JACK's client/port system is fairly involved, so it is separated
452 * into its own routine.
453 */
454
455 static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
456 {
457 /* Utility macros for the repetitive process of allocating memory */
458
459 /* JACK has no concept of a device. To JACK, there are clients
460 * which have an arbitrary number of ports. To make this
461 * intelligible to PortAudio clients, we will group each JACK client
462 * into a device, and make each port of that client a channel */
463
464 PaError result = paNoError;
465 PaUtilHostApiRepresentation *commonApi = &jackApi->commonHostApiRep;
466
467 const char **jack_ports = NULL;
468 char **client_names = NULL;
469 char *regex_pattern = NULL;
470 int port_index, client_index, i;
471 double globalSampleRate;
472 regex_t port_regex;
473 unsigned long numClients = 0, numPorts = 0;
474 char *tmp_client_name = NULL;
475
476 commonApi->info.defaultInputDevice = paNoDevice;
477 commonApi->info.defaultOutputDevice = paNoDevice;
478 commonApi->info.deviceCount = 0;
479
480 /* Parse the list of ports, using a regex to grab the client names */
481 ASSERT_CALL( regcomp( &port_regex, "^[^:]*", REG_EXTENDED ), 0 );
482
483 /* since we are rebuilding the list of devices, free all memory
484 * associated with the previous list */
485 PaUtil_FreeAllAllocations( jackApi->deviceInfoMemory );
486
487 regex_pattern = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, jack_client_name_size() + 3 );
488 tmp_client_name = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, jack_client_name_size() );
489
490 /* We can only retrieve the list of clients indirectly, by first
491 * asking for a list of all ports, then parsing the port names
492 * according to the client_name:port_name convention (which is
493 * enforced by jackd)
494 * A: If jack_get_ports returns NULL, there's nothing for us to do */
495 UNLESS( (jack_ports = jack_get_ports( jackApi->jack_client, "", "", 0 )) && jack_ports[0], paNoError );
496 /* Find number of ports */
497 while( jack_ports[numPorts] )
498 ++numPorts;
499 /* At least there will be one port per client :) */
500 UNLESS( client_names = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, numPorts *
501 sizeof (char *) ), paInsufficientMemory );
502
503 /* Build a list of clients from the list of ports */
504 for( numClients = 0, port_index = 0; jack_ports[port_index] != NULL; port_index++ )
505 {
506 int client_seen = FALSE;
507 regmatch_t match_info;
508 const char *port = jack_ports[port_index];
509
510 /* extract the client name from the port name, using a regex
511 * that parses the clientname:portname syntax */
512 UNLESS( !regexec( &port_regex, port, 1, &match_info, 0 ), paInternalError );
513 assert(match_info.rm_eo - match_info.rm_so < jack_client_name_size());
514 memcpy( tmp_client_name, port + match_info.rm_so,
515 match_info.rm_eo - match_info.rm_so );
516 tmp_client_name[match_info.rm_eo - match_info.rm_so] = '\0';
517
518 /* do we know about this port's client yet? */
519 for( i = 0; i < numClients; i++ )
520 {
521 if( strcmp( tmp_client_name, client_names[i] ) == 0 )
522 client_seen = TRUE;
523 }
524
525 if (client_seen)
526 continue; /* A: Nothing to see here, move along */
527
528 UNLESS( client_names[numClients] = (char*)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory,
529 strlen(tmp_client_name) + 1), paInsufficientMemory );
530
531 /* The alsa_pcm client should go in spot 0. If this
532 * is the alsa_pcm client AND we are NOT about to put
533 * it in spot 0 put it in spot 0 and move whatever
534 * was already in spot 0 to the end. */
535 if( strcmp( "alsa_pcm", tmp_client_name ) == 0 && numClients > 0 )
536 {
537 /* alsa_pcm goes in spot 0 */
538 strcpy( client_names[ numClients ], client_names[0] );
539 strcpy( client_names[0], tmp_client_name );
540 }
541 else
542 {
543 /* put the new client at the end of the client list */
544 strcpy( client_names[ numClients ], tmp_client_name );
545 }
546 ++numClients;
547 }
548
549 /* Now we have a list of clients, which will become the list of
550 * PortAudio devices. */
551
552 /* there is one global sample rate all clients must conform to */
553
554 globalSampleRate = jack_get_sample_rate( jackApi->jack_client );
555 UNLESS( commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory,
556 sizeof(PaDeviceInfo*) * numClients ), paInsufficientMemory );
557
558 assert( commonApi->info.deviceCount == 0 );
559
560 /* Create a PaDeviceInfo structure for every client */
561 for( client_index = 0; client_index < numClients; client_index++ )
562 {
563 PaDeviceInfo *curDevInfo;
564 const char **clientPorts = NULL;
565
566 UNLESS( curDevInfo = (PaDeviceInfo*)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory,
567 sizeof(PaDeviceInfo) ), paInsufficientMemory );
568 UNLESS( curDevInfo->name = (char*)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory,
569 strlen(client_names[client_index]) + 1 ), paInsufficientMemory );
570 strcpy( (char *)curDevInfo->name, client_names[client_index] );
571
572 curDevInfo->structVersion = 2;
573 curDevInfo->hostApi = jackApi->hostApiIndex;
574
575 /* JACK is very inflexible: there is one sample rate the whole
576 * system must run at, and all clients must speak IEEE float. */
577 curDevInfo->defaultSampleRate = globalSampleRate;
578
579 /* To determine how many input and output channels are available,
580 * we re-query jackd with more specific parameters. */
581
582 sprintf( regex_pattern, "%s:.*", client_names[client_index] );
583
584 /* ... what are your output ports (that we could input from)? */
585 clientPorts = jack_get_ports( jackApi->jack_client, regex_pattern,
586 NULL, JackPortIsOutput);
587 curDevInfo->maxInputChannels = 0;
588 curDevInfo->defaultLowInputLatency = 0.;
589 curDevInfo->defaultHighInputLatency = 0.;
590 if( clientPorts )
591 {
592 jack_port_t *p = jack_port_by_name( jackApi->jack_client, clientPorts[0] );
593 curDevInfo->defaultLowInputLatency = curDevInfo->defaultHighInputLatency =
594 jack_port_get_latency( p ) / globalSampleRate;
595
596 for( i = 0; clientPorts[i] != NULL; i++)
597 {
598 /* The number of ports returned is the number of output channels.
599 * We don't care what they are, we just care how many */
600 curDevInfo->maxInputChannels++;
601 }
602 free(clientPorts);
603 }
604
605 /* ... what are your input ports (that we could output to)? */
606 clientPorts = jack_get_ports( jackApi->jack_client, regex_pattern,
607 NULL, JackPortIsInput);
608 curDevInfo->maxOutputChannels = 0;
609 curDevInfo->defaultLowOutputLatency = 0.;
610 curDevInfo->defaultHighOutputLatency = 0.;
611 if( clientPorts )
612 {
613 jack_port_t *p = jack_port_by_name( jackApi->jack_client, clientPorts[0] );
614 curDevInfo->defaultLowOutputLatency = curDevInfo->defaultHighOutputLatency =
615 jack_port_get_latency( p ) / globalSampleRate;
616
617 for( i = 0; clientPorts[i] != NULL; i++)
618 {
619 /* The number of ports returned is the number of input channels.
620 * We don't care what they are, we just care how many */
621 curDevInfo->maxOutputChannels++;
622 }
623 free(clientPorts);
624 }
625
626 /* Add this client to the list of devices */
627 commonApi->deviceInfos[client_index] = curDevInfo;
628 ++commonApi->info.deviceCount;
629 if( commonApi->info.defaultInputDevice == paNoDevice && curDevInfo->maxInputChannels > 0 )
630 commonApi->info.defaultInputDevice = client_index;
631 if( commonApi->info.defaultOutputDevice == paNoDevice && curDevInfo->maxOutputChannels > 0 )
632 commonApi->info.defaultOutputDevice = client_index;
633 }
634
635 error:
636 regfree( &port_regex );
637 free( jack_ports );
638 return result;
639 }
640
641 static void UpdateSampleRate( PaJackStream *stream, double sampleRate )
642 {
643 /* XXX: Maybe not the cleanest way of going about this? */
644 stream->cpuLoadMeasurer.samplingPeriod = stream->bufferProcessor.samplePeriod = 1. / sampleRate;
645 stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
646 }
647
648 static void JackErrorCallback( const char *msg )
649 {
650 if( pthread_self() == mainThread_ )
651 {
652 assert( msg );
653 jackErr_ = realloc( jackErr_, strlen( msg ) + 1 );
654 strcpy( jackErr_, msg );
655 }
656 }
657
658 static void JackOnShutdown( void *arg )
659 {
660 PaJackHostApiRepresentation *jackApi = (PaJackHostApiRepresentation *)arg;
661 PaJackStream *stream = jackApi->processQueue;
662
663 PA_DEBUG(( "%s: JACK server is shutting down\n", __FUNCTION__ ));
664 for( ; stream; stream = stream->next )
665 {
666 stream->is_active = 0;
667 }
668
669 /* Make sure that the main thread doesn't get stuck waiting on the condition */
670 ASSERT_CALL( pthread_mutex_lock( &jackApi->mtx ), 0 );
671 jackApi->jackIsDown = 1;
672 ASSERT_CALL( pthread_cond_signal( &jackApi->cond ), 0 );
673 ASSERT_CALL( pthread_mutex_unlock( &jackApi->mtx ), 0 );
674
675 }
676
677 static int JackSrCb( jack_nframes_t nframes, void *arg )
678 {
679 PaJackHostApiRepresentation *jackApi = (PaJackHostApiRepresentation *)arg;
680 double sampleRate = (double)nframes;
681 PaJackStream *stream = jackApi->processQueue;
682
683 /* Update all streams in process queue */
684 PA_DEBUG(( "%s: Acting on change in JACK samplerate: %f\n", __FUNCTION__, sampleRate ));
685 for( ; stream; stream = stream->next )
686 {
687 if( stream->streamRepresentation.streamInfo.sampleRate != sampleRate )
688 {
689 PA_DEBUG(( "%s: Updating samplerate\n", __FUNCTION__ ));
690 UpdateSampleRate( stream, sampleRate );
691 }
692 }
693
694 return 0;
695 }
696
697 static int JackXRunCb(void *arg) {
698 PaJackHostApiRepresentation *hostApi = (PaJackHostApiRepresentation *)arg;
699 assert( hostApi );
700 hostApi->xrun = TRUE;
701 PA_DEBUG(( "%s: JACK signalled xrun\n", __FUNCTION__ ));
702 return 0;
703 }
704
705 PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi,
706 PaHostApiIndex hostApiIndex )
707 {
708 PaError result = paNoError;
709 PaJackHostApiRepresentation *jackHostApi;
710 int activated = 0;
711 jack_status_t jackStatus = 0;
712 *hostApi = NULL; /* Initialize to NULL */
713
714 UNLESS( jackHostApi = (PaJackHostApiRepresentation*)
715 PaUtil_AllocateMemory( sizeof(PaJackHostApiRepresentation) ), paInsufficientMemory );
716 UNLESS( jackHostApi->deviceInfoMemory = PaUtil_CreateAllocationGroup(), paInsufficientMemory );
717
718 mainThread_ = pthread_self();
719 ASSERT_CALL( pthread_mutex_init( &jackHostApi->mtx, NULL ), 0 );
720 ASSERT_CALL( pthread_cond_init( &jackHostApi->cond, NULL ), 0 );
721
722 /* Try to become a client of the JACK server. If we cannot do
723 * this, then this API cannot be used.
724 *
725 * Without the JackNoStartServer option, the jackd server is started
726 * automatically which we do not want.
727 */
728
729 jackHostApi->jack_client = jack_client_open( clientName_, JackNoStartServer, &jackStatus );
730 if( !jackHostApi->jack_client )
731 {
732 /* the V19 development docs say that if an implementation
733 * detects that it cannot be used, it should return a NULL
734 * interface and paNoError */
735 PA_DEBUG(( "%s: Couldn't connect to JACK, status: %d\n", __FUNCTION__, jackStatus ));
736 result = paNoError;
737 goto error;
738 }
739
740 jackHostApi->hostApiIndex = hostApiIndex;
741
742 *hostApi = &jackHostApi->commonHostApiRep;
743 (*hostApi)->info.structVersion = 1;
744 (*hostApi)->info.type = paJACK;
745 (*hostApi)->info.name = "JACK Audio Connection Kit";
746
747 /* Build a device list by querying the JACK server */
748 ENSURE_PA( BuildDeviceList( jackHostApi ) );
749
750 /* Register functions */
751
752 (*hostApi)->Terminate = Terminate;
753 (*hostApi)->OpenStream = OpenStream;
754 (*hostApi)->IsFormatSupported = IsFormatSupported;
755
756 PaUtil_InitializeStreamInterface( &jackHostApi->callbackStreamInterface,
757 CloseStream, StartStream,
758 StopStream, AbortStream,
759 IsStreamStopped, IsStreamActive,
760 GetStreamTime, GetStreamCpuLoad,
761 PaUtil_DummyRead, PaUtil_DummyWrite,
762 PaUtil_DummyGetReadAvailable,
763 PaUtil_DummyGetWriteAvailable );
764
765 PaUtil_InitializeStreamInterface( &jackHostApi->blockingStreamInterface, CloseStream, StartStream,
766 StopStream, AbortStream, IsStreamStopped, IsStreamActive,
767 GetStreamTime, PaUtil_DummyGetCpuLoad,
768 BlockingReadStream, BlockingWriteStream,
769 BlockingGetStreamReadAvailable, BlockingGetStreamWriteAvailable );
770
771 jackHostApi->inputBase = jackHostApi->outputBase = 0;
772 jackHostApi->xrun = 0;
773 jackHostApi->toAdd = jackHostApi->toRemove = NULL;
774 jackHostApi->processQueue = NULL;
775 jackHostApi->jackIsDown = 0;
776
777 jack_on_shutdown( jackHostApi->jack_client, JackOnShutdown, jackHostApi );
778 jack_set_error_function( JackErrorCallback );
779 jackHostApi->jack_buffer_size = jack_get_buffer_size ( jackHostApi->jack_client );
780 /* Don't check for error, may not be supported (deprecated in at least jackdmp) */
781 jack_set_sample_rate_callback( jackHostApi->jack_client, JackSrCb, jackHostApi );
782 UNLESS( !jack_set_xrun_callback( jackHostApi->jack_client, JackXRunCb, jackHostApi ), paUnanticipatedHostError );
783 UNLESS( !jack_set_process_callback( jackHostApi->jack_client, JackCallback, jackHostApi ), paUnanticipatedHostError );
784 UNLESS( !jack_activate( jackHostApi->jack_client ), paUnanticipatedHostError );
785 activated = 1;
786
787 return result;
788
789 error:
790 if( activated )
791 ASSERT_CALL( jack_deactivate( jackHostApi->jack_client ), 0 );
792
793 if( jackHostApi )
794 {
795 if( jackHostApi->jack_client )
796 ASSERT_CALL( jack_client_close( jackHostApi->jack_client ), 0 );
797
798 if( jackHostApi->deviceInfoMemory )
799 {
800 PaUtil_FreeAllAllocations( jackHostApi->deviceInfoMemory );
801 PaUtil_DestroyAllocationGroup( jackHostApi->deviceInfoMemory );
802 }
803
804 PaUtil_FreeMemory( jackHostApi );
805 }
806 return result;
807 }
808
809
810 static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
811 {
812 PaJackHostApiRepresentation *jackHostApi = (PaJackHostApiRepresentation*)hostApi;
813
814 /* note: this automatically disconnects all ports, since a deactivated
815 * client is not allowed to have any ports connected */
816 ASSERT_CALL( jack_deactivate( jackHostApi->jack_client ), 0 );
817
818 ASSERT_CALL( pthread_mutex_destroy( &jackHostApi->mtx ), 0 );
819 ASSERT_CALL( pthread_cond_destroy( &jackHostApi->cond ), 0 );
820
821 ASSERT_CALL( jack_client_close( jackHostApi->jack_client ), 0 );
822
823 if( jackHostApi->deviceInfoMemory )
824 {
825 PaUtil_FreeAllAllocations( jackHostApi->deviceInfoMemory );
826 PaUtil_DestroyAllocationGroup( jackHostApi->deviceInfoMemory );
827 }
828
829 PaUtil_FreeMemory( jackHostApi );
830
831 free( jackErr_ );
832 jackErr_ = NULL;
833 }
834
835 static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
836 const PaStreamParameters *inputParameters,
837 const PaStreamParameters *outputParameters,
838 double sampleRate )
839 {
840 int inputChannelCount = 0, outputChannelCount = 0;
841 PaSampleFormat inputSampleFormat, outputSampleFormat;
842
843 if( inputParameters )
844 {
845 inputChannelCount = inputParameters->channelCount;
846 inputSampleFormat = inputParameters->sampleFormat;
847
848 /* unless alternate device specification is supported, reject the use of
849 paUseHostApiSpecificDeviceSpecification */
850
851 if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
852 return paInvalidDevice;
853
854 /* check that input device can support inputChannelCount */
855 if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
856 return paInvalidChannelCount;
857
858 /* validate inputStreamInfo */
859 if( inputParameters->hostApiSpecificStreamInfo )
860 return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
861 }
862 else
863 {
864 inputChannelCount = 0;
865 }
866
867 if( outputParameters )
868 {
869 outputChannelCount = outputParameters->channelCount;
870 outputSampleFormat = outputParameters->sampleFormat;
871
872 /* unless alternate device specification is supported, reject the use of
873 paUseHostApiSpecificDeviceSpecification */
874
875 if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
876 return paInvalidDevice;
877
878 /* check that output device can support inputChannelCount */
879 if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
880 return paInvalidChannelCount;
881
882 /* validate outputStreamInfo */
883 if( outputParameters->hostApiSpecificStreamInfo )
884 return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
885 }
886 else
887 {
888 outputChannelCount = 0;
889 }
890
891 /*
892 The following check is not necessary for JACK.
893
894 - if a full duplex stream is requested, check that the combination
895 of input and output parameters is supported
896
897
898 Because the buffer adapter handles conversion between all standard
899 sample formats, the following checks are only required if paCustomFormat
900 is implemented, or under some other unusual conditions.
901
902 - check that input device can support inputSampleFormat, or that
903 we have the capability to convert from outputSampleFormat to
904 a native format
905
906 - check that output device can support outputSampleFormat, or that
907 we have the capability to convert from outputSampleFormat to
908 a native format
909 */
910
911 /* check that the device supports sampleRate */
912
913 #define ABS(x) ( (x) > 0 ? (x) : -(x) )
914 if( ABS(sampleRate - jack_get_sample_rate(((PaJackHostApiRepresentation *) hostApi)->jack_client )) > 1 )
915 return paInvalidSampleRate;
916 #undef ABS
917
918 return paFormatIsSupported;
919 }
920
921 /* Basic stream initialization */
922 static PaError InitializeStream( PaJackStream *stream, PaJackHostApiRepresentation *hostApi, int numInputChannels,
923 int numOutputChannels )
924 {
925 PaError result = paNoError;
926 assert( stream );
927
928 memset( stream, 0, sizeof (PaJackStream) );
929 UNLESS( stream->stream_memory = PaUtil_CreateAllocationGroup(), paInsufficientMemory );
930 stream->jack_client = hostApi->jack_client;
931 stream->hostApi = hostApi;
932
933 if( numInputChannels > 0 )
934 {
935 UNLESS( stream->local_input_ports =
936 (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numInputChannels ),
937 paInsufficientMemory );
938 memset( stream->local_input_ports, 0, sizeof(jack_port_t*) * numInputChannels );
939 UNLESS( stream->remote_output_ports =
940 (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numInputChannels ),
941 paInsufficientMemory );
942 memset( stream->remote_output_ports, 0, sizeof(jack_port_t*) * numInputChannels );
943 }
944 if( numOutputChannels > 0 )
945 {
946 UNLESS( stream->local_output_ports =
947 (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numOutputChannels ),
948 paInsufficientMemory );
949 memset( stream->local_output_ports, 0, sizeof(jack_port_t*) * numOutputChannels );
950 UNLESS( stream->remote_input_ports =
951 (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numOutputChannels ),
952 paInsufficientMemory );
953 memset( stream->remote_input_ports, 0, sizeof(jack_port_t*) * numOutputChannels );
954 }
955
956 stream->num_incoming_connections = numInputChannels;
957 stream->num_outgoing_connections = numOutputChannels;
958
959 error:
960 return result;
961 }
962
963 /*!
964 * Free resources associated with stream, and eventually stream itself.
965 *
966 * Frees allocated memory, and closes opened pcms.
967 */
968 static void CleanUpStream( PaJackStream *stream, int terminateStreamRepresentation, int terminateBufferProcessor )
969 {
970 int i;
971 assert( stream );
972
973 if( stream->isBlockingStream )
974 BlockingEnd( stream );
975
976 for( i = 0; i < stream->num_incoming_connections; ++i )
977 {
978 if( stream->local_input_ports[i] )
979 ASSERT_CALL( jack_port_unregister( stream->jack_client, stream->local_input_ports[i] ), 0 );
980 }
981 for( i = 0; i < stream->num_outgoing_connections; ++i )
982 {
983 if( stream->local_output_ports[i] )
984 ASSERT_CALL( jack_port_unregister( stream->jack_client, stream->local_output_ports[i] ), 0 );
985 }
986
987 if( terminateStreamRepresentation )
988 PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
989 if( terminateBufferProcessor )
990 PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
991
992 if( stream->stream_memory )
993 {
994 PaUtil_FreeAllAllocations( stream->stream_memory );
995 PaUtil_DestroyAllocationGroup( stream->stream_memory );
996 }
997 PaUtil_FreeMemory( stream );
998 }
999
1000 static PaError WaitCondition( PaJackHostApiRepresentation *hostApi )
1001 {
1002 PaError result = paNoError;
1003 int err = 0;
1004 PaTime pt = PaUtil_GetTime();
1005 struct timespec ts;
1006
1007 ts.tv_sec = (time_t) floor( pt + 10 * 60 /* 10 minutes */ );
1008 ts.tv_nsec = (long) ((pt - floor( pt )) * 1000000000);
1009 /* XXX: Best enclose in loop, in case of spurious wakeups? */
1010 err = pthread_cond_timedwait( &hostApi->cond, &hostApi->mtx, &ts );
1011
1012 /* Make sure we didn't time out */
1013 UNLESS( err != ETIMEDOUT, paTimedOut );
1014 UNLESS( !err, paInternalError );
1015
1016 error:
1017 return result;
1018 }
1019
1020 static PaError AddStream( PaJackStream *stream )
1021 {
1022 PaError result = paNoError;
1023 PaJackHostApiRepresentation *hostApi = stream->hostApi;
1024 /* Add to queue of streams that should be processed */
1025 ASSERT_CALL( pthread_mutex_lock( &hostApi->mtx ), 0 );
1026 if( !hostApi->jackIsDown )
1027 {
1028 hostApi->toAdd = stream;
1029 /* Unlock mutex and await signal from processing thread */
1030 result = WaitCondition( stream->hostApi );
1031 }
1032 ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 );
1033 ENSURE_PA( result );
1034
1035 UNLESS( !hostApi->jackIsDown, paDeviceUnavailable );
1036
1037 error:
1038 return result;
1039 }
1040
1041 /* Remove stream from processing queue */
1042 static PaError RemoveStream( PaJackStream *stream )
1043 {
1044 PaError result = paNoError;
1045 PaJackHostApiRepresentation *hostApi = stream->hostApi;
1046
1047 /* Add to queue over streams that should be processed */
1048 ASSERT_CALL( pthread_mutex_lock( &hostApi->mtx ), 0 );
1049 if( !hostApi->jackIsDown )
1050 {
1051 hostApi->toRemove = stream;
1052 /* Unlock mutex and await signal from processing thread */
1053 result = WaitCondition( stream->hostApi );
1054 }
1055 ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 );
1056 ENSURE_PA( result );
1057
1058 error:
1059 return result;
1060 }
1061
1062 /* Add stream to JACK callback processing queue */
1063 static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
1064 PaStream** s,
1065 const PaStreamParameters *inputParameters,
1066 const PaStreamParameters *outputParameters,
1067 double sampleRate,
1068 unsigned long framesPerBuffer,
1069 PaStreamFlags streamFlags,
1070 PaStreamCallback *streamCallback,
1071 void *userData )
1072 {
1073 PaError result = paNoError;
1074 PaJackHostApiRepresentation *jackHostApi = (PaJackHostApiRepresentation*)hostApi;
1075 PaJackStream *stream = NULL;
1076 char *port_string = PaUtil_GroupAllocateMemory( jackHostApi->deviceInfoMemory, jack_port_name_size() );
1077 unsigned long regexSz = jack_client_name_size() + 3;
1078 char *regex_pattern = PaUtil_GroupAllocateMemory( jackHostApi->deviceInfoMemory, regexSz );
1079 const char **jack_ports = NULL;
1080 /* int jack_max_buffer_size = jack_get_buffer_size( jackHostApi->jack_client ); */
1081 int i;
1082 int inputChannelCount, outputChannelCount;
1083 const double jackSr = jack_get_sample_rate( jackHostApi->jack_client );
1084 PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0;
1085 int bpInitialized = 0, srInitialized = 0; /* Initialized buffer processor and stream representation? */
1086 unsigned long ofs;
1087
1088 /* validate platform specific flags */
1089 if( (streamFlags & paPlatformSpecificFlags) != 0 )
1090 return paInvalidFlag; /* unexpected platform specific flag */
1091 if( (streamFlags & paPrimeOutputBuffersUsingStreamCallback) != 0 )
1092 {
1093 streamFlags &= ~paPrimeOutputBuffersUsingStreamCallback;
1094 /*return paInvalidFlag;*/ /* This implementation does not support buffer priming */
1095 }
1096
1097 if( framesPerBuffer != paFramesPerBufferUnspecified )
1098 {
1099 /* Jack operates with power of two buffers, and we don't support non-integer buffer adaption (yet) */
1100 /*UNLESS( !(framesPerBuffer & (framesPerBuffer - 1)), paBufferTooBig );*/ /* TODO: Add descriptive error code? */
1101 }
1102
1103 /* Preliminary checks */
1104
1105 if( inputParameters )
1106 {
1107 inputChannelCount = inputParameters->channelCount;
1108 inputSampleFormat = inputParameters->sampleFormat;
1109
1110 /* unless alternate device specification is supported, reject the use of
1111 paUseHostApiSpecificDeviceSpecification */
1112
1113 if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
1114 return paInvalidDevice;
1115
1116 /* check that input device can support inputChannelCount */
1117 if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
1118 return paInvalidChannelCount;
1119
1120 /* validate inputStreamInfo */
1121 if( inputParameters->hostApiSpecificStreamInfo )
1122 return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
1123 }
1124 else
1125 {
1126 inputChannelCount = 0;
1127 }
1128
1129 if( outputParameters )
1130 {
1131 outputChannelCount = outputParameters->channelCount;
1132 outputSampleFormat = outputParameters->sampleFormat;
1133
1134 /* unless alternate device specification is supported, reject the use of
1135 paUseHostApiSpecificDeviceSpecification */
1136
1137 if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
1138 return paInvalidDevice;
1139
1140 /* check that output device can support inputChannelCount */
1141 if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
1142 return paInvalidChannelCount;
1143
1144 /* validate outputStreamInfo */
1145 if( outputParameters->hostApiSpecificStreamInfo )
1146 return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
1147 }
1148 else
1149 {
1150 outputChannelCount = 0;
1151 }
1152
1153 /* ... check that the sample rate exactly matches the ONE acceptable rate
1154 * A: This rate isn't necessarily constant though? */
1155
1156 #define ABS(x) ( (x) > 0 ? (x) : -(x) )
1157 if( ABS(sampleRate - jackSr) > 1 )
1158 return paInvalidSampleRate;
1159 #undef ABS
1160
1161 UNLESS( stream = (PaJackStream*)PaUtil_AllocateMemory( sizeof(PaJackStream) ), paInsufficientMemory );
1162 ENSURE_PA( InitializeStream( stream, jackHostApi, inputChannelCount, outputChannelCount ) );
1163
1164 /* the blocking emulation, if necessary */
1165 stream->isBlockingStream = !streamCallback;
1166 if( stream->isBlockingStream )
1167 {
1168 float latency = 0.001; /* 1ms is the absolute minimum we support */
1169 int minimum_buffer_frames = 0;
1170
1171 if( inputParameters && inputParameters->suggestedLatency > latency )
1172 latency = inputParameters->suggestedLatency;
1173 else if( outputParameters && outputParameters->suggestedLatency > latency )
1174 latency = outputParameters->suggestedLatency;
1175
1176 /* the latency the user asked for indicates the minimum buffer size in frames */
1177 minimum_buffer_frames = (int) (latency * jack_get_sample_rate( jackHostApi->jack_client ));
1178
1179 /* we also need to be able to store at least three full jack buffers to avoid dropouts */
1180 if( jackHostApi->jack_buffer_size * 3 > minimum_buffer_frames )
1181 minimum_buffer_frames = jackHostApi->jack_buffer_size * 3;
1182
1183 /* setup blocking API data structures (FIXME: can fail) */
1184 BlockingBegin( stream, minimum_buffer_frames );
1185
1186 /* install our own callback for the blocking API */
1187 streamCallback = BlockingCallback;
1188 userData = stream;
1189
1190 PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
1191 &jackHostApi->blockingStreamInterface, streamCallback, userData );
1192 }
1193 else
1194 {
1195 PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
1196 &jackHostApi->callbackStreamInterface, streamCallback, userData );
1197 }
1198 srInitialized = 1;
1199 PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, jackSr );
1200
1201 /* create the JACK ports. We cannot connect them until audio
1202 * processing begins */
1203
1204 /* Register a unique set of ports for this stream
1205 * TODO: Robust allocation of new port names */
1206
1207 ofs = jackHostApi->inputBase;
1208 for( i = 0; i < inputChannelCount; i++ )
1209 {
1210 snprintf( port_string, jack_port_name_size(), "in_%lu", ofs + i );
1211 UNLESS( stream->local_input_ports[i] = jack_port_register(
1212 jackHostApi->jack_client, port_string,
1213 JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ), paInsufficientMemory );
1214 }
1215 jackHostApi->inputBase += inputChannelCount;
1216
1217 ofs = jackHostApi->outputBase;
1218 for( i = 0; i < outputChannelCount; i++ )
1219 {
1220 snprintf( port_string, jack_port_name_size(), "out_%lu", ofs + i );
1221 UNLESS( stream->local_output_ports[i] = jack_port_register(
1222 jackHostApi->jack_client, port_string,
1223 JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ), paInsufficientMemory );
1224 }
1225 jackHostApi->outputBase += outputChannelCount;
1226
1227 /* look up the jack_port_t's for the remote ports. We could do
1228 * this at stream start time, but doing it here ensures the
1229 * name lookup only happens once. */
1230
1231 if( inputChannelCount > 0 )
1232 {
1233 int err = 0;
1234
1235 /* Get output ports of our capture device */
1236 snprintf( regex_pattern, regexSz, "%s:.*", hostApi->deviceInfos[ inputParameters->device ]->name );
1237 UNLESS( jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern,
1238 NULL, JackPortIsOutput ), paUnanticipatedHostError );
1239 for( i = 0; i < inputChannelCount && jack_ports[i]; i++ )
1240 {
1241 if( (stream->remote_output_ports[i] = jack_port_by_name(
1242 jackHostApi->jack_client, jack_ports[i] )) == NULL )
1243 {
1244 err = 1;
1245 break;
1246 }
1247 }
1248 free( jack_ports );
1249 UNLESS( !err, paInsufficientMemory );
1250
1251 /* Fewer ports than expected? */
1252 UNLESS( i == inputChannelCount, paInternalError );
1253 }
1254
1255 if( outputChannelCount > 0 )
1256 {
1257 int err = 0;
1258
1259 /* Get input ports of our playback device */
1260 snprintf( regex_pattern, regexSz, "%s:.*", hostApi->deviceInfos[ outputParameters->device ]->name );
1261 UNLESS( jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern,
1262 NULL, JackPortIsInput ), paUnanticipatedHostError );
1263 for( i = 0; i < outputChannelCount && jack_ports[i]; i++ )
1264 {
1265 if( (stream->remote_input_ports[i] = jack_port_by_name(
1266 jackHostApi->jack_client, jack_ports[i] )) == 0 )
1267 {
1268 err = 1;
1269 break;
1270 }
1271 }
1272 free( jack_ports );
1273 UNLESS( !err , paInsufficientMemory );
1274
1275 /* Fewer ports than expected? */
1276 UNLESS( i == outputChannelCount, paInternalError );
1277 }
1278
1279 ENSURE_PA( PaUtil_InitializeBufferProcessor(
1280 &stream->bufferProcessor,
1281 inputChannelCount,
1282 inputSampleFormat,
1283 paFloat32 | paNonInterleaved, /* hostInputSampleFormat */
1284 outputChannelCount,
1285 outputSampleFormat,
1286 paFloat32 | paNonInterleaved, /* hostOutputSampleFormat */
1287 jackSr,
1288 streamFlags,
1289 framesPerBuffer,
1290 0, /* Ignored */
1291 paUtilUnknownHostBufferSize, /* Buffer size may vary on JACK's discretion */
1292 streamCallback,
1293 userData ) );
1294 bpInitialized = 1;
1295
1296 if( stream->num_incoming_connections > 0 )
1297 stream->streamRepresentation.streamInfo.inputLatency = (jack_port_get_latency( stream->remote_output_ports[0] )
1298 - jack_get_buffer_size( jackHostApi->jack_client ) /* One buffer is not counted as latency */
1299 + PaUtil_GetBufferProcessorInputLatency( &stream->bufferProcessor )) / sampleRate;
1300 if( stream->num_outgoing_connections > 0 )
1301 stream->streamRepresentation.streamInfo.outputLatency = (jack_port_get_latency( stream->remote_input_ports[0] )
1302 - jack_get_buffer_size( jackHostApi->jack_client ) /* One buffer is not counted as latency */
1303 + PaUtil_GetBufferProcessorOutputLatency( &stream->bufferProcessor )) / sampleRate;
1304
1305 stream->streamRepresentation.streamInfo.sampleRate = jackSr;
1306 stream->t0 = jack_frame_time( jackHostApi->jack_client ); /* A: Time should run from Pa_OpenStream */
1307
1308 /* Add to queue of opened streams */
1309 ENSURE_PA( AddStream( stream ) );
1310
1311 *s = (PaStream*)stream;
1312
1313 return result;
1314
1315 error:
1316 if( stream )
1317 CleanUpStream( stream, srInitialized, bpInitialized );
1318
1319 return result;
1320 }
1321
1322 /*
1323 When CloseStream() is called, the multi-api layer ensures that
1324 the stream has already been stopped or aborted.
1325 */
1326 static PaError CloseStream( PaStream* s )
1327 {
1328 PaError result = paNoError;
1329 PaJackStream *stream = (PaJackStream*)s;
1330
1331 /* Remove this stream from the processing queue */
1332 ENSURE_PA( RemoveStream( stream ) );
1333
1334 error:
1335 CleanUpStream( stream, 1, 1 );
1336 return result;
1337 }
1338
1339 static PaError RealProcess( PaJackStream *stream, jack_nframes_t frames )
1340 {
1341 PaError result = paNoError;
1342 PaStreamCallbackTimeInfo timeInfo = {0,0,0};
1343 int chn;
1344 int framesProcessed;
1345 const double sr = jack_get_sample_rate( stream->jack_client ); /* Shouldn't change during the process callback */
1346 PaStreamCallbackFlags cbFlags = 0;
1347
1348 /* If the user has returned !paContinue from the callback we'll want to flush the internal buffers,
1349 * when these are empty we can finally mark the stream as inactive */
1350 if( stream->callbackResult != paContinue &&
1351 PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) )
1352 {
1353 stream->is_active = 0;
1354 if( stream->streamRepresentation.streamFinishedCallback )
1355 stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
1356 PA_DEBUG(( "%s: Callback finished\n", __FUNCTION__ ));
1357
1358 goto end;
1359 }
1360
1361 timeInfo.currentTime = (jack_frame_time( stream->jack_client ) - stream->t0) / sr;
1362 if( stream->num_incoming_connections > 0 )
1363 timeInfo.inputBufferAdcTime = timeInfo.currentTime - jack_port_get_latency( stream->remote_output_ports[0] )
1364 / sr;
1365 if( stream->num_outgoing_connections > 0 )
1366 timeInfo.outputBufferDacTime = timeInfo.currentTime + jack_port_get_latency( stream->remote_input_ports[0] )
1367 / sr;
1368
1369 PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
1370
1371 if( stream->xrun )
1372 {
1373 /* XXX: Any way to tell which of these occurred? */
1374 cbFlags = paOutputUnderflow | paInputOverflow;
1375 stream->xrun = FALSE;
1376 }
1377 PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo,
1378 cbFlags );
1379
1380 if( stream->num_incoming_connections > 0 )
1381 PaUtil_SetInputFrameCount( &stream->bufferProcessor, frames );
1382 if( stream->num_outgoing_connections > 0 )
1383 PaUtil_SetOutputFrameCount( &stream->bufferProcessor, frames );
1384
1385 for( chn = 0; chn < stream->num_incoming_connections; chn++ )
1386 {
1387 jack_default_audio_sample_t *channel_buf = (jack_default_audio_sample_t*)
1388 jack_port_get_buffer( stream->local_input_ports[chn],
1389 frames );
1390
1391 PaUtil_SetNonInterleavedInputChannel( &stream->bufferProcessor,
1392 chn,
1393 channel_buf );
1394 }
1395
1396 for( chn = 0; chn < stream->num_outgoing_connections; chn++ )
1397 {
1398 jack_default_audio_sample_t *channel_buf = (jack_default_audio_sample_t*)
1399 jack_port_get_buffer( stream->local_output_ports[chn],
1400 frames );
1401
1402 PaUtil_SetNonInterleavedOutputChannel( &stream->bufferProcessor,
1403 chn,
1404 channel_buf );
1405 }
1406
1407 framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor,
1408 &stream->callbackResult );
1409 /* We've specified a host buffer size mode where every frame should be consumed by the buffer processor */
1410 assert( framesProcessed == frames );
1411
1412 PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
1413
1414 end:
1415 return result;
1416 }
1417
1418 /* Update the JACK callback's stream processing queue. */
1419 static PaError UpdateQueue( PaJackHostApiRepresentation *hostApi )
1420 {
1421 PaError result = paNoError;
1422 int queueModified = 0;
1423 const double jackSr = jack_get_sample_rate( hostApi->jack_client );
1424 int err;
1425
1426 if( (err = pthread_mutex_trylock( &hostApi->mtx )) != 0 )
1427 {
1428 assert( err == EBUSY );
1429 return paNoError;
1430 }
1431
1432 if( hostApi->toAdd )
1433 {
1434 if( hostApi->processQueue )
1435 {
1436 PaJackStream *node = hostApi->processQueue;
1437 /* Advance to end of queue */
1438 while( node->next )
1439 node = node->next;
1440
1441 node->next = hostApi->toAdd;
1442 }
1443 else
1444 {
1445 /* The only queue entry. */
1446 hostApi->processQueue = (PaJackStream *)hostApi->toAdd;
1447 }
1448
1449 /* If necessary, update stream state */
1450 if( hostApi->toAdd->streamRepresentation.streamInfo.sampleRate != jackSr )
1451 UpdateSampleRate( hostApi->toAdd, jackSr );
1452
1453 hostApi->toAdd = NULL;
1454 queueModified = 1;
1455 }
1456 if( hostApi->toRemove )
1457 {
1458 int removed = 0;
1459 PaJackStream *node = hostApi->processQueue, *prev = NULL;
1460 assert( hostApi->processQueue );
1461
1462 while( node )
1463 {
1464 if( node == hostApi->toRemove )
1465 {
1466 if( prev )
1467 prev->next = node->next;
1468 else
1469 hostApi->processQueue = (PaJackStream *)node->next;
1470
1471 removed = 1;
1472 break;
1473 }
1474
1475 prev = node;
1476 node = node->next;
1477 }
1478 UNLESS( removed, paInternalError );
1479 hostApi->toRemove = NULL;
1480 PA_DEBUG(( "%s: Removed stream from processing queue\n", __FUNCTION__ ));
1481 queueModified = 1;
1482 }
1483
1484 if( queueModified )
1485 {
1486 /* Signal that we've done what was asked of us */
1487 ASSERT_CALL( pthread_cond_signal( &hostApi->cond ), 0 );
1488 }
1489
1490 error:
1491 ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 );
1492
1493 return result;
1494 }
1495
1496 /* Audio processing callback invoked periodically from JACK. */
1497 static int JackCallback( jack_nframes_t frames, void *userData )
1498 {
1499 PaError result = paNoError;
1500 PaJackHostApiRepresentation *hostApi = (PaJackHostApiRepresentation *)userData;
1501 PaJackStream *stream = NULL;
1502 int xrun = hostApi->xrun;
1503 hostApi->xrun = 0;
1504
1505 assert( hostApi );
1506
1507 ENSURE_PA( UpdateQueue( hostApi ) );
1508
1509 /* Process each stream */
1510 stream = hostApi->processQueue;
1511 for( ; stream; stream = stream->next )
1512 {
1513 if( xrun ) /* Don't override if already set */
1514 stream->xrun = 1;
1515
1516 /* See if this stream is to be started */
1517 if( stream->doStart )
1518 {
1519 /* If we can't obtain a lock, we'll try next time */
1520 int err = pthread_mutex_trylock( &stream->hostApi->mtx );
1521 if( !err )
1522 {
1523 if( stream->doStart ) /* Could potentially change before obtaining the lock */
1524 {
1525 stream->is_active = 1;
1526 stream->doStart = 0;
1527 PA_DEBUG(( "%s: Starting stream\n", __FUNCTION__ ));
1528 ASSERT_CALL( pthread_cond_signal( &stream->hostApi->cond ), 0 );
1529 stream->callbackResult = paContinue;
1530 stream->isSilenced = 0;
1531 }
1532
1533 ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 );
1534 }
1535 else
1536 assert( err == EBUSY );
1537 }
1538 else if( stream->doStop || stream->doAbort ) /* Should we stop/abort stream? */
1539 {
1540 if( stream->callbackResult == paContinue ) /* Ok, make it stop */
1541 {
1542 PA_DEBUG(( "%s: Stopping stream\n", __FUNCTION__ ));
1543 stream->callbackResult = stream->doStop ? paComplete : paAbort;
1544 }
1545 }
1546
1547 if( stream->is_active )
1548 ENSURE_PA( RealProcess( stream, frames ) );
1549 /* If we have just entered inactive state, silence output */
1550 if( !stream->is_active && !stream->isSilenced )
1551 {
1552 int i;
1553
1554 /* Silence buffer after entering inactive state */
1555 PA_DEBUG(( "Silencing the output\n" ));
1556 for( i = 0; i < stream->num_outgoing_connections; ++i )
1557 {
1558 jack_default_audio_sample_t *buffer = jack_port_get_buffer( stream->local_output_ports[i], frames );
1559 memset( buffer, 0, sizeof (jack_default_audio_sample_t) * frames );
1560 }
1561
1562 stream->isSilenced = 1;
1563 }
1564
1565 if( stream->doStop || stream->doAbort )
1566 {
1567 /* See if RealProcess has acted on the request */
1568 if( !stream->is_active ) /* Ok, signal to the main thread that we've carried out the operation */
1569 {
1570 /* If we can't obtain a lock, we'll try next time */
1571 int err = pthread_mutex_trylock( &stream->hostApi->mtx );
1572 if( !err )
1573 {
1574 stream->doStop = stream->doAbort = 0;
1575 ASSERT_CALL( pthread_cond_signal( &stream->hostApi->cond ), 0 );
1576 ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 );
1577 }
1578 else
1579 assert( err == EBUSY );
1580 }
1581 }
1582 }
1583
1584 return 0;
1585 error:
1586 return -1;
1587 }
1588
1589 static PaError StartStream( PaStream *s )
1590 {
1591 PaError result = paNoError;
1592 PaJackStream *stream = (PaJackStream*)s;
1593 int i;
1594
1595 /* Ready the processor */
1596 PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
1597
1598 /* Connect the ports. Note that the ports may already have been connected by someone else in
1599 * the meantime, in which case JACK returns EEXIST. */
1600
1601 if( stream->num_incoming_connections > 0 )
1602 {
1603 for( i = 0; i < stream->num_incoming_connections; i++ )
1604 {
1605 int r = jack_connect( stream->jack_client, jack_port_name( stream->remote_output_ports[i] ),
1606 jack_port_name( stream->local_input_ports[i] ) );
1607 UNLESS( 0 == r || EEXIST == r, paUnanticipatedHostError );
1608 }
1609 }
1610
1611 if( stream->num_outgoing_connections > 0 )
1612 {
1613 for( i = 0; i < stream->num_outgoing_connections; i++ )
1614 {
1615 int r = jack_connect( stream->jack_client, jack_port_name( stream->local_output_ports[i] ),
1616 jack_port_name( stream->remote_input_ports[i] ) );
1617 UNLESS( 0 == r || EEXIST == r, paUnanticipatedHostError );
1618 }
1619 }
1620
1621 stream->xrun = FALSE;
1622
1623 /* Enable processing */
1624
1625 ASSERT_CALL( pthread_mutex_lock( &stream->hostApi->mtx ), 0 );
1626 stream->doStart = 1;
1627
1628 /* Wait for stream to be started */
1629 result = WaitCondition( stream->hostApi );
1630 /*
1631 do
1632 {
1633 err = pthread_cond_timedwait( &stream->hostApi->cond, &stream->hostApi->mtx, &ts );
1634 } while( !stream->is_active && !err );
1635 */
1636 if( result != paNoError ) /* Something went wrong, call off the stream start */
1637 {
1638 stream->doStart = 0;
1639 stream->is_active = 0; /* Cancel any processing */
1640 }
1641 ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 );
1642
1643 ENSURE_PA( result );
1644
1645 stream->is_running = TRUE;
1646 PA_DEBUG(( "%s: Stream started\n", __FUNCTION__ ));
1647
1648 error:
1649 return result;
1650 }
1651
1652 static PaError RealStop( PaJackStream *stream, int abort )
1653 {
1654 PaError result = paNoError;
1655 int i;
1656
1657 if( stream->isBlockingStream )
1658 BlockingWaitEmpty ( stream );
1659
1660 ASSERT_CALL( pthread_mutex_lock( &stream->hostApi->mtx ), 0 );
1661 if( abort )
1662 stream->doAbort = 1;
1663 else
1664 stream->doStop = 1;
1665
1666 /* Wait for stream to be stopped */
1667 result = WaitCondition( stream->hostApi );
1668 ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 );
1669 ENSURE_PA( result );
1670
1671 UNLESS( !stream->is_active, paInternalError );
1672
1673 PA_DEBUG(( "%s: Stream stopped\n", __FUNCTION__ ));
1674
1675 error:
1676 stream->is_running = FALSE;
1677
1678 /* Disconnect ports belonging to this stream */
1679
1680 if( !stream->hostApi->jackIsDown ) /* XXX: Well? */
1681 {
1682 for( i = 0; i < stream->num_incoming_connections; i++ )
1683 {
1684 if( jack_port_connected( stream->local_input_ports[i] ) )
1685 {
1686 UNLESS( !jack_port_disconnect( stream->jack_client, stream->local_input_ports[i] ),
1687 paUnanticipatedHostError );
1688 }
1689 }
1690 for( i = 0; i < stream->num_outgoing_connections; i++ )
1691 {
1692 if( jack_port_connected( stream->local_output_ports[i] ) )
1693 {
1694 UNLESS( !jack_port_disconnect( stream->jack_client, stream->local_output_ports[i] ),
1695 paUnanticipatedHostError );
1696 }
1697 }
1698 }
1699
1700 return result;
1701 }
1702
1703 static PaError StopStream( PaStream *s )
1704 {
1705 assert(s);
1706 return RealStop( (PaJackStream *)s, 0 );
1707 }
1708
1709 static PaError AbortStream( PaStream *s )
1710 {
1711 assert(s);
1712 return RealStop( (PaJackStream *)s, 1 );
1713 }
1714
1715 static PaError IsStreamStopped( PaStream *s )
1716 {
1717 PaJackStream *stream = (PaJackStream*)s;
1718 return !stream->is_running;
1719 }
1720
1721
1722 static PaError IsStreamActive( PaStream *s )
1723 {
1724 PaJackStream *stream = (PaJackStream*)s;
1725 return stream->is_active;
1726 }
1727
1728
1729 static PaTime GetStreamTime( PaStream *s )
1730 {
1731 PaJackStream *stream = (PaJackStream*)s;
1732
1733 /* A: Is this relevant?? --> TODO: what if we're recording-only? */
1734 return (jack_frame_time( stream->jack_client ) - stream->t0) / (PaTime)jack_get_sample_rate( stream->jack_client );
1735 }
1736
1737
1738 static double GetStreamCpuLoad( PaStream* s )
1739 {
1740 PaJackStream *stream = (PaJackStream*)s;
1741 return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
1742 }
1743
1744 PaError PaJack_SetClientName( const char* name )
1745 {
1746 if( strlen( name ) > jack_client_name_size() )
1747 {
1748 /* OK, I don't know any better error code */
1749 return paInvalidFlag;
1750 }
1751 clientName_ = name;
1752 return paNoError;
1753 }
1754
1755 PaError PaJack_GetClientName(const char** clientName)
1756 {
1757 PaError result = paNoError;
1758 PaJackHostApiRepresentation* jackHostApi = NULL;
1759 PaJackHostApiRepresentation** ref = &jackHostApi;
1760 ENSURE_PA( PaUtil_GetHostApiRepresentation( (PaUtilHostApiRepresentation**)ref, paJACK ) );
1761 *clientName = jack_get_client_name( jackHostApi->jack_client );
1762
1763 error:
1764 return result;
1765 }

  ViewVC Help
Powered by ViewVC 1.1.22