📄 pa_jack.c
字号:
/* * $Id: pa_jack.c,v 1.5 2004/06/09 06:41:17 dmazzoni Exp $ * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * JACK Implementation by Joshua Haberman * * Copyright (c) 2002 Joshua Haberman <joshua@haberman.com> * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */#include <string.h>#include <regex.h>#include <stdlib.h>#include <stdio.h>#include <jack/types.h>#include <jack/jack.h>#include "pa_util.h"#include "pa_hostapi.h"#include "pa_stream.h"#include "pa_process.h"#include "pa_allocation.h"#include "pa_cpuload.h"PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex );/* * Functions that directly map to the PortAudio stream interface */static void Terminate( struct PaUtilHostApiRepresentation *hostApi );static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate );static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData );static PaError CloseStream( PaStream* stream );static PaError StartStream( PaStream *stream );static PaError StopStream( PaStream *stream );static PaError AbortStream( PaStream *stream );static PaError IsStreamStopped( PaStream *s );static PaError IsStreamActive( PaStream *stream );static PaTime GetStreamInputLatency( PaStream *stream );static PaTime GetStreamOutputLatency( PaStream *stream );static PaTime GetStreamTime( PaStream *stream );static double GetStreamCpuLoad( PaStream* stream );/*static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );static signed long GetStreamReadAvailable( PaStream* stream );static signed long GetStreamWriteAvailable( PaStream* stream );*//* * Data specific to this API */typedef struct{ PaUtilHostApiRepresentation commonHostApiRep; PaUtilStreamInterface callbackStreamInterface; PaUtilAllocationGroup *deviceInfoMemory; jack_client_t *jack_client; PaHostApiIndex hostApiIndex;}PaJackHostApiRepresentation;#define MAX_CLIENTS 100#define TRUE 1#define FALSE 0/* * Functions specific to this API */static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi );static int JackCallback( jack_nframes_t frames, void *userData );/* * * Implementation * *//* BuildDeviceList(): * * The process of determining a list of PortAudio "devices" from * JACK's client/port system is fairly involved, so it is separated * into its own routine. */static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi ){ /* Utility macros for the repetitive process of allocating memory */ /* ... MALLOC: allocate memory as part of the device list * allocation group */#define MALLOC(size) \ (PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, (size) )) /* ... MEMVERIFY: make sure we didn't get NULL */#define MEMVERIFY(ptr) \ if( (ptr) == NULL ) return paInsufficientMemory; /* JACK has no concept of a device. To JACK, there are clients * which have an arbitrary number of ports. To make this * intelligible to PortAudio clients, we will group each JACK client * into a device, and make each port of that client a channel */ PaUtilHostApiRepresentation *commonApi = &jackApi->commonHostApiRep; const char **jack_ports; char *client_names[MAX_CLIENTS]; int num_clients = 0; int port_index, client_index, i; double *globalSampleRate; regex_t port_regex; /* since we are rebuilding the list of devices, free all memory * associated with the previous list */ PaUtil_FreeAllAllocations( jackApi->deviceInfoMemory ); /* We can only retrieve the list of clients indirectly, by first * asking for a list of all ports, then parsing the port names * according to the client_name:port_name convention (which is * enforced by jackd) */ jack_ports = jack_get_ports( jackApi->jack_client, "", "", 0 ); if( jack_ports == NULL ) return paUnanticipatedHostError; /* Parse the list of ports, using a regex to grab the client names */ regcomp( &port_regex, "^[^:]*", REG_EXTENDED ); /* Build a list of clients from the list of ports */ for( port_index = 0; jack_ports[port_index] != NULL; port_index++ ) { int client_seen; regmatch_t match_info; char tmp_client_name[100]; /* extract the client name from the port name, using a regex * that parses the clientname:portname syntax */ regexec( &port_regex, jack_ports[port_index], 1, &match_info, 0 ); memcpy( tmp_client_name, &jack_ports[port_index][match_info.rm_so], match_info.rm_eo - match_info.rm_so ); tmp_client_name[ match_info.rm_eo - match_info.rm_so ] = '\0'; /* do we know about this port's client yet? */ client_seen = FALSE; for( i = 0; i < num_clients; i++ ) if( strcmp( tmp_client_name, client_names[i] ) == 0 ) client_seen = TRUE; if( client_seen == FALSE ) { client_names[num_clients] = (char*)MALLOC(strlen(tmp_client_name) + 1); MEMVERIFY( client_names[num_clients] ); /* The alsa_pcm client should go in spot 0. If this * is the alsa_pcm client AND we are NOT about to put * it in spot 0 put it in spot 0 and move whatever * was already in spot 0 to the end. */ if( strcmp( "alsa_pcm", tmp_client_name ) == 0 && num_clients > 0 ) { /* alsa_pcm goes in spot 0 */ strcpy( client_names[ num_clients ], client_names[0] ); strcpy( client_names[0], "alsa_pcm" ); num_clients++; } else { /* put the new client at the end of the client list */ strcpy( client_names[ num_clients ], tmp_client_name ); num_clients++; } } } free( jack_ports ); /* Now we have a list of clients, which will become the list of * PortAudio devices. */ commonApi->info.deviceCount = num_clients; commonApi->info.defaultInputDevice = 0; commonApi->info.defaultOutputDevice = 0; /* there is one global sample rate all clients must conform to */ globalSampleRate = (double*)MALLOC( sizeof(double) ); MEMVERIFY( globalSampleRate ); *globalSampleRate = jack_get_sample_rate( jackApi->jack_client ); commonApi->deviceInfos = (PaDeviceInfo**)MALLOC( sizeof(PaDeviceInfo*) * num_clients ); MEMVERIFY(commonApi->deviceInfos); /* Create a PaDeviceInfo structure for every client */ for( client_index = 0; client_index < num_clients; client_index++ ) { char regex_pattern[100]; PaDeviceInfo *curDevInfo; curDevInfo = (PaDeviceInfo*)MALLOC( sizeof(PaDeviceInfo) ); MEMVERIFY( curDevInfo ); curDevInfo->name = (char*)MALLOC( strlen(client_names[client_index]) + 1 ); MEMVERIFY( curDevInfo->name ); strcpy( (char*)curDevInfo->name, client_names[client_index] ); curDevInfo->structVersion = 2; curDevInfo->hostApi = jackApi->hostApiIndex; /* JACK is very inflexible: there is one sample rate the whole * system must run at, and all clients must speak IEEE float. */ curDevInfo->defaultSampleRate = *globalSampleRate; /* To determine how many input and output channels are available, * we re-query jackd with more specific parameters. */ sprintf( regex_pattern, "%s:.*", client_names[client_index] ); /* ... what are your output ports (that we could input to)? */ jack_ports = jack_get_ports( jackApi->jack_client, regex_pattern, NULL, JackPortIsOutput); curDevInfo->maxInputChannels = 0; if (jack_ports) { for( i = 0; jack_ports[i] != NULL ; i++) { /* The number of ports returned is the number of output channels. * We don't care what they are, we just care how many */ curDevInfo->maxInputChannels++; } free(jack_ports); } /* ... what are your input ports (that we could output to)? */ jack_ports = jack_get_ports( jackApi->jack_client, regex_pattern, NULL, JackPortIsInput); if (jack_ports) { curDevInfo->maxOutputChannels = 0; for( i = 0; jack_ports[i] != NULL ; i++) { /* The number of ports returned is the number of input channels. * We don't care what they are, we just care how many */ curDevInfo->maxOutputChannels++; } free(jack_ports); } curDevInfo->defaultLowInputLatency = 0.; /* IMPLEMENT ME */ curDevInfo->defaultLowOutputLatency = 0.; /* IMPLEMENT ME */ curDevInfo->defaultHighInputLatency = 0.; /* IMPLEMENT ME */ curDevInfo->defaultHighOutputLatency = 0.; /* IMPLEMENT ME */ /* Add this client to the list of devices */ commonApi->deviceInfos[client_index] = curDevInfo; }#undef MALLOC#undef MEMVERIFY return paNoError;}PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ){ PaError result = paNoError; PaJackHostApiRepresentation *jackHostApi; jackHostApi = (PaJackHostApiRepresentation*) PaUtil_AllocateMemory( sizeof(PaJackHostApiRepresentation) ); if( !jackHostApi ) { result = paInsufficientMemory; goto error; } jackHostApi->deviceInfoMemory = NULL; /* Try to become a client of the JACK server. If we cannot do * this, than this API cannot be used. */ jackHostApi->jack_client = jack_client_new( "PortAudio client" ); if( jackHostApi->jack_client == 0 ) { /* the V19 development docs say that if an implementation * detects that it cannot be used, it should return a NULL * interface and paNoError */ result = paNoError; *hostApi = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -