To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

The primary repository for this project is hosted at https://github.com/sonic-visualiser/sv-dependency-builds .
This repository is a read-only copy which is updated automatically every hour.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / src / portaudio_20161030_catalina_patch / src / hostapi / jack / pa_jack.c @ 164:9fa11135915a

History | View | Annotate | Download (61.9 KB)

1
/*
2
 * $Id$
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
/* In calls to jack_get_ports() this filter expression is used instead of ""
236
 * to prevent any other types (eg Midi ports etc) being listed */
237
#define JACK_PORT_TYPE_FILTER "audio"
238

    
239
#define TRUE 1
240
#define FALSE 0
241

    
242
/*
243
 * Functions specific to this API
244
 */
245

    
246
static int JackCallback( jack_nframes_t frames, void *userData );
247

    
248

    
249
/*
250
 *
251
 * Implementation
252
 *
253
 */
254

    
255
/* ---- blocking emulation layer ---- */
256

    
257
/* Allocate buffer. */
258
static PaError BlockingInitFIFO( PaUtilRingBuffer *rbuf, long numFrames, long bytesPerFrame )
259
{
260
    long numBytes = numFrames * bytesPerFrame;
261
    char *buffer = (char *) malloc( numBytes );
262
    if( buffer == NULL ) return paInsufficientMemory;
263
    memset( buffer, 0, numBytes );
264
    return (PaError) PaUtil_InitializeRingBuffer( rbuf, 1, numBytes, buffer );
265
}
266

    
267
/* Free buffer. */
268
static PaError BlockingTermFIFO( PaUtilRingBuffer *rbuf )
269
{
270
    if( rbuf->buffer ) free( rbuf->buffer );
271
    rbuf->buffer = NULL;
272
    return paNoError;
273
}
274

    
275
static int
276
BlockingCallback( const void                      *inputBuffer,
277
                  void                            *outputBuffer,
278
                  unsigned long                    framesPerBuffer,
279
                  const PaStreamCallbackTimeInfo*  timeInfo,
280
                  PaStreamCallbackFlags            statusFlags,
281
                  void                             *userData )
282
{
283
    struct PaJackStream *stream = (PaJackStream *)userData;
284
    long numBytes = stream->bytesPerFrame * framesPerBuffer;
285

    
286
    /* This may get called with NULL inputBuffer during initial setup. */
287
    if( inputBuffer != NULL )
288
    {
289
        PaUtil_WriteRingBuffer( &stream->inFIFO, inputBuffer, numBytes );
290
    }
291
    if( outputBuffer != NULL )
292
    {
293
        int numRead = PaUtil_ReadRingBuffer( &stream->outFIFO, outputBuffer, numBytes );
294
        /* Zero out remainder of buffer if we run out of data. */
295
        memset( (char *)outputBuffer + numRead, 0, numBytes - numRead );
296
    }
297

    
298
    if( !stream->data_available )
299
    {
300
        stream->data_available = 1;
301
        sem_post( &stream->data_semaphore );
302
    }
303
    return paContinue;
304
}
305

    
306
static PaError
307
BlockingBegin( PaJackStream *stream, int minimum_buffer_size )
308
{
309
    long    doRead = 0;
310
    long    doWrite = 0;
311
    PaError result = paNoError;
312
    long    numFrames;
313

    
314
    doRead = stream->local_input_ports != NULL;
315
    doWrite = stream->local_output_ports != NULL;
316
    /* <FIXME> */
317
    stream->samplesPerFrame = 2;
318
    stream->bytesPerFrame = sizeof(float) * stream->samplesPerFrame;
319
    /* </FIXME> */
320
    numFrames = 32;
321
    while (numFrames < minimum_buffer_size)
322
        numFrames *= 2;
323

    
324
    if( doRead )
325
    {
326
        ENSURE_PA( BlockingInitFIFO( &stream->inFIFO, numFrames, stream->bytesPerFrame ) );
327
    }
328
    if( doWrite )
329
    {
330
        long numBytes;
331

    
332
        ENSURE_PA( BlockingInitFIFO( &stream->outFIFO, numFrames, stream->bytesPerFrame ) );
333

    
334
        /* Make Write FIFO appear full initially. */
335
        numBytes = PaUtil_GetRingBufferWriteAvailable( &stream->outFIFO );
336
        PaUtil_AdvanceRingBufferWriteIndex( &stream->outFIFO, numBytes );
337
    }
338

    
339
    stream->data_available = 0;
340
    sem_init( &stream->data_semaphore, 0, 0 );
341

    
342
error:
343
    return result;
344
}
345

    
346
static void
347
BlockingEnd( PaJackStream *stream )
348
{
349
    BlockingTermFIFO( &stream->inFIFO );
350
    BlockingTermFIFO( &stream->outFIFO );
351

    
352
    sem_destroy( &stream->data_semaphore );
353
}
354

    
355
static PaError BlockingReadStream( PaStream* s, void *data, unsigned long numFrames )
356
{
357
    PaError result = paNoError;
358
    PaJackStream *stream = (PaJackStream *)s;
359

    
360
    long bytesRead;
361
    char *p = (char *) data;
362
    long numBytes = stream->bytesPerFrame * numFrames;
363
    while( numBytes > 0 )
364
    {
365
        bytesRead = PaUtil_ReadRingBuffer( &stream->inFIFO, p, numBytes );
366
        numBytes -= bytesRead;
367
        p += bytesRead;
368
        if( numBytes > 0 )
369
        {
370
            /* see write for an explanation */
371
            if( stream->data_available )
372
                stream->data_available = 0;
373
            else
374
                sem_wait( &stream->data_semaphore );
375
        }
376
    }
377

    
378
    return result;
379
}
380

    
381
static PaError BlockingWriteStream( PaStream* s, const void *data, unsigned long numFrames )
382
{
383
    PaError result = paNoError;
384
    PaJackStream *stream = (PaJackStream *)s;
385
    long bytesWritten;
386
    char *p = (char *) data;
387
    long numBytes = stream->bytesPerFrame * numFrames;
388
    while( numBytes > 0 )
389
    {
390
        bytesWritten = PaUtil_WriteRingBuffer( &stream->outFIFO, p, numBytes );
391
        numBytes -= bytesWritten;
392
        p += bytesWritten;
393
        if( numBytes > 0 )
394
        {
395
            /* we use the following algorithm:
396
             *   (1) write data
397
             *   (2) if some data didn't fit into the ringbuffer, set data_available to 0
398
             *       to indicate to the audio that if space becomes available, we want to know
399
             *   (3) retry to write data (because it might be that between (1) and (2)
400
             *       new space in the buffer became available)
401
             *   (4) if this failed, we are sure that the buffer is really empty and
402
             *       we will definitely receive a notification when it becomes available
403
             *       thus we can safely sleep
404
             *
405
             * if the algorithm bailed out in step (3) before, it leaks a count of 1
406
             * on the semaphore; however, it doesn't matter, because if we block in (4),
407
             * we also do it in a loop
408
             */
409
            if( stream->data_available )
410
                stream->data_available = 0;
411
            else
412
                sem_wait( &stream->data_semaphore );
413
        }
414
    }
415

    
416
    return result;
417
}
418

    
419
static signed long
420
BlockingGetStreamReadAvailable( PaStream* s )
421
{
422
    PaJackStream *stream = (PaJackStream *)s;
423

    
424
    int bytesFull = PaUtil_GetRingBufferReadAvailable( &stream->inFIFO );
425
    return bytesFull / stream->bytesPerFrame;
426
}
427

    
428
static signed long
429
BlockingGetStreamWriteAvailable( PaStream* s )
430
{
431
    PaJackStream *stream = (PaJackStream *)s;
432

    
433
    int bytesEmpty = PaUtil_GetRingBufferWriteAvailable( &stream->outFIFO );
434
    return bytesEmpty / stream->bytesPerFrame;
435
}
436

    
437
static PaError
438
BlockingWaitEmpty( PaStream *s )
439
{
440
    PaJackStream *stream = (PaJackStream *)s;
441

    
442
    while( PaUtil_GetRingBufferReadAvailable( &stream->outFIFO ) > 0 )
443
    {
444
        stream->data_available = 0;
445
        sem_wait( &stream->data_semaphore );
446
    }
447
    return 0;
448
}
449

    
450
/* ---- jack driver ---- */
451

    
452
/* BuildDeviceList():
453
 *
454
 * The process of determining a list of PortAudio "devices" from
455
 * JACK's client/port system is fairly involved, so it is separated
456
 * into its own routine.
457
 */
458

    
459
static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
460
{
461
    /* Utility macros for the repetitive process of allocating memory */
462

    
463
    /* JACK has no concept of a device.  To JACK, there are clients
464
     * which have an arbitrary number of ports.  To make this
465
     * intelligible to PortAudio clients, we will group each JACK client
466
     * into a device, and make each port of that client a channel */
467

    
468
    PaError result = paNoError;
469
    PaUtilHostApiRepresentation *commonApi = &jackApi->commonHostApiRep;
470

    
471
    const char **jack_ports = NULL;
472
    char **client_names = NULL;
473
    char *regex_pattern = NULL;
474
    int port_index, client_index, i;
475
    double globalSampleRate;
476
    regex_t port_regex;
477
    unsigned long numClients = 0, numPorts = 0;
478
    char *tmp_client_name = NULL;
479

    
480
    commonApi->info.defaultInputDevice = paNoDevice;
481
    commonApi->info.defaultOutputDevice = paNoDevice;
482
    commonApi->info.deviceCount = 0;
483

    
484
    /* Parse the list of ports, using a regex to grab the client names */
485
    ASSERT_CALL( regcomp( &port_regex, "^[^:]*", REG_EXTENDED ), 0 );
486

    
487
    /* since we are rebuilding the list of devices, free all memory
488
     * associated with the previous list */
489
    PaUtil_FreeAllAllocations( jackApi->deviceInfoMemory );
490

    
491
    regex_pattern = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, jack_client_name_size() + 3 );
492
    tmp_client_name = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, jack_client_name_size() );
493

    
494
    /* We can only retrieve the list of clients indirectly, by first
495
     * asking for a list of all ports, then parsing the port names
496
     * according to the client_name:port_name convention (which is
497
     * enforced by jackd)
498
     * A: If jack_get_ports returns NULL, there's nothing for us to do */
499
    UNLESS( (jack_ports = jack_get_ports( jackApi->jack_client, "", JACK_PORT_TYPE_FILTER, 0 )) && jack_ports[0], paNoError );
500
    /* Find number of ports */
501
    while( jack_ports[numPorts] )
502
        ++numPorts;
503
    /* At least there will be one port per client :) */
504
    UNLESS( client_names = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, numPorts *
505
                sizeof (char *) ), paInsufficientMemory );
506

    
507
    /* Build a list of clients from the list of ports */
508
    for( numClients = 0, port_index = 0; jack_ports[port_index] != NULL; port_index++ )
509
    {
510
        int client_seen = FALSE;
511
        regmatch_t match_info;
512
        const char *port = jack_ports[port_index];
513

    
514
        /* extract the client name from the port name, using a regex
515
         * that parses the clientname:portname syntax */
516
        UNLESS( !regexec( &port_regex, port, 1, &match_info, 0 ), paInternalError );
517
        assert(match_info.rm_eo - match_info.rm_so < jack_client_name_size());
518
        memcpy( tmp_client_name, port + match_info.rm_so,
519
                match_info.rm_eo - match_info.rm_so );
520
        tmp_client_name[match_info.rm_eo - match_info.rm_so] = '\0';
521

    
522
        /* do we know about this port's client yet? */
523
        for( i = 0; i < numClients; i++ )
524
        {
525
            if( strcmp( tmp_client_name, client_names[i] ) == 0 )
526
                client_seen = TRUE;
527
        }
528

    
529
        if (client_seen)
530
            continue;   /* A: Nothing to see here, move along */
531

    
532
        UNLESS( client_names[numClients] = (char*)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory,
533
                    strlen(tmp_client_name) + 1), paInsufficientMemory );
534

    
535
        /* The alsa_pcm client should go in spot 0.  If this
536
         * is the alsa_pcm client AND we are NOT about to put
537
         * it in spot 0 put it in spot 0 and move whatever
538
         * was already in spot 0 to the end. */
539
        if( strcmp( "alsa_pcm", tmp_client_name ) == 0 && numClients > 0 )
540
        {
541
            /* alsa_pcm goes in spot 0 */
542
            strcpy( client_names[ numClients ], client_names[0] );
543
            strcpy( client_names[0], tmp_client_name );
544
        }
545
        else
546
        {
547
            /* put the new client at the end of the client list */
548
            strcpy( client_names[ numClients ], tmp_client_name );
549
        }
550
        ++numClients;
551
    }
552

    
553
    /* Now we have a list of clients, which will become the list of
554
     * PortAudio devices. */
555

    
556
    /* there is one global sample rate all clients must conform to */
557

    
558
    globalSampleRate = jack_get_sample_rate( jackApi->jack_client );
559
    UNLESS( commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory,
560
                sizeof(PaDeviceInfo*) * numClients ), paInsufficientMemory );
561

    
562
    assert( commonApi->info.deviceCount == 0 );
563

    
564
    /* Create a PaDeviceInfo structure for every client */
565
    for( client_index = 0; client_index < numClients; client_index++ )
566
    {
567
        PaDeviceInfo *curDevInfo;
568
        const char **clientPorts = NULL;
569

    
570
        UNLESS( curDevInfo = (PaDeviceInfo*)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory,
571
                    sizeof(PaDeviceInfo) ), paInsufficientMemory );
572
        UNLESS( curDevInfo->name = (char*)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory,
573
                    strlen(client_names[client_index]) + 1 ), paInsufficientMemory );
574
        strcpy( (char *)curDevInfo->name, client_names[client_index] );
575

    
576
        curDevInfo->structVersion = 2;
577
        curDevInfo->hostApi = jackApi->hostApiIndex;
578

    
579
        /* JACK is very inflexible: there is one sample rate the whole
580
         * system must run at, and all clients must speak IEEE float. */
581
        curDevInfo->defaultSampleRate = globalSampleRate;
582

    
583
        /* To determine how many input and output channels are available,
584
         * we re-query jackd with more specific parameters. */
585

    
586
        sprintf( regex_pattern, "%s:.*", client_names[client_index] );
587

    
588
        /* ... what are your output ports (that we could input from)? */
589
        clientPorts = jack_get_ports( jackApi->jack_client, regex_pattern,
590
                                     JACK_PORT_TYPE_FILTER, JackPortIsOutput);
591
        curDevInfo->maxInputChannels = 0;
592
        curDevInfo->defaultLowInputLatency = 0.;
593
        curDevInfo->defaultHighInputLatency = 0.;
594
        if( clientPorts )
595
        {
596
            jack_port_t *p = jack_port_by_name( jackApi->jack_client, clientPorts[0] );
597
            curDevInfo->defaultLowInputLatency = curDevInfo->defaultHighInputLatency =
598
                jack_port_get_latency( p ) / globalSampleRate;
599

    
600
            for( i = 0; clientPorts[i] != NULL; i++)
601
            {
602
                /* The number of ports returned is the number of output channels.
603
                 * We don't care what they are, we just care how many */
604
                curDevInfo->maxInputChannels++;
605
            }
606
            free(clientPorts);
607
        }
608

    
609
        /* ... what are your input ports (that we could output to)? */
610
        clientPorts = jack_get_ports( jackApi->jack_client, regex_pattern,
611
                                     JACK_PORT_TYPE_FILTER, JackPortIsInput);
612
        curDevInfo->maxOutputChannels = 0;
613
        curDevInfo->defaultLowOutputLatency = 0.;
