📄 pa_sgi.c
字号:
return translateSGIerror();
pad->pad_Info.maxInputChannels = max;
DBUG(("Pa_QueryDevice: maxInputChannels = %d\n", pad->pad_Info.maxInputChannels))
if (ALgetminmax(ALdev, AL_OUTPUT_COUNT, &min, &max))
return translateSGIerror();
pad->pad_Info.maxOutputChannels = max;
DBUG(("Pa_QueryDevice: maxOutputChannels = %d\n", pad->pad_Info.maxOutputChannels))
/*--------------------------------- supported samplerates: ----------------------*/
pad->pad_Info.numSampleRates = 7;
pad->pad_Info.sampleRates = pad->pad_SampleRates;
pad->pad_SampleRates[0] = (double)AL_RATE_8000; /* long -> double. */
pad->pad_SampleRates[1] = (double)AL_RATE_11025;
pad->pad_SampleRates[2] = (double)AL_RATE_16000;
pad->pad_SampleRates[3] = (double)AL_RATE_22050;
pad->pad_SampleRates[4] = (double)AL_RATE_32000;
pad->pad_SampleRates[5] = (double)AL_RATE_44100;
pad->pad_SampleRates[6] = (double)AL_RATE_48000;
if (ALgetminmax(ALdev, AL_INPUT_RATE, &min, &max)) /* Ask INPUT rate-max. */
return translateSGIerror(); /* double -> long. */
if (max != (long)(0.5 + pad->pad_SampleRates[6])) /* FP-compare not recommndd. */
goto weird;
if (ALgetminmax(ALdev, AL_OUTPUT_RATE, &min, &max)) /* Ask OUTPUT rate-max. */
return translateSGIerror();
if (max != (long)(0.5 + pad->pad_SampleRates[6]))
{
weird: ERR_RPT(("Pa_sgiQueryDevice() did not confirm max samplerate (%ld)\n",max));
return paHostError; /* Or make it a warning and just carry on... */
}
/*-------------------------------------------------------------------------------*/
return paNoError;
}
/*--------------------------------------------------------------------------------*/
int Pa_CountDevices() /* Name of this function suggests it only counts and */
{ /* is NOT destructive, it however resets whole PA ! */
int numDevices = 0; /* Let 's not do that here. */
internalPortAudioDevice* currentDevice = sDeviceList; /* COPY GLOBAL VAR. */
#if 0 /* Remains from linux_oss v15: Pa_Initialize(), on */
if (!currentDevice) /* its turn, calls PaHost_Init() via file pa_lib.c. */
Pa_Initialize(); /* Isn't that a bit too 'rude'? Don't be too */
#endif /* friendly to clients that forgot to initialize PA. */
while (currentDevice) /* Slower but more elegant than the sNumDevices-way: */
{
numDevices++;
currentDevice = currentDevice->pad_Next;
}
return numDevices;
}
/*-------------------------------------------------------------------------------*/
static internalPortAudioDevice *Pa_GetInternalDevice(PaDeviceID id)
{
int numDevices = 0;
internalPortAudioDevice *res = (internalPortAudioDevice*)NULL;
internalPortAudioDevice *pad = sDeviceList; /* COPY GLOBAL VAR. */
while (pad) /* pad may be NULL, that's ok, return 0. */
{ /* (Added ->pad_DeviceID field to the pad-struct, Pieter, 2001.) */
if (pad->pad_DeviceID == id) /* This the device we were looking for? */
res = pad; /* But keep on(!) counting so we don't */
numDevices++; /* have to call Pa_CountDevices() later. */
pad = pad->pad_Next; /* Advance to the next device or NULL. */
} /* No assumptions about order of ID's in */
if (!res) /* the list. */
ERR_RPT(("Pa_GetInternalDevice() could not find specified ID (%d).\n",id));
if ((id < 0) || (id >= numDevices))
{
ERR_RPT(("Pa_GetInternalDevice() supplied with an illegal ID (%d).\n",id));
#if 1 /* Be strict, even when found, */
res = (internalPortAudioDevice*)NULL; /* do not accept illegal ID's. */
#endif
}
return res;
}
/*----------------------------------------------------------------------*/
const PaDeviceInfo* Pa_GetDeviceInfo(PaDeviceID id)
{
PaDeviceInfo* res = (PaDeviceInfo*)NULL;
internalPortAudioDevice* pad = Pa_GetInternalDevice(id); /* Call. */
if (pad)
res = &pad->pad_Info; /* Not finding the specified ID is not */
if (!res) /* the same as &pad->pad_Info == NULL. */
ERR_RPT(("Pa_GetDeviceInfo() could not find it (ID=%d).\n", id));
return res; /* So (maybe) a second/third ERR_RPT(). */
}
/*------------------------------------------------*/
PaDeviceID Pa_GetDefaultInputDeviceID(void)
{
return 0; /* 0 is the default device ID. */
}
/*------------------------------------------------*/
PaDeviceID Pa_GetDefaultOutputDeviceID(void)
{
return 0;
}
/*-------------------------------------------------------------------------------------------------*/
/* Build linked a list with all the available audio devices on this SGI machine (only 1 for now). */
PaError PaHost_Init(void) /* Called by Pa_Initialize() from pa_lib.c. */
{
internalPortAudioDevice* pad;
PaError r = paNoError;
int audioLibFileID; /* To test for the presence of audio. */
if (sDeviceList) /* Allow re-init, only warn, no error. */
{
ERR_RPT(("Warning: PaHost_Init() did not really re-init PA.\n"));
return r;
}
/*------------- ADD THE SGI DEFAULT DEVICE TO THE LIST: ---------------------------------------*/
audioLibFileID = open("/dev/hdsp/hdsp0master", O_RDONLY); /* Try to open Indigo style audio */
if (audioLibFileID < 0) /* IO port. On failure, machine */
{ /* has no audio ability. */
ERR_RPT(("PaHost_Init(): This machine has no (Indigo-style) audio abilities.\n"));
return paHostError;
}
close(audioLibFileID); /* Allocate fast mem to hold device info. */
pad = PaHost_AllocateFastMemory(sizeof(internalPortAudioDevice));
if (pad == NULL)
return paInsufficientMemory;
memset(pad, 0, sizeof(internalPortAudioDevice)); /* "pad->pad_Next = NULL" is more elegant. */
r = Pa_sgiQueryDevice(AL_DEFAULT_DEVICE, /* Set AL device num (AL_DEFAULT_DEVICE). */
Pa_GetDefaultOutputDeviceID(),/* Set PA device num (or InputDeviceID()). */
"AL default", /* A suitable name. */
pad); /* Write args and queried info into pad. */
if (r != paNoError)
{
ERR_RPT(("Pa_QueryDevice for '%s' returned: %d\n", pad->pad_DeviceName, r));
PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); /* sDeviceList still NULL ! */
}
else
sDeviceList = pad; /* First element in linked list. pad->pad_Next already NULL. */
/*------------- QUERY AND ADD MORE POSSIBLE SGI DEVICES TO THE LINKED LIST: -------------------*/
/*---------------------------------------------------------------------------------------------*/
return r;
}
/*--------------------------------------------------------------------------------------------*/
#define MIN(a,b) ((a)<(b)?(a):(b)) /* MIN()-function is used below. */
#define kPollSEMA 0 /* To index the pollfd-array, reads nicer than just */
#define kPollOUT 1 /* numbers. */
#define kPollIN 2
void Pa_SgiAudioProcess(void *v) /* This function is sproc-ed by PaHost_StartEngine() */
{ /* as a separate thread. (Argument must be void*). */
short evtLoop; /* Reset by parent indirectly, or at local errors. */
PaError result;
struct pollfd PollFD[3]; /* To catch kPollSEMA-, kPollOUT- and kPollIN-events. */
internalPortAudioStream *past = (internalPortAudioStream*)v; /* Copy void-ptr-argument. */
PaHostSoundControl *pahsc;
short n, inputEvent, outputEvent, ioEvent, semaEvent = 0;
short *inBuffer, *outBuffer; /* Only 16 bit for now, may change... */
unsigned int samplesPerInputUserBuffer, samplesPerOutputUserBuffer;
DBUG(("Entering sproc-thread.\n"));
if (!past)
{
sPaHostError = paInternalError; /* Or paBadStreamPtr ? */
ERR_RPT(("argument NULL!\n"));
goto noPast;
}
pahsc = (PaHostSoundControl*)past->past_DeviceData;
if (!pahsc)
{
sPaHostError = paInternalError; /* The only way is to signal error to shared area?! */
ERR_RPT(("past_DeviceData NULL!\n"));
goto noPahsc; /* Sproc-ed threads MAY NOT RETURN paInternalError. */
}
/*----------------------------- open AL-ports here, after sproc(): -----------------------*/
if (past->past_NumInputChannels > 0) /* Open input port. */
{
pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", pahsc->pahsc_ALconfigIN);
if (!pahsc->pahsc_ALportIN)
{
ERR_RPT(("Failed to open AL input port.\n"));
sPaHostError = paInternalError;
goto skip;
}
DBUG(("Opened %d input channel(s).\n", past->past_NumInputChannels));
samplesPerInputUserBuffer = pahsc->pahsc_SamplesPerInputHostBuffer /
pahsc->pahsc_UserBuffersPerHostBuffer;
}
else
samplesPerInputUserBuffer = 0; /* Added 2003. */
if (past->past_NumOutputChannels > 0) /* Open output port. */
{
pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", pahsc->pahsc_ALconfigOUT);
if (!pahsc->pahsc_ALportOUT)
{
ERR_RPT(("Failed to open AL output port.\n"));
sPaHostError = paInternalError; /* Assume pahsc_ALconfigs are the */
goto skip; /* same for IN and OUT in case */
} /* both ports are opened (bidir). */
DBUG(("Opened %d output channel(s).\n", past->past_NumOutputChannels));
samplesPerOutputUserBuffer = pahsc->pahsc_SamplesPerOutputHostBuffer /
pahsc->pahsc_UserBuffersPerHostBuffer;
DBUG(("samplesPerOutputUserBuffer = %d\n", samplesPerOutputUserBuffer));
}
else
samplesPerOutputUserBuffer = 0; /* Added 2003. */
/*-----------------------------------------------------------------------*/
past->past_IsActive = 1; /* Wasn't this already done by the calling parent?! */
PollFD[kPollIN].fd = ALgetfd(pahsc->pahsc_ALportIN); /* ALgetfd returns -1 on failures */
PollFD[kPollIN].events = POLLIN; /* such as ALport not there. */
PollFD[kPollOUT].fd = ALgetfd(pahsc->pahsc_ALportOUT);
PollFD[kPollOUT].events = POLLOUT; /* .events = POLLOUT is OK. */
schedctl(NDPRI, NDPHIMIN); /* Sets non-degrading priority for this process. */
PollFD[kPollSEMA].fd = usopenpollsema(SendSema, 0777); /* To communicate with parent. */
PollFD[kPollSEMA].events = POLLIN; /* .events = POLLIN is OK. */
uspsema(SendSema); /* Blocks until ... MUST be here, this uspsema(). */
evtLoop = ((past->past_StopNow | past->past_StopSoon) == 0);
while (evtLoop)
{
/*----------------------------- SET FILLPOINTS AND WAIT UNTIL SOMETHING HAPPENS: ---------*/
if (pahsc->pahsc_InputHostBuffer) /* Then pahsc_ALportIN should also be there. */
{
/* For input port, fill point is number of locations in the sample queue that must be */
/* filled in order to trigger a return from select(). (or poll()) */
/* Notice IRIX docs mention number of samples as argument, not number of sampleframes.*/
if (ALsetfillpoint(pahsc->pahsc_ALportIN, pahsc->pahsc_SamplesPerInputHostBuffer))
{ /* Multiple amount as transferred per time. */
ERR_RPT(("ALsetfillpoint() for ALportIN failed.\n"));
sPaHostError = paInternalError; /* (Using exit(-1) would be a bit rude.) */
goto skip;
}
}
/* 'else' added march 2003: set only one of both fillpoints: input or output. When */
/* setting both fillpoints (as in earlier version) clicks occur at full duplex-mode. */
else if (pahsc->pahsc_OutputHostBuffer) /* Then pahsc_ALportOUT should also be there. */
{
/* For output port, fill point is number of locations that must be free in order to */
/* wake up from select(). (or poll()) */
if (ALsetfillpoint(pahsc->pahsc_ALportOUT, pahsc->pahsc_SamplesPerOutputHostBuffer))
{
ERR_RPT(("ALsetfillpoint() for ALportOUT failed.\n"));
sPaHostError = paInternalError;
goto skip;
}
} /* poll() with timeout=-1 makes it block until a requested */
poll(PollFD, 3, -1); /* event occurs or until call is interrupted. If fd-value in */
/* array <0, events is ignored and revents is set to 0. */
/*---------------------------- MESSAGE-EVENT FROM PARENT THREAD: -------------------------*/
semaEvent = PollFD[kPollSEMA].revents & POLLIN;
if (semaEvent)
{
if (past->past_StopSoon)
evtLoop = 0;
if (past->past_StopNow)
goto skip;
}
/*------------------------------------- FILLED-EVENT FROM INPUT BUFFER: --------------------------*/
inputEvent = PollFD[kPollIN].revents & POLLIN;
if (inputEvent) /* Don't need to check (pahsc->pahsc_InputHostBuffer): */
{ /* if buffer was not there, ALport not there, no events! */
if (ALreadsamps(pahsc->pahsc_ALportIN, (void*)pahsc->pahsc_InputHostBuffer,
pahsc->pahsc_SamplesPerInputHostBuffer))
{ /* Here again: number of samples instead of number of frames. */
ERR_RPT(("ALreadsamps() failed.\n"));
sPaHostError = paInternalError;
goto skip;
}
}
outputEvent = PollFD[kPollOUT].revents & POLLOUT;
ioEvent = (inputEvent | outputEvent); /* Binary or is ok. */
/*------------------------------------- USER-CALLBACK-ROUTINE: -----------------------------------*/
if (ioEvent) /* Always true? Or can some other system-event awaken the */
{ /* poll? Sure it wasn't just a "sema"- (i.e. user)-event? */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -