I am sending this to the audio-dev list after an initial review in the
RealPlayer for MID project, but I still need testing on non-Linux
platforms.

On Wed, 2008-04-09 at 11:29 -0700, Greg Wright wrote:
> If the writelist is not empty then we have removed the
> sleep all together and we will be in a tight spin until
> we have drained the list. This might not happen for the
> whole length of the clip. Perhaps we can sleep while the
> list is full and then wait on that event when the list
> becomes empty. I don't mind changing the sleep time, it
> might be too aggressive. Basically we know how much data
> the audio hardware can hole (pushdown) in MS so we just
> need to make sure we can wake up and push more data before
> that runs out.

It is likely that I am not understanding the failure case, but the tight
loop will lock and then unlock the writelist lock, giving the other
thread a chance to write more blocks.

I can't seem to find a failure case where the lack of a sleep breaks
anything (causing audio or video artifacts), and adding a sleep only
seems to add unneeded interrupts.


Description
----------------------------------
The audio out class for UNIX is creating a thread that continuously 
attempts to read from the list of available audio data buffers, and
then use the device specific method for writting that data to the audio
device.

This change will introduce a new HXEvent for letting the main thread
signal the data writing thread when new data is available for pushing to
the audio device, instead of having the audio thread do a bunch of small
micro sleeps while it waits for some new data to push.

By doing this we remove a source of interrupts that tend to drive
the CPU into high C0 (full power mode) residency.  This is especially
true when on a MID device that has the ASound prealloc buffer max'ed
out, allowing large periods of time for the original output audio thread
to wait for new blocks of data.

Files Modified
----------------------------------
audio/device/platform/unix/audUnix.cpp
audio/device/pub/platform/unix/audUnix.h

Branches
---------------------------------
HEAD, hxclient_3_1_0_atlas

Index: platform/unix/audUnix.cpp
===================================================================
RCS file: /cvsroot/audio/device/platform/unix/audUnix.cpp,v
retrieving revision 1.12
diff -u -r1.12 audUnix.cpp
--- platform/unix/audUnix.cpp   6 Jul 2007 20:21:16 -0000       1.12
+++ platform/unix/audUnix.cpp   16 Apr 2008 00:42:15 -0000
@@ -63,7 +63,6 @@
 #include "hxmutex.h"
 #include "debug.h"
 
-#include "microsleep.h"
 //me.
 #include "audUnix.h"
 
@@ -73,7 +72,8 @@
 #include "hxprefs.h"
 #endif 
 
-
+#include "hxtlogutil.h"
+#include "ihxtlogsystem.h"
 
 //-1 is usually considered to be no file descriptor.
 const int CAudioOutUNIX::NO_FILE_DESCRIPTOR = -1;
@@ -101,7 +101,7 @@
     m_mtxDeviceStateLock(NULL),
     m_audioThread(NULL),
     m_bUserWantsThreads(TRUE),
-    m_ulSleepTime(0),
+    m_pAvailableDataEvent(NULL),
 #endif
     m_pRollbackBuffer(NULL)
 {
@@ -114,7 +114,6 @@
     //Allco our write buffer list. Want to throw from here? You will,
like
     //it or not.
     m_pWriteList = new CHXSimpleList();
-    
 }
 
 void CAudioOutUNIX::_initAfterContext()
@@ -142,6 +141,7 @@
        CreateInstanceCCF(CLSID_IHXMutex,
(void**)&m_mtxWriteListPlayStateLock, m_pContext);
        CreateInstanceCCF(CLSID_IHXMutex, (void**)&m_mtxDeviceStateLock,
m_pContext);
        CreateInstanceCCF(CLSID_IHXThread, (void**)&m_audioThread,
m_pContext);
+       HXEvent::MakeEvent(m_pAvailableDataEvent, "Available Audio Data",
FALSE);
     }
 #endif    
 
@@ -194,6 +194,7 @@
         HX_RELEASE( m_mtxWriteListPlayStateLock );
         HX_RELEASE( m_mtxDeviceStateLock );
         HX_RELEASE( m_audioThread );
+        HX_DELETE( m_pAvailableDataEvent );
     }
 #endif    
 
@@ -271,14 +272,6 @@
             }
             else
             {
-#if defined(_THREADED_AUDIO) && defined(_UNIX_THREADS_SUPPORTED)
-                //We want to sleep as a function of device buffer size.
-                //If we have a small m_ulDeviceBufferSize we can only 
-                //afford to sleep just a little while.
-                HX_ASSERT( m_ulDeviceBufferSize != 0 );
-                m_ulSleepTime =
(((float)m_ulDeviceBufferSize/(float)m_uSampFrameSize)/
-                                 (float)m_unSampleRate) * 1000 /
(float)m_unNumChannels;
-#endif
                 if (!m_bMixerPresent)
                     _OpenMixer();   
 
@@ -353,6 +346,8 @@
     //Wait for it to do so and clean up.
     if( m_bUserWantsThreads )
     {
+        HXLOGL4 (HXLOG_ADEV, "CAudioUnixOUT::_Imp_Close signaling
event..."); 
+        m_pAvailableDataEvent->SignalEvent();
         m_audioThread->Exit(0);
     }
     
@@ -778,8 +773,11 @@
         that->m_mtxDeviceStateLock->Unlock();
         that->m_mtxWriteListPlayStateLock->Unlock();
 
-        //OK, sleep the amount of time it takes to play 1/4 of the
device's buffer.
-        microsleep(that->m_ulSleepTime/4); 
+        if(bReadyToExit == FALSE && (that->m_pWriteList->GetCount() ==
0 || that->m_wState == RA_AOS_OPEN_PAUSED))
+       {
+           HXLOGL4 (HXLOG_ADEV, "CAudioUnixOUT::AudioThread() waiting for
audio data..."); 
+           that->m_pAvailableDataEvent->Wait();
+       }
     }
 
     //Signal the parent thread that we are done.
@@ -833,6 +831,7 @@
     }
 
     UNLOCK(m_mtxWriteListPlayStateLock);
+    HXLOGL4 (HXLOG_ADEV, "CAudioUnixOUT::_PushBits() writing %i bits",
(int)ulBufLen);
     _WriteBytes(pData, ulBufLen, lCount);
     LOCK(m_mtxWriteListPlayStateLock);
 
@@ -995,6 +994,8 @@
     //grab the data and write it to the device.
     if( m_bUserWantsThreads )
     {
+        HXLOGL4 (HXLOG_ADEV, "CAudioUnixOUT::_Imp_Write signaling
event..."); 
+        m_pAvailableDataEvent->SignalEvent();
         return RA_AOE_NOERR;
     }
 #endif    
Index: pub/platform/unix/audUnix.h
===================================================================
RCS file: /cvsroot/audio/device/pub/platform/unix/audUnix.h,v
retrieving revision 1.8
diff -u -r1.8 audUnix.h
--- pub/platform/unix/audUnix.h 6 Jul 2007 20:21:19 -0000       1.8
+++ pub/platform/unix/audUnix.h 16 Apr 2008 00:42:15 -0000
@@ -288,7 +288,7 @@
     IHXMutex*  m_mtxDeviceStateLock;
     IHXThread* m_audioThread;
     HXBOOL      m_bUserWantsThreads;
-    ULONG32    m_ulSleepTime;
+    HXEvent*    m_pAvailableDataEvent;
 #endif    
     
   private:

Description
----------------------------------
The audio out class for UNIX is creating a thread that continuously 
attempts to read from the list of available audio data buffers, and
then use the device specific method for writting that data to the audio
device.

This change will introduce a new HXEvent for letting the main thread
signal the data writing thread when new data is available for pushing to
the audio device, instead of having the audio thread do a bunch of small
micro sleeps while it waits for some new data to push.

By doing this we remove a source of interrupts that tend to drive
the CPU into high C0 (full power mode) residency.  This is especially
true when on a MID device that has the ASound prealloc buffer max'ed
out, allowing large periods of time for the original output audio thread
to wait for new blocks of data.

Files Modified
----------------------------------
audio/device/platform/unix/audUnix.cpp
audio/device/pub/platform/unix/audUnix.h

Branches
---------------------------------
HEAD, hxclient_3_1_0_atlas

Index: platform/unix/audUnix.cpp
===================================================================
RCS file: /cvsroot/audio/device/platform/unix/audUnix.cpp,v
retrieving revision 1.12
diff -u -r1.12 audUnix.cpp
--- platform/unix/audUnix.cpp	6 Jul 2007 20:21:16 -0000	1.12
+++ platform/unix/audUnix.cpp	16 Apr 2008 00:42:15 -0000
@@ -63,7 +63,6 @@
 #include "hxmutex.h"
 #include "debug.h"
 
-#include "microsleep.h"
 //me.
 #include "audUnix.h"
 
@@ -73,7 +72,8 @@
 #include "hxprefs.h"
 #endif 
 
-
+#include "hxtlogutil.h"
+#include "ihxtlogsystem.h"
 
 //-1 is usually considered to be no file descriptor.
 const int CAudioOutUNIX::NO_FILE_DESCRIPTOR = -1;
@@ -101,7 +101,7 @@
     m_mtxDeviceStateLock(NULL),
     m_audioThread(NULL),
     m_bUserWantsThreads(TRUE),
-    m_ulSleepTime(0),
+    m_pAvailableDataEvent(NULL),
 #endif
     m_pRollbackBuffer(NULL)
 {
@@ -114,7 +114,6 @@
     //Allco our write buffer list. Want to throw from here? You will, like
     //it or not.
     m_pWriteList = new CHXSimpleList();
-    
 }
 
 void CAudioOutUNIX::_initAfterContext()
@@ -142,6 +141,7 @@
 	CreateInstanceCCF(CLSID_IHXMutex, (void**)&m_mtxWriteListPlayStateLock, m_pContext);
 	CreateInstanceCCF(CLSID_IHXMutex, (void**)&m_mtxDeviceStateLock, m_pContext);
 	CreateInstanceCCF(CLSID_IHXThread, (void**)&m_audioThread, m_pContext);
+	HXEvent::MakeEvent(m_pAvailableDataEvent, "Available Audio Data", FALSE);
     }
 #endif    
 
@@ -194,6 +194,7 @@
         HX_RELEASE( m_mtxWriteListPlayStateLock );
         HX_RELEASE( m_mtxDeviceStateLock );
         HX_RELEASE( m_audioThread );
+        HX_DELETE( m_pAvailableDataEvent );
     }
 #endif    
 
@@ -271,14 +272,6 @@
             }
             else
             {
-#if defined(_THREADED_AUDIO) && defined(_UNIX_THREADS_SUPPORTED)
-                //We want to sleep as a function of device buffer size.
-                //If we have a small m_ulDeviceBufferSize we can only 
-                //afford to sleep just a little while.
-                HX_ASSERT( m_ulDeviceBufferSize != 0 );
-                m_ulSleepTime = (((float)m_ulDeviceBufferSize/(float)m_uSampFrameSize)/
-                                 (float)m_unSampleRate) * 1000 / (float)m_unNumChannels;
-#endif
                 if (!m_bMixerPresent)
                     _OpenMixer();   
 
@@ -353,6 +346,8 @@
     //Wait for it to do so and clean up.
     if( m_bUserWantsThreads )
     {
+        HXLOGL4 (HXLOG_ADEV, "CAudioUnixOUT::_Imp_Close signaling event..."); 
+        m_pAvailableDataEvent->SignalEvent();
         m_audioThread->Exit(0);
     }
     
@@ -778,8 +773,11 @@
         that->m_mtxDeviceStateLock->Unlock();
         that->m_mtxWriteListPlayStateLock->Unlock();
 
-        //OK, sleep the amount of time it takes to play 1/4 of the device's buffer.
-        microsleep(that->m_ulSleepTime/4); 
+        if(bReadyToExit == FALSE && (that->m_pWriteList->GetCount() == 0 || that->m_wState == RA_AOS_OPEN_PAUSED))
+	{
+	    HXLOGL4 (HXLOG_ADEV, "CAudioUnixOUT::AudioThread() waiting for audio data..."); 
+	    that->m_pAvailableDataEvent->Wait();
+	}
     }
 
     //Signal the parent thread that we are done.
@@ -833,6 +831,7 @@
     }
 
     UNLOCK(m_mtxWriteListPlayStateLock);
+    HXLOGL4 (HXLOG_ADEV, "CAudioUnixOUT::_PushBits() writing %i bits", (int)ulBufLen);
     _WriteBytes(pData, ulBufLen, lCount);
     LOCK(m_mtxWriteListPlayStateLock);
 
@@ -995,6 +994,8 @@
     //grab the data and write it to the device.
     if( m_bUserWantsThreads )
     {
+        HXLOGL4 (HXLOG_ADEV, "CAudioUnixOUT::_Imp_Write signaling event..."); 
+        m_pAvailableDataEvent->SignalEvent();
         return RA_AOE_NOERR;
     }
 #endif    
Index: pub/platform/unix/audUnix.h
===================================================================
RCS file: /cvsroot/audio/device/pub/platform/unix/audUnix.h,v
retrieving revision 1.8
diff -u -r1.8 audUnix.h
--- pub/platform/unix/audUnix.h	6 Jul 2007 20:21:19 -0000	1.8
+++ pub/platform/unix/audUnix.h	16 Apr 2008 00:42:15 -0000
@@ -288,7 +288,7 @@
     IHXMutex*	m_mtxDeviceStateLock;
     IHXThread*	m_audioThread;
     HXBOOL      m_bUserWantsThreads;
-    ULONG32	m_ulSleepTime;
+    HXEvent*    m_pAvailableDataEvent;
 #endif    
     
   private:
_______________________________________________
Audio-dev mailing list
[email protected]
http://lists.helixcommunity.org/mailman/listinfo/audio-dev

Reply via email to