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

📄 pa_sgi.c

📁 ppciaxclient softphone
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
 * $Id: pa_sgi.c,v 1.2.4.2 2003/03/13 00:56:47 pieter Exp $
 * PortAudio Portable Real-Time Audio Library. Copyright (c) 1999-2001 Phil Burk.
 * Latest Version at: http://www.portaudio.com
 *
 * Silicon Graphics (SGI) IRIX implementation by Pieter Suurmond.
 * This implementation uses sproc()-spawning, not the POSIX-threads.
 *
 * 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.
 *
MODIFICATIONS:
  8/12/2001 - Pieter Suurmond - took the v15 pa_linux_oss.c file and started to adapt for IRIX 6.2.
  8/17/2001 - v15, first unstable alpha release for IRIX, sent to Phil & Ross. 
  9/23/2001 - Many fixes and changes: POLLIN for input, not POLLOUT!
  7/04/2002 - Implemented multiple user buffers per host buffer to allow clients that 
              request smaller buffersizes.
  3/13/2003 - Fixed clicks in full-duplex (wire) mode. Fixed some uninitialised vars, got rid of
              all GCC-warnings (-Wall). Tested with MIPS compiler and GCC 3.0.4. on IRIX 6.5 (AL v7).
TODO:
  - Dynamically switch to 32 bit float as native format when appropriate (let SGI do the conversion), 
    and maybe also the other natively supported formats? (might increase performance)
  - Implement fancy callback block adapter as described in the PDF by Stephane Letz in the ASIO dir.

REFERENCES:
  - IRIX 6.2 man pages regarding SGI AL library.
  - IRIS Digital Media Programming Guide (online books and man-pages come
    with IRIX 6.2 and may not be publically available on the internet).
*/

#include <stdio.h>              /* Standard libraries. */
#include <stdlib.h>

#include "../pa_common/portaudio.h" /* (Makefile fails to find in subdirs, -I doesn't work?). */
#include "../pa_common/pa_host.h"
#include "../pa_common/pa_trace.h"

#include <errno.h>              /* Needed for int oserror(void);. */
#include <sys/time.h>
#include <sys/types.h>
#include <sys/prctl.h>
#include <sys/schedctl.h>       /* For schedctl(NDPRI, NDPHIMIN). */
#include <fcntl.h>              /* fcntl.h needed.                */
#include <unistd.h>             /* For streams, ioctl(), etc.     */
#include <ulocks.h>
#include <poll.h>
#include <dmedia/audio.h>      /* System specific (IRIX 6.2-6.5). */

/*----------------- MACROS --------------------*/
#define PRINT(x)    { printf x; fflush(stdout); }
#define ERR_RPT(x)  PRINT(x)
#define DBUG(x)     /* PRINT(x) */
#define DBUGX(x)    /* PRINT(x) */

#define MAX_CHARS_DEVNAME           (16)
#define MAX_SAMPLE_RATES            (8)         /* Known from SGI AL there are 7.                      */
                                                /* Constants used in 'Pa_GetMinNumBuffers()' below:    */
#define MIN_LATENCY_MSEC            (200)       /* Used if 'getenv("PA_MIN_LATENCY_MSEC")' fails.      */
#define PA_LATENCY_ENV_NAME         ("PA_MIN_LATENCY_MSEC")        /* Same names as in file pa_unix.h. */

/*------------------------------- IRIX AL specific device info: --------------------------------------*/
typedef struct                    internalPortAudioDevice
{
  PaDeviceID                      pad_DeviceID;                         /* THIS "ID" IS NEW HERE.         */
  long                            pad_ALdevice;                         /* SGI-number!                    */
  double                          pad_SampleRates[MAX_SAMPLE_RATES];    /* For pointing to from pad_Info  */
  char                            pad_DeviceName[MAX_CHARS_DEVNAME+1];  /* +1 for \0, one more than OSS.  */
  PaDeviceInfo                    pad_Info;                             /* pad_Info (v15) contains:       */
  struct internalPortAudioDevice* pad_Next;                             /* Singly linked list (NULL=end). */
} internalPortAudioDevice;

/*----------------- Structure containing all SGI IRIX specific data: ---------------------------------------*/
typedef struct      PaHostSoundControl
{
  ALconfig          pahsc_ALconfigIN,                   /* IRIX-audio-library-datatype. Configuration       */
                    pahsc_ALconfigOUT;                  /* stucts separate for input and output ports.      */
  ALport            pahsc_ALportIN,                     /* IRIX-audio-library-datatype. ALports can only be */
                    pahsc_ALportOUT;                    /* unidirectional, so we sometimes need 2 of them.  */
  int               pahsc_threadPID;                    /* Sproc()-result, written by PaHost_StartEngine(). */

  unsigned int      pahsc_UserBuffersPerHostBuffer,
                    pahsc_SamplesPerInputHostBuffer,    /* Channels per frame are accounted for. */
                    pahsc_SamplesPerOutputHostBuffer,
                    pahsc_BytesPerInputHostBuffer,      /* Size per sample are accounted for. */
                    pahsc_BytesPerOutputHostBuffer;
  short            *pahsc_InputHostBuffer,              /* Allocated here, in this file, if necessary.      */
                   *pahsc_OutputHostBuffer;

  struct itimerval  pahsc_EntryTime,                    /* For measuring CPU utilization (same as linux).   */
                    pahsc_LastExitTime;
  long              pahsc_InsideCountSum,
                    pahsc_TotalCountSum;
} PaHostSoundControl;

/*-------------------------------------------------------- Shared Data -------------------------------*/
static internalPortAudioDevice* sDeviceList = NULL;     /* FIXME - put Mutex around this shared data. */
static int                      sPaHostError = 0;       /* Maybe more than one process writing errs!? */
usema_t                         *SendSema,              /* These variables are shared between the     */
                                *RcvSema;               /* audio handling process and main process.   */
/*--------------------------*/
long Pa_GetHostError(void)
{
    return (long)sPaHostError;
}

/*----------------------------- BEGIN CPU UTILIZATION MEASUREMENT -----------------*/
/*                              (copied from source pa_linux_oss/pa_linux_oss.c)   */
static void Pa_StartUsageCalculation( internalPortAudioStream   *past )
{    
    PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
    if( pahsc == NULL ) return;
    /* Query system timer for usage analysis and to prevent overuse of CPU. */
    getitimer( ITIMER_REAL, &pahsc->pahsc_EntryTime );
}

static long SubtractTime_AminusB( struct itimerval *timeA, struct itimerval *timeB )
{
    long secs = timeA->it_value.tv_sec - timeB->it_value.tv_sec;
    long usecs = secs * 1000000;
    usecs += (timeA->it_value.tv_usec - timeB->it_value.tv_usec);
    return usecs;
}

static void Pa_EndUsageCalculation( internalPortAudioStream   *past )
{
    struct itimerval currentTime;
    long  insideCount;
    long  totalCount;       /* Measure CPU utilization during this callback. */

#define LOWPASS_COEFFICIENT_0   (0.95)
#define LOWPASS_COEFFICIENT_1   (0.99999 - LOWPASS_COEFFICIENT_0)

    PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
    if (pahsc == NULL)
        return;
    if (getitimer( ITIMER_REAL, &currentTime ) == 0 )
        {
        if (past->past_IfLastExitValid)
            {
            insideCount = SubtractTime_AminusB( &pahsc->pahsc_EntryTime, &currentTime );
            pahsc->pahsc_InsideCountSum += insideCount;
            totalCount =  SubtractTime_AminusB( &pahsc->pahsc_LastExitTime, &currentTime );
            pahsc->pahsc_TotalCountSum += totalCount;
        /*  DBUG(("insideCount = %d, totalCount = %d\n", insideCount, totalCount )); */
            /* Low pass filter the result because sometimes we get called several times in a row. */
            /* That can cause the TotalCount to be very low which can cause the usage to appear   */
            /* unnaturally high. So we must filter numerator and denominator separately!!!        */
            if (pahsc->pahsc_InsideCountSum > 0)
                {
                past->past_AverageInsideCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) +
                                                 (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_InsideCountSum));
                past->past_AverageTotalCount  = ((LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) +
                                                 (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_TotalCountSum));
                past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount;
                pahsc->pahsc_InsideCountSum = 0;
                pahsc->pahsc_TotalCountSum = 0;
                }
            }
        past->past_IfLastExitValid = 1;
        }
    pahsc->pahsc_LastExitTime.it_value.tv_sec = 100;
    pahsc->pahsc_LastExitTime.it_value.tv_usec = 0;
    setitimer( ITIMER_REAL, &pahsc->pahsc_LastExitTime, NULL );
    past->past_IfLastExitValid = 1;
}   /*----------- END OF CPU UTILIZATION CODE (from pa_linux_oss/pa_linux_oss.c v15)--------------------*/


