⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pa_jack.c

📁 一个开源的sip源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
    PaJackStream *stream = (PaJackStream *)s;    long bytesRead;    char *p = (char *) data;    long numBytes = stream->bytesPerFrame * numFrames;    while( numBytes > 0 )    {        bytesRead = PaUtil_ReadRingBuffer( &stream->inFIFO, p, numBytes );        numBytes -= bytesRead;        p += bytesRead;        if( numBytes > 0 )        {            /* see write for an explanation */            if( stream->data_available )                stream->data_available = 0;            else                sem_wait( &stream->data_semaphore );        }    }    return result;}static PaError BlockingWriteStream( PaStream* s, const void *data, unsigned long numFrames ){    PaError result = paNoError;    PaJackStream *stream = (PaJackStream *)s;    long bytesWritten;    char *p = (char *) data;    long numBytes = stream->bytesPerFrame * numFrames;    while( numBytes > 0 )    {        bytesWritten = PaUtil_WriteRingBuffer( &stream->outFIFO, p, numBytes );        numBytes -= bytesWritten;        p += bytesWritten;        if( numBytes > 0 )         {            /* we use the following algorithm:              *   (1) write data             *   (2) if some data didn't fit into the ringbuffer, set data_available to 0             *       to indicate to the audio that if space becomes available, we want to know             *   (3) retry to write data (because it might be that between (1) and (2)             *       new space in the buffer became available)             *   (4) if this failed, we are sure that the buffer is really empty and             *       we will definitely receive a notification when it becomes available             *       thus we can safely sleep             *             * if the algorithm bailed out in step (3) before, it leaks a count of 1             * on the semaphore; however, it doesn't matter, because if we block in (4),             * we also do it in a loop             */            if( stream->data_available )                stream->data_available = 0;            else                sem_wait( &stream->data_semaphore );        }    }    return result;}static signed longBlockingGetStreamReadAvailable( PaStream* s ){    PaJackStream *stream = (PaJackStream *)s;    int bytesFull = PaUtil_GetRingBufferReadAvailable( &stream->inFIFO );    return bytesFull / stream->bytesPerFrame;}static signed longBlockingGetStreamWriteAvailable( PaStream* s ){    PaJackStream *stream = (PaJackStream *)s;    int bytesEmpty = PaUtil_GetRingBufferWriteAvailable( &stream->outFIFO );    return bytesEmpty / stream->bytesPerFrame;}static PaErrorBlockingWaitEmpty( PaStream *s ){    PaJackStream *stream = (PaJackStream *)s;    while( PaUtil_GetRingBufferReadAvailable( &stream->outFIFO ) > 0 )    {        stream->data_available = 0;        sem_wait( &stream->data_semaphore );    }    return 0;}/* ---- jack driver ---- *//* 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 */    /* 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 */    PaError result = paNoError;    PaUtilHostApiRepresentation *commonApi = &jackApi->commonHostApiRep;    const char **jack_ports = NULL;    char **client_names = NULL;    char *regex_pattern = NULL;    int port_index, client_index, i;    double globalSampleRate;    regex_t port_regex;    unsigned long numClients = 0, numPorts = 0;    char *tmp_client_name = NULL;    commonApi->info.defaultInputDevice = paNoDevice;    commonApi->info.defaultOutputDevice = paNoDevice;    commonApi->info.deviceCount = 0;    /* Parse the list of ports, using a regex to grab the client names */    ASSERT_CALL( regcomp( &port_regex, "^[^:]*", REG_EXTENDED ), 0 );    /* since we are rebuilding the list of devices, free all memory     * associated with the previous list */    PaUtil_FreeAllAllocations( jackApi->deviceInfoMemory );    regex_pattern = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, jack_client_name_size() + 3 );    tmp_client_name = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, jack_client_name_size() );    /* 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)     * A: If jack_get_ports returns NULL, there's nothing for us to do */    UNLESS( (jack_ports = jack_get_ports( jackApi->jack_client, "", "", 0 )) && jack_ports[0], paNoError );    /* Find number of ports */    while( jack_ports[numPorts] )        ++numPorts;    /* At least there will be one port per client :) */    UNLESS( client_names = PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, numPorts *                sizeof (char *) ), paInsufficientMemory );    /* Build a list of clients from the list of ports */    for( numClients = 0, port_index = 0; jack_ports[port_index] != NULL; port_index++ )    {        int client_seen = FALSE;        regmatch_t match_info;        const char *port = jack_ports[port_index];        /* extract the client name from the port name, using a regex         * that parses the clientname:portname syntax */        UNLESS( !regexec( &port_regex, port, 1, &match_info, 0 ), paInternalError );        assert(match_info.rm_eo - match_info.rm_so < jack_client_name_size());        memcpy( tmp_client_name, port + 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? */        for( i = 0; i < numClients; i++ )        {            if( strcmp( tmp_client_name, client_names[i] ) == 0 )                client_seen = TRUE;        }        if (client_seen)            continue;   /* A: Nothing to see here, move along */        UNLESS( client_names[numClients] = (char*)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory,                    strlen(tmp_client_name) + 1), paInsufficientMemory );        /* 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 && numClients > 0 )        {            /* alsa_pcm goes in spot 0 */            strcpy( client_names[ numClients ], client_names[0] );            strcpy( client_names[0], tmp_client_name );        }        else        {            /* put the new client at the end of the client list */            strcpy( client_names[ numClients ], tmp_client_name );        }        ++numClients;    }    /* Now we have a list of clients, which will become the list of     * PortAudio devices. */    /* there is one global sample rate all clients must conform to */    globalSampleRate = jack_get_sample_rate( jackApi->jack_client );    UNLESS( commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory,                sizeof(PaDeviceInfo*) * numClients ), paInsufficientMemory );    assert( commonApi->info.deviceCount == 0 );    /* Create a PaDeviceInfo structure for every client */    for( client_index = 0; client_index < numClients; client_index++ )    {        PaDeviceInfo *curDevInfo;        const char **clientPorts = NULL;        UNLESS( curDevInfo = (PaDeviceInfo*)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory,                    sizeof(PaDeviceInfo) ), paInsufficientMemory );        UNLESS( curDevInfo->name = (char*)PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory,                    strlen(client_names[client_index]) + 1 ), paInsufficientMemory );        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 from)? */        clientPorts = jack_get_ports( jackApi->jack_client, regex_pattern,                                     NULL, JackPortIsOutput);        curDevInfo->maxInputChannels = 0;        curDevInfo->defaultLowInputLatency = 0.;        curDevInfo->defaultHighInputLatency = 0.;        if( clientPorts )        {            jack_port_t *p = jack_port_by_name( jackApi->jack_client, clientPorts[0] );            curDevInfo->defaultLowInputLatency = curDevInfo->defaultHighInputLatency =                jack_port_get_latency( p ) / globalSampleRate;            for( i = 0; clientPorts[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(clientPorts);        }        /* ... what are your input ports (that we could output to)? */        clientPorts = jack_get_ports( jackApi->jack_client, regex_pattern,                                     NULL, JackPortIsInput);        curDevInfo->maxOutputChannels = 0;        curDevInfo->defaultLowOutputLatency = 0.;        curDevInfo->defaultHighOutputLatency = 0.;        if( clientPorts )        {            jack_port_t *p = jack_port_by_name( jackApi->jack_client, clientPorts[0] );            curDevInfo->defaultLowOutputLatency = curDevInfo->defaultHighOutputLatency =                jack_port_get_latency( p ) / globalSampleRate;            for( i = 0; clientPorts[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(clientPorts);        }        /* Add this client to the list of devices */        commonApi->deviceInfos[client_index] = curDevInfo;        ++commonApi->info.deviceCount;        if( commonApi->info.defaultInputDevice == paNoDevice && curDevInfo->maxInputChannels > 0 )            commonApi->info.defaultInputDevice = client_index;        if( commonApi->info.defaultOutputDevice == paNoDevice && curDevInfo->maxOutputChannels > 0 )            commonApi->info.defaultOutputDevice = client_index;    }error:    regfree( &port_regex );    free( jack_ports );    return result;}static void UpdateSampleRate( PaJackStream *stream, double sampleRate ){    /* XXX: Maybe not the cleanest way of going about this? */    stream->cpuLoadMeasurer.samplingPeriod = stream->bufferProcessor.samplePeriod = 1. / sampleRate;    stream->streamRepresentation.streamInfo.sampleRate = sampleRate;}static void JackErrorCallback( const char *msg ){    if( pthread_self() == mainThread_ )    {        assert( msg );        jackErr_ = realloc( jackErr_, strlen( msg ) + 1 );        strcpy( jackErr_, msg );    }}static void JackOnShutdown( void *arg ){    PaJackHostApiRepresentation *jackApi = (PaJackHostApiRepresentation *)arg;    PaJackStream *stream = jackApi->processQueue;    PA_DEBUG(( "%s: JACK server is shutting down\n", __FUNCTION__ ));    for( ; stream; stream = stream->next )    {        stream->is_active = 0;    }    /* Make sure that the main thread doesn't get stuck waiting on the condition */    ASSERT_CALL( pthread_mutex_lock( &jackApi->mtx ), 0 );    jackApi->jackIsDown = 1;    ASSERT_CALL( pthread_cond_signal( &jackApi->cond ), 0 );    ASSERT_CALL( pthread_mutex_unlock( &jackApi->mtx ), 0 );}static int JackSrCb( jack_nframes_t nframes, void *arg ){    PaJackHostApiRepresentation *jackApi = (PaJackHostApiRepresentation *)arg;    double sampleRate = (double)nframes;    PaJackStream *stream = jackApi->processQueue;    /* Update all streams in process queue */    PA_DEBUG(( "%s: Acting on change in JACK samplerate: %f\n", __FUNCTION__, sampleRate ));    for( ; stream; stream = stream->next )    {        if( stream->streamRepresentation.streamInfo.sampleRate != sampleRate )        {            PA_DEBUG(( "%s: Updating samplerate\n", __FUNCTION__ ));            UpdateSampleRate( stream, sampleRate );        }    }    return 0;}static int JackXRunCb(void *arg) {    PaJackHostApiRepresentation *hostApi = (PaJackHostApiRepresentation *)arg;    assert( hostApi );    hostApi->xrun = TRUE;    PA_DEBUG(( "%s: JACK signalled xrun\n", __FUNCTION__ ));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -