]> Repos - portaudio/commitdiff
Fixed the nonblocking open - now it tries to open each device in
authordmazzoni <dmazzoni@0f58301d-fd10-0410-b4af-bbb618454e57>
Tue, 19 Feb 2002 08:24:21 +0000 (08:24 +0000)
committerdmazzoni <dmazzoni@0f58301d-fd10-0410-b4af-bbb618454e57>
Tue, 19 Feb 2002 08:24:21 +0000 (08:24 +0000)
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.

pa_unix_oss/pa_unix_oss.c

index accd7c1b113af0100111e8ecad174032fb2d6b2a..9b7211f6fbee892fedc5857a2174042adda4c1f4 100644 (file)
@@ -58,9 +58,14 @@ Modfication History
   PLB20010927 - Phil - Improved negotiation for numChannels.
   SG20011005 - Stewart Greenhill - set numChannels back to reasonable value after query.
   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
-O- change Pa_StreamTime() to query device (patest_sync.c)
 O- put semaphore lock around shared data?
 O- handle native formats better
 O- handle stereo-only device better ???
@@ -159,6 +164,10 @@ typedef struct PaHostSoundControl
     /* For measuring CPU utilization. */
     struct timeval   pahsc_EntryTime;
     double           pahsc_InverseMicrosPerBuffer; /* 1/Microseconds of real-time audio per user buffer. */
+
+   /* For calculating stream time */
+    int              pahsc_LastPosPtr;
+    double           pahsc_LastStreamBytes;
 }
 PaHostSoundControl;
 
@@ -511,6 +520,8 @@ static PaError Pa_AudioThreadProc( internalPortAudioStream   *past )
     PaError    result = 0;
     PaHostSoundControl             *pahsc;
     short    bytes_read = 0;
+    count_info info;
+    int        delta;
 
 #ifdef GNUSTEP
     GSRegisterCurrentThread(); /* SB20010904 */
@@ -526,12 +537,12 @@ static PaError Pa_AudioThreadProc( internalPortAudioStream   *past )
 
         if (sched_setscheduler(0, SCHEDULER_POLICY, &schp) != 0)
         {
-            perror("sched_setscheduler");
-            printf("PortAudio: only superuser can use real-time priority.\n");
+            DBUG(("sched_setscheduler"));
+            DBUG(("PortAudio: only superuser can use real-time priority.\n"));
         }
         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
@@ -578,6 +589,17 @@ static PaError Pa_AudioThreadProc( internalPortAudioStream   *past )
                   (void *)pahsc->pahsc_NativeOutputBuffer,
                   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;
@@ -776,8 +798,20 @@ PaError PaHost_OpenStream( internalPortAudioStream   *past )
         {
             pad = Pa_GetInternalDevice( past->past_OutputDeviceID );
             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 =
-                                            open(pad->pad_DeviceName,O_RDWR|O_NONBLOCK);
+                                            open(pad->pad_DeviceName,O_RDWR);
             if(pahsc->pahsc_InputHandle==-1)
             {
                 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 );
             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);
             if(pahsc->pahsc_OutputHandle==-1)
             {
@@ -804,6 +840,15 @@ PaError PaHost_OpenStream( internalPortAudioStream   *past )
                 result = paHostError;
                 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,
                            past->past_NumUserBuffers, past->past_FramesPerUserBuffer,
                            past->past_NumOutputChannels );
@@ -815,6 +860,8 @@ PaError PaHost_OpenStream( internalPortAudioStream   *past )
         {
             pad = Pa_GetInternalDevice( past->past_InputDeviceID );
             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);
             if(pahsc->pahsc_InputHandle==-1)
             {
@@ -822,6 +869,15 @@ PaError PaHost_OpenStream( internalPortAudioStream   *past )
                 result = paHostError;
                 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! */
                            past->past_NumUserBuffers, past->past_FramesPerUserBuffer,
                            past->past_NumInputChannels );
@@ -1058,11 +1114,24 @@ PaError PaHost_StreamActive( internalPortAudioStream   *past )
 PaTimestamp Pa_StreamTime( PortAudioStream *stream )
 {
     internalPortAudioStream *past = (internalPortAudioStream *) stream;
-    /* FIXME - return actual frames played, not frames generated.
-    ** Need to query the output device somehow.
-    */
+    PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+    PaTimestamp   streamTime;
+    count_info    info;
+    int           delta;
+
     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));
+
+    }
 }
 
 /***********************************************************************/