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

📄 pa_unix_oss.c

📁 Audacity是一款用於錄音和編輯聲音的、免費的開放源碼軟體。它可以執行於Mac OS X、Microsoft Windows、GNU/Linux和其它作業系統
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * $Id: pa_unix_oss.c,v 1.2 2004/04/22 04:19:51 mbrubeck Exp $ * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * OSS implementation by: *   Douglas Repetto *   Phil Burk *   Dominic Mazzoni * * 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 <stdio.h>#include <string.h>#include <math.h>#include <sys/ioctl.h>#include <fcntl.h>#include <unistd.h>#include <pthread.h>#ifdef __linux__# include <linux/soundcard.h># define DEVICE_NAME_BASE            "/dev/dsp"#else# include <machine/soundcard.h> /* JH20010905 */# define DEVICE_NAME_BASE            "/dev/audio"#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"/* TODO: add error text handling#define PA_UNIX_OSS_ERROR( errorCode, errorText ) \    PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText )*/#define PRINT(x)   { printf x; fflush(stdout); }#define DBUG(x)    /* PRINT(x) *//* PaOSSHostApiRepresentation - host api datastructure specific to this implementation */typedef struct{    PaUtilHostApiRepresentation inheritedHostApiRep;    PaUtilStreamInterface callbackStreamInterface;    PaUtilStreamInterface blockingStreamInterface;    PaUtilAllocationGroup *allocations;    PaHostApiIndex hostApiIndex;}PaOSSHostApiRepresentation;typedef struct PaOSS_DeviceList {    PaDeviceInfo *deviceInfo;    struct PaOSS_DeviceList *next;}PaOSS_DeviceList;/* prototypes for functions declared in this file */PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex );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, void *buffer, unsigned long frames );static signed long GetStreamReadAvailable( PaStream* stream );static signed long GetStreamWriteAvailable( PaStream* stream );static PaError BuildDeviceList( PaOSSHostApiRepresentation *hostApi );PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ){    PaError result = paNoError;    PaOSSHostApiRepresentation *ossHostApi;    DBUG(("PaOSS_Initialize\n"));    ossHostApi = (PaOSSHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaOSSHostApiRepresentation) );    if( !ossHostApi )    {        result = paInsufficientMemory;        goto error;    }    ossHostApi->allocations = PaUtil_CreateAllocationGroup();    if( !ossHostApi->allocations )    {        result = paInsufficientMemory;        goto error;    }    *hostApi = &ossHostApi->inheritedHostApiRep;    (*hostApi)->info.structVersion = 1;    (*hostApi)->info.type = paOSS;    (*hostApi)->info.name = "OSS";    ossHostApi->hostApiIndex = hostApiIndex;    BuildDeviceList( ossHostApi );    (*hostApi)->Terminate = Terminate;    (*hostApi)->OpenStream = OpenStream;    (*hostApi)->IsFormatSupported = IsFormatSupported;    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 );    return result;error:    if( ossHostApi )    {        if( ossHostApi->allocations )        {            PaUtil_FreeAllAllocations( ossHostApi->allocations );            PaUtil_DestroyAllocationGroup( ossHostApi->allocations );        }                        PaUtil_FreeMemory( ossHostApi );    }    return result;}#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;}#endifPaError PaOSS_SetFormat(const char *callingFunctionName, int deviceHandle,                        char *deviceName, int inputChannelCount, int outputChannelCount,                        double *sampleRate){    int format;    int rate;    int temp;    /* Attempt to set format to 16-bit */        format = AFMT_S16_NE;    if (ioctl(deviceHandle, SNDCTL_DSP_SETFMT, &format) == -1) {       DBUG(("%s: could not set format: %s\n", callingFunctionName, deviceName ));       return paSampleFormatNotSupported;    }    if (format != AFMT_S16_NE) {       DBUG(("%s: device does not support AFMT_S16_NE: %s\n", callingFunctionName, deviceName ));       return paSampleFormatNotSupported;    }    /* try to set the number of channels */    if (inputChannelCount > 0) {       temp = inputChannelCount;              if( ioctl(deviceHandle, SNDCTL_DSP_CHANNELS, &temp) < 0 ) {          DBUG(("%s: Couldn't set device %s to %d channels\n", callingFunctionName, deviceName, inputChannelCount ));          return paSampleFormatNotSupported;       }    }        if (outputChannelCount > 0) {       temp = outputChannelCount;              if( ioctl(deviceHandle, SNDCTL_DSP_CHANNELS, &temp) < 0 ) {          DBUG(("%s: Couldn't set device %s to %d channels\n", callingFunctionName, deviceName, outputChannelCount ));                    return paSampleFormatNotSupported;       }    }    /* try to set the sample rate */    rate = (int)(*sampleRate);    if (ioctl(deviceHandle, SNDCTL_DSP_SPEED, &rate) == -1)    {        DBUG(("%s: Device %s, couldn't set sample rate to %d\n",              callingFunctionName, deviceName, (int)*sampleRate ));        return paInvalidSampleRate;    }    /* reject if there's no sample rate within 1% of the one requested */    if ((fabs(*sampleRate - rate) / *sampleRate) > 0.01)    {        DBUG(("%s: Device %s, wanted %d, closest sample rate was %d\n",              callingFunctionName, deviceName, (int)*sampleRate, rate ));                         return paInvalidSampleRate;    }    *sampleRate = rate;    return paNoError;}static PaError PaOSS_QueryDevice(char *deviceName, PaDeviceInfo *deviceInfo){    PaError result = paNoError;    int tempDevHandle;    int numChannels, maxNumChannels;    int sampleRate;    int format;    /* 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    */    if ( (tempDevHandle = open(deviceName,O_WRONLY|O_NONBLOCK))  == -1 )    {        DBUG(("PaOSS_QueryDevice: could not open %s\n", deviceName ));        return paDeviceUnavailable;    }    /* Attempt to set format to 16-bit */    format = AFMT_S16_NE;    if (ioctl(tempDevHandle, SNDCTL_DSP_SETFMT, &format) == -1) {       DBUG(("PaOSS_QueryDevice: could not set format: %s\n", deviceName ));       result = paSampleFormatNotSupported;       goto error;    }    if (format != AFMT_S16_NE) {       DBUG(("PaOSS_QueryDevice: device does not support AFMT_S16_NE: %s\n", deviceName ));       result = paSampleFormatNotSupported;       goto error;    }    /* 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;        DBUG(("PaOSS_QueryDevice: use SNDCTL_DSP_CHANNELS, numChannels = %d\n", numChannels ))        if(ioctl(tempDevHandle, SNDCTL_DSP_CHANNELS, &temp) < 0 )        {            /* ioctl() failed so bail out if we already have stereo */            if( numChannels > 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;            DBUG(("PaOSS_QueryDevice: temp = %d\n", temp ))            if( temp > maxNumChannels ) maxNumChannels = temp; /* Save maximum. */        }    }    /* The above negotiation may fail for an old driver so try this older technique. */    if( maxNumChannels < 1 )    {        int stereo = 1;        if(ioctl(tempDevHandle, SNDCTL_DSP_STEREO, &stereo) < 0)        {            maxNumChannels = 1;        }        else        {            maxNumChannels = (stereo) ? 2 : 1;        }        DBUG(("PaOSS_QueryDevice: use SNDCTL_DSP_STEREO, maxNumChannels = %d\n", maxNumChannels ))    }    DBUG(("PaOSS_QueryDevice: maxNumChannels = %d\n", maxNumChannels))    deviceInfo->maxOutputChannels = maxNumChannels;    /* FIXME - for now, assume maxInputChannels = maxOutputChannels.     *    Eventually do separate queries for O_WRONLY and O_RDONLY    */    deviceInfo->maxInputChannels = deviceInfo->maxOutputChannels;    /* 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 */    {        int temp = maxNumChannels;        if( temp > 2 ) temp = 2; /* use most reasonable default value */        ioctl(tempDevHandle, SNDCTL_DSP_CHANNELS, &temp);    }    /* Get supported sample rate closest to 44100 Hz */    sampleRate = 44100;    if (ioctl(tempDevHandle, SNDCTL_DSP_SPEED, &sampleRate) == -1)    {        result = paUnanticipatedHostError;        goto error;    }    deviceInfo->defaultSampleRate = sampleRate;    deviceInfo->structVersion = 2;    /* TODO */    deviceInfo->defaultLowInputLatency = 128.0 / sampleRate;    deviceInfo->defaultLowOutputLatency = 128.0 / sampleRate;    deviceInfo->defaultHighInputLatency = 16384.0 / sampleRate;    deviceInfo->defaultHighOutputLatency = 16384.0 / sampleRate;    result = paNoError;error:    /* We MUST close the handle here or we won't be able to reopen it later!!!  */    close(tempDevHandle);    return result;}static PaError BuildDeviceList( PaOSSHostApiRepresentation *ossApi ){    PaUtilHostApiRepresentation *commonApi = &ossApi->inheritedHostApiRep;    PaOSS_DeviceList *head = NULL, *tail = NULL, *entry;    int i;    int numDevices;    /* Find devices by calling PaOSS_QueryDevice on each       potential device names.  When we find a valid one,       add it to a linked list. */    for(i=0; i<10; i++) {       char deviceName[32];       PaDeviceInfo deviceInfo;       int testResult;       if (i==0)          sprintf(deviceName, "%s", DEVICE_NAME_BASE);       else          sprintf(deviceName, "%s%d", DEVICE_NAME_BASE, i);

⌨️ 快捷键说明

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