📄 pa_sgi.c
字号:
arena = usinit(tmpnam(0)); /* motifexample.c, function */
SendSema = usnewpollsema(arena, 0); /* InitializeAudioProcess().) */
RcvSema = usnewsema(arena, 1); /* 1= common mutual exclusion semaphore, where 1 and only 1 process
will be permitted through a semaphore at a time. Values > 1
imply that up to val resources may be simultaneously used, but requests
for more than val resources cause the calling process to block until a
resource comes free (by a process holding a resource performing a
usvsema(). IS THIS usnewsema() TOO PLATFORM SPECIFIC? */
prctl(PR_SETEXITSIG, 0); /* No not (void*)9, but 0, which doesn't kill the parent! */
/* PR_SETEXITSIG controls whether all members of a share group will be
signaled if any one of them leaves the share group (either via exit()
or exec()). If 2nd arg, interpreted as an int is 0, then normal IRIX
process termination rules apply, namely that the parent is sent a
SIGCLD upon death of child, but no indication of death of parent is
given. If the second argument is a valid signal number then if any
member of a share group leaves the share group, a signal is
sent to ALL surviving members of the share group. */
/* SPAWN AUDIO-CHILD: */
pahsc->pahsc_threadPID = sproc(Pa_SgiAudioProcess, /* Returns process ID of */
PR_SALL, /* new process, or -1. */
(void*)past); /* Pass past as optional */ /* IS THIS SAFE, will past never */
if (pahsc->pahsc_threadPID == -1) /* third void-ptr-arg. */ /* be moved around in memory???? */
{
ERR_RPT(("PaHost_StartEngine() failed to spawn audio-thread.\n"));
sPaHostError = oserror(); /* Pass native error-number to shared area. */
return paHostError; /* But return the generic error-number. */
}
return paNoError; /* Hmmm, errno may come from other threads in same group! */
} /* ("man sproc" in IRIX6.2 to read about _SGI_MP_SOURCE.) */
/*------------------------------------------------------------------------------*/
PaError PaHost_StopEngine(internalPortAudioStream *past, int abort)
{
PaError result = paNoError;
PaHostSoundControl *pahsc;
DBUG(("PaHost_StopEngine() called.\n"));
if (!past)
return paBadStreamPtr;
pahsc = (PaHostSoundControl*)past->past_DeviceData;
/* Prevent from doing this twice!! */
if ((!pahsc) || /* Some tests call this CLOSE twice!! */
(!past->past_IsActive) ||
past->past_StopSoon || past->past_StopNow)
return result; /* paNoError (already stopped, no err?). */
past->past_StopSoon = 1; /* Tell background thread to stop generating */
if (abort) /* more and to let current data play out. If */
past->past_StopNow = 1; /* aborting, tell backgrnd thread to stop NOW! */
/*---- USE SEMAPHORE LOCK TO COMMUNICATE: -----*/
usvsema(SendSema); /* Increments count associated with SendSema. */
/* Wait for the response. */
uspsema(RcvSema); /* Decrements count of previously allocated */
/* semaphore specified by RcvSema. */
while (past->past_IsActive) /* REALLY WAIT. */
{
/* DBUG(("wait 1 ms for audio-thread to stop.\n")); */
Pa_Sleep(1);
}
#if 0 /* We don't need to KILL(), just COMMUNICATE and be patient... */
if (pahsc->pahsc_threadPID != -1) /* Did we really init it to -1 somewhere? */
{
DBUG(("PaHost_StopEngine() is about to kill(SIGKILL) audio-thread.\n"));
if (kill(pahsc->pahsc_threadPID, SIGKILL)) /* Or SIGTERM or SIGQUIT(core) */
{ /* Returns -1 in case of error. */
result = paHostError;
sPaHostError = oserror(); /* Hmmm, other threads may also write here! */
ERR_RPT(("PaHost_StopEngine() failed to kill audio-thread.\n"));
}
else
pahsc->pahsc_threadPID = -1; /* Notify that we've killed this thread. */
}
#endif
past->past_IsActive = 0; /* Even when kill() failed and pahsc_threadPID still there??? */
return result;
}
/*---------------------------------------------------------------*/
PaError PaHost_StopOutput(internalPortAudioStream *past, int abort)
{
return paNoError; /* Not implemented yet? */
}
PaError PaHost_StopInput(internalPortAudioStream *past, int abort )
{
return paNoError;
}
/*******************************************************************/
PaError PaHost_CloseStream(internalPortAudioStream *past)
{
PaHostSoundControl *pahsc;
PaError result = paNoError;
DBUG(("PaHost_CloseStream() called.\n"));
if (!past)
return paBadStreamPtr;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
if (!pahsc) /* If pahsc not NULL, past_DeviceData will be freed, and set to NULL. */
return result; /* This test prevents from freeing NULL-pointers. */
if (pahsc->pahsc_ALconfigIN)
{ /* Release configuration structs, only if allocated. */
ALfreeconfig(pahsc->pahsc_ALconfigIN);
pahsc->pahsc_ALconfigIN = NULL;
}
if (pahsc->pahsc_ALconfigOUT)
{
ALfreeconfig(pahsc->pahsc_ALconfigOUT); /* (Al-ports were already closed by audioProcess). */
pahsc->pahsc_ALconfigOUT = NULL;
}
if (pahsc->pahsc_InputHostBuffer)
{
PaHost_FreeFastMemory(pahsc->pahsc_InputHostBuffer, pahsc->pahsc_BytesPerInputHostBuffer);
pahsc->pahsc_InputHostBuffer = NULL;
}
if (pahsc->pahsc_OutputHostBuffer)
{
PaHost_FreeFastMemory(pahsc->pahsc_OutputHostBuffer, pahsc->pahsc_BytesPerOutputHostBuffer);
pahsc->pahsc_OutputHostBuffer = NULL;
}
PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl));
past->past_DeviceData = NULL; /* PaHost_OpenStream() allocated FAST MEM. */
return result;
}
/*------------------------------------------------------------------------*/
/* Determine minimum number of buffers required for (SGI) host based on */
/* minimum latency. Latency can be optionally set by user by setting an */
/* environment variable. For example, to set my latency to 200 msec, I've */
/* put this line in my '.cshrc' file: setenv PA_MIN_LATENCY_MSEC 200 */
/* It always calls the 'PRINT' macro. */
/* The minimum number that is returned is 2. */
/* This number is directly proportional to the AL-queue sizes to set up. */
/* It is one more than the number of user buffers per host buffer - in */
/* case minimum is returned, or, twice the user buffers per host buffer. */
/*------------------------------------------------------------------------*/
int Pa_GetMinNumBuffers(int framesPerUserBuffer, double framesPerSecond)
{
int minBuffers, minLatencyMsec;
char *minLatencyText;
double actualLatency;
minLatencyText = getenv(PA_LATENCY_ENV_NAME); /* Defined at top of file. */
if (minLatencyText)
{
minLatencyMsec = atoi(minLatencyText);
if (minLatencyMsec < 10)
{ /* 10 is the minimum. */
minLatencyMsec = 10;
PRINT (("Environment variable 'PA_MIN_LATENCY_MSEC' below minimum of %d milliseconds.\n",
minLatencyMsec));
}
else if (minLatencyMsec > 4000)
{ /* 4000 is the maximum. */
minLatencyMsec = 4000;
PRINT (("Environment variable 'PA_MIN_LATENCY_MSEC' above maximum of %d milliseconds.\n",
minLatencyMsec));
}
else
PRINT (("Using environment variable 'PA_MIN_LATENCY_MSEC' (set to %d milliseconds).\n",
minLatencyMsec));
}
else
{
minLatencyMsec = MIN_LATENCY_MSEC; /* Defined at top of this file. */
PRINT (("Environment variable 'PA_MIN_LATENCY_MSEC' not found.\nUsing default of %d milliseconds\n",
minLatencyMsec));
}
minBuffers = (int)((minLatencyMsec * framesPerSecond) /
(1000.0 * framesPerUserBuffer));
if (minBuffers < 2)
minBuffers = 2;
actualLatency = 1000.0 * minBuffers * framesPerUserBuffer / framesPerSecond;
PRINT (("Actual AL latency set to %.2f milliseconds\n", actualLatency));
return minBuffers;
}
/*---------------------------------------------------------------------*/
PaError PaHost_Term(void) /* Frees all of the linked audio-devices. */
{ /* Called by Pa_Terminate() from pa_lib.c. */
internalPortAudioDevice *pad = sDeviceList,
*nxt;
while (pad)
{
DBUG(("PaHost_Term: freeing %s\n", pad->pad_DeviceName));
nxt = pad->pad_Next;
PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice));
pad = nxt; /* PaHost_Init allocated this fast mem.*/
}
sDeviceList = (internalPortAudioDevice*)NULL;
return 0;
}
/***********************************************************************/
void Pa_Sleep( long msec ) /* Sleep requested number of milliseconds. */
{
#if 0
struct timeval timeout;
timeout.tv_sec = msec / 1000;
timeout.tv_usec = (msec % 1000) * 1000;
select(0, NULL, NULL, NULL, &timeout);
#else
long usecs = msec * 1000;
usleep( usecs );
#endif
}
/*---------------------------------------------------------------------------------------*/
/* Allocate memory that can be accessed in real-time. This may need to be held in physi- */
/* cal memory so that it is not paged to virtual memory. This call MUST be balanced with */
/* a call to PaHost_FreeFastMemory(). */
void *PaHost_AllocateFastMemory(long numBytes)
{
void *addr = malloc(numBytes); /* mpin() reads into memory all pages over the given */
if (addr) /* range and locks the pages into memory. A counter */
{ /* is incremented each time the page is locked. The */
if (mpin(addr, numBytes)) /* superuser can lock as many pages as it wishes, */
{ /* others are limited to the configurable PLOCK_MA. */
ERR_RPT(("PaHost_AllocateFastMemory() failed to mpin() memory.\n"));
#if 1
free(addr); /* You MAY cut out these 2 lines to be less strict, */
addr = NULL; /* you then only get the warning but PA goes on... */
#endif /* Only problem then may be corresponding munpin() */
} /* call at PaHost_FreeFastMemory(), below. */
memset(addr, 0, numBytes); /* Locks established with mlock are not inherited by */
} /* a child process after a fork. Furthermore, IRIX- */
return addr; /* man-pages warn against mixing both mpin and mlock */
} /* in 1 piece of code, so stick to mpin()/munpin() ! */
/*---------------------------------------------------------------------------------------*/
/* Free memory that could be accessed in real-time. This call MUST be balanced with a */
/* call to PaHost_AllocateFastMemory(). */
void PaHost_FreeFastMemory(void *addr, long numBytes)
{
if (addr)
{
if (munpin(addr, numBytes)) /* Will munpin() fail when it was never mpinned? */
ERR_RPT(("WARNING: PaHost_FreeFastMemory() failed to munpin() memory.\n"));
free(addr); /* But go on, try to release it, just warn... */
}
}
/*----------------------------------------------------------*/
PaError PaHost_StreamActive( internalPortAudioStream *past )
{
PaHostSoundControl *pahsc;
if (past == NULL)
return paBadStreamPtr;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
if (pahsc == NULL)
return paInternalError;
return (PaError)(past->past_IsActive != 0);
}
/*-------------------------------------------------------------------*/
PaTimestamp Pa_StreamTime( PortAudioStream *stream )
{
internalPortAudioStream *past = (internalPortAudioStream *) stream;
/* FIXME - return actual frames played, not frames generated.
** Need to query the output device somehow.
*/
return past->past_FrameCount;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -