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

📄 pa_unix_oss.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 5 页
字号:
    assert( component );

    if( component->fd >= 0 )
        close( component->fd );
    if( component->buffer )
        PaUtil_FreeMemory( component->buffer );

    if( component->userBuffers )
        PaUtil_FreeMemory( component->userBuffers );

    PaUtil_FreeMemory( component );
}

static PaError ModifyBlocking( int fd, int blocking )
{
    PaError result = paNoError;
    int fflags;

    ENSURE_( fflags = fcntl( fd, F_GETFL ), paUnanticipatedHostError );

    if( blocking )
        fflags &= ~O_NONBLOCK;
    else
        fflags |= O_NONBLOCK;

    ENSURE_( fcntl( fd, F_SETFL, fflags ), paUnanticipatedHostError );

error:
    return result;
}

static PaError OpenDevices( const char *idevName, const char *odevName, int *idev, int *odev )
{
    PaError result = paNoError;
    int flags = O_NONBLOCK, duplex = 0;
    int enableBits = 0;
    *idev = *odev = -1;

    if( idevName && odevName )
    {
        duplex = 1;
        flags |= O_RDWR;
    }
    else if( idevName )
        flags |= O_RDONLY;
    else
        flags |= O_WRONLY;

    /* open first in nonblocking mode, in case it's busy...
     * A: then unset the non-blocking attribute */
    assert( flags & O_NONBLOCK );
    if( idevName )
    {
        ENSURE_( *idev = open( idevName, flags ), paDeviceUnavailable );
        PA_ENSURE( ModifyBlocking( *idev, 1 ) ); /* Blocking */

        /* Initially disable */
        enableBits = ~PCM_ENABLE_INPUT;
        ENSURE_( ioctl( *idev, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
    }
    if( odevName )
    {
        if( !idevName )
        {
            ENSURE_( *odev = open( odevName, flags ), paDeviceUnavailable );
            PA_ENSURE( ModifyBlocking( *odev, 1 ) ); /* Blocking */

            /* Initially disable */
            enableBits = ~PCM_ENABLE_OUTPUT;
            ENSURE_( ioctl( *odev, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
        }
        else
        {
            ENSURE_( *odev = dup( *idev ), paUnanticipatedHostError );
        }
    }

error:
    return result;
}

static PaError PaOssStream_Initialize( PaOssStream *stream, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters,
        PaStreamCallback callback, void *userData, PaStreamFlags streamFlags,
        PaOSSHostApiRepresentation *ossApi )
{
    PaError result = paNoError;
    int idev, odev;
    PaUtilHostApiRepresentation *hostApi = &ossApi->inheritedHostApiRep;
    const char *idevName = NULL, *odevName = NULL;

    assert( stream );

    memset( stream, 0, sizeof (PaOssStream) );
    stream->isStopped = 1;

    PA_ENSURE( PaUtil_InitializeThreading( &stream->threading ) );

    if( inputParameters && outputParameters )
    {
        if( inputParameters->device == outputParameters->device )
            stream->sharedDevice = 1;
    }

    if( inputParameters )
        idevName = hostApi->deviceInfos[inputParameters->device]->name;
    if( outputParameters )
        odevName = hostApi->deviceInfos[outputParameters->device]->name;
    PA_ENSURE( OpenDevices( idevName, odevName, &idev, &odev ) );
    if( inputParameters )
    {
        PA_UNLESS( stream->capture = PaUtil_AllocateMemory( sizeof (PaOssStreamComponent) ), paInsufficientMemory );
        PA_ENSURE( PaOssStreamComponent_Initialize( stream->capture, inputParameters, callback != NULL, idev, idevName ) );
    }
    if( outputParameters )
    {
        PA_UNLESS( stream->playback = PaUtil_AllocateMemory( sizeof (PaOssStreamComponent) ), paInsufficientMemory );
        PA_ENSURE( PaOssStreamComponent_Initialize( stream->playback, outputParameters, callback != NULL, odev, odevName ) );
    }

    if( callback != NULL )
    {
        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
                                               &ossApi->callbackStreamInterface, callback, userData );
        stream->callbackMode = 1;
    }
    else
    {
        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
                                               &ossApi->blockingStreamInterface, callback, userData );
    }    

    ENSURE_( sem_init( &stream->semaphore, 0, 0 ), paInternalError );

error:
    return result;
}

static void PaOssStream_Terminate( PaOssStream *stream )
{
    assert( stream );

    PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
    PaUtil_TerminateThreading( &stream->threading );

    if( stream->capture )
        PaOssStreamComponent_Terminate( stream->capture );
    if( stream->playback )
        PaOssStreamComponent_Terminate( stream->playback );

    sem_destroy( &stream->semaphore );

    PaUtil_FreeMemory( stream );
}

/** Translate from PA format to OSS native.
 *
 */
static PaError Pa2OssFormat( PaSampleFormat paFormat, int *ossFormat )
{
    switch( paFormat )
    {
        case paUInt8:
            *ossFormat = AFMT_U8;
            break;
        case paInt8:
            *ossFormat = AFMT_S8;
            break;
        case paInt16:
            *ossFormat = AFMT_S16_NE;
            break;
        default:
            return paInternalError;     /* This shouldn't happen */
    }

    return paNoError;
}

/** Return the PA-compatible formats that this device can support.
 *
 */
static PaError GetAvailableFormats( PaOssStreamComponent *component, PaSampleFormat *availableFormats )
{
    PaError result = paNoError;
    int mask = 0;
    PaSampleFormat frmts = 0;

    ENSURE_( ioctl( component->fd, SNDCTL_DSP_GETFMTS, &mask ), paUnanticipatedHostError );
    if( mask & AFMT_U8 )
        frmts |= paUInt8;
    if( mask & AFMT_S8 )
        frmts |= paInt8;
    if( mask & AFMT_S16_NE )
        frmts |= paInt16;
    else
        result = paSampleFormatNotSupported;
    
    *availableFormats = frmts;

error:
    return result;
}

static unsigned int PaOssStreamComponent_FrameSize( PaOssStreamComponent *component )
{
    return Pa_GetSampleSize( component->hostFormat ) * component->hostChannelCount;
}

/** Buffer size in bytes.
 *
 */
static unsigned long PaOssStreamComponent_BufferSize( PaOssStreamComponent *component )
{
    return PaOssStreamComponent_FrameSize( component ) * component->hostFrames * component->numBufs;
}

static int CalcHigherLogTwo( int n )
{
    int log2 = 0;
    while( (1<<log2) < n ) log2++;
    return log2;
}

static PaError PaOssStreamComponent_Configure( PaOssStreamComponent *component, double sampleRate, unsigned long framesPerBuffer,
        StreamMode streamMode, PaOssStreamComponent *master )
{
    PaError result = paNoError;
    int temp, nativeFormat;
    int sr = (int)sampleRate;
    PaSampleFormat availableFormats = 0, hostFormat;
    int chans = component->userChannelCount;
    int frgmt;
    int numBufs;
    int bytesPerBuf;
    double bufSz;
    unsigned long fragSz;
    audio_buf_info bufInfo;

    /* We may have a situation where only one component (the master) is configured, if both point to the same device.
     * In that case, the second component will copy settings from the other */
    if( !master )
    {
        /* Aspect BufferSettings: If framesPerBuffer is unspecified we have to infer a suitable fragment size.
         * The hardware need not respect the requested fragment size, so we may have to adapt.
         */
        if( framesPerBuffer == paFramesPerBufferUnspecified )
        { 
            bufSz = component->latency * sampleRate;
            fragSz = bufSz / 4;
        }
        else
        {
            fragSz = framesPerBuffer;
            bufSz = component->latency * sampleRate + fragSz; /* Latency + 1 buffer */
        }

        PA_ENSURE( GetAvailableFormats( component, &availableFormats ) );
        hostFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, component->userFormat );

        /* OSS demands at least 2 buffers, and 16 bytes per buffer */
        numBufs = PA_MAX( bufSz / fragSz, 2 );
        bytesPerBuf = PA_MAX( fragSz * Pa_GetSampleSize( hostFormat ) * chans, 16 );

        /* The fragment parameters are encoded like this:
         * Most significant byte: number of fragments
         * Least significant byte: exponent of fragment size (i.e., for 256, 8)
         */
        frgmt = (numBufs << 16) + (CalcHigherLogTwo( bytesPerBuf ) & 0xffff);
        ENSURE_( ioctl( component->fd, SNDCTL_DSP_SETFRAGMENT, &frgmt ), paUnanticipatedHostError );

        /* A: according to the OSS programmer's guide parameters should be set in this order:
         * format, channels, rate */

        /* This format should be deemed good before we get this far */
        PA_ENSURE( Pa2OssFormat( hostFormat, &temp ) );
        nativeFormat = temp;
        ENSURE_( ioctl( component->fd, SNDCTL_DSP_SETFMT, &temp ), paUnanticipatedHostError );
        PA_UNLESS( temp == nativeFormat, paInternalError );

        /* try to set the number of channels */
        ENSURE_( ioctl( component->fd, SNDCTL_DSP_CHANNELS, &chans ), paSampleFormatNotSupported );   /* XXX: Should be paInvalidChannelCount? */
        /* It's possible that the minimum number of host channels is greater than what the user requested */
        PA_UNLESS( chans >= component->userChannelCount, paInvalidChannelCount );

        /* try to set the sample rate */
        ENSURE_( ioctl( component->fd, SNDCTL_DSP_SPEED, &sr ), paInvalidSampleRate );

        /* reject if there's no sample rate within 1% of the one requested */
        if( (fabs( sampleRate - sr ) / sampleRate) > 0.01 )
        {
            PA_DEBUG(("%s: Wanted %f, closest sample rate was %d\n", __FUNCTION__, sampleRate, sr ));                 
            PA_ENSURE( paInvalidSampleRate );
        }

        ENSURE_( ioctl( component->fd, streamMode == StreamMode_In ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &bufInfo ),
                paUnanticipatedHostError );
        component->numBufs = bufInfo.fragstotal;

        /* This needs to be the last ioctl call before the first read/write, according to the OSS programmer's guide */
        ENSURE_( ioctl( component->fd, SNDCTL_DSP_GETBLKSIZE, &bytesPerBuf ), paUnanticipatedHostError );

        component->hostFrames = bytesPerBuf / Pa_GetSampleSize( hostFormat ) / chans;
        component->hostChannelCount = chans;
        component->hostFormat = hostFormat;
    }
    else
    {
        component->hostFormat = master->hostFormat;
        component->hostFrames = master->hostFrames;
        component->hostChannelCount = master->hostChannelCount;
        component->numBufs = master->numBufs;
    }

    PA_UNLESS( component->buffer = PaUtil_AllocateMemory( PaOssStreamComponent_BufferSize( component ) ),
            paInsufficientMemory );

error:
    return result;
}

static PaError PaOssStreamComponent_Read( PaOssStreamComponent *component, unsigned long *frames )
{
    PaError result = paNoError;
    size_t len = *frames * PaOssStreamComponent_FrameSize( component );
    ssize_t bytesRead;

    ENSURE_( bytesRead = read( component->fd, component->buffer, len ), paUnanticipatedHostError );
    *frames = bytesRead / PaOssStreamComponent_FrameSize( component );

error:
    return result;
}

static PaError PaOssStreamComponent_Write( PaOssStreamComponent *component, unsigned long *frames )
{
    PaError result = paNoError;
    size_t len = *frames * PaOssStreamComponent_FrameSize( component );
    ssize_t bytesWritten;

    ENSURE_( bytesWritten = write( component->fd, component->buffer, len ), paUnanticipatedHostError );
    *frames = bytesWritten / PaOssStreamComponent_FrameSize( component );

error:
    return result;
}

/** Configure the stream according to input/output parameters.
 *
 * Aspect StreamChannels: The minimum number of channels supported by the device may exceed that requested by
 * the user, if so we'll record the actual number of host channels and adapt later.
 */
static PaError PaOssStream_Configure( PaOssStream *stream, double sampleRate, unsigned long framesPerBuffer,
        double *inputLatency, double *outputLatency )
{
    PaError result = paNoError;
    int duplex = stream->capture && stream->playback;
    unsigned long framesPerHostBuffer = 0;

    /* We should request full duplex first thing after opening the device */
    if( duplex && stream->sharedDevice )
        ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETDUPLEX, 0 ), paUnanticipatedHostError );

    if( stream->capture )
    {
        PaOssStreamComponent *component = stream->capture;
        PaOssStreamComponent_Configure( component, sampleRate, framesPerBuffer, StreamMode_In, NULL );

        assert( component->hostChannelCount > 0 );
        assert( component->hostFrames > 0 );

⌨️ 快捷键说明

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