614
        curDevInfo->defaultHighOutputLatency = 0.;
615
        if( clientPorts )
616
        {
617
            jack_port_t *p = jack_port_by_name( jackApi->jack_client, clientPorts[0] );
618
            curDevInfo->defaultLowOutputLatency = curDevInfo->defaultHighOutputLatency =
619
                jack_port_get_latency( p ) / globalSampleRate;
620

    
621
            for( i = 0; clientPorts[i] != NULL; i++)
622
            {
623
                /* The number of ports returned is the number of input channels.
624
                 * We don't care what they are, we just care how many */
625
                curDevInfo->maxOutputChannels++;
626
            }
627
            free(clientPorts);
628
        }
629

    
630
        /* Add this client to the list of devices */
631
        commonApi->deviceInfos[client_index] = curDevInfo;
632
        ++commonApi->info.deviceCount;
633
        if( commonApi->info.defaultInputDevice == paNoDevice && curDevInfo->maxInputChannels > 0 )
634
            commonApi->info.defaultInputDevice = client_index;
635
        if( commonApi->info.defaultOutputDevice == paNoDevice && curDevInfo->maxOutputChannels > 0 )
636
            commonApi->info.defaultOutputDevice = client_index;
637
    }
638

    
639
error:
640
    regfree( &port_regex );
641
    free( jack_ports );
642
    return result;
643
}
644

    
645
static void UpdateSampleRate( PaJackStream *stream, double sampleRate )
646
{
647
    /* XXX: Maybe not the cleanest way of going about this? */
648
    stream->cpuLoadMeasurer.samplingPeriod = stream->bufferProcessor.samplePeriod = 1. / sampleRate;
649
    stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
650
}
651

    
652
static void JackErrorCallback( const char *msg )
653
{
654
    if( pthread_self() == mainThread_ )
655
    {
656
        assert( msg );
657
        jackErr_ = realloc( jackErr_, strlen( msg ) + 1 );
658
        strcpy( jackErr_, msg );
659
    }
660
}
661

    
662
static void JackOnShutdown( void *arg )
663
{
664
    PaJackHostApiRepresentation *jackApi = (PaJackHostApiRepresentation *)arg;
665
    PaJackStream *stream = jackApi->processQueue;
666

    
667
    PA_DEBUG(( "%s: JACK server is shutting down\n", __FUNCTION__ ));
668
    for( ; stream; stream = stream->next )
669
    {
670
        stream->is_active = 0;
671
    }
672

    
673
    /* Make sure that the main thread doesn't get stuck waiting on the condition */
674
    ASSERT_CALL( pthread_mutex_lock( &jackApi->mtx ), 0 );
675
    jackApi->jackIsDown = 1;
676
    ASSERT_CALL( pthread_cond_signal( &jackApi->cond ), 0 );
677
    ASSERT_CALL( pthread_mutex_unlock( &jackApi->mtx ), 0 );
678

    
679
}
680

    
681
static int JackSrCb( jack_nframes_t nframes, void *arg )
682
{
683
    PaJackHostApiRepresentation *jackApi = (PaJackHostApiRepresentation *)arg;
684
    double sampleRate = (double)nframes;
685
    PaJackStream *stream = jackApi->processQueue;
686

    
687
    /* Update all streams in process queue */
688
    PA_DEBUG(( "%s: Acting on change in JACK samplerate: %f\n", __FUNCTION__, sampleRate ));
689
    for( ; stream; stream = stream->next )
690
    {
691
        if( stream->streamRepresentation.streamInfo.sampleRate != sampleRate )
692
        {
693
            PA_DEBUG(( "%s: Updating samplerate\n", __FUNCTION__ ));
694
            UpdateSampleRate( stream, sampleRate );
695
        }
696
    }
697

    
698
    return 0;
699
}
700

    
701
static int JackXRunCb(void *arg) {
702
    PaJackHostApiRepresentation *hostApi = (PaJackHostApiRepresentation *)arg;
703
    assert( hostApi );
704
    hostApi->xrun = TRUE;
705
    PA_DEBUG(( "%s: JACK signalled xrun\n", __FUNCTION__ ));
706
    return 0;
707
}
708

    
709
PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi,
710
                           PaHostApiIndex hostApiIndex )
711
{
712
    PaError result = paNoError;
713
    PaJackHostApiRepresentation *jackHostApi;
714
    int activated = 0;
715
    jack_status_t jackStatus = 0;
716
    *hostApi = NULL;    /* Initialize to NULL */
717

    
718
    UNLESS( jackHostApi = (PaJackHostApiRepresentation*)
719
        PaUtil_AllocateMemory( sizeof(PaJackHostApiRepresentation) ), paInsufficientMemory );
720
    UNLESS( jackHostApi->deviceInfoMemory = PaUtil_CreateAllocationGroup(), paInsufficientMemory );
721

    
722
    mainThread_ = pthread_self();
723
    ASSERT_CALL( pthread_mutex_init( &jackHostApi->mtx, NULL ), 0 );
724
    ASSERT_CALL( pthread_cond_init( &jackHostApi->cond, NULL ), 0 );
725

    
726
    /* Try to become a client of the JACK server.  If we cannot do
727
     * this, then this API cannot be used.
728
     *
729
     * Without the JackNoStartServer option, the jackd server is started
730
     * automatically which we do not want.
731
     */
732

    
733
    jackHostApi->jack_client = jack_client_open( clientName_, JackNoStartServer, &jackStatus );
734
    if( !jackHostApi->jack_client )
735
    {
736
        /* the V19 development docs say that if an implementation
737
         * detects that it cannot be used, it should return a NULL
738
         * interface and paNoError */
739
        PA_DEBUG(( "%s: Couldn't connect to JACK, status: %d\n", __FUNCTION__, jackStatus ));
740
        result = paNoError;
741
        goto error;
742
    }
743

    
744
    jackHostApi->hostApiIndex = hostApiIndex;
745

    
746
    *hostApi = &jackHostApi->commonHostApiRep;
747
    (*hostApi)->info.structVersion = 1;
748
    (*hostApi)->info.type = paJACK;
749
    (*hostApi)->info.name = "JACK Audio Connection Kit";
750

    
751
    /* Build a device list by querying the JACK server */
752
    ENSURE_PA( BuildDeviceList( jackHostApi ) );
753

    
754
    /* Register functions */
755

    
756
    (*hostApi)->Terminate = Terminate;
757
    (*hostApi)->OpenStream = OpenStream;
758
    (*hostApi)->IsFormatSupported = IsFormatSupported;
759

    
760
    PaUtil_InitializeStreamInterface( &jackHostApi->callbackStreamInterface,
761
                                      CloseStream, StartStream,
762
                                      StopStream, AbortStream,
763
                                      IsStreamStopped, IsStreamActive,
764
                                      GetStreamTime, GetStreamCpuLoad,
765
                                      PaUtil_DummyRead, PaUtil_DummyWrite,
766
                                      PaUtil_DummyGetReadAvailable,
767
                                      PaUtil_DummyGetWriteAvailable );
768

    
769
    PaUtil_InitializeStreamInterface( &jackHostApi->blockingStreamInterface, CloseStream, StartStream,
770
                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
771
                                      GetStreamTime, PaUtil_DummyGetCpuLoad,
772
                                      BlockingReadStream, BlockingWriteStream,
773
                                      BlockingGetStreamReadAvailable, BlockingGetStreamWriteAvailable );
774

    
775
    jackHostApi->inputBase = jackHostApi->outputBase = 0;
776
    jackHostApi->xrun = 0;
777
    jackHostApi->toAdd = jackHostApi->toRemove = NULL;
778
    jackHostApi->processQueue = NULL;
779
    jackHostApi->jackIsDown = 0;
780

    
781
    jack_on_shutdown( jackHostApi->jack_client, JackOnShutdown, jackHostApi );
782
    jack_set_error_function( JackErrorCallback );
783
    jackHostApi->jack_buffer_size = jack_get_buffer_size ( jackHostApi->jack_client );
784
    /* Don't check for error, may not be supported (deprecated in at least jackdmp) */
785
    jack_set_sample_rate_callback( jackHostApi->jack_client, JackSrCb, jackHostApi );
786
    UNLESS( !jack_set_xrun_callback( jackHostApi->jack_client, JackXRunCb, jackHostApi ), paUnanticipatedHostError );
787
    UNLESS( !jack_set_process_callback( jackHostApi->jack_client, JackCallback, jackHostApi ), paUnanticipatedHostError );
788
    UNLESS( !jack_activate( jackHostApi->jack_client ), paUnanticipatedHostError );
789
    activated = 1;
790

    
791
    return result;
792

    
793
error:
794
    if( activated )
795
        ASSERT_CALL( jack_deactivate( jackHostApi->jack_client ), 0 );
796

    
797
    if( jackHostApi )
798
    {
799
        if( jackHostApi->jack_client )
800
            ASSERT_CALL( jack_client_close( jackHostApi->jack_client ), 0 );
801

    
802
        if( jackHostApi->deviceInfoMemory )
803
        {
804
            PaUtil_FreeAllAllocations( jackHostApi->deviceInfoMemory );
805
            PaUtil_DestroyAllocationGroup( jackHostApi->deviceInfoMemory );
806
        }
807

    
808
        PaUtil_FreeMemory( jackHostApi );
809
    }
810
    return result;
811
}
812

    
813

    
814
static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
815
{
816
    PaJackHostApiRepresentation *jackHostApi = (PaJackHostApiRepresentation*)hostApi;
817

    
818
    /* note: this automatically disconnects all ports, since a deactivated
819
     * client is not allowed to have any ports connected */
820
    ASSERT_CALL( jack_deactivate( jackHostApi->jack_client ), 0 );
821

    
822
    ASSERT_CALL( pthread_mutex_destroy( &jackHostApi->mtx ), 0 );
823
    ASSERT_CALL( pthread_cond_destroy( &jackHostApi->cond ), 0 );
824

    
825
    ASSERT_CALL( jack_client_close( jackHostApi->jack_client ), 0 );
826

    
827
    if( jackHostApi->deviceInfoMemory )
828
    {
829
        PaUtil_FreeAllAllocations( jackHostApi->deviceInfoMemory );
830
        PaUtil_DestroyAllocationGroup( jackHostApi->deviceInfoMemory );
831
    }
832

    
833
    PaUtil_FreeMemory( jackHostApi );
834

    
835
    free( jackErr_ );
836
    jackErr_ = NULL;
837
}
838

    
839
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
840
                                  const PaStreamParameters *inputParameters,
841
                                  const PaStreamParameters *outputParameters,
842
                                  double sampleRate )
843
{
844
    int inputChannelCount = 0, outputChannelCount = 0;
845
    PaSampleFormat inputSampleFormat, outputSampleFormat;
846

    
847
    if( inputParameters )
848
    {
849
        inputChannelCount = inputParameters->channelCount;
850
        inputSampleFormat = inputParameters->sampleFormat;
851

    
852
        /* unless alternate device specification is supported, reject the use of
853
            paUseHostApiSpecificDeviceSpecification */
854

    
855
        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
856
            return paInvalidDevice;
857

    
858
        /* check that input device can support inputChannelCount */
859
        if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
860
            return paInvalidChannelCount;
861

    
862
        /* validate inputStreamInfo */
863
        if( inputParameters->hostApiSpecificStreamInfo )
864
            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
865
    }
866
    else
867
    {
868
        inputChannelCount = 0;
869
    }
870

    
871
    if( outputParameters )
872
    {
873
        outputChannelCount = outputParameters->channelCount;
874
        outputSampleFormat = outputParameters->sampleFormat;
875

    
876
        /* unless alternate device specification is supported, reject the use of
877
            paUseHostApiSpecificDeviceSpecification */
878

    
879
        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
880
            return paInvalidDevice;
881

    
882
        /* check that output device can support inputChannelCount */
883
        if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
884
            return paInvalidChannelCount;
885

    
886
        /* validate outputStreamInfo */
887
        if( outputParameters->hostApiSpecificStreamInfo )
888
            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
889
    }
890
    else
891
    {
892
        outputChannelCount = 0;
893
    }
894

    
895
    /*
896
        The following check is not necessary for JACK.
897

898
            - if a full duplex stream is requested, check that the combination
899
                of input and output parameters is supported
900

901

902
        Because the buffer adapter handles conversion between all standard
903
        sample formats, the following checks are only required if paCustomFormat
904
        is implemented, or under some other unusual conditions.
905

906
            - check that input device can support inputSampleFormat, or that
907
                we have the capability to convert from outputSampleFormat to
908
                a native format
909

910
            - check that output device can support outputSampleFormat, or that
911
                we have the capability to convert from outputSampleFormat to
912
                a native format
913
    */
914

    
915
    /* check that the device supports sampleRate */
916

    
917
#define ABS(x) ( (x) > 0 ? (x) : -(x) )
918
    if( ABS(sampleRate - jack_get_sample_rate(((PaJackHostApiRepresentation *) hostApi)->jack_client )) > 1 )
919
       return paInvalidSampleRate;
920
#undef ABS
921

    
922
    return paFormatIsSupported;
923
}
924

    
925
/* Basic stream initialization */
926
static PaError InitializeStream( PaJackStream *stream, PaJackHostApiRepresentation *hostApi, int numInputChannels,
927
        int numOutputChannels )
928
{
929
    PaError result = paNoError;
930
    assert( stream );
931

    
932
    memset( stream, 0, sizeof (PaJackStream) );
933
    UNLESS( stream->stream_memory = PaUtil_CreateAllocationGroup(), paInsufficientMemory );
934
    stream->jack_client = hostApi->jack_client;
935
    stream->hostApi = hostApi;
936

    
937
    if( numInputChannels > 0 )
938
    {
939
        UNLESS( stream->local_input_ports =
940
                (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numInputChannels ),
941
                paInsufficientMemory );
942
        memset( stream->local_input_ports, 0, sizeof(jack_port_t*) * numInputChannels );
943
        UNLESS( stream->remote_output_ports =
944
                (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numInputChannels ),
945
                paInsufficientMemory );
946
        memset( stream->remote_output_ports, 0, sizeof(jack_port_t*) * numInputChannels );
947
    }
948
    if( numOutputChannels > 0 )
949
    {
950
        UNLESS( stream->local_output_ports =
951
                (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numOutputChannels ),
952
                paInsufficientMemory );
953
        memset( stream->local_output_ports, 0, sizeof(jack_port_t*) * numOutputChannels );
954
        UNLESS( stream->remote_input_ports =
955
                (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numOutputChannels ),
956
                paInsufficientMemory );
957
        memset( stream->remote_input_ports, 0, sizeof(jack_port_t*) * numOutputChannels );
958
    }
959

    
960
    stream->num_incoming_connections = numInputChannels;
961
    stream->num_outgoing_connections = numOutputChannels;
962

    
963
error:
964
    return result;
965
}
966

    
967
/*!
968
 * Free resources associated with stream, and eventually stream itself.
969
 *
970
 * Frees allocated memory, and closes opened pcms.
971
 */