/*--------------------------------------------------------------------------------------*/
PaError translateSGIerror(void) /* Calls oserror(), may be used after an SGI AL-library */
{                               /* call to report via ERR_RPT(), yields a PaError-num.  */
    const char* a = "SGI AL ";  /* (Not absolutely sure errno came from THIS thread!    */
    switch(oserror())           /* Read IRIX man-pages about the _SGI_MP_SOURCE macro.) */
        {
        case AL_BAD_OUT_OF_MEM:
             ERR_RPT(("%sout of memory.\n", a)); 
             return paInsufficientMemory;                   /* Known PaError.   */
        case AL_BAD_CONFIG:
             ERR_RPT(("%sconfiguration invalid or NULL.\n", a));
             return paHostError;                            /* Generic PaError. */
        case AL_BAD_CHANNELS:
             ERR_RPT(("%schannels not 1,2 or 4.\n", a));
             return paHostError;                            /* Generic PaError. */
        case AL_BAD_NO_PORTS:
             ERR_RPT(("%sout of audio ports.\n", a));
             return paHostError;                            /* Generic PaError. */
        case AL_BAD_DEVICE:
             ERR_RPT(("%swrong device number.\n", a));
             return paHostError;                            /* Generic PaError. */
        case AL_BAD_DEVICE_ACCESS:
             ERR_RPT(("%swrong device access.\n", a));
             return paHostError;                            /* Generic PaError. */
        case AL_BAD_DIRECTION:
             ERR_RPT(("%sinvalid direction.\n", a));
             return paHostError;                            /* Generic PaError. */
        case AL_BAD_SAMPFMT:
             ERR_RPT(("%sdoesn't accept sampleformat.\n", a));
             return paHostError;                            /* Generic PaError. */
        case AL_BAD_FLOATMAX:
             ERR_RPT(("%smax float value is zero.\n", a));
             return paHostError;                            /* Generic PaError. */
        case AL_BAD_WIDTH:
             ERR_RPT(("%sunsupported samplewidth.\n", a));
             return paHostError;                            /* Generic PaError. */
        case AL_BAD_QSIZE:
             ERR_RPT(("%sinvalid queue size.\n", a));
             return paHostError;                            /* Generic PaError. */
        case AL_BAD_PVBUFFER:
             ERR_RPT(("%sPVbuffer null.\n", a));
             return paHostError;                            /* Generic PaError. */
        case AL_BAD_BUFFERLENGTH_NEG:
             ERR_RPT(("%snegative bufferlength.\n", a));
             return paHostError;                            /* Generic PaError. */
        case AL_BAD_BUFFERLENGTH_ODD:
             ERR_RPT(("%sodd bufferlength.\n", a));
             return paHostError;                            /* Generic PaError. */
        case AL_BAD_PARAM:
             ERR_RPT(("%sparameter not valid for device.\n", a));
             return paHostError;                            /* Generic PaError. */
        default:
             ERR_RPT(("%sunknown error.\n", a));
             return paHostError;                            /* Generic PaError. */
        }
}

/*------------------------------------------------------------------------------------------*/
/* Tries to set various rates and formats and fill in the device info structure.            */
static PaError Pa_sgiQueryDevice(long                     ALdev,  /* (AL_DEFAULT_DEVICE)    */
                                 PaDeviceID               id,     /* (DefaultI|ODeviceID()) */
                                 char*                    name,   /* (for example "SGI AL") */
                                 internalPortAudioDevice* pad)    /* Result written to pad. */
{
    long    min, max;                           /* To catch hardware characteristics.       */
    ALseterrorhandler(0);                       /* 0 = turn off the default error handler.  */
    /*--------------------------------------------------------------------------------------*/
    pad->pad_ALdevice = ALdev;                              /* Set the AL device number.    */
    pad->pad_DeviceID = id;                                 /* Set the PA device number.    */
    if (strlen(name) > MAX_CHARS_DEVNAME)                   /* MAX_CHARS defined above.     */
        {
        ERR_RPT(("Pa_QueryDevice(): name too long (%s).\n", name));
        return paHostError;
        }
    strcpy(pad->pad_DeviceName, name);                      /* Write name-string.           */
    pad->pad_Info.name = pad->pad_DeviceName;               /* Set pointer,..hmmm.          */
    /*--------------------------------- natively supported sample formats: -----------------*/
    pad->pad_Info.nativeSampleFormats = paInt16; /* Later also include paFloat32 | ..| etc. */
                                                 /* Then also choose other CallConvertXX()! */
    /*--------------------------------- number of available i/o channels: ------------------*/
    if (ALgetminmax(ALdev, AL_INPUT_COUNT, &min, &max))

⌨️ 快捷键说明

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