📄 pthread-pa_sgi.c
字号:
/*
* PortAudio Portable Real-Time Audio Library
* Latest Version at: http://www.portaudio.com
* SGI IRIX implementation by Pieter Suurmond, september 22, 2001 (#0.18).
*
* Copyright (c) 1999-2001 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.
*/
/*
Modfication History:
8/12/2001 - Pieter Suurmond - took the v15 pa_linux_oss.c file and started to adapt for IRIX 6.2.
8/17/2001 - alpha release with IRIX sproc()-method, may sometimes let IRIX6.2 crash at closing audiostream.
9/22/2001 - #0.18 pthread starts to work a bit:
BUT UNDER IRIX6.2, I DON'T GET IT TO WORK REALLY CORRECTLY,
this POSIX-attempt,
DON'T USE THIS FILE FOR RELIABLE OPERATION, IT IS HERE JUST
FOR DOCUMENTATION/ARCHIVE... OR FOR ANYONE WHO WANTS TO FIX......
TODO:
- Test under IRIX 6.5.
- 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)
- Not sure whether CPU UTILIZATION MEASUREMENT (from OSS/linux) really works. Changed nothing yet,
seems ok, but I've not yet tested it thoroughly. (maybe utilization-code may be made _unix_common_ then?)
- The minimal number of buffers setting... I do not yet fully understand it.. I now just take *4.
REFERENCES:
- IRIX 6.2 man pages regarding SGI AL library.
- IRIS Digital MediaProgramming Guide (online books as well as 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" /* Portaudio headers. */
#include "../pa_common/pa_host.h"
#include "../pa_common/pa_trace.h"
/*
#include <malloc.h>
#include <memory.h>
#include <sys/prctl.h> Not needed
#include <sys/types.h>
#include <sys/schedctl.h>
#include <signal.h>
#include <sys/ioctl.h> Needed?
#include <sys/time.h>
#include <sched.h> sched_param struct and related functions
used in setting thread priorities.
#include <limits.h> Some POSIX constants such as _POSIX_THREAD_THREADS_MAX
*/
#include <pthread.h> /* Pthreads are supported by IRIX 6.2 after */
/* patches 1361, 1367, and 1429 are applied. */
#include <fcntl.h> /* fcntl.h needed for "O_RDONLY". */
#include <unistd.h> /* For usleep() and constants used when calling sysconf() */
/* to query POSIX limits (see the sysconf(3) ref. page. */
#include <dmedia/audio.h> /* SGI-specific audio library. */
/*--------------------------------------------*/
#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) /* Was 32 in OSS (20 for AL but "in"/"out" is concat. */
#define MAX_SAMPLE_RATES (8) /* Known from SGI AL there are 7 (was 10 in OSS v15). */
typedef struct internalPortAudioDevice /* IRIX specific device info: */
{
PaDeviceID /* NEW: */ pad_DeviceID; /* THIS "ID" IS NEW HERE (Pieter)! */
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: */
/* int structVersion; */
/* const char* name; */
/* int maxInputChannels, maxOutputChannels; */
/* int numSampleRates; Num rates, or -1 if range supprtd. */
/* const double* sampleRates; Array of supported sample rates, */
/* PaSampleFormat nativeSampleFormats; or {min,max} if range supported. */
struct internalPortAudioDevice* pad_Next; /* Singly linked list, (NULL=end). */
} internalPortAudioDevice;
typedef struct PaHostSoundControl /* Structure to contain all SGI IRIX specific data. */
{
ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */
pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */
pthread_t pahsc_ThreadPID;
short *pahsc_NativeInputBuffer, /* Allocated here, in this file, if necessary. */
*pahsc_NativeOutputBuffer;
unsigned int pahsc_BytesPerInputBuffer, /* Native buffer sizes in bytes, really needed here */
pahsc_BytesPerOutputBuffer; /* to free FAST memory, if buffs were alloctd FAST. */
unsigned int pahsc_SamplesPerInputBuffer, /* These amounts are needed again and again in the */
pahsc_SamplesPerOutputBuffer; /* audio-thread (don't need to be kept globally). */
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!? */
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 )
{
struct itimerval itimer;
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, ¤tTime ) == 0 )
{
if (past->past_IfLastExitValid)
{
insideCount = SubtractTime_AminusB( &pahsc->pahsc_EntryTime, ¤tTime );
pahsc->pahsc_InsideCountSum += insideCount;
totalCount = SubtractTime_AminusB( &pahsc->pahsc_LastExitTime, ¤tTime );
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:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -