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

📄 pa_unix_oss.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 5 页
字号:
            maxNumChannels = (stereo) ? 2 : 1;
        }
        PA_DEBUG(( "%s: use SNDCTL_DSP_STEREO, maxNumChannels = %d\n", __FUNCTION__, maxNumChannels ))
    }

    /* During channel negotiation, the last ioctl() may have failed. This can
     * also cause sample rate negotiation to fail. Hence the following, to return
     * to a supported number of channels. SG20011005 */
    {
        /* use most reasonable default value */
        int temp = PA_MIN( maxNumChannels, 2 );
        ENSURE_( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &temp ), paUnanticipatedHostError );
    }

    /* Get supported sample rate closest to 44100 Hz */
    if( *defaultSampleRate < 0 )
    {
        sr = 44100;
        if( ioctl( devHandle, SNDCTL_DSP_SPEED, &sr ) < 0 )
        {
            result = paUnanticipatedHostError;
            goto error;
        }

        *defaultSampleRate = sr;
    }

    *maxChannelCount = maxNumChannels;
    /* TODO */
    *defaultLowLatency = 512. / *defaultSampleRate;
    *defaultHighLatency = 2048. / *defaultSampleRate;

error:
    if( devHandle >= 0 )
        close( devHandle );

    return result;
}

/** Query OSS device.
 *
 * This is where PaDeviceInfo objects are constructed and filled in with relevant information.
 *
 * Aspect DeviceCapabilities: The inferred device capabilities are recorded in a PaDeviceInfo object that is constructed
 * in place.
 */
static PaError QueryDevice( char *deviceName, PaOSSHostApiRepresentation *ossApi, PaDeviceInfo **deviceInfo )
{
    PaError result = paNoError;
    double sampleRate = -1.;
    int maxInputChannels, maxOutputChannels;
    PaTime defaultLowInputLatency, defaultLowOutputLatency, defaultHighInputLatency, defaultHighOutputLatency;
    PaError tmpRes = paNoError;
    int busy = 0;
    *deviceInfo = NULL;

    /* douglas:
       we have to do this querying in a slightly different order. apparently
       some sound cards will give you different info based on their settins. 
       e.g. a card might give you stereo at 22kHz but only mono at 44kHz.
       the correct order for OSS is: format, channels, sample rate
    */

    /* Aspect StreamChannels: The number of channels supported for a device may depend on the mode it is
     * opened in, it may have more channels available for capture than playback and vice versa. Therefore
     * we will open the device in both read- and write-only mode to determine the supported number.
     */
    if( (tmpRes = QueryDirection( deviceName, StreamMode_In, &sampleRate, &maxInputChannels, &defaultLowInputLatency,
                &defaultHighInputLatency )) != paNoError )
    {
        if( tmpRes != paDeviceUnavailable )
        {
            PA_DEBUG(( "%s: Querying device %s for capture failed!\n", __FUNCTION__, deviceName ));
            /* PA_ENSURE( tmpRes ); */
        }
        ++busy;
    }
    if( (tmpRes = QueryDirection( deviceName, StreamMode_Out, &sampleRate, &maxOutputChannels, &defaultLowOutputLatency,
                &defaultHighOutputLatency )) != paNoError )
    {
        if( tmpRes != paDeviceUnavailable )
        {
            PA_DEBUG(( "%s: Querying device %s for playback failed!\n", __FUNCTION__, deviceName ));
            /* PA_ENSURE( tmpRes ); */
        }
        ++busy;
    }
    assert( 0 <= busy && busy <= 2 );
    if( 2 == busy )     /* Both directions are unavailable to us */
    {
        result = paDeviceUnavailable;
        goto error;
    }

    PA_UNLESS( *deviceInfo = PaUtil_GroupAllocateMemory( ossApi->allocations, sizeof (PaDeviceInfo) ), paInsufficientMemory );
    PA_ENSURE( PaUtil_InitializeDeviceInfo( *deviceInfo, deviceName, ossApi->hostApiIndex, maxInputChannels, maxOutputChannels,
                defaultLowInputLatency, defaultLowOutputLatency, defaultHighInputLatency, defaultHighOutputLatency, sampleRate,
                ossApi->allocations ) );

error:
    return result;
}

/** Query host devices.
 *
 * Loop over host devices and query their capabilitiesu
 *
 * Aspect DeviceCapabilities: This function calls QueryDevice on each device entry and receives a filled in PaDeviceInfo object
 * per device, these are placed in the host api representation's deviceInfos array.
 */
static PaError BuildDeviceList( PaOSSHostApiRepresentation *ossApi )
{
    PaError result = paNoError;
    PaUtilHostApiRepresentation *commonApi = &ossApi->inheritedHostApiRep;
    int i;
    int numDevices = 0, maxDeviceInfos = 1;
    PaDeviceInfo **deviceInfos = NULL;

    /* These two will be set to the first working input and output device, respectively */
    commonApi->info.defaultInputDevice = paNoDevice;
    commonApi->info.defaultOutputDevice = paNoDevice;

    /* Find devices by calling QueryDevice on each
     * potential device names.  When we find a valid one,
     * add it to a linked list.
     * A: Can there only be 10 devices? */

    for( i = 0; i < 10; i++ )
    {
       char deviceName[32];
       PaDeviceInfo *deviceInfo;
       int testResult;
       struct stat stbuf;

       if( i == 0 )
          snprintf(deviceName, sizeof (deviceName), "%s", DEVICE_NAME_BASE);
       else
          snprintf(deviceName, sizeof (deviceName), "%s%d", DEVICE_NAME_BASE, i);

       /* PA_DEBUG(("PaOSS BuildDeviceList: trying device %s\n", deviceName )); */
       if( stat( deviceName, &stbuf ) < 0 )
       {
           if( ENOENT != errno )
               PA_DEBUG(( "%s: Error stat'ing %s: %s\n", __FUNCTION__, deviceName, strerror( errno ) ));
           continue;
       }
       if( (testResult = QueryDevice( deviceName, ossApi, &deviceInfo )) != paNoError )
       {
           if( testResult != paDeviceUnavailable )
               PA_ENSURE( testResult );

           continue;
       }

       ++numDevices;
       if( !deviceInfos || numDevices > maxDeviceInfos )
       {
           maxDeviceInfos *= 2;
           PA_UNLESS( deviceInfos = (PaDeviceInfo **) realloc( deviceInfos, maxDeviceInfos * sizeof (PaDeviceInfo *) ),
                   paInsufficientMemory );
       }
       deviceInfos[numDevices - 1] = deviceInfo;

       if( commonApi->info.defaultInputDevice == paNoDevice && deviceInfo->maxInputChannels > 0 )
           commonApi->info.defaultInputDevice = i;
       if( commonApi->info.defaultOutputDevice == paNoDevice && deviceInfo->maxOutputChannels > 0 )
           commonApi->info.defaultOutputDevice = i;
    }

    /* Make an array of PaDeviceInfo pointers out of the linked list */

    PA_DEBUG(("PaOSS %s: Total number of devices found: %d\n", __FUNCTION__, numDevices));

    commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
        ossApi->allocations, sizeof(PaDeviceInfo*) * numDevices );
    memcpy( commonApi->deviceInfos, deviceInfos, numDevices * sizeof (PaDeviceInfo *) );

    commonApi->info.deviceCount = numDevices;

error:
    free( deviceInfos );

    return result;
}

static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
{
    PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi;

    if( ossHostApi->allocations )
    {
        PaUtil_FreeAllAllocations( ossHostApi->allocations );
        PaUtil_DestroyAllocationGroup( ossHostApi->allocations );
    }

    PaUtil_FreeMemory( ossHostApi );
}