972
static void CleanUpStream( PaJackStream *stream, int terminateStreamRepresentation, int terminateBufferProcessor )
973
{
974
    int i;
975
    assert( stream );
976

    
977
    if( stream->isBlockingStream )
978
        BlockingEnd( stream );
979

    
980
    for( i = 0; i < stream->num_incoming_connections; ++i )
981
    {
982
        if( stream->local_input_ports[i] )
983
            ASSERT_CALL( jack_port_unregister( stream->jack_client, stream->local_input_ports[i] ), 0 );
984
    }
985
    for( i = 0; i < stream->num_outgoing_connections; ++i )
986
    {
987
        if( stream->local_output_ports[i] )
988
            ASSERT_CALL( jack_port_unregister( stream->jack_client, stream->local_output_ports[i] ), 0 );
989
    }
990

    
991
    if( terminateStreamRepresentation )
992
        PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
993
    if( terminateBufferProcessor )
994
        PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
995

    
996
    if( stream->stream_memory )
997
    {
998
        PaUtil_FreeAllAllocations( stream->stream_memory );
999
        PaUtil_DestroyAllocationGroup( stream->stream_memory );
1000
    }
1001
    PaUtil_FreeMemory( stream );
1002
}
1003

    
1004
static PaError WaitCondition( PaJackHostApiRepresentation *hostApi )
1005
{
1006
    PaError result = paNoError;
1007
    int err = 0;
1008
    PaTime pt = PaUtil_GetTime();
1009
    struct timespec ts;
1010

    
1011
    ts.tv_sec = (time_t) floor( pt + 10 * 60 /* 10 minutes */ );
1012
    ts.tv_nsec = (long) ((pt - floor( pt )) * 1000000000);
1013
    /* XXX: Best enclose in loop, in case of spurious wakeups? */
1014
    err = pthread_cond_timedwait( &hostApi->cond, &hostApi->mtx, &ts );
1015

    
1016
    /* Make sure we didn't time out */
1017
    UNLESS( err != ETIMEDOUT, paTimedOut );
1018
    UNLESS( !err, paInternalError );
1019

    
1020
error:
1021
    return result;
1022
}
1023

    
1024
static PaError AddStream( PaJackStream *stream )
1025
{
1026
    PaError result = paNoError;
1027
    PaJackHostApiRepresentation *hostApi = stream->hostApi;
1028
    /* Add to queue of streams that should be processed */
1029
    ASSERT_CALL( pthread_mutex_lock( &hostApi->mtx ), 0 );
1030
    if( !hostApi->jackIsDown )
1031
    {
1032
        hostApi->toAdd = stream;
1033
        /* Unlock mutex and await signal from processing thread */
1034
        result = WaitCondition( stream->hostApi );
1035
    }
1036
    ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 );
1037
    ENSURE_PA( result );
1038

    
1039
    UNLESS( !hostApi->jackIsDown, paDeviceUnavailable );
1040

    
1041
error:
1042
    return result;
1043
}
1044

    
1045
/* Remove stream from processing queue */
1046
static PaError RemoveStream( PaJackStream *stream )
1047
{
1048
    PaError result = paNoError;
1049
    PaJackHostApiRepresentation *hostApi = stream->hostApi;
1050

    
1051
    /* Add to queue over streams that should be processed */
1052
    ASSERT_CALL( pthread_mutex_lock( &hostApi->mtx ), 0 );
1053
    if( !hostApi->jackIsDown )
1054
    {
1055
        hostApi->toRemove = stream;
1056
        /* Unlock mutex and await signal from processing thread */
1057
        result = WaitCondition( stream->hostApi );
1058
    }
1059
    ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 );
1060
    ENSURE_PA( result );
1061

    
1062
error:
1063
    return result;
1064
}
1065

    
1066
/* Add stream to JACK callback processing queue */
1067
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
1068
                           PaStream** s,
1069
                           const PaStreamParameters *inputParameters,
1070
                           const PaStreamParameters *outputParameters,
1071
                           double sampleRate,
1072
                           unsigned long framesPerBuffer,
1073
                           PaStreamFlags streamFlags,
1074
                           PaStreamCallback *streamCallback,
1075
                           void *userData )
1076
{
1077
    PaError result = paNoError;
1078
    PaJackHostApiRepresentation *jackHostApi = (PaJackHostApiRepresentation*)hostApi;
1079
    PaJackStream *stream = NULL;
1080
    char *port_string = PaUtil_GroupAllocateMemory( jackHostApi->deviceInfoMemory, jack_port_name_size() );
1081
    unsigned long regexSz = jack_client_name_size() + 3;
1082
    char *regex_pattern = PaUtil_GroupAllocateMemory( jackHostApi->deviceInfoMemory, regexSz );
1083
    const char **jack_ports = NULL;
1084
    /* int jack_max_buffer_size = jack_get_buffer_size( jackHostApi->jack_client ); */
1085
    int i;
1086
    int inputChannelCount, outputChannelCount;
1087
    const double jackSr = jack_get_sample_rate( jackHostApi->jack_client );
1088
    PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0;
1089
    int bpInitialized = 0, srInitialized = 0;   /* Initialized buffer processor and stream representation? */
1090
    unsigned long ofs;
1091

    
1092
    /* validate platform specific flags */
1093
    if( (streamFlags & paPlatformSpecificFlags) != 0 )
1094
        return paInvalidFlag; /* unexpected platform specific flag */
1095
    if( (streamFlags & paPrimeOutputBuffersUsingStreamCallback) != 0 )
1096
    {
1097
        streamFlags &= ~paPrimeOutputBuffersUsingStreamCallback;
1098
        /*return paInvalidFlag;*/   /* This implementation does not support buffer priming */
1099
    }
1100

    
1101
    if( framesPerBuffer != paFramesPerBufferUnspecified )
1102
    {
1103
        /* Jack operates with power of two buffers, and we don't support non-integer buffer adaption (yet) */
1104
        /*UNLESS( !(framesPerBuffer & (framesPerBuffer - 1)), paBufferTooBig );*/  /* TODO: Add descriptive error code? */
1105
    }
1106

    
1107
    /* Preliminary checks */
1108

    
1109
    if( inputParameters )
1110
    {
1111
        inputChannelCount = inputParameters->channelCount;
1112
        inputSampleFormat = inputParameters->sampleFormat;
1113

    
1114
        /* unless alternate device specification is supported, reject the use of
1115
            paUseHostApiSpecificDeviceSpecification */
1116

    
1117
        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
1118
            return paInvalidDevice;
1119

    
1120
        /* check that input device can support inputChannelCount */
1121
        if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
1122
            return paInvalidChannelCount;
1123

    
1124
        /* validate inputStreamInfo */
1125
        if( inputParameters->hostApiSpecificStreamInfo )
1126
            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
1127
    }
1128
    else
1129
    {
1130
        inputChannelCount = 0;
1131
    }
1132

    
1133
    if( outputParameters )
1134
    {
1135
        outputChannelCount = outputParameters->channelCount;
1136
        outputSampleFormat = outputParameters->sampleFormat;
1137

    
1138
        /* unless alternate device specification is supported, reject the use of
1139
            paUseHostApiSpecificDeviceSpecification */
1140

    
1141
        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
1142
            return paInvalidDevice;
1143

    
1144
        /* check that output device can support inputChannelCount */
1145
        if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
1146
            return paInvalidChannelCount;
1147

    
1148
        /* validate outputStreamInfo */
1149
        if( outputParameters->hostApiSpecificStreamInfo )
1150
            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
1151
    }
1152
    else
1153
    {
1154
        outputChannelCount = 0;
1155
    }
1156

    
1157
    /* ... check that the sample rate exactly matches the ONE acceptable rate
1158
     * A: This rate isn't necessarily constant though? */
1159

    
1160
#define ABS(x) ( (x) > 0 ? (x) : -(x) )
1161
    if( ABS(sampleRate - jackSr) > 1 )
1162
       return paInvalidSampleRate;
1163
#undef ABS
1164

    
1165
    UNLESS( stream = (PaJackStream*)PaUtil_AllocateMemory( sizeof(PaJackStream) ), paInsufficientMemory );
1166
    ENSURE_PA( InitializeStream( stream, jackHostApi, inputChannelCount, outputChannelCount ) );
1167

    
1168
    /* the blocking emulation, if necessary */
1169
    stream->isBlockingStream = !streamCallback;
1170
    if( stream->isBlockingStream )
1171
    {
1172
        float latency = 0.001; /* 1ms is the absolute minimum we support */
1173
        int   minimum_buffer_frames = 0;
1174

    
1175
        if( inputParameters && inputParameters->suggestedLatency > latency )
1176
            latency = inputParameters->suggestedLatency;
1177
        else if( outputParameters && outputParameters->suggestedLatency > latency )
1178
            latency = outputParameters->suggestedLatency;
1179

    
1180
        /* the latency the user asked for indicates the minimum buffer size in frames */
1181
        minimum_buffer_frames = (int) (latency * jack_get_sample_rate( jackHostApi->jack_client ));
1182

    
1183
        /* we also need to be able to store at least three full jack buffers to avoid dropouts */
1184
        if( jackHostApi->jack_buffer_size * 3 > minimum_buffer_frames )
1185
            minimum_buffer_frames = jackHostApi->jack_buffer_size * 3;
1186

    
1187
        /* setup blocking API data structures (FIXME: can fail) */
1188
        BlockingBegin( stream, minimum_buffer_frames );
1189

    
1190
        /* install our own callback for the blocking API */
1191
        streamCallback = BlockingCallback;
1192
        userData = stream;
1193

    
1194
        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
1195
                                               &jackHostApi->blockingStreamInterface, streamCallback, userData );
1196
    }
