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

📄 pa_unix_oss.c

📁 一个开源的sip源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * $Id: pa_unix_oss.c 1183 2007-03-25 20:20:31Z aknudsen $ * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * OSS implementation by: *   Douglas Repetto *   Phil Burk *   Dominic Mazzoni *   Arve Knudsen * * 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. * * 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. *//* * The text above constitutes the entire PortAudio license; however,  * the PortAudio community also makes the following non-binding requests: * * 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. It is also  * requested that these non-binding requests be included along with the  * license above. *//** @file @ingroup hostaip_src*/#include <stdio.h>#include <string.h>#include <math.h>#include <fcntl.h>#include <sys/ioctl.h>#include <unistd.h>#include <pthread.h>#include <stdlib.h>#include <assert.h>#include <errno.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/poll.h>#include <limits.h>#include <semaphore.h>#ifdef HAVE_SYS_SOUNDCARD_H# include <sys/soundcard.h># define DEVICE_NAME_BASE            "/dev/dsp"#elif defined(HAVE_LINUX_SOUNDCARD_H)# include <linux/soundcard.h># define DEVICE_NAME_BASE            "/dev/dsp"#elif defined(HAVE_MACHINE_SOUNDCARD_H)# include <machine/soundcard.h> /* JH20010905 */# define DEVICE_NAME_BASE            "/dev/audio"#else# error No sound card header file#endif#include "portaudio.h"#include "pa_util.h"#include "pa_allocation.h"#include "pa_hostapi.h"#include "pa_stream.h"#include "pa_cpuload.h"#include "pa_process.h"#include "pa_unix_util.h"static int sysErr_;static pthread_t mainThread_;/* Check return value of system call, and map it to PaError */#define ENSURE_(expr, code) \    do { \        if( UNLIKELY( (sysErr_ = (expr)) < 0 ) ) \        { \            /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \            if( (code) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \            { \                PaUtil_SetLastHostErrorInfo( paALSA, sysErr_, strerror( errno ) ); \            } \            \            PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \            result = (code); \            goto error; \        } \    } while( 0 );#ifndef AFMT_S16_NE#define AFMT_S16_NE  Get_AFMT_S16_NE()/********************************************************************* * Some versions of OSS do not define AFMT_S16_NE. So check CPU. * PowerPC is Big Endian. X86 is Little Endian. */static int Get_AFMT_S16_NE( void ){    long testData = 1;     char *ptr = (char *) &testData;    int isLittle = ( *ptr == 1 ); /* Does address point to least significant byte? */    return isLittle ? AFMT_S16_LE : AFMT_S16_BE;}#endif/* PaOSSHostApiRepresentation - host api datastructure specific to this implementation */typedef struct{    PaUtilHostApiRepresentation inheritedHostApiRep;    PaUtilStreamInterface callbackStreamInterface;    PaUtilStreamInterface blockingStreamInterface;    PaUtilAllocationGroup *allocations;    PaHostApiIndex hostApiIndex;}PaOSSHostApiRepresentation;/** Per-direction structure for PaOssStream. * * Aspect StreamChannels: In case the user requests to open the same device for both capture and playback, * but with different number of channels we will have to adapt between the number of user and host * channels for at least one direction, since the configuration space is the same for both directions * of an OSS device. */typedef struct{    int fd;    const char *devName;    int userChannelCount, hostChannelCount;    int userInterleaved;    void *buffer;    PaSampleFormat userFormat, hostFormat;    double latency;    unsigned long hostFrames, numBufs;    void **userBuffers; /* For non-interleaved blocking */} PaOssStreamComponent;/** Implementation specific representation of a PaStream. * */typedef struct PaOssStream{    PaUtilStreamRepresentation streamRepresentation;    PaUtilCpuLoadMeasurer cpuLoadMeasurer;    PaUtilBufferProcessor bufferProcessor;    PaUtilThreading threading;    int sharedDevice;    unsigned long framesPerHostBuffer;    int triggered;  /* Have the devices been triggered yet (first start) */    int isActive;    int isStopped;    int lastPosPtr;    double lastStreamBytes;    int framesProcessed;    double sampleRate;    int callbackMode;    int callbackStop, callbackAbort;    PaOssStreamComponent *capture, *playback;    unsigned long pollTimeout;    sem_t semaphore;}PaOssStream;typedef enum {    StreamMode_In,    StreamMode_Out} StreamMode;/* prototypes for functions declared in this file */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 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 );static PaError BuildDeviceList( PaOSSHostApiRepresentation *hostApi );/** Initialize the OSS API implementation. * * This function will initialize host API datastructures and query host devices for information. * * Aspect DeviceCapabilities: Enumeration of host API devices is initiated from here * * Aspect FreeResources: If an error is encountered under way we have to free each resource allocated in this function, * this happens with the usual "error" label. */PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ){    PaError result = paNoError;    PaOSSHostApiRepresentation *ossHostApi = NULL;    PA_UNLESS( ossHostApi = (PaOSSHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaOSSHostApiRepresentation) ),            paInsufficientMemory );    PA_UNLESS( ossHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory );    ossHostApi->hostApiIndex = hostApiIndex;    /* Initialize host API structure */    *hostApi = &ossHostApi->inheritedHostApiRep;    (*hostApi)->info.structVersion = 1;    (*hostApi)->info.type = paOSS;    (*hostApi)->info.name = "OSS";    (*hostApi)->Terminate = Terminate;    (*hostApi)->OpenStream = OpenStream;    (*hostApi)->IsFormatSupported = IsFormatSupported;    PA_ENSURE( BuildDeviceList( ossHostApi ) );    PaUtil_InitializeStreamInterface( &ossHostApi->callbackStreamInterface, CloseStream, StartStream,                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,                                      GetStreamTime, GetStreamCpuLoad,                                      PaUtil_DummyRead, PaUtil_DummyWrite,                                      PaUtil_DummyGetReadAvailable,                                      PaUtil_DummyGetWriteAvailable );    PaUtil_InitializeStreamInterface( &ossHostApi->blockingStreamInterface, CloseStream, StartStream,                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,                                      GetStreamTime, PaUtil_DummyGetCpuLoad,                                      ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );    mainThread_ = pthread_self();    return result;error:    if( ossHostApi )    {        if( ossHostApi->allocations )        {            PaUtil_FreeAllAllocations( ossHostApi->allocations );            PaUtil_DestroyAllocationGroup( ossHostApi->allocations );        }                        PaUtil_FreeMemory( ossHostApi );    }    return result;}PaError PaUtil_InitializeDeviceInfo( PaDeviceInfo *deviceInfo, const char *name, PaHostApiIndex hostApiIndex, int maxInputChannels,        int maxOutputChannels, PaTime defaultLowInputLatency, PaTime defaultLowOutputLatency, PaTime defaultHighInputLatency,        PaTime defaultHighOutputLatency, double defaultSampleRate, PaUtilAllocationGroup *allocations  ){    PaError result = paNoError;        deviceInfo->structVersion = 2;    if( allocations )    {        size_t len = strlen( name ) + 1;        PA_UNLESS( deviceInfo->name = PaUtil_GroupAllocateMemory( allocations, len ), paInsufficientMemory );        strncpy( (char *)deviceInfo->name, name, len );    }    else        deviceInfo->name = name;    deviceInfo->hostApi = hostApiIndex;    deviceInfo->maxInputChannels = maxInputChannels;    deviceInfo->maxOutputChannels = maxOutputChannels;    deviceInfo->defaultLowInputLatency = defaultLowInputLatency;    deviceInfo->defaultLowOutputLatency = defaultLowOutputLatency;    deviceInfo->defaultHighInputLatency = defaultHighInputLatency;    deviceInfo->defaultHighOutputLatency = defaultHighOutputLatency;    deviceInfo->defaultSampleRate = defaultSampleRate;error:    return result;}static PaError QueryDirection( const char *deviceName, StreamMode mode, double *defaultSampleRate, int *maxChannelCount,        double *defaultLowLatency, double *defaultHighLatency ){    PaError result = paNoError;    int numChannels, maxNumChannels;    int busy = 0;    int devHandle = -1;    int sr;    *maxChannelCount = 0;  /* Default value in case this fails */    if ( (devHandle = open( deviceName, (mode == StreamMode_In ? O_RDONLY : O_WRONLY) | O_NONBLOCK ))  < 0 )    {        if( errno == EBUSY || errno == EAGAIN )        {            PA_DEBUG(( "%s: Device %s busy\n", __FUNCTION__, deviceName ));        }        else        {            PA_DEBUG(( "%s: Can't access device: %s\n", __FUNCTION__, strerror( errno ) ));        }        return paDeviceUnavailable;    }    /* Negotiate for the maximum number of channels for this device. PLB20010927     * Consider up to 16 as the upper number of channels.     * Variable maxNumChannels should contain the actual upper limit after the call.     * Thanks to John Lazzaro and Heiko Purnhagen for suggestions.     */    maxNumChannels = 0;    for( numChannels = 1; numChannels <= 16; numChannels++ )    {        int temp = numChannels;        if( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &temp ) < 0 )        {            busy = EAGAIN == errno || EBUSY == errno;            /* ioctl() failed so bail out if we already have stereo */            if( maxNumChannels >= 2 )                break;        }        else        {            /* ioctl() worked but bail out if it does not support numChannels.             * We don't want to leave gaps in the numChannels supported.             */            if( (numChannels > 2) && (temp != numChannels) )                break;            if( temp > maxNumChannels )                maxNumChannels = temp; /* Save maximum. */        }    }    /* A: We're able to open a device for capture if it's busy playing back and vice versa,     * but we can't configure anything */    if( 0 == maxNumChannels && busy )    {        result = paDeviceUnavailable;        goto error;    }    /* The above negotiation may fail for an old driver so try this older technique. */    if( maxNumChannels < 1 )

⌨️ 快捷键说明

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