static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
                                  const PaStreamParameters *inputParameters,
                                  const PaStreamParameters *outputParameters,
                                  double sampleRate )
{
    PaError result = paNoError;
    PaDeviceIndex device;
    PaDeviceInfo *deviceInfo;
    char *deviceName;
    int inputChannelCount, outputChannelCount;
    int tempDevHandle = -1;
    int flags;
    PaSampleFormat inputSampleFormat, outputSampleFormat;
    
    if( inputParameters )
    {
        inputChannelCount = inputParameters->channelCount;
        inputSampleFormat = inputParameters->sampleFormat;

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

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

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

        /* validate inputStreamInfo */
        if( inputParameters->hostApiSpecificStreamInfo )
            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
    }
    else
    {
        inputChannelCount = 0;
    }

    if( outputParameters )
    {
        outputChannelCount = outputParameters->channelCount;
        outputSampleFormat = outputParameters->sampleFormat;
        
        /* unless alternate device specification is supported, reject the use of
            paUseHostApiSpecificDeviceSpecification */

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

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

        /* validate outputStreamInfo */
        if( outputParameters->hostApiSpecificStreamInfo )
            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
    }
    else
    {
        outputChannelCount = 0;
    }

    if (inputChannelCount == 0 && outputChannelCount == 0)
        return paInvalidChannelCount;

    /* if full duplex, make sure that they're the same device */

    if (inputChannelCount > 0 && outputChannelCount > 0 &&
        inputParameters->device != outputParameters->device)
        return paInvalidDevice;

    /* if full duplex, also make sure that they're the same number of channels */

    if (inputChannelCount > 0 && outputChannelCount > 0 &&
        inputChannelCount != outputChannelCount)
       return paInvalidChannelCount;

    /* open the device so we can do more tests */
    
    if( inputChannelCount > 0 )
    {
        result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, inputParameters->device, hostApi);
        if (result != paNoError)
            return result;
    }
    else
    {
        result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, outputParameters->device, hostApi);
        if (result != paNoError)
            return result;
    }

    deviceInfo = hostApi->deviceInfos[device];
    deviceName = (char *)deviceInfo->name;
    
    flags = O_NONBLOCK;
    if (inputChannelCount > 0 && outputChannelCount > 0)
       flags |= O_RDWR;
    else if (inputChannelCount > 0)
       flags |= O_RDONLY;
    else
       flags |= O_WRONLY;

    ENSURE_( tempDevHandle = open( deviceInfo->name, flags ), paDeviceUnavailable );

    /* PaOssStream_Configure will do the rest of the checking for us */
    /* PA_ENSURE( PaOssStream_Configure( tempDevHandle, deviceName, outputChannelCount, &sampleRate ) ); */

    /* everything succeeded! */

 error:
    if( tempDevHandle >= 0 )
        close( tempDevHandle );         

    return result;
}

/** Validate stream parameters.
 *
 * Aspect StreamChannels: We verify that the number of channels is within the allowed range for the device
 */
static PaError ValidateParameters( const PaStreamParameters *parameters, const PaDeviceInfo *deviceInfo, StreamMode mode )
{
    int maxChans;

    assert( parameters );

    if( parameters->device == paUseHostApiSpecificDeviceSpecification )
    {
        return paInvalidDevice;
    }

    maxChans = (mode == StreamMode_In ? deviceInfo->maxInputChannels :
        deviceInfo->maxOutputChannels);
    if( parameters->channelCount > maxChans )
    {
        return paInvalidChannelCount;
    }

    return paNoError;
}

static PaError PaOssStreamComponent_Initialize( PaOssStreamComponent *component, const PaStreamParameters *parameters,
        int callbackMode, int fd, const char *deviceName )
{
    PaError result = paNoError;
    assert( component );

    memset( component, 0, sizeof (PaOssStreamComponent) );

    component->fd = fd;
    component->devName = deviceName;
    component->userChannelCount = parameters->channelCount;
    component->userFormat = parameters->sampleFormat;
    component->latency = parameters->suggestedLatency;
    component->userInterleaved = !(parameters->sampleFormat & paNonInterleaved);

    if( !callbackMode && !component->userInterleaved )
    {
        /* Pre-allocate non-interleaved user provided buffers */
        PA_UNLESS( component->userBuffers = PaUtil_AllocateMemory( sizeof (void *) * component->userChannelCount ),
                paInsufficientMemory );
    }

error:
    return result;
}

static void PaOssStreamComponent_Terminate( PaOssStreamComponent *component )
{

⌨️ 快捷键说明

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