1197
    else
1198
    {
1199
        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
1200
                                               &jackHostApi->callbackStreamInterface, streamCallback, userData );
1201
    }
1202
    srInitialized = 1;
1203
    PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, jackSr );
1204

    
1205
    /* create the JACK ports.  We cannot connect them until audio
1206
     * processing begins */
1207

    
1208
    /* Register a unique set of ports for this stream
1209
     * TODO: Robust allocation of new port names */
1210

    
1211
    ofs = jackHostApi->inputBase;
1212
    for( i = 0; i < inputChannelCount; i++ )
1213
    {
1214
        snprintf( port_string, jack_port_name_size(), "in_%lu", ofs + i );
1215
        UNLESS( stream->local_input_ports[i] = jack_port_register(
1216
              jackHostApi->jack_client, port_string,
1217
              JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ), paInsufficientMemory );
1218
    }
1219
    jackHostApi->inputBase += inputChannelCount;
1220

    
1221
    ofs = jackHostApi->outputBase;
1222
    for( i = 0; i < outputChannelCount; i++ )
1223
    {
1224
        snprintf( port_string, jack_port_name_size(), "out_%lu", ofs + i );
1225
        UNLESS( stream->local_output_ports[i] = jack_port_register(
1226
             jackHostApi->jack_client, port_string,
1227
             JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ), paInsufficientMemory );
1228
    }
1229
    jackHostApi->outputBase += outputChannelCount;
1230

    
1231
    /* look up the jack_port_t's for the remote ports.  We could do
1232
     * this at stream start time, but doing it here ensures the
1233
     * name lookup only happens once. */
1234

    
1235
    if( inputChannelCount > 0 )
1236
    {
1237
        int err = 0;
1238

    
1239
        /* Get output ports of our capture device */
1240
        snprintf( regex_pattern, regexSz, "%s:.*", hostApi->deviceInfos[ inputParameters->device ]->name );
1241
        UNLESS( jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern,
1242
                                     JACK_PORT_TYPE_FILTER, JackPortIsOutput ), paUnanticipatedHostError );
1243
        for( i = 0; i < inputChannelCount && jack_ports[i]; i++ )
1244
        {
1245
            if( (stream->remote_output_ports[i] = jack_port_by_name(
1246
                 jackHostApi->jack_client, jack_ports[i] )) == NULL )
1247
            {
1248
                err = 1;
1249
                break;
1250
            }
1251
        }
1252
        free( jack_ports );
1253
        UNLESS( !err, paInsufficientMemory );
1254

    
1255
        /* Fewer ports than expected? */
1256
        UNLESS( i == inputChannelCount, paInternalError );
1257
    }
1258

    
1259
    if( outputChannelCount > 0 )
1260
    {
1261
        int err = 0;
1262

    
1263
        /* Get input ports of our playback device */
1264
        snprintf( regex_pattern, regexSz, "%s:.*", hostApi->deviceInfos[ outputParameters->device ]->name );
1265
        UNLESS( jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern,
1266
                                     JACK_PORT_TYPE_FILTER, JackPortIsInput ), paUnanticipatedHostError );
1267
        for( i = 0; i < outputChannelCount && jack_ports[i]; i++ )
1268
        {
1269
            if( (stream->remote_input_ports[i] = jack_port_by_name(
1270
                 jackHostApi->jack_client, jack_ports[i] )) == 0 )
1271
            {
1272
                err = 1;
1273
                break;
1274
            }
1275
        }
1276
        free( jack_ports );
1277
        UNLESS( !err , paInsufficientMemory );
1278

    
1279
        /* Fewer ports than expected? */
1280
        UNLESS( i == outputChannelCount, paInternalError );
1281
    }
1282

    
1283
    ENSURE_PA( PaUtil_InitializeBufferProcessor(
1284
                  &stream->bufferProcessor,
1285
                  inputChannelCount,
1286
                  inputSampleFormat,
1287
                  paFloat32 | paNonInterleaved, /* hostInputSampleFormat */
1288
                  outputChannelCount,
1289
                  outputSampleFormat,
1290
                  paFloat32 | paNonInterleaved, /* hostOutputSampleFormat */
1291
                  jackSr,
1292
                  streamFlags,
1293
                  framesPerBuffer,
1294
                  0,                            /* Ignored */
1295
                  paUtilUnknownHostBufferSize,  /* Buffer size may vary on JACK's discretion */
1296
                  streamCallback,
1297
                  userData ) );
1298
    bpInitialized = 1;
1299

    
1300
    if( stream->num_incoming_connections > 0 )
1301
        stream->streamRepresentation.streamInfo.inputLatency = (jack_port_get_latency( stream->remote_output_ports[0] )
1302
                - jack_get_buffer_size( jackHostApi->jack_client )  /* One buffer is not counted as latency */
1303
            + PaUtil_GetBufferProcessorInputLatencyFrames( &stream->bufferProcessor )) / sampleRate;
1304
    if( stream->num_outgoing_connections > 0 )
1305
        stream->streamRepresentation.streamInfo.outputLatency = (jack_port_get_latency( stream->remote_input_ports[0] )
1306
                - jack_get_buffer_size( jackHostApi->jack_client )  /* One buffer is not counted as latency */
1307
            + PaUtil_GetBufferProcessorOutputLatencyFrames( &stream->bufferProcessor )) / sampleRate;
1308

    
1309
    stream->streamRepresentation.streamInfo.sampleRate = jackSr;
1310
    stream->t0 = jack_frame_time( jackHostApi->jack_client );   /* A: Time should run from Pa_OpenStream */
1311

    
1312
    /* Add to queue of opened streams */
1313
    ENSURE_PA( AddStream( stream ) );
1314

    
1315
    *s = (PaStream*)stream;
1316

    
1317
    return result;
1318

    
1319
error:
1320
    if( stream )
1321
        CleanUpStream( stream, srInitialized, bpInitialized );
1322

    
1323
    return result;
1324
}
1325

    
1326
/*
1327
    When CloseStream() is called, the multi-api layer ensures that
1328
    the stream has already been stopped or aborted.
1329
*/
1330
static PaError CloseStream( PaStream* s )
1331
{
1332
    PaError result = paNoError;
1333
    PaJackStream *stream = (PaJackStream*)s;
1334

    
1335
    /* Remove this stream from the processing queue */
1336
    ENSURE_PA( RemoveStream( stream ) );
1337

    
1338
error:
1339
    CleanUpStream( stream, 1, 1 );
1340
    return result;
1341
}
1342

    
1343
static PaError RealProcess( PaJackStream *stream, jack_nframes_t frames )
1344
{
1345
    PaError result = paNoError;
1346
    PaStreamCallbackTimeInfo timeInfo = {0,0,0};
1347
    int chn;
1348
    int framesProcessed;
1349
    const double sr = jack_get_sample_rate( stream->jack_client );    /* Shouldn't change during the process callback */
1350
    PaStreamCallbackFlags cbFlags = 0;
1351

    
1352
    /* If the user has returned !paContinue from the callback we'll want to flush the internal buffers,
1353
     * when these are empty we can finally mark the stream as inactive */
1354
    if( stream->callbackResult != paContinue &&
1355
            PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) )
