Fixed the nonblocking open - now it tries to open each device in

nonblocking mode, and if that succeeds, closes it and opens it
again in blocking mode - and added a new Pa_StreamTime
implementation that uses SNDCTL_DSP_GET[I/O]PTR.
This commit is contained in:
dmazzoni 2002-02-19 08:24:21 +00:00
commit 7e73ac614d

View file

@ -58,9 +58,14 @@ Modfication History
PLB20010927 - Phil - Improved negotiation for numChannels. PLB20010927 - Phil - Improved negotiation for numChannels.
SG20011005 - Stewart Greenhill - set numChannels back to reasonable value after query. SG20011005 - Stewart Greenhill - set numChannels back to reasonable value after query.
DH20010115 - David Herring - fixed uninitialized handle. DH20010115 - David Herring - fixed uninitialized handle.
DM20020218 - Dominic Mazzoni - Try to open in nonblocking mode first, in case
the device is already open. New implementation of
Pa_StreamTime that uses SNDCTL_DSP_GETOPTR but
uses our own counter to avoid wraparound.
TODO TODO
O- change Pa_StreamTime() to query device (patest_sync.c)
O- put semaphore lock around shared data? O- put semaphore lock around shared data?
O- handle native formats better O- handle native formats better
O- handle stereo-only device better ??? O- handle stereo-only device better ???
@ -159,6 +164,10 @@ typedef struct PaHostSoundControl
/* For measuring CPU utilization. */ /* For measuring CPU utilization. */
struct timeval pahsc_EntryTime; struct timeval pahsc_EntryTime;
double pahsc_InverseMicrosPerBuffer; /* 1/Microseconds of real-time audio per user buffer. */ double pahsc_InverseMicrosPerBuffer; /* 1/Microseconds of real-time audio per user buffer. */
/* For calculating stream time */
int pahsc_LastPosPtr;
double pahsc_LastStreamBytes;
} }
PaHostSoundControl; PaHostSoundControl;
@ -511,6 +520,8 @@ static PaError Pa_AudioThreadProc( internalPortAudioStream *past )
PaError result = 0; PaError result = 0;
PaHostSoundControl *pahsc; PaHostSoundControl *pahsc;
short bytes_read = 0; short bytes_read = 0;
count_info info;
int delta;
#ifdef GNUSTEP #ifdef GNUSTEP
GSRegisterCurrentThread(); /* SB20010904 */ GSRegisterCurrentThread(); /* SB20010904 */
@ -526,12 +537,12 @@ static PaError Pa_AudioThreadProc( internalPortAudioStream *past )
if (sched_setscheduler(0, SCHEDULER_POLICY, &schp) != 0) if (sched_setscheduler(0, SCHEDULER_POLICY, &schp) != 0)
{ {
perror("sched_setscheduler"); DBUG(("sched_setscheduler"));
printf("PortAudio: only superuser can use real-time priority.\n"); DBUG(("PortAudio: only superuser can use real-time priority.\n"));
} }
else else
{ {
printf("PortAudio: callback priority set to level %d!\n", schp.sched_priority); DBUG(("PortAudio: callback priority set to level %d!\n", schp.sched_priority));
} }
} }
#endif #endif
@ -578,6 +589,17 @@ static PaError Pa_AudioThreadProc( internalPortAudioStream *past )
(void *)pahsc->pahsc_NativeOutputBuffer, (void *)pahsc->pahsc_NativeOutputBuffer,
pahsc->pahsc_BytesPerOutputBuffer); pahsc->pahsc_BytesPerOutputBuffer);
} }
/* Update current stream time (using a double so that
we don't wrap around like info.bytes does) */
if( pahsc->pahsc_NativeOutputBuffer )
ioctl(pahsc->pahsc_OutputHandle, SNDCTL_DSP_GETOPTR, &info);
else
ioctl(pahsc->pahsc_InputHandle, SNDCTL_DSP_GETIPTR, &info);
delta = (info.bytes - pahsc->pahsc_LastPosPtr) & 0x000FFFFF;
pahsc->pahsc_LastStreamBytes += delta;
pahsc->pahsc_LastPosPtr = info.bytes;
} }
past->past_IsActive = 0; past->past_IsActive = 0;
@ -776,8 +798,20 @@ PaError PaHost_OpenStream( internalPortAudioStream *past )
{ {
pad = Pa_GetInternalDevice( past->past_OutputDeviceID ); pad = Pa_GetInternalDevice( past->past_OutputDeviceID );
DBUG(("PaHost_OpenStream: attempt to open %s for O_RDWR\n", pad->pad_DeviceName )); DBUG(("PaHost_OpenStream: attempt to open %s for O_RDWR\n", pad->pad_DeviceName ));
/* dmazzoni: test it first in nonblocking mode to
make sure the device is not busy */
pahsc->pahsc_InputHandle = open(pad->pad_DeviceName,O_RDWR|O_NONBLOCK);
if(pahsc->pahsc_InputHandle==-1)
{
ERR_RPT(("PaHost_OpenStream: could not open %s for O_RDWR\n", pad->pad_DeviceName ));
result = paHostError;
goto error;
}
close(pahsc->pahsc_InputHandle);
pahsc->pahsc_OutputHandle = pahsc->pahsc_InputHandle = pahsc->pahsc_OutputHandle = pahsc->pahsc_InputHandle =
open(pad->pad_DeviceName,O_RDWR|O_NONBLOCK); open(pad->pad_DeviceName,O_RDWR);
if(pahsc->pahsc_InputHandle==-1) if(pahsc->pahsc_InputHandle==-1)
{ {
ERR_RPT(("PaHost_OpenStream: could not open %s for O_RDWR\n", pad->pad_DeviceName )); ERR_RPT(("PaHost_OpenStream: could not open %s for O_RDWR\n", pad->pad_DeviceName ));
@ -797,6 +831,8 @@ PaError PaHost_OpenStream( internalPortAudioStream *past )
{ {
pad = Pa_GetInternalDevice( past->past_OutputDeviceID ); pad = Pa_GetInternalDevice( past->past_OutputDeviceID );
DBUG(("PaHost_OpenStream: attempt to open %s for O_WRONLY\n", pad->pad_DeviceName )); DBUG(("PaHost_OpenStream: attempt to open %s for O_WRONLY\n", pad->pad_DeviceName ));
/* dmazzoni: test it first in nonblocking mode to
make sure the device is not busy */
pahsc->pahsc_OutputHandle = open(pad->pad_DeviceName,O_WRONLY|O_NONBLOCK); pahsc->pahsc_OutputHandle = open(pad->pad_DeviceName,O_WRONLY|O_NONBLOCK);
if(pahsc->pahsc_OutputHandle==-1) if(pahsc->pahsc_OutputHandle==-1)
{ {
@ -804,6 +840,15 @@ PaError PaHost_OpenStream( internalPortAudioStream *past )
result = paHostError; result = paHostError;
goto error; goto error;
} }
close(pahsc->pahsc_OutputHandle);
pahsc->pahsc_OutputHandle = open(pad->pad_DeviceName,O_WRONLY);
if(pahsc->pahsc_OutputHandle==-1)
{
ERR_RPT(("PaHost_OpenStream: could not open %s for O_WRONLY\n", pad->pad_DeviceName ));
result = paHostError;
goto error;
}
Pa_SetLatency( pahsc->pahsc_OutputHandle, Pa_SetLatency( pahsc->pahsc_OutputHandle,
past->past_NumUserBuffers, past->past_FramesPerUserBuffer, past->past_NumUserBuffers, past->past_FramesPerUserBuffer,
past->past_NumOutputChannels ); past->past_NumOutputChannels );
@ -815,6 +860,8 @@ PaError PaHost_OpenStream( internalPortAudioStream *past )
{ {
pad = Pa_GetInternalDevice( past->past_InputDeviceID ); pad = Pa_GetInternalDevice( past->past_InputDeviceID );
DBUG(("PaHost_OpenStream: attempt to open %s for O_RDONLY\n", pad->pad_DeviceName )); DBUG(("PaHost_OpenStream: attempt to open %s for O_RDONLY\n", pad->pad_DeviceName ));
/* dmazzoni: test it first in nonblocking mode to
make sure the device is not busy */
pahsc->pahsc_InputHandle = open(pad->pad_DeviceName,O_RDONLY|O_NONBLOCK); pahsc->pahsc_InputHandle = open(pad->pad_DeviceName,O_RDONLY|O_NONBLOCK);
if(pahsc->pahsc_InputHandle==-1) if(pahsc->pahsc_InputHandle==-1)
{ {
@ -822,6 +869,15 @@ PaError PaHost_OpenStream( internalPortAudioStream *past )
result = paHostError; result = paHostError;
goto error; goto error;
} }
close(pahsc->pahsc_InputHandle);
pahsc->pahsc_InputHandle = open(pad->pad_DeviceName,O_RDONLY);
if(pahsc->pahsc_InputHandle==-1)
{
ERR_RPT(("PaHost_OpenStream: could not open %s for O_RDONLY\n", pad->pad_DeviceName ));
result = paHostError;
goto error;
}
Pa_SetLatency( pahsc->pahsc_InputHandle, /* DH20010115 - was OutputHandle! */ Pa_SetLatency( pahsc->pahsc_InputHandle, /* DH20010115 - was OutputHandle! */
past->past_NumUserBuffers, past->past_FramesPerUserBuffer, past->past_NumUserBuffers, past->past_FramesPerUserBuffer,
past->past_NumInputChannels ); past->past_NumInputChannels );
@ -1058,11 +1114,24 @@ PaError PaHost_StreamActive( internalPortAudioStream *past )
PaTimestamp Pa_StreamTime( PortAudioStream *stream ) PaTimestamp Pa_StreamTime( PortAudioStream *stream )
{ {
internalPortAudioStream *past = (internalPortAudioStream *) stream; internalPortAudioStream *past = (internalPortAudioStream *) stream;
/* FIXME - return actual frames played, not frames generated. PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
** Need to query the output device somehow. PaTimestamp streamTime;
*/ count_info info;
int delta;
if( past == NULL ) return paBadStreamPtr; if( past == NULL ) return paBadStreamPtr;
return past->past_FrameCount;
if( pahsc->pahsc_NativeOutputBuffer ) {
ioctl(pahsc->pahsc_OutputHandle, SNDCTL_DSP_GETOPTR, &info);
delta = (info.bytes - pahsc->pahsc_LastPosPtr) & 0x000FFFFF;
return (pahsc->pahsc_LastStreamBytes + delta) / (past->past_NumOutputChannels * sizeof(short));
}
else {
ioctl(pahsc->pahsc_InputHandle, SNDCTL_DSP_GETIPTR, &info);
delta = (info.bytes - pahsc->pahsc_LastPosPtr) & 0x000FFFFF;
return (pahsc->pahsc_LastStreamBytes + delta) / (past->past_NumInputChannels * sizeof(short));
}
} }
/***********************************************************************/ /***********************************************************************/