PageRenderTime 65ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/Einstein/portaudio/pa_jack/pa_jack.c

http://einstein.googlecode.com/
C | 1714 lines | 1174 code | 284 blank | 256 comment | 189 complexity | 08ded61083748cf4f12cb1eeac2c7542 MD5 | raw file
Possible License(s): GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * $Id: pa_jack.c,v 1.1.2.20 2005/10/02 22:02:26 aknudsen Exp $
  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. * Any person wishing to distribute modifications to the Software is
  26. * requested to send the modifications to the original developer so that
  27. * they can be incorporated into the canonical version.
  28. *
  29. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  30. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  31. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  32. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
  33. * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  34. * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  35. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  36. */
  37. #include <string.h>
  38. #include <regex.h>
  39. #include <stdlib.h>
  40. #include <stdio.h>
  41. #include <assert.h>
  42. #include <sys/types.h>
  43. #include <unistd.h>
  44. #include <errno.h> /* EBUSY */
  45. #include <signal.h> /* sig_atomic_t */
  46. #include <math.h>
  47. #include <semaphore.h>
  48. #include <jack/types.h>
  49. #include <jack/jack.h>
  50. #include "pa_util.h"
  51. #include "pa_hostapi.h"
  52. #include "pa_stream.h"
  53. #include "pa_process.h"
  54. #include "pa_allocation.h"
  55. #include "pa_cpuload.h"
  56. #include "../pablio/ringbuffer.c"
  57. static int aErr_;
  58. static PaError paErr_; /* For use with ENSURE_PA */
  59. static pthread_t mainThread_;
  60. static char *jackErr_ = NULL;
  61. #define STRINGIZE_HELPER(expr) #expr
  62. #define STRINGIZE(expr) STRINGIZE_HELPER(expr)
  63. /* Check PaError */
  64. #define ENSURE_PA(expr) \
  65. do { \
  66. if( (paErr_ = (expr)) < paNoError ) \
  67. { \
  68. if( (paErr_) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \
  69. { \
  70. assert( jackErr_ ); \
  71. PaUtil_SetLastHostErrorInfo( paJACK, -1, jackErr_ ); \
  72. } \
  73. PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
  74. result = paErr_; \
  75. goto error; \
  76. } \
  77. } while( 0 )
  78. #define UNLESS(expr, code) \
  79. do { \
  80. if( (expr) == 0 ) \
  81. { \
  82. if( (code) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \
  83. { \
  84. assert( jackErr_ ); \
  85. PaUtil_SetLastHostErrorInfo( paJACK, -1, jackErr_ ); \
  86. } \
  87. PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
  88. result = (code); \
  89. goto error; \
  90. } \
  91. } while( 0 )
  92. #define ASSERT_CALL(expr, success) \
  93. aErr_ = (expr); \
  94. assert( aErr_ == success );
  95. /*
  96. * Functions that directly map to the PortAudio stream interface
  97. */
  98. static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
  99. static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
  100. const PaStreamParameters *inputParameters,
  101. const PaStreamParameters *outputParameters,
  102. double sampleRate );
  103. static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
  104. PaStream** s,
  105. const PaStreamParameters *inputParameters,
  106. const PaStreamParameters *outputParameters,
  107. double sampleRate,
  108. unsigned long framesPerBuffer,
  109. PaStreamFlags streamFlags,
  110. PaStreamCallback *streamCallback,
  111. void *userData );
  112. static PaError CloseStream( PaStream* stream );
  113. static PaError StartStream( PaStream *stream );
  114. static PaError StopStream( PaStream *stream );
  115. static PaError AbortStream( PaStream *stream );
  116. static PaError IsStreamStopped( PaStream *s );
  117. static PaError IsStreamActive( PaStream *stream );
  118. /*static PaTime GetStreamInputLatency( PaStream *stream );*/
  119. /*static PaTime GetStreamOutputLatency( PaStream *stream );*/
  120. static PaTime GetStreamTime( PaStream *stream );
  121. static double GetStreamCpuLoad( PaStream* stream );
  122. /*
  123. * Data specific to this API
  124. */
  125. struct PaJackStream;
  126. typedef struct
  127. {
  128. PaUtilHostApiRepresentation commonHostApiRep;
  129. PaUtilStreamInterface callbackStreamInterface;
  130. PaUtilStreamInterface blockingStreamInterface;
  131. PaUtilAllocationGroup *deviceInfoMemory;
  132. jack_client_t *jack_client;
  133. int jack_buffer_size;
  134. PaHostApiIndex hostApiIndex;
  135. pthread_mutex_t mtx;
  136. pthread_cond_t cond;
  137. unsigned long inputBase, outputBase;
  138. /* For dealing with the process thread */
  139. volatile int xrun; /* Received xrun notification from JACK? */
  140. struct PaJackStream * volatile toAdd, * volatile toRemove;
  141. struct PaJackStream *processQueue;
  142. volatile sig_atomic_t jackIsDown;
  143. }
  144. PaJackHostApiRepresentation;
  145. /* PaJackStream - a stream data structure specifically for this implementation */
  146. typedef struct PaJackStream
  147. {
  148. PaUtilStreamRepresentation streamRepresentation;
  149. PaUtilBufferProcessor bufferProcessor;
  150. PaUtilCpuLoadMeasurer cpuLoadMeasurer;
  151. PaJackHostApiRepresentation *hostApi;
  152. /* our input and output ports */
  153. jack_port_t **local_input_ports;
  154. jack_port_t **local_output_ports;
  155. /* the input and output ports of the client we are connecting to */
  156. jack_port_t **remote_input_ports;
  157. jack_port_t **remote_output_ports;
  158. int num_incoming_connections;
  159. int num_outgoing_connections;
  160. jack_client_t *jack_client;
  161. /* The stream is running if it's still producing samples.
  162. * The stream is active if samples it produced are still being heard.
  163. */
  164. volatile sig_atomic_t is_running;
  165. volatile sig_atomic_t is_active;
  166. /* Used to signal processing thread that stream should start or stop, respectively */
  167. volatile sig_atomic_t doStart, doStop, doAbort;
  168. jack_nframes_t t0;
  169. PaUtilAllocationGroup *stream_memory;
  170. /* These are useful in the process callback */
  171. int callbackResult;
  172. int isSilenced;
  173. int xrun;
  174. /* These are useful for the blocking API */
  175. int isBlockingStream;
  176. RingBuffer inFIFO;
  177. RingBuffer outFIFO;
  178. volatile sig_atomic_t data_available;
  179. sem_t data_semaphore;
  180. int bytesPerFrame;
  181. int samplesPerFrame;
  182. struct PaJackStream *next;
  183. }
  184. PaJackStream;
  185. #define TRUE 1
  186. #define FALSE 0
  187. /*
  188. * Functions specific to this API
  189. */
  190. static int JackCallback( jack_nframes_t frames, void *userData );
  191. /*
  192. *
  193. * Implementation
  194. *
  195. */
  196. /* ---- blocking emulation layer ---- */
  197. /* Allocate buffer. */
  198. static PaError BlockingInitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame )
  199. {
  200. long numBytes = numFrames * bytesPerFrame;
  201. char *buffer = (char *) malloc( numBytes );
  202. if( buffer == NULL ) return paInsufficientMemory;
  203. memset( buffer, 0, numBytes );
  204. return (PaError) RingBuffer_Init( rbuf, numBytes, buffer );
  205. }
  206. /* Free buffer. */
  207. static PaError BlockingTermFIFO( RingBuffer *rbuf )
  208. {
  209. if( rbuf->buffer ) free( rbuf->buffer );
  210. rbuf->buffer = NULL;
  211. return paNoError;
  212. }
  213. static int
  214. BlockingCallback( const void *inputBuffer,
  215. void *outputBuffer,
  216. unsigned long framesPerBuffer,
  217. const PaStreamCallbackTimeInfo* timeInfo,
  218. PaStreamCallbackFlags statusFlags,
  219. void *userData )
  220. {
  221. struct PaJackStream *stream = (PaJackStream *)userData;
  222. long numBytes = stream->bytesPerFrame * framesPerBuffer;
  223. /* This may get called with NULL inputBuffer during initial setup. */
  224. if( inputBuffer != NULL )
  225. {
  226. RingBuffer_Write( &stream->inFIFO, inputBuffer, numBytes );
  227. }
  228. if( outputBuffer != NULL )
  229. {
  230. int numRead = RingBuffer_Read( &stream->outFIFO, outputBuffer, numBytes );
  231. /* Zero out remainder of buffer if we run out of data. */
  232. memset( (char *)outputBuffer + numRead, 0, numBytes - numRead );
  233. }
  234. if( !stream->data_available )
  235. {
  236. stream->data_available = 1;
  237. sem_post( &stream->data_semaphore );
  238. }
  239. return paContinue;
  240. }
  241. static PaError
  242. BlockingBegin( PaJackStream *stream, int minimum_buffer_size )
  243. {
  244. long doRead = 0;
  245. long doWrite = 0;
  246. PaError result = paNoError;
  247. long numFrames;
  248. doRead = stream->local_input_ports != NULL;
  249. doWrite = stream->local_output_ports != NULL;
  250. /* <FIXME> */
  251. stream->samplesPerFrame = 2;
  252. stream->bytesPerFrame = sizeof(float) * stream->samplesPerFrame;
  253. /* </FIXME> */
  254. numFrames = 32;
  255. while (numFrames < minimum_buffer_size)
  256. numFrames *= 2;
  257. if( doRead )
  258. {
  259. ENSURE_PA( BlockingInitFIFO( &stream->inFIFO, numFrames, stream->bytesPerFrame ) );
  260. }
  261. if( doWrite )
  262. {
  263. long numBytes;
  264. ENSURE_PA( BlockingInitFIFO( &stream->outFIFO, numFrames, stream->bytesPerFrame ) );
  265. /* Make Write FIFO appear full initially. */
  266. numBytes = RingBuffer_GetWriteAvailable( &stream->outFIFO );
  267. RingBuffer_AdvanceWriteIndex( &stream->outFIFO, numBytes );
  268. }
  269. stream->data_available = 0;
  270. sem_init( &stream->data_semaphore, 0, 0 );
  271. error:
  272. return result;
  273. }
  274. static void
  275. BlockingEnd( PaJackStream *stream )
  276. {
  277. BlockingTermFIFO( &stream->inFIFO );
  278. BlockingTermFIFO( &stream->outFIFO );
  279. sem_destroy( &stream->data_semaphore );
  280. }
  281. static PaError BlockingReadStream( PaStream* s, void *data, unsigned long numFrames )
  282. {
  283. PaError result = paNoError;
  284. PaJackStream *stream = (PaJackStream *)s;
  285. long bytesRead;
  286. char *p = (char *) data;
  287. long numBytes = stream->bytesPerFrame * numFrames;
  288. while( numBytes > 0 )
  289. {
  290. bytesRead = RingBuffer_Read( &stream->inFIFO, p, numBytes );
  291. numBytes -= bytesRead;
  292. p += bytesRead;
  293. if( numBytes > 0 )
  294. {
  295. /* see write for an explanation */
  296. if( stream->data_available )
  297. stream->data_available = 0;
  298. else
  299. sem_wait( &stream->data_semaphore );
  300. }
  301. }
  302. return result;
  303. }
  304. static PaError BlockingWriteStream( PaStream* s, const void *data, unsigned long numFrames )
  305. {
  306. PaError result = paNoError;
  307. PaJackStream *stream = (PaJackStream *)s;
  308. long bytesWritten;
  309. char *p = (char *) data;
  310. long numBytes = stream->bytesPerFrame * numFrames;
  311. while( numBytes > 0 )
  312. {
  313. bytesWritten = RingBuffer_Write( &stream->outFIFO, p, numBytes );
  314. numBytes -= bytesWritten;
  315. p += bytesWritten;
  316. if( numBytes > 0 )
  317. {
  318. /* we use the following algorithm:
  319. * (1) write data
  320. * (2) if some data didn't fit into the ringbuffer, set data_available to 0
  321. * to indicate to the audio that if space becomes available, we want to know
  322. * (3) retry to write data (because it might be that between (1) and (2)
  323. * new space in the buffer became available)
  324. * (4) if this failed, we are sure that the buffer is really empty and
  325. * we will definitely receive a notification when it becomes available
  326. * thus we can safely sleep
  327. *
  328. * if the algorithm bailed out in step (3) before, it leaks a count of 1
  329. * on the semaphore; however, it doesn't matter, because if we block in (4),
  330. * we also do it in a loop
  331. */
  332. if( stream->data_available )
  333. stream->data_available = 0;
  334. else
  335. sem_wait( &stream->data_semaphore );
  336. }
  337. }
  338. return result;
  339. }
  340. static signed long
  341. BlockingGetStreamReadAvailable( PaStream* s )
  342. {
  343. PaJackStream *stream = (PaJackStream *)s;
  344. int bytesFull = RingBuffer_GetReadAvailable( &stream->inFIFO );
  345. return bytesFull / stream->bytesPerFrame;
  346. }
  347. static signed long
  348. BlockingGetStreamWriteAvailable( PaStream* s )
  349. {
  350. PaJackStream *stream = (PaJackStream *)s;
  351. int bytesEmpty = RingBuffer_GetWriteAvailable( &stream->outFIFO );
  352. return bytesEmpty / stream->bytesPerFrame;
  353. }
  354. static PaError
  355. BlockingWaitEmpty( PaStream *s )
  356. {
  357. PaJackStream *stream = (PaJackStream *)s;
  358. while( RingBuffer_GetReadAvailable( &stream->outFIFO ) > 0 )
  359. {
  360. stream->data_available = 0;
  361. sem_wait( &stream->data_semaphore );
  362. }
  363. return 0;
  364. }
  365. /* ---- jack driver ---- */
  366. /* BuildDeviceList():
  367. *
  368. * The process of determining a list of PortAudio "devices" from
  369. * JACK's client/port system is fairly involved, so it is separated
  370. * into its own routine.
  371. */
  372. static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
  373. {
  374. /* Utility macros for the repetitive process of allocating memory */
  375. /* ... MALLOC: allocate memory as part of the device list
  376. * allocation group */
  377. #define MALLOC(size) \
  378. (PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, (size) ))
  379. /* JACK has no concept of a device. To JACK, there are clients
  380. * which have an arbitrary number of ports. To make this
  381. * intelligible to PortAudio clients, we will group each JACK client
  382. * into a device, and make each port of that client a channel */
  383. PaError result = paNoError;
  384. PaUtilHostApiRepresentation *commonApi = &jackApi->commonHostApiRep;
  385. const char **jack_ports = NULL;
  386. char **client_names = NULL;
  387. char *regex_pattern = alloca( jack_client_name_size() + 3 );
  388. int port_index, client_index, i;
  389. double globalSampleRate;
  390. regex_t port_regex;
  391. unsigned long numClients = 0, numPorts = 0;
  392. char *tmp_client_name = alloca( jack_client_name_size() );
  393. commonApi->info.defaultInputDevice = paNoDevice;
  394. commonApi->info.defaultOutputDevice = paNoDevice;
  395. commonApi->info.deviceCount = 0;
  396. /* Parse the list of ports, using a regex to grab the client names */
  397. ASSERT_CALL( regcomp( &port_regex, "^[^:]*", REG_EXTENDED ), 0 );
  398. /* since we are rebuilding the list of devices, free all memory
  399. * associated with the previous list */
  400. PaUtil_FreeAllAllocations( jackApi->deviceInfoMemory );
  401. /* We can only retrieve the list of clients indirectly, by first
  402. * asking for a list of all ports, then parsing the port names
  403. * according to the client_name:port_name convention (which is
  404. * enforced by jackd)
  405. * A: If jack_get_ports returns NULL, there's nothing for us to do */
  406. UNLESS( (jack_ports = jack_get_ports( jackApi->jack_client, "", "", 0 )) && jack_ports[0], paNoError );
  407. /* Find number of ports */
  408. while( jack_ports[numPorts] )
  409. ++numPorts;
  410. /* At least there will be one port per client :) */
  411. UNLESS( client_names = alloca( numPorts * sizeof (char *) ), paInsufficientMemory );
  412. /* Build a list of clients from the list of ports */
  413. for( numClients = 0, port_index = 0; jack_ports[port_index] != NULL; port_index++ )
  414. {
  415. int client_seen = FALSE;
  416. regmatch_t match_info;
  417. const char *port = jack_ports[port_index];
  418. /* extract the client name from the port name, using a regex
  419. * that parses the clientname:portname syntax */
  420. UNLESS( !regexec( &port_regex, port, 1, &match_info, 0 ), paInternalError );
  421. assert(match_info.rm_eo - match_info.rm_so < jack_client_name_size());
  422. memcpy( tmp_client_name, port + match_info.rm_so,
  423. match_info.rm_eo - match_info.rm_so );
  424. tmp_client_name[match_info.rm_eo - match_info.rm_so] = '\0';
  425. /* do we know about this port's client yet? */
  426. for( i = 0; i < numClients; i++ )
  427. {
  428. if( strcmp( tmp_client_name, client_names[i] ) == 0 )
  429. client_seen = TRUE;
  430. }
  431. if (client_seen)
  432. continue; /* A: Nothing to see here, move along */
  433. UNLESS( client_names[numClients] = (char*)MALLOC(strlen(tmp_client_name) + 1), paInsufficientMemory );
  434. /* The alsa_pcm client should go in spot 0. If this
  435. * is the alsa_pcm client AND we are NOT about to put
  436. * it in spot 0 put it in spot 0 and move whatever
  437. * was already in spot 0 to the end. */
  438. if( strcmp( "alsa_pcm", tmp_client_name ) == 0 && numClients > 0 )
  439. {
  440. /* alsa_pcm goes in spot 0 */
  441. strcpy( client_names[ numClients ], client_names[0] );
  442. strcpy( client_names[0], tmp_client_name );
  443. }
  444. else
  445. {
  446. /* put the new client at the end of the client list */
  447. strcpy( client_names[ numClients ], tmp_client_name );
  448. }
  449. ++numClients;
  450. }
  451. /* Now we have a list of clients, which will become the list of
  452. * PortAudio devices. */
  453. /* there is one global sample rate all clients must conform to */
  454. globalSampleRate = jack_get_sample_rate( jackApi->jack_client );
  455. UNLESS( commonApi->deviceInfos = (PaDeviceInfo**)MALLOC( sizeof(PaDeviceInfo*) *
  456. numClients ), paInsufficientMemory );
  457. assert( commonApi->info.deviceCount == 0 );
  458. /* Create a PaDeviceInfo structure for every client */
  459. for( client_index = 0; client_index < numClients; client_index++ )
  460. {
  461. PaDeviceInfo *curDevInfo;
  462. const char **clientPorts = NULL;
  463. UNLESS( curDevInfo = (PaDeviceInfo*)MALLOC( sizeof(PaDeviceInfo) ), paInsufficientMemory );
  464. UNLESS( curDevInfo->name = (char*)MALLOC( strlen(client_names[client_index]) + 1 ), paInsufficientMemory );
  465. strcpy( (char *)curDevInfo->name, client_names[client_index] );
  466. curDevInfo->structVersion = 2;
  467. curDevInfo->hostApi = jackApi->hostApiIndex;
  468. /* JACK is very inflexible: there is one sample rate the whole
  469. * system must run at, and all clients must speak IEEE float. */
  470. curDevInfo->defaultSampleRate = globalSampleRate;
  471. /* To determine how many input and output channels are available,
  472. * we re-query jackd with more specific parameters. */
  473. sprintf( regex_pattern, "%s:.*", client_names[client_index] );
  474. /* ... what are your output ports (that we could input from)? */
  475. clientPorts = jack_get_ports( jackApi->jack_client, regex_pattern,
  476. NULL, JackPortIsOutput);
  477. curDevInfo->maxInputChannels = 0;
  478. curDevInfo->defaultLowInputLatency = 0.;
  479. curDevInfo->defaultHighInputLatency = 0.;
  480. if( clientPorts )
  481. {
  482. jack_port_t *p = jack_port_by_name( jackApi->jack_client, clientPorts[0] );
  483. curDevInfo->defaultLowInputLatency = curDevInfo->defaultHighInputLatency =
  484. jack_port_get_latency( p ) / globalSampleRate;
  485. for( i = 0; clientPorts[i] != NULL; i++)
  486. {
  487. /* The number of ports returned is the number of output channels.
  488. * We don't care what they are, we just care how many */
  489. curDevInfo->maxInputChannels++;
  490. }
  491. free(clientPorts);
  492. }
  493. /* ... what are your input ports (that we could output to)? */
  494. clientPorts = jack_get_ports( jackApi->jack_client, regex_pattern,
  495. NULL, JackPortIsInput);
  496. curDevInfo->maxOutputChannels = 0;
  497. curDevInfo->defaultLowOutputLatency = 0.;
  498. curDevInfo->defaultHighOutputLatency = 0.;
  499. if( clientPorts )
  500. {
  501. jack_port_t *p = jack_port_by_name( jackApi->jack_client, clientPorts[0] );
  502. curDevInfo->defaultLowOutputLatency = curDevInfo->defaultHighOutputLatency =
  503. jack_port_get_latency( p ) / globalSampleRate;
  504. for( i = 0; clientPorts[i] != NULL; i++)
  505. {
  506. /* The number of ports returned is the number of input channels.
  507. * We don't care what they are, we just care how many */
  508. curDevInfo->maxOutputChannels++;
  509. }
  510. free(clientPorts);
  511. }
  512. /* Add this client to the list of devices */
  513. commonApi->deviceInfos[client_index] = curDevInfo;
  514. ++commonApi->info.deviceCount;
  515. if( commonApi->info.defaultInputDevice == paNoDevice && curDevInfo->maxInputChannels > 0 )
  516. commonApi->info.defaultInputDevice = client_index;
  517. if( commonApi->info.defaultOutputDevice == paNoDevice && curDevInfo->maxOutputChannels > 0 )
  518. commonApi->info.defaultOutputDevice = client_index;
  519. }
  520. error:
  521. regfree( &port_regex );
  522. free( jack_ports );
  523. return result;
  524. }
  525. #undef MALLOC
  526. static void UpdateSampleRate( PaJackStream *stream, double sampleRate )
  527. {
  528. /* XXX: Maybe not the cleanest way of going about this? */
  529. stream->cpuLoadMeasurer.samplingPeriod = stream->bufferProcessor.samplePeriod = 1. / sampleRate;
  530. stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
  531. }
  532. static void JackErrorCallback( const char *msg )
  533. {
  534. if( pthread_self() == mainThread_ )
  535. {
  536. assert( msg );
  537. free( jackErr_ );
  538. jackErr_ = malloc( strlen( msg ) );
  539. sprintf( jackErr_, msg );
  540. }
  541. }
  542. static void JackOnShutdown( void *arg )
  543. {
  544. PaJackHostApiRepresentation *jackApi = (PaJackHostApiRepresentation *)arg;
  545. PaJackStream *stream = jackApi->processQueue;
  546. PA_DEBUG(( "%s: JACK server is shutting down\n", __FUNCTION__ ));
  547. for( ; stream; stream = stream->next )
  548. {
  549. stream->is_active = 0;
  550. }
  551. /* Make sure that the main thread doesn't get stuck waiting on the condition */
  552. ASSERT_CALL( pthread_mutex_lock( &jackApi->mtx ), 0 );
  553. jackApi->jackIsDown = 1;
  554. ASSERT_CALL( pthread_cond_signal( &jackApi->cond ), 0 );
  555. ASSERT_CALL( pthread_mutex_unlock( &jackApi->mtx ), 0 );
  556. }
  557. static int JackSrCb( jack_nframes_t nframes, void *arg )
  558. {
  559. PaJackHostApiRepresentation *jackApi = (PaJackHostApiRepresentation *)arg;
  560. double sampleRate = (double)nframes;
  561. PaJackStream *stream = jackApi->processQueue;
  562. /* Update all streams in process queue */
  563. PA_DEBUG(( "%s: Acting on change in JACK samplerate: %f\n", __FUNCTION__, sampleRate ));
  564. for( ; stream; stream = stream->next )
  565. {
  566. if( stream->streamRepresentation.streamInfo.sampleRate != sampleRate )
  567. {
  568. PA_DEBUG(( "%s: Updating samplerate\n", __FUNCTION__ ));
  569. UpdateSampleRate( stream, sampleRate );
  570. }
  571. }
  572. return 0;
  573. }
  574. static int JackXRunCb(void *arg) {
  575. PaJackHostApiRepresentation *hostApi = (PaJackHostApiRepresentation *)arg;
  576. assert( hostApi );
  577. hostApi->xrun = TRUE;
  578. PA_DEBUG(( "%s: JACK signalled xrun\n", __FUNCTION__ ));
  579. return 0;
  580. }
  581. PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi,
  582. PaHostApiIndex hostApiIndex )
  583. {
  584. PaError result = paNoError;
  585. PaJackHostApiRepresentation *jackHostApi;
  586. int activated = 0;
  587. char *clientName;
  588. int written;
  589. *hostApi = NULL; /* Initialize to NULL */
  590. UNLESS( jackHostApi = (PaJackHostApiRepresentation*)
  591. PaUtil_AllocateMemory( sizeof(PaJackHostApiRepresentation) ), paInsufficientMemory );
  592. jackHostApi->deviceInfoMemory = NULL;
  593. mainThread_ = pthread_self();
  594. ASSERT_CALL( pthread_mutex_init( &jackHostApi->mtx, NULL ), 0 );
  595. ASSERT_CALL( pthread_cond_init( &jackHostApi->cond, NULL ), 0 );
  596. /* Try to become a client of the JACK server. If we cannot do
  597. * this, then this API cannot be used. */
  598. clientName = alloca( jack_client_name_size() );
  599. written = snprintf( clientName, jack_client_name_size(), "PortAudio-%d", getpid() );
  600. assert( written < jack_client_name_size() );
  601. jackHostApi->jack_client = jack_client_new( clientName );
  602. if( jackHostApi->jack_client == NULL )
  603. {
  604. /* the V19 development docs say that if an implementation
  605. * detects that it cannot be used, it should return a NULL
  606. * interface and paNoError */
  607. result = paNoError;
  608. goto error;
  609. }
  610. UNLESS( jackHostApi->deviceInfoMemory = PaUtil_CreateAllocationGroup(), paInsufficientMemory );
  611. jackHostApi->hostApiIndex = hostApiIndex;
  612. *hostApi = &jackHostApi->commonHostApiRep;
  613. (*hostApi)->info.structVersion = 1;
  614. (*hostApi)->info.type = paJACK;
  615. (*hostApi)->info.name = "JACK Audio Connection Kit";
  616. /* Build a device list by querying the JACK server */
  617. ENSURE_PA( BuildDeviceList( jackHostApi ) );
  618. /* Register functions */
  619. (*hostApi)->Terminate = Terminate;
  620. (*hostApi)->OpenStream = OpenStream;
  621. (*hostApi)->IsFormatSupported = IsFormatSupported;
  622. PaUtil_InitializeStreamInterface( &jackHostApi->callbackStreamInterface,
  623. CloseStream, StartStream,
  624. StopStream, AbortStream,
  625. IsStreamStopped, IsStreamActive,
  626. GetStreamTime, GetStreamCpuLoad,
  627. PaUtil_DummyRead, PaUtil_DummyWrite,
  628. PaUtil_DummyGetReadAvailable,
  629. PaUtil_DummyGetWriteAvailable );
  630. PaUtil_InitializeStreamInterface( &jackHostApi->blockingStreamInterface, CloseStream, StartStream,
  631. StopStream, AbortStream, IsStreamStopped, IsStreamActive,
  632. GetStreamTime, PaUtil_DummyGetCpuLoad,
  633. BlockingReadStream, BlockingWriteStream,
  634. BlockingGetStreamReadAvailable, BlockingGetStreamWriteAvailable );
  635. jackHostApi->inputBase = jackHostApi->outputBase = 0;
  636. jackHostApi->xrun = 0;
  637. jackHostApi->toAdd = jackHostApi->toRemove = NULL;
  638. jackHostApi->processQueue = NULL;
  639. jackHostApi->jackIsDown = 0;
  640. jack_on_shutdown( jackHostApi->jack_client, JackOnShutdown, jackHostApi );
  641. jack_set_error_function( JackErrorCallback );
  642. jackHostApi->jack_buffer_size = jack_get_buffer_size ( jackHostApi->jack_client );
  643. UNLESS( !jack_set_sample_rate_callback( jackHostApi->jack_client, JackSrCb, jackHostApi ), paUnanticipatedHostError );
  644. UNLESS( !jack_set_xrun_callback( jackHostApi->jack_client, JackXRunCb, jackHostApi ), paUnanticipatedHostError );
  645. UNLESS( !jack_set_process_callback( jackHostApi->jack_client, JackCallback, jackHostApi ), paUnanticipatedHostError );
  646. UNLESS( !jack_activate( jackHostApi->jack_client ), paUnanticipatedHostError );
  647. activated = 1;
  648. return result;
  649. error:
  650. if( activated )
  651. ASSERT_CALL( jack_deactivate( jackHostApi->jack_client ), 0 );
  652. if( jackHostApi )
  653. {
  654. if( jackHostApi->jack_client )
  655. ASSERT_CALL( jack_client_close( jackHostApi->jack_client ), 0 );
  656. if( jackHostApi->deviceInfoMemory )
  657. {
  658. PaUtil_FreeAllAllocations( jackHostApi->deviceInfoMemory );
  659. PaUtil_DestroyAllocationGroup( jackHostApi->deviceInfoMemory );
  660. }
  661. PaUtil_FreeMemory( jackHostApi );
  662. }
  663. return result;
  664. }
  665. static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
  666. {
  667. PaJackHostApiRepresentation *jackHostApi = (PaJackHostApiRepresentation*)hostApi;
  668. /* note: this automatically disconnects all ports, since a deactivated
  669. * client is not allowed to have any ports connected */
  670. ASSERT_CALL( jack_deactivate( jackHostApi->jack_client ), 0 );
  671. ASSERT_CALL( pthread_mutex_destroy( &jackHostApi->mtx ), 0 );
  672. ASSERT_CALL( pthread_cond_destroy( &jackHostApi->cond ), 0 );
  673. ASSERT_CALL( jack_client_close( jackHostApi->jack_client ), 0 );
  674. if( jackHostApi->deviceInfoMemory )
  675. {
  676. PaUtil_FreeAllAllocations( jackHostApi->deviceInfoMemory );
  677. PaUtil_DestroyAllocationGroup( jackHostApi->deviceInfoMemory );
  678. }
  679. PaUtil_FreeMemory( jackHostApi );
  680. free( jackErr_ );
  681. }
  682. static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
  683. const PaStreamParameters *inputParameters,
  684. const PaStreamParameters *outputParameters,
  685. double sampleRate )
  686. {
  687. int inputChannelCount = 0, outputChannelCount = 0;
  688. PaSampleFormat inputSampleFormat, outputSampleFormat;
  689. if( inputParameters )
  690. {
  691. inputChannelCount = inputParameters->channelCount;
  692. inputSampleFormat = inputParameters->sampleFormat;
  693. /* unless alternate device specification is supported, reject the use of
  694. paUseHostApiSpecificDeviceSpecification */
  695. if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
  696. return paInvalidDevice;
  697. /* check that input device can support inputChannelCount */
  698. if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
  699. return paInvalidChannelCount;
  700. /* validate inputStreamInfo */
  701. if( inputParameters->hostApiSpecificStreamInfo )
  702. return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
  703. }
  704. else
  705. {
  706. inputChannelCount = 0;
  707. }
  708. if( outputParameters )
  709. {
  710. outputChannelCount = outputParameters->channelCount;
  711. outputSampleFormat = outputParameters->sampleFormat;
  712. /* unless alternate device specification is supported, reject the use of
  713. paUseHostApiSpecificDeviceSpecification */
  714. if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
  715. return paInvalidDevice;
  716. /* check that output device can support inputChannelCount */
  717. if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
  718. return paInvalidChannelCount;
  719. /* validate outputStreamInfo */
  720. if( outputParameters->hostApiSpecificStreamInfo )
  721. return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
  722. }
  723. else
  724. {
  725. outputChannelCount = 0;
  726. }
  727. /*
  728. The following check is not necessary for JACK.
  729. - if a full duplex stream is requested, check that the combination
  730. of input and output parameters is supported
  731. Because the buffer adapter handles conversion between all standard
  732. sample formats, the following checks are only required if paCustomFormat
  733. is implemented, or under some other unusual conditions.
  734. - check that input device can support inputSampleFormat, or that
  735. we have the capability to convert from outputSampleFormat to
  736. a native format
  737. - check that output device can support outputSampleFormat, or that
  738. we have the capability to convert from outputSampleFormat to
  739. a native format
  740. */
  741. /* check that the device supports sampleRate */
  742. #define ABS(x) ( (x) > 0 ? (x) : -(x) )
  743. if( ABS(sampleRate - jack_get_sample_rate(((PaJackHostApiRepresentation *) hostApi)->jack_client )) > 1 )
  744. return paInvalidSampleRate;
  745. #undef ABS
  746. return paFormatIsSupported;
  747. }
  748. /* Basic stream initialization */
  749. static PaError InitializeStream( PaJackStream *stream, PaJackHostApiRepresentation *hostApi, int numInputChannels,
  750. int numOutputChannels )
  751. {
  752. PaError result = paNoError;
  753. assert( stream );
  754. memset( stream, 0, sizeof (PaJackStream) );
  755. UNLESS( stream->stream_memory = PaUtil_CreateAllocationGroup(), paInsufficientMemory );
  756. stream->jack_client = hostApi->jack_client;
  757. stream->hostApi = hostApi;
  758. if( numInputChannels > 0 )
  759. {
  760. UNLESS( stream->local_input_ports =
  761. (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numInputChannels ),
  762. paInsufficientMemory );
  763. memset( stream->local_input_ports, 0, sizeof(jack_port_t*) * numInputChannels );
  764. UNLESS( stream->remote_output_ports =
  765. (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numInputChannels ),
  766. paInsufficientMemory );
  767. memset( stream->remote_output_ports, 0, sizeof(jack_port_t*) * numInputChannels );
  768. }
  769. if( numOutputChannels > 0 )
  770. {
  771. UNLESS( stream->local_output_ports =
  772. (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numOutputChannels ),
  773. paInsufficientMemory );
  774. memset( stream->local_output_ports, 0, sizeof(jack_port_t*) * numOutputChannels );
  775. UNLESS( stream->remote_input_ports =
  776. (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numOutputChannels ),
  777. paInsufficientMemory );
  778. memset( stream->remote_input_ports, 0, sizeof(jack_port_t*) * numOutputChannels );
  779. }
  780. stream->num_incoming_connections = numInputChannels;
  781. stream->num_outgoing_connections = numOutputChannels;
  782. error:
  783. return result;
  784. }
  785. /*!
  786. * Free resources associated with stream, and eventually stream itself.
  787. *
  788. * Frees allocated memory, and closes opened pcms.
  789. */
  790. static void CleanUpStream( PaJackStream *stream, int terminateStreamRepresentation, int terminateBufferProcessor )
  791. {
  792. int i;
  793. assert( stream );
  794. if( stream->isBlockingStream )
  795. BlockingEnd( stream );
  796. for( i = 0; i < stream->num_incoming_connections; ++i )
  797. {
  798. if( stream->local_input_ports[i] )
  799. ASSERT_CALL( jack_port_unregister( stream->jack_client, stream->local_input_ports[i] ), 0 );
  800. }
  801. for( i = 0; i < stream->num_outgoing_connections; ++i )
  802. {
  803. if( stream->local_output_ports[i] )
  804. ASSERT_CALL( jack_port_unregister( stream->jack_client, stream->local_output_ports[i] ), 0 );
  805. }
  806. if( terminateStreamRepresentation )
  807. PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
  808. if( terminateBufferProcessor )
  809. PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
  810. if( stream->stream_memory )
  811. {
  812. PaUtil_FreeAllAllocations( stream->stream_memory );
  813. PaUtil_DestroyAllocationGroup( stream->stream_memory );
  814. }
  815. PaUtil_FreeMemory( stream );
  816. }
  817. static PaError WaitCondition( PaJackHostApiRepresentation *hostApi )
  818. {
  819. PaError result = paNoError;
  820. int err = 0;
  821. PaTime pt = PaUtil_GetTime();
  822. struct timespec ts;
  823. ts.tv_sec = (time_t) floor( pt + 1 );
  824. ts.tv_nsec = (long) ((pt - floor( pt )) * 1000000000);
  825. /* XXX: Best enclose in loop, in case of spurious wakeups? */
  826. err = pthread_cond_timedwait( &hostApi->cond, &hostApi->mtx, &ts );
  827. /* Make sure we didn't time out */
  828. UNLESS( err != ETIMEDOUT, paTimedOut );
  829. UNLESS( !err, paInternalError );
  830. error:
  831. return result;
  832. }
  833. static PaError AddStream( PaJackStream *stream )
  834. {
  835. PaError result = paNoError;
  836. PaJackHostApiRepresentation *hostApi = stream->hostApi;
  837. /* Add to queue of streams that should be processed */
  838. ASSERT_CALL( pthread_mutex_lock( &hostApi->mtx ), 0 );
  839. if( !hostApi->jackIsDown )
  840. {
  841. hostApi->toAdd = stream;
  842. /* Unlock mutex and await signal from processing thread */
  843. result = WaitCondition( stream->hostApi );
  844. }
  845. ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 );
  846. ENSURE_PA( result );
  847. UNLESS( !hostApi->jackIsDown, paDeviceUnavailable );
  848. error:
  849. return result;
  850. }
  851. /* Remove stream from processing queue */
  852. static PaError RemoveStream( PaJackStream *stream )
  853. {
  854. PaError result = paNoError;
  855. PaJackHostApiRepresentation *hostApi = stream->hostApi;
  856. /* Add to queue over streams that should be processed */
  857. ASSERT_CALL( pthread_mutex_lock( &hostApi->mtx ), 0 );
  858. if( !hostApi->jackIsDown )
  859. {
  860. hostApi->toRemove = stream;
  861. /* Unlock mutex and await signal from processing thread */
  862. result = WaitCondition( stream->hostApi );
  863. }
  864. ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 );
  865. ENSURE_PA( result );
  866. error:
  867. return result;
  868. }
  869. /* Add stream to processing queue */
  870. static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
  871. PaStream** s,
  872. const PaStreamParameters *inputParameters,
  873. const PaStreamParameters *outputParameters,
  874. double sampleRate,
  875. unsigned long framesPerBuffer,
  876. PaStreamFlags streamFlags,
  877. PaStreamCallback *streamCallback,
  878. void *userData )
  879. {
  880. PaError result = paNoError;
  881. PaJackHostApiRepresentation *jackHostApi = (PaJackHostApiRepresentation*)hostApi;
  882. PaJackStream *stream = NULL;
  883. char *port_string = alloca( jack_port_name_size() );
  884. unsigned long regexSz = jack_client_name_size() + 3;
  885. char *regex_pattern = alloca( regexSz );
  886. const char **jack_ports = NULL;
  887. /* int jack_max_buffer_size = jack_get_buffer_size( jackHostApi->jack_client ); */
  888. int i;
  889. int inputChannelCount, outputChannelCount;
  890. const double jackSr = jack_get_sample_rate( jackHostApi->jack_client );
  891. PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0;
  892. int bpInitialized = 0, srInitialized = 0; /* Initialized buffer processor and stream representation? */
  893. unsigned long ofs;
  894. /* validate platform specific flags */
  895. if( (streamFlags & paPlatformSpecificFlags) != 0 )
  896. return paInvalidFlag; /* unexpected platform specific flag */
  897. if( (streamFlags & paPrimeOutputBuffersUsingStreamCallback) != 0 )
  898. {
  899. streamFlags &= ~paPrimeOutputBuffersUsingStreamCallback;
  900. /*return paInvalidFlag;*/ /* This implementation does not support buffer priming */
  901. }
  902. if( framesPerBuffer != paFramesPerBufferUnspecified )
  903. {
  904. /* Jack operates with power of two buffers, and we don't support non-integer buffer adaption (yet) */
  905. /*UNLESS( !(framesPerBuffer & (framesPerBuffer - 1)), paBufferTooBig );*/ /* TODO: Add descriptive error code? */
  906. }
  907. /* Preliminary checks */
  908. if( inputParameters )
  909. {
  910. inputChannelCount = inputParameters->channelCount;
  911. inputSampleFormat = inputParameters->sampleFormat;
  912. /* unless alternate device specification is supported, reject the use of
  913. paUseHostApiSpecificDeviceSpecification */
  914. if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
  915. return paInvalidDevice;
  916. /* check that input device can support inputChannelCount */
  917. if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
  918. return paInvalidChannelCount;
  919. /* validate inputStreamInfo */
  920. if( inputParameters->hostApiSpecificStreamInfo )
  921. return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
  922. }
  923. else
  924. {
  925. inputChannelCount = 0;
  926. }
  927. if( outputParameters )
  928. {
  929. outputChannelCount = outputParameters->channelCount;
  930. outputSampleFormat = outputParameters->sampleFormat;
  931. /* unless alternate device specification is supported, reject the use of
  932. paUseHostApiSpecificDeviceSpecification */
  933. if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
  934. return paInvalidDevice;
  935. /* check that output device can support inputChannelCount */
  936. if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
  937. return paInvalidChannelCount;
  938. /* validate outputStreamInfo */
  939. if( outputParameters->hostApiSpecificStreamInfo )
  940. return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
  941. }
  942. else
  943. {
  944. outputChannelCount = 0;
  945. }
  946. /* ... check that the sample rate exactly matches the ONE acceptable rate
  947. * A: This rate isn't necessarily constant though? */
  948. #define ABS(x) ( (x) > 0 ? (x) : -(x) )
  949. if( ABS(sampleRate - jackSr) > 1 )
  950. return paInvalidSampleRate;
  951. #undef ABS
  952. UNLESS( stream = (PaJackStream*)PaUtil_AllocateMemory( sizeof(PaJackStream) ), paInsufficientMemory );
  953. ENSURE_PA( InitializeStream( stream, jackHostApi, inputChannelCount, outputChannelCount ) );
  954. /* the blocking emulation, if necessary */
  955. stream->isBlockingStream = !streamCallback;
  956. if( stream->isBlockingStream )
  957. {
  958. float latency = 0.001; /* 1ms is the absolute minimum we support */
  959. int minimum_buffer_frames = 0;
  960. if( inputParameters && inputParameters->suggestedLatency > latency )
  961. latency = inputParameters->suggestedLatency;
  962. else if( outputParameters && outputParameters->suggestedLatency > latency )
  963. latency = outputParameters->suggestedLatency;
  964. /* the latency the user asked for indicates the minimum buffer size in frames */
  965. minimum_buffer_frames = (int) (latency * jack_get_sample_rate( jackHostApi->jack_client ));
  966. /* we also need to be able to store at least three full jack buffers to avoid dropouts */
  967. if( jackHostApi->jack_buffer_size * 3 > minimum_buffer_frames )
  968. minimum_buffer_frames = jackHostApi->jack_buffer_size * 3;
  969. /* setup blocking API data structures (FIXME: can fail) */
  970. BlockingBegin( stream, minimum_buffer_frames );
  971. /* install our own callback for the blocking API */
  972. streamCallback = BlockingCallback;
  973. userData = stream;
  974. PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
  975. &jackHostApi->blockingStreamInterface, streamCallback, userData );
  976. }
  977. else
  978. {
  979. PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
  980. &jackHostApi->callbackStreamInterface, streamCallback, userData );
  981. }
  982. srInitialized = 1;
  983. PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, jackSr );
  984. /* create the JACK ports. We cannot connect them until audio
  985. * processing begins */
  986. /* Register a unique set of ports for this stream
  987. * TODO: Robust allocation of new port names */
  988. ofs = jackHostApi->inputBase;
  989. for( i = 0; i < inputChannelCount; i++ )
  990. {
  991. snprintf( port_string, jack_port_name_size(), "in_%lu", ofs + i );
  992. UNLESS( stream->local_input_ports[i] = jack_port_register(
  993. jackHostApi->jack_client, port_string,
  994. JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ), paInsufficientMemory );
  995. }
  996. jackHostApi->inputBase += inputChannelCount;
  997. ofs = jackHostApi->outputBase;
  998. for( i = 0; i < outputChannelCount; i++ )
  999. {
  1000. snprintf( port_string, jack_port_name_size(), "out_%lu", ofs + i );
  1001. UNLESS( stream->local_output_ports[i] = jack_port_register(
  1002. jackHostApi->jack_client, port_string,
  1003. JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ), paInsufficientMemory );
  1004. }
  1005. jackHostApi->outputBase += outputChannelCount;
  1006. /* look up the jack_port_t's for the remote ports. We could do
  1007. * this at stream start time, but doing it here ensures the
  1008. * name lookup only happens once. */
  1009. if( inputChannelCount > 0 )
  1010. {
  1011. int err = 0;
  1012. /* ... remote output ports (that we input from) */
  1013. snprintf( regex_pattern, regexSz, "%s:.*", hostApi->deviceInfos[ inputParameters->device ]->name );
  1014. UNLESS( jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern,
  1015. NULL, JackPortIsOutput ), paUnanticipatedHostError );
  1016. for( i = 0; i < inputChannelCount && jack_ports[i]; i++ )
  1017. {
  1018. if( (stream->remote_output_ports[i] = jack_port_by_name(
  1019. jackHostApi->jack_client, jack_ports[i] )) == NULL )
  1020. {
  1021. err = 1;
  1022. break;
  1023. }
  1024. }
  1025. free( jack_ports );
  1026. UNLESS( !err, paInsufficientMemory );
  1027. /* Fewer ports than expected? */
  1028. UNLESS( i == inputChannelCount, paInternalError );
  1029. }
  1030. if( outputChannelCount > 0 )
  1031. {
  1032. int err = 0;
  1033. /* ... remote input ports (that we output to) */
  1034. snprintf( regex_pattern, regexSz, "%s:.*", hostApi->deviceInfos[ outputParameters->device ]->name );
  1035. UNLESS( jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern,
  1036. NULL, JackPortIsInput ), paUnanticipatedHostError );
  1037. for( i = 0; i < outputChannelCount && jack_ports[i]; i++ )
  1038. {
  1039. if( (stream->remote_input_ports[i] = jack_port_by_name(
  1040. jackHostApi->jack_client, jack_ports[i] )) == 0 )
  1041. {
  1042. err = 1;
  1043. break;
  1044. }
  1045. }
  1046. free( jack_ports );
  1047. UNLESS( !err , paInsufficientMemory );
  1048. /* Fewer ports than expected? */
  1049. UNLESS( i == outputChannelCount, paInternalError );
  1050. }
  1051. ENSURE_PA( PaUtil_InitializeBufferProcessor(
  1052. &stream->bufferProcessor,
  1053. inputChannelCount,
  1054. inputSampleFormat,
  1055. paFloat32, /* hostInputSampleFormat */
  1056. outputChannelCount,
  1057. outputSampleFormat,
  1058. paFloat32, /* hostOutputSampleFormat */
  1059. jackSr,
  1060. streamFlags,
  1061. framesPerBuffer,
  1062. 0, /* Ignored */
  1063. paUtilUnknownHostBufferSize, /* Buffer size may vary on JACK's discretion */
  1064. streamCallback,
  1065. userData ) );
  1066. bpInitialized = 1;
  1067. if( stream->num_incoming_connections > 0 )
  1068. stream->streamRepresentation.streamInfo.inputLatency = (jack_port_get_latency( stream->remote_output_ports[0] )
  1069. - jack_get_buffer_size( jackHostApi->jack_client ) /* One buffer is not counted as latency */
  1070. + PaUtil_GetBufferProcessorInputLatency( &stream->bufferProcessor )) / sampleRate;
  1071. if( stream->num_outgoing_connections > 0 )
  1072. stream->streamRepresentation.streamInfo.outputLatency = (jack_port_get_latency( stream->remote_input_ports[0] )
  1073. - jack_get_buffer_size( jackHostApi->jack_client ) /* One buffer is not counted as latency */
  1074. + PaUtil_GetBufferProcessorOutputLatency( &stream->bufferProcessor )) / sampleRate;
  1075. stream->streamRepresentation.streamInfo.sampleRate = jackSr;
  1076. stream->t0 = jack_frame_time( jackHostApi->jack_client ); /* A: Time should run from Pa_OpenStream */
  1077. ENSURE_PA( AddStream( stream ) ); /* Add to queue over opened streams */
  1078. *s = (PaStream*)stream;
  1079. return result;
  1080. error:
  1081. if( stream )
  1082. CleanUpStream( stream, srInitialized, bpInitialized );
  1083. return result;
  1084. }
  1085. /*
  1086. When CloseStream() is called, the multi-api layer ensures that
  1087. the stream has already been stopped or aborted.
  1088. */
  1089. static PaError CloseStream( PaStream* s )
  1090. {
  1091. PaError result = paNoError;
  1092. PaJackStream *stream = (PaJackStream*)s;
  1093. /* Remove this stream from the processing queue */
  1094. ENSURE_PA( RemoveStream( stream ) );
  1095. error:
  1096. CleanUpStream( stream, 1, 1 );
  1097. return result;
  1098. }
  1099. static PaError RealProcess( PaJackStream *stream, jack_nframes_t frames )
  1100. {
  1101. PaError result = paNoError;
  1102. PaStreamCallbackTimeInfo timeInfo = {0,0,0};
  1103. int chn;
  1104. int framesProcessed;
  1105. const double sr = jack_get_sample_rate( stream->jack_client ); /* Shouldn't change during the process callback */
  1106. PaStreamCallbackFlags cbFlags = 0;
  1107. /* If the user has returned !paContinue from the callback we'll want to flush the internal buffers,
  1108. * when these are empty we can finally mark the stream as inactive */
  1109. if( stream->callbackResult != paContinue &&
  1110. PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) )
  1111. {
  1112. stream->is_active = 0;
  1113. if( stream->streamRepresentation.streamFinishedCallback )
  1114. stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
  1115. PA_DEBUG(( "%s: Callback finished\n", __FUNCTION__ ));
  1116. goto end;
  1117. }
  1118. timeInfo.currentTime = (jack_frame_time( stream->jack_client ) - stream->t0) / sr;
  1119. if( stream->num_incoming_connections > 0 )
  1120. timeInfo.inputBufferAdcTime = timeInfo.currentTime - jack_port_get_latency( stream->remote_output_ports[0] )
  1121. / sr;
  1122. if( stream->num_outgoing_connections > 0 )
  1123. timeInfo.outputBufferDacTime = timeInfo.currentTime + jack_port_get_latency( stream->remote_input_ports[0] )
  1124. / sr;
  1125. PaUtil_

Large files files are truncated, but you can click here to view the full file