1356
    {
1357
        stream->is_active = 0;
1358
        if( stream->streamRepresentation.streamFinishedCallback )
1359
            stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
1360
        PA_DEBUG(( "%s: Callback finished\n", __FUNCTION__ ));
1361

    
1362
        goto end;
1363
    }
1364

    
1365
    timeInfo.currentTime = (jack_frame_time( stream->jack_client ) - stream->t0) / sr;
1366
    if( stream->num_incoming_connections > 0 )
1367
        timeInfo.inputBufferAdcTime = timeInfo.currentTime - jack_port_get_latency( stream->remote_output_ports[0] )
1368
            / sr;
1369
    if( stream->num_outgoing_connections > 0 )
1370
        timeInfo.outputBufferDacTime = timeInfo.currentTime + jack_port_get_latency( stream->remote_input_ports[0] )
1371
            / sr;
1372

    
1373
    PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
1374

    
1375
    if( stream->xrun )
1376
    {
1377
        /* XXX: Any way to tell which of these occurred? */
1378
        cbFlags = paOutputUnderflow | paInputOverflow;
1379
        stream->xrun = FALSE;
1380
    }
1381
    PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo,
1382
            cbFlags );
1383

    
1384
    if( stream->num_incoming_connections > 0 )
1385
        PaUtil_SetInputFrameCount( &stream->bufferProcessor, frames );
1386
    if( stream->num_outgoing_connections > 0 )
1387
        PaUtil_SetOutputFrameCount( &stream->bufferProcessor, frames );
1388

    
1389
    for( chn = 0; chn < stream->num_incoming_connections; chn++ )
1390
    {
1391
        jack_default_audio_sample_t *channel_buf = (jack_default_audio_sample_t*)
1392
            jack_port_get_buffer( stream->local_input_ports[chn],
1393
                    frames );
1394

    
1395
        PaUtil_SetNonInterleavedInputChannel( &stream->bufferProcessor,
1396
                chn,
1397
                channel_buf );
1398
    }
1399

    
1400
    for( chn = 0; chn < stream->num_outgoing_connections; chn++ )
1401
    {
1402
        jack_default_audio_sample_t *channel_buf = (jack_default_audio_sample_t*)
1403
            jack_port_get_buffer( stream->local_output_ports[chn],
1404
                    frames );
1405

    
1406
        PaUtil_SetNonInterleavedOutputChannel( &stream->bufferProcessor,
1407
                chn,
1408
                channel_buf );
1409
    }
1410

    
1411
    framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor,
1412
            &stream->callbackResult );
1413
    /* We've specified a host buffer size mode where every frame should be consumed by the buffer processor */
1414
    assert( framesProcessed == frames );
1415

    
1416
    PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
1417

    
1418
end:
1419
    return result;
1420
}
1421

    
1422
/* Update the JACK callback's stream processing queue. */
1423
static PaError UpdateQueue( PaJackHostApiRepresentation *hostApi )
1424
{
1425
    PaError result = paNoError;
1426
    int queueModified = 0;
1427
    const double jackSr = jack_get_sample_rate( hostApi->jack_client );
1428
    int err;
1429

    
1430
    if( (err = pthread_mutex_trylock( &hostApi->mtx )) != 0 )
1431
    {
1432
        assert( err == EBUSY );
1433
        return paNoError;
1434
    }
1435

    
1436
    if( hostApi->toAdd )
1437
    {
1438
        if( hostApi->processQueue )
1439
        {
1440
            PaJackStream *node = hostApi->processQueue;
1441
            /* Advance to end of queue */
1442
            while( node->next )
1443
                node = node->next;
1444

    
1445
            node->next = hostApi->toAdd;
1446
        }
1447
        else
1448
        {
1449
            /* The only queue entry. */
1450
            hostApi->processQueue = (PaJackStream *)hostApi->toAdd;
1451
        }
1452

    
1453
        /* If necessary, update stream state */
1454
        if( hostApi->toAdd->streamRepresentation.streamInfo.sampleRate != jackSr )
1455
            UpdateSampleRate( hostApi->toAdd, jackSr );
1456

    
1457
        hostApi->toAdd = NULL;
1458
        queueModified = 1;
1459
    }
1460
    if( hostApi->toRemove )
1461
    {
1462
        int removed = 0;
1463
        PaJackStream *node = hostApi->processQueue, *prev = NULL;
1464
        assert( hostApi->processQueue );
1465

    
1466
        while( node )
1467
        {
1468
            if( node == hostApi->toRemove )
1469
            {
1470
                if( prev )
1471
                    prev->next = node->next;
1472
                else
1473
                    hostApi->processQueue = (PaJackStream *)node->next;
1474

    
1475
                removed = 1;
1476
                break;
1477
            }
1478

    
1479
            prev = node;
1480
            node = node->next;
1481
        }
1482
        UNLESS( removed, paInternalError );
1483
        hostApi->toRemove = NULL;
1484
        PA_DEBUG(( "%s: Removed stream from processing queue\n", __FUNCTION__ ));
1485
        queueModified = 1;
1486
    }
1487

    
1488
    if( queueModified )
1489
    {
1490
        /* Signal that we've done what was asked of us */
1491
        ASSERT_CALL( pthread_cond_signal( &hostApi->cond ), 0 );
1492
    }
1493

    
1494
error:
1495
    ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 );
1496

    
1497
    return result;
1498
}
1499

    
1500
/* Audio processing callback invoked periodically from JACK. */
1501
static int JackCallback( jack_nframes_t frames, void *userData )
1502
{
1503
    PaError result = paNoError;
1504
    PaJackHostApiRepresentation *hostApi = (PaJackHostApiRepresentation *)userData;
1505
    PaJackStream *stream = NULL;
1506
    int xrun = hostApi->xrun;
1507
    hostApi->xrun = 0;
1508

    
1509
    assert( hostApi );
1510

    
1511
    ENSURE_PA( UpdateQueue( hostApi ) );
1512

    
1513
    /* Process each stream */
1514
    stream = hostApi->processQueue;
1515
    for( ; stream; stream = stream->next )
1516
    {
1517
        if( xrun )  /* Don't override if already set */
1518
            stream->xrun = 1;
1519

    
1520
        /* See if this stream is to be started */
1521
        if( stream->doStart )
1522
        {
1523
            /* If we can't obtain a lock, we'll try next time */
1524
            int err = pthread_mutex_trylock( &stream->hostApi->mtx );
1525
            if( !err )
1526
            {
1527
                if( stream->doStart )   /* Could potentially change before obtaining the lock */
1528
                {
1529
                    stream->is_active = 1;
1530
                    stream->doStart = 0;
1531
                    PA_DEBUG(( "%s: Starting stream\n", __FUNCTION__ ));
1532
                    ASSERT_CALL( pthread_cond_signal( &stream->hostApi->cond ), 0 );
1533
                    stream->callbackResult = paContinue;
1534
                    stream->isSilenced = 0;
1535
                }
1536

    
1537
                ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 );
1538
            }
1539
            else
1540
                assert( err == EBUSY );
1541
        }
1542
        else if( stream->doStop || stream->doAbort )    /* Should we stop/abort stream? */
1543
        {
1544
            if( stream->callbackResult == paContinue )     /* Ok, make it stop */
1545
            {
1546
                PA_DEBUG(( "%s: Stopping stream\n", __FUNCTION__ ));
1547
                stream->callbackResult = stream->doStop ? paComplete : paAbort;
1548
            }
1549
        }
1550

    
1551
        if( stream->is_active )
1552
            ENSURE_PA( RealProcess( stream, frames ) );
1553
        /* If we have just entered inactive state, silence output */
1554
        if( !stream->is_active && !stream->isSilenced )
1555
        {
1556
            int i;
1557

    
1558
            /* Silence buffer after entering inactive state */
1559
            PA_DEBUG(( "Silencing the output\n" ));
1560
            for( i = 0; i < stream->num_outgoing_connections; ++i )
1561
            {
1562
                jack_default_audio_sample_t *buffer = jack_port_get_buffer( stream->local_output_ports[i], frames );
1563
                memset( buffer, 0, sizeof (jack_default_audio_sample_t) * frames );
1564
            }
1565

    
1566
            stream->isSilenced = 1;
1567
        }
1568

    
1569
        if( stream->doStop || stream->doAbort )
1570
        {
1571
            /* See if RealProcess has acted on the request */
1572
            if( !stream->is_active )   /* Ok, signal to the main thread that we've carried out the operation */
1573
            {
1574
                /* If we can't obtain a lock, we'll try next time */
1575
                int err = pthread_mutex_trylock( &stream->hostApi->mtx );
1576
                if( !err )
1577
                {
1578
                    stream->doStop = stream->doAbort = 0;
1579
                    ASSERT_CALL( pthread_cond_signal( &stream->hostApi->cond ), 0 );
1580
                    ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 );
1581
                }
1582
                else
1583
                    assert( err == EBUSY );
1584
            }
1585
        }
1586
    }
1587

    
1588
    return 0;
1589
error:
1590
    return -1;
1591
}
1592

    
1593
static PaError StartStream( PaStream *s )
1594
{
1595
    PaError result = paNoError;
1596
    PaJackStream *stream = (PaJackStream*)s;
1597
    int i;
1598

    
1599
    /* Ready the processor */
1600
    PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
1601

    
1602
    /* Connect the ports. Note that the ports may already have been connected by someone else in
1603
     * the meantime, in which case JACK returns EEXIST. */
1604

    
1605
    if( stream->num_incoming_connections > 0 )
1606
    {
1607
        for( i = 0; i < stream->num_incoming_connections; i++ )
1608
        {
1609
            int r = jack_connect( stream->jack_client, jack_port_name( stream->remote_output_ports[i] ),
1610
                    jack_port_name( stream->local_input_ports[i] ) );
1611
           UNLESS( 0 == r || EEXIST == r, paUnanticipatedHostError );
1612
        }
1613
    }
1614

    
1615
    if( stream->num_outgoing_connections > 0 )
1616
    {
1617
        for( i = 0; i < stream->num_outgoing_connections; i++ )
1618
        {
1619
            int r = jack_connect( stream->jack_client, jack_port_name( stream->local_output_ports[i] ),
1620
                    jack_port_name( stream->remote_input_ports[i] ) );
1621
           UNLESS( 0 == r || EEXIST == r, paUnanticipatedHostError );
1622
        }
1623
    }
1624

    
1625
    stream->xrun = FALSE;
1626

    
1627
    /* Enable processing */
1628

    
1629
    ASSERT_CALL( pthread_mutex_lock( &stream->hostApi->mtx ), 0 );
1630
    stream->doStart = 1;
1631

    
1632
    /* Wait for stream to be started */
1633
    result = WaitCondition( stream->hostApi );
1634
    /*
1635
    do
1636
    {
1637
        err = pthread_cond_timedwait( &stream->hostApi->cond, &stream->hostApi->mtx, &ts );
1638
    } while( !stream->is_active && !err );
1639
    */
1640
    if( result != paNoError )   /* Something went wrong, call off the stream start */
1641
    {
1642
        stream->doStart = 0;
1643
        stream->is_active = 0;  /* Cancel any processing */
1644
    }
1645
    ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 );
1646

    
1647
    ENSURE_PA( result );
1648

    
1649
    stream->is_running = TRUE;
1650
    PA_DEBUG(( "%s: Stream started\n", __FUNCTION__ ));
1651

    
1652
error:
1653
    return result;
1654
}
1655

    
1656
static PaError RealStop( PaJackStream *stream, int abort )
1657
{
1658
    PaError result = paNoError;
1659
    int i;
1660

    
1661
    if( stream->isBlockingStream )
1662
        BlockingWaitEmpty ( stream );
1663

    
1664
    ASSERT_CALL( pthread_mutex_lock( &stream->hostApi->mtx ), 0 );
1665
    if( abort )
1666
        stream->doAbort = 1;
1667
    else
1668
        stream->doStop = 1;
1669

    
1670
    /* Wait for stream to be stopped */
1671
    result = WaitCondition( stream->hostApi );
1672
    ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 );
1673
    ENSURE_PA( result );
1674

    
1675
    UNLESS( !stream->is_active, paInternalError );
1676

    
1677
    PA_DEBUG(( "%s: Stream stopped\n", __FUNCTION__ ));
1678

    
1679
error:
1680
    stream->is_running = FALSE;
1681

    
1682
    /* Disconnect ports belonging to this stream */
1683

    
1684
    if( !stream->hostApi->jackIsDown )  /* XXX: Well? */
1685
    {
1686
        for( i = 0; i < stream->num_incoming_connections; i++ )
1687
        {
1688
            if( jack_port_connected( stream->local_input_ports[i] ) )
1689
            {
1690
                UNLESS( !jack_port_disconnect( stream->jack_client, stream->local_input_ports[i] ),
1691
                        paUnanticipatedHostError );
1692
            }
1693
        }
1694
        for( i = 0; i < stream->num_outgoing_connections; i++ )
1695
        {
1696
            if( jack_port_connected( stream->local_output_ports[i] ) )
1697
            {
1698
                UNLESS( !jack_port_disconnect( stream->jack_client, stream->local_output_ports[i] ),
1699
                        paUnanticipatedHostError );
1700
            }
1701
        }
1702
    }
1703

    
1704
    return result;
1705
}
1706

    
1707
static PaError StopStream( PaStream *s )
1708
{
1709
    assert(s);
1710
    return RealStop( (PaJackStream *)s, 0 );
1711
}
1712

    
1713
static PaError AbortStream( PaStream *s )
1714
{
1715
    assert(s);
1716
    return RealStop( (PaJackStream *)s, 1 );
1717
}
1718

    
1719
static PaError IsStreamStopped( PaStream *s )
1720
{
1721
    PaJackStream *stream = (PaJackStream*)s;
1722
    return !stream->is_running;
1723
}
1724

    
1725

    
1726
static PaError IsStreamActive( PaStream *s )
1727
{
1728
    PaJackStream *stream = (PaJackStream*)s;
1729
    return stream->is_active;
1730
}
1731

    
1732

    
1733
static PaTime GetStreamTime( PaStream *s )
1734
{
1735
    PaJackStream *stream = (PaJackStream*)s;
1736

    
1737
    /* A: Is this relevant?? --> TODO: what if we're recording-only? */
1738
    return (jack_frame_time( stream->jack_client ) - stream->t0) / (PaTime)jack_get_sample_rate( stream->jack_client );
1739
}
1740

    
1741

    
1742
static double GetStreamCpuLoad( PaStream* s )
1743
{
1744
    PaJackStream *stream = (PaJackStream*)s;
1745
    return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
1746
}
1747

    
1748
PaError PaJack_SetClientName( const char* name )
1749
{
1750
    if( strlen( name ) > jack_client_name_size() )
1751
    {
1752
        /* OK, I don't know any better error code */
1753
        return paInvalidFlag;
1754
    }
1755
    clientName_ = name;
1756
    return paNoError;
1757
}
1758

    
1759
PaError PaJack_GetClientName(const char** clientName)
1760
{
1761
    PaError result = paNoError;
1762
    PaJackHostApiRepresentation* jackHostApi = NULL;
1763
    PaJackHostApiRepresentation** ref = &jackHostApi;
1764
    ENSURE_PA( PaUtil_GetHostApiRepresentation( (PaUtilHostApiRepresentation**)ref, paJACK ) );
1765
    *clientName = jack_get_client_name( jackHostApi->jack_client );
1766

    
1767
error:
1768
    return result;
1769
}