Eric Hyche wrote:

Some general questions:

1) GetBlocksRemainingToPlay() seems to depend on the accuracy
of m_dGranularity. Where do we get m_dGranularity and how do we know it's accurate?

It gets set in CHXAudioSession::SetGranularity(), and the value
passed in is hardcoded to 50 or 100ms by the defines:

+#  define MINIMUM_AUDIO_GRANULARITY       50
+#  define MAXIMUM_AUDIO_GRANULARITY       MINIMUM_AUDIO_GRANULARITY
...
...
+#  define MINIMUM_AUDIO_GRANULARITY       50
+#  define MAXIMUM_AUDIO_GRANULARITY       100



2) This seems to round either up or down:
   >          ulBlocksPlayed = (ULONG32)(ulCurTime/m_dGranularity+.5);
   but I would think we would always want to round up, right?
   Then we would be always err on the side of sometimes *over-estimating*
   the number of blocks played, which would tend to make us err
   on the side of writing more to the device quicker.


There is a trade off here between HEAP/latency and being conservative
with regards to pushing down PCM data to the device. My feelings on
this is that it is much more important to be accurate then it is to be
conservative. Some of the problems we have had in the buffering and
audio pushdown logic have arisen from each component in the system
being conservative in its own way. If you add up all of the difference
through the system that result from these conservative algorithms you
can see that it is hard to determine actual performance given a
certain stream. Also, at least in this case, we are free to change the
constants to control the minimum pushdown values. This can be changed
for each device and/or build profile to prevent any underflow that
might happen. As an example, look at the following charts.  They
represent the amount of PCM data in the audio device at any given
random time that we happen to check. The first chart shows the values
for rounding to the nearest block, the 2nd charts shows rounding
up. Each chart starts at the value of the maximum attainable pushdown
for each algorithm used, and therefore the maximum we would compute
for each algorithm. The math was done every MS level, but I have
just shown every 5ms in the charts to save space. Also, these
show values for a MIN_HEAP build, 100ms pushdown, 50ms granularity:


Rounding to nearest:
Device  Blocks  Pushed  Total
MS      Remain  Blocks  MS After
------  ------  ------  ------------
125     3       0       125
120     2       0       120
115     2       0       115
110     2       0       110
105     2       0       105
100     2       0       100
95      2       0       95
90      2       0       90
85      2       0       85
80      2       0       80
75      2       0       75
70      1       1       120
65      1       1       115
60      1       1       110
55      1       1       105
50      1       1       100
45      1       1       95
40      1       1       90
35      1       1       85
30      1       1       80
25      1       1       75
20      0       2       120
15      0       2       115
10      0       2       110
5       0       2       105
0       0       2       100
------  ------  ------  ------------
Average in device:      99.504950
Min: 75   Max: 124


Device  Blocks  Pushed  Total
MS      Remain  Blocks  MS After
------  ------  ------  ------------
150     3       0       150
145     2       0       145
140     2       0       140
135     2       0       135
130     2       0       130
125     2       0       125
120     2       0       120
115     2       0       115
110     2       0       110
105     2       0       105
100     2       0       100
95      1       1       145
90      1       1       140
85      1       1       135
80      1       1       130
75      1       1       125
70      1       1       120
65      1       1       115
60      1       1       110
55      1       1       105
50      1       1       100
45      0       2       145
40      0       2       140
35      0       2       135
30      0       2       130
25      0       2       125
20      0       2       120
15      0       2       115
10      0       2       110
5       0       2       105
0       0       2       100
------  ------  ------  ------------
Average in device:      124.257426
Min: 100   Max: 149


Notice how rounding up keeps us about 25% above our target for
pushdown on average and almost 49% at the worst. Rounding to the
nearest, on average, is just -.5% low and at worst is ~24% high.

Now, I can see that if you wanted the minimum pushdown to mean that
there should never be less then that many blocks in the device at any
given time then the 2nd option is better. However, I prefer to interpret
the pushdown value as the average latency from the time you write to the
device to the time it gets consumed by the hardware. I believe this 2nd
interpretation better lets us determine and tweak the performance of the
system. If it turns out that the given build can not handle that low of
a latency without underflowing, then is should just be raised.

I am open to other interpretations and use cases or something I might
be missing.

Also, for non MIN_HEAP builds, this is irrelevent because we will always
be within 100ms of a full second of pushdown.


3) Are there any concurrency issues? Do we know that the code that's
   modifying m_ulBlocksWritten is on the same thread as the code that's
   running GetBlocksRemainingToPlay()? Perhaps we might want to read
   m_ulBlocksWritten into a local variable....

If there are (I will look) then they already existed. The only place
we call GetBlocksRemainingToPlay() is the same place we used m_ulBlocksWritten
before.



--greg.


Changes themselves look good.

Eric


-----Original Message-----
From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Greg Wright
Sent: Tuesday, August 16, 2005 5:11 PM
To: [EMAIL PROTECTED]; [EMAIL PROTECTED] Subject: [Audio-dev] CR-Client: Make audio pushdown calculations more robust.


Synopsis
========

MIN_HEAP Playback. With MIN_HEAP builds (or very low latency
modes) it was possible to have glitches in the audio. This was
from audio underflows as a result of not being able to accurately
determine how much push down we had across platforms. This was
mostly due to differences in how different platforms calculated
the number of block remaining to play, but also had to do with
differences in certain constants used.

Fix
===

The first thing to do was to bring all the different defines into
one place, they were in 3 separate files. All defines that control
the pushdown, granularity and scheduling are now in one big section.
This should keep problem from occurring when one of these was changed
without knowledge of the others. Here is the pertinent part of that
chage:

+// These defines control how much audio PCM data we push down into the +// audio device. MINIMUM_AUDIO_STARTUP_PUSHDOWN determines how much we
+// push before calling Resume() on the device (and starting playback)
+// and MINIMUM_AUDIO_PUSHDOWN determines how much PCM data we push
+// down during steady state playback. It is also important that the
+// granularity be less then or equal to MINIMUM_AUDIO_PUSHDOWN/2. If
+// not, underflows could result because only 1 block will be in the
+// audio device at any given time. Currently MINIMUM_AUDIO_GRANULARITY
+// is not used. In CHXAudioPlayer::Setup() hardcodes this:
+//
+//     m_ulGranularity = MAXIMUM_AUDIO_GRANULARITY;
+//
+// The CHECK_AUDIO_INTERVAL define tells the audio session how often
+// to check how much data we have pushed down in the audio device.
+// for min heap builds it is more important to check often because we
+// have very few blocks pushed down at any one time. The value for
+// this define is a percentage (0-100) of the granularity in
+// milliseconds. IE, 40 means 40% of whatever granulatiry is in use.
+//
+#ifdef HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES
+#  define MINIMUM_AUDIO_GRANULARITY       50
+#  define MAXIMUM_AUDIO_GRANULARITY       MINIMUM_AUDIO_GRANULARITY
+#  define MINIMUM_AUDIO_PUSHDOWN          100
+#  define MINIMUM_AUDIO_STARTUP_PUSHDOWN  MINIMUM_AUDIO_PUSHDOWN
+#  define CHECK_AUDIO_INTERVAL            40
+#else
+#  define MINIMUM_AUDIO_GRANULARITY       50
+#  define MAXIMUM_AUDIO_GRANULARITY       100
+#  define MINIMUM_AUDIO_PUSHDOWN          1000
+#  define MINIMUM_AUDIO_STARTUP_PUSHDOWN  100
+#  define CHECK_AUDIO_INTERVAL            90
+#endif

The second thing to do was to re-do our logic on how we calculate the
amount of audio pushdown, given the above defines. The new logic makes
sure that we are conservative with regards to block count and that all
the calculated and defined values make sense together. The changes are
to UpdateMinimumPushdown() but the diffs are hard to read, here is the
new version:

void CHXAudioSession::UpdateMinimumPushdown()
{
    //This is called whenever the granularity or audio pushdown
    //changes.  In this method we need to make sure that the
    //granularity is results in at least 2 blocks being the min
    //pushdown. If we are left with only one block, it can be hard to
    //prevent underflow in the audio device. You don't have to
    //increase the amount of PCM pushdown, just decrease the
    //granularity.
    if( m_ulGranularity )
    {
        //Basically, integer versions of 'ceil' function.
m_ulMinBlocksTobeQueued = (m_ulMinimumPushdown+m_ulGranularity-1)/m_ulGranularity; m_ulMinBlocksTobeQueuedAtStart = (m_ulMinimumStartupPushdown+m_ulGranularity-1)/m_ulGranularity;

#if defined(HELIX_FEATURE_PREFERENCES)
        HXBOOL bRestore = FALSE;
ReadPrefBOOL( m_pPreferences, "RestoreMinimumPushdown", bRestore );
        if( bRestore)
        {
            m_ulMinBlocksTobeQueuedAtStart = m_ulMinBlocksTobeQueued;
        }
#endif

        //Invarients to ensure glitch free audio playback.
        HX_ASSERT( m_ulGranularity <= m_ulMinimumPushdown/2 );
        HX_ASSERT( m_ulMinBlocksTobeQueued>1 );
HX_ASSERT( m_ulMinBlocksTobeQueued >= m_ulMinBlocksTobeQueuedAtStart ); HX_ASSERT( m_ulMinimumPushdown >= m_ulMinimumStartupPushdown );
    }
}


Next, we had to fix the problem with each platform calculating the number of blocks remaining to play differently. One implementation might return values 1 greater or 1 less then another. This is a problem for the core when the total pushdown was just 1 or 2 blocks, we could run into underflow pretty easily. Even if I did go and fix each platform, it is possible that new platforms would not be correct or that old ones would get changed again. This is mostly because it is hard to tell if you are doing it correctly in normal operations. It takes a MIN_HEAP build and some testing to figure it out. However, one thing each platform's audio code *must* do correctly is return a smooth accurate time-line. If they don't it is very obvious. So, I have opted to use that information instead of relying on the buggy NumberOfBlocksRemainingToPlay() method. This was already being done for audio code that returned FALSE from IsWaveOutDevice(). Currently, this only includes the DirectSound driver being used on Window's player builds. This change results in a lot cleaner code and some image size reduction. It also moves the calculation of audio pushdown to a single spot in the code base. A new method, GetBlocksRemainingToPlay():

ULONG32 CHXAudioSession::GetBlocksRemainingToPlay()
{
    ULONG32 ulRetVal        = 0;
    ULONG32 ulBlocksPlayed  = 0;
    ULONG32 ulCurTime       = 0;
    if( m_pAudioDev->GetCurrentAudioTime(ulCurTime) == HXR_OK )
    {
        ulBlocksPlayed = (ULONG32)(ulCurTime/m_dGranularity+.5);
        if( m_ulBlocksWritten>ulBlocksPlayed )
        {
            ulRetVal = m_ulBlocksWritten-ulBlocksPlayed;
        }
    }
    return ulRetVal;
}


So that this code:


- if ( (!m_bReplacedDev) && (((CHXAudioDevice*)m_pAudioDev)->IsWaveOutDevice()) )
-        {
- m_uNumToBePlayed = uNumBlocks = ((CHXAudioDevice*)m_pAudioDev)->NumberOfBlocksRemainingToPlay();
-
-
-
- /* Now that m_ulMinimumPushdown can be set by the user, it is possible
-             * for MIN_BLOCKS_TOBEQUEUED to be 0.
-             */
-            if (uNumBlocks == 0 ||
-                uNumBlocks < m_ulMinBlocksTobeQueued)
-            {
-                bPlay = TRUE;
-            }
-        }
-        else
-        {
-            ULONG32 ulCurTime = 0;
- if (m_pAudioDev->GetCurrentAudioTime(ulCurTime) == HXR_OK)
-            {
- UINT32 ulNumBlocksPlayed = (UINT32) ((double) ulCurTime / m_dGranularity);
-                if (m_ulBlocksWritten > ulNumBlocksPlayed)
-                {
- m_uNumToBePlayed = uNumBlocks = (UINT16) (m_ulBlocksWritten - ulNumBlocksPlayed);
-                }
-
- /* Now that m_ulMinimumPushdown can be set by the user, it is possible
-                 * for MIN_BLOCKS_TOBEQUEUED to be 0.
-                 */
-                if (uNumBlocks == 0 ||
-                    uNumBlocks < m_ulMinBlocksTobeQueued)
-                {
-                    bPlay = TRUE;
-                }
-            }
-        }
- HXLOGL4(HXLOG_ADEV, "CHXAudioSession[%p]::CheckToPlayMoreAudio(): block count = %lu (min to queue = %lu); play = '%s'", this, uNumBlocks, m_ulMinBlocksTobeQueued, bPlay ? "true" : "false");
-

simply becomes:

+        m_uNumToBePushed = uNumBlocks = GetBlocksRemainingToPlay();
+        bPlay = (uNumBlocks<m_ulMinBlocksTobeQueued) ? TRUE : FALSE;
+        HXLOGL4( HXLOG_ADEV,
+ "CHXAudioSession[%p]::CheckToPlayMoreAudio(): block count = %lu",
+                 this,
+                 uNumBlocks);


The rest of the changes are just general clean changes that should not
have any affect except on readability.

A few things left to do:

o CHXAudioDevice::NumberOfBlocksRemainingToPlay is not longer used by the core. So, we could go through and remove it to reduce image size in some of the platform audio code (assuming it isn't used internally by the platform).
o Same with IsWaveOutDevice(). We no longer use it.
o Granularities were originally designed to be set programmatically, but they have been hardcoded historically. We might look into the usefulness of removing the hardcoded value and letting it change for each clip depending on the audio pushdown set by the renderer. This would be required to get audio pushdown values less then 100ms (which is about our lowest pushdown we can do right now without audio glitches). This would also require more
  testing.


Files Modified
==============
    client/audiosvc/hxaudply.cpp
    audio/device/pub/hxaudev.h
    client/audiosvc/hxaudses.cpp
    client/audiosvc/pub/hxaudses.h


Branch(s)
=========
HEAD, 150Cay.


Image Size and Heap Use impact
==============================
Small reduction in image size, no heap changes.


Platforms and Profiles Affected
===============================
All platforms, all profiles.


Distribution Libraries affected
===============================
None.


Platforms and Profiles Build Verified
=====================================
Windows min heap. Linux/all-defines/min-heap.


Platforms and Profiles Functionality verified
=============================================
Windows min heap. Linux/all-defines/min-heap.


--greg.



Index: hxaudply.cpp
===================================================================
RCS file: /cvsroot/client/audiosvc/hxaudply.cpp,v
retrieving revision 1.36.2.6
diff -u -w -r1.36.2.6 hxaudply.cpp
--- hxaudply.cpp        3 May 2005 22:19:26 -0000       1.36.2.6
+++ hxaudply.cpp        16 Aug 2005 19:37:04 -0000
@@ -97,8 +97,7 @@
 #include "hxprefutil.h"
 #endif /* HELIX_FEATURE_PREFERENCES */

-#define MINIMUM_AUDIO_GRANULARITY       50
-#define MAXIMUM_AUDIO_GRANULARITY       100
+
#define MAX_WAIT_AT_SAME_TIME (MAXIMUM_AUDIO_GRANULARITY+50)

 CHXAudioPlayer::CHXAudioPlayer( CHXAudioSession* owner )


Index: pub/hxaudev.h
===================================================================
RCS file: /cvsroot/audio/device/pub/hxaudev.h,v
retrieving revision 1.11.6.1
diff -u -w -r1.11.6.1 hxaudev.h
--- pub/hxaudev.hernalCl5 May 2005 09:19:33 -0000       1.11.6.1
+++ pub/hxaudev.h       16 Aug 2005 19:30:19 -0000
@@ -59,11 +59,6 @@String("BEFORE CALL TO:Register\r\n");
 #  define kUSound            4
 #endif
        return HXR_OK;
-#ifdef HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES
-#define MINIMUM_AUDIO_PUSHDOWN    100RUE;
-#else  }
-#define MINIMUM_AUDIO_PUSHDOWN    1000
-#endifOutputDebugString("BEFORE CALL TO:CreateWindow\r\n");
     // Now create an instance of the window


Index: hxaudses.cpp
===================================================================
RCS file: /cvsroot/client/audiosvc/hxaudses.cpp,v
retrieving revision 1.52.2.11
diff -u -w -r1.52.2.11 hxaudses.cpp
--- hxaudses.cpp        9 Jun 2005 17:03:19 -0000       1.52.2.11
+++ hxaudses.cpp        16 Aug 2005 20:27:47 -0000
@@ -66,13 +66,9 @@
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-
 #if defined (_WINDOWS) || defined (_WIN32)
-
 #include <io.h>
-
 #endif
-
 #endif

 //#include "racodec.h"
@@ -125,15 +121,6 @@
 static const char HX_THIS_FILE[] = __FILE__;
 #endif

-#if defined(HELIX_FEATURE_MIN_HEAP)
-#define MINIMUM_AUDIO_STARTUP_PUSHDOWN  200 //ms
-#define CHECK_AUDIO_INTERVAL            40  //%
-#else
-#define MINIMUM_AUDIO_STARTUP_PUSHDOWN  100 //ms
-#define CHECK_AUDIO_INTERVAL            90  //%
-#endif
-
-
 #define SOME_INSANELY_LARGE_VALUE       3600000 /* 1 hour */

 #ifdef _WIN32
@@ -643,20 +630,18 @@
     {
ReadPrefUINT32(m_pPreferences, "MinimumAudioPushdown", m_ulMinimumPushdown); ReadPrefUINT32(m_pPreferences, "MinimumAudioStartupInitalPushdown", m_ulMinimumStartupPushdown); + ReadPrefUINT32(m_pPreferences, "CheckAudioPct", m_nPercentage);
+    }
+#endif /* HELIX_FEATURE_PREFERENCES */

         if (m_ulMinimumStartupPushdown > m_ulMinimumPushdown)
         {
             m_ulMinimumPushdown = m_ulMinimumStartupPushdown;
         }
HXLOGL3(HXLOG_ADEV, "CHXAudioSession[%p]::Init(): min audio push = %lu; min startup = %lu ", this, m_ulMinimumPushdown, m_ulMinimumStartupPushdown);
-    }
-
-    ReadPrefUINT32(m_pPreferences, "CheckAudioPct", m_nPercentage);
HXLOGL2(HXLOG_ADEV, "Setting callback granulatiry percentage to %d", m_nPercentage );


-#endif /* HELIX_FEATURE_PREFERENCES */
-
     // Create a device volume interface.
     if ( !theErr )
     {
@@ -2942,7 +2927,9 @@
     m_ulMinimumPushdown = ulMinimumPushdown;
     UpdateMinimumPushdown();

- HXLOGL3(HXLOG_ADEV, "CHXAudioSession[%p]::SetAudioPushdown(): push down = %lu", this, ulMinimumPushdown);
+    HXLOGL3(HXLOG_ADEV,
+ "CHXAudioSession[%p]::SetAudioPushdown(): push down = %lu",
+            this, ulMinimumPushdown);
     return HXR_OK;
 }

@@ -2972,38 +2959,38 @@
CHXAudioSession::GetCurrentAudioDevicePushdown(REF(UINT32) /*OUT*/ ulAudioPusheddown)
 {
     HX_RESULT   rc = HXR_OK;
-    UINT16      uNumBlocks = 0;
-    UINT32      ulNumBlocksPlayed = 0;
-    UINT32      ulCurTime = 0;

     ulAudioPusheddown = 0;

-    if (m_bToBeReOpened || !m_pAudioDev)
+    if( !m_bToBeReOpened && m_pAudioDev )
     {
-        goto cleanup;
+ ulAudioPusheddown = (UINT32)(GetBlocksRemainingToPlay() * m_dGranularity);
     }

- if ( (!m_bReplacedDev) && (((CHXAudioDevice*)m_pAudioDev)->IsWaveOutDevice()) )
-    {
- uNumBlocks = ((CHXAudioDevice*)m_pAudioDev)->NumberOfBlocksRemainingToPlay();
+    return rc;
     }
-    else
+
+// We no longer use CHXAudioDevice::NumberOfBlocksRemainingToPlay() to
+// determine how much data is left in the audio device. Not only did
+// we have the problem of differences on how it was calculated between +// different platforms but each platform already has to give back very
+// accurate timeline information. Since we keep track of how many
+// blocks we have written, we just use that and the current playback
+// time to determine how much data is down in the device.
+ULONG32 CHXAudioSession::GetBlocksRemainingToPlay()
     {
+    ULONG32 ulRetVal        = 0;
+    ULONG32 ulBlocksPlayed  = 0;
+    ULONG32 ulCurTime       = 0;
         if (m_pAudioDev->GetCurrentAudioTime(ulCurTime) == HXR_OK)
         {
- ulNumBlocksPlayed = (UINT32) ((double) ulCurTime / m_dGranularity);
-            if (m_ulBlocksWritten > ulNumBlocksPlayed)
+        ulBlocksPlayed = (ULONG32)(ulCurTime/m_dGranularity+.5);
+        if( m_ulBlocksWritten>ulBlocksPlayed )
             {
- uNumBlocks = (UINT16) (m_ulBlocksWritten - ulNumBlocksPlayed);
+            ulRetVal = m_ulBlocksWritten-ulBlocksPlayed;
             }
         }
-    }
-
-    ulAudioPusheddown = (UINT32)(uNumBlocks * m_dGranularity);
-
-cleanup:
-
-    return rc;
+    return ulRetVal;
 }

/*************************************************************
***********
@@ -3129,39 +3116,35 @@
     return theErr;
 }

-void
-CHXAudioSession::UpdateMinimumPushdown()
+void CHXAudioSession::UpdateMinimumPushdown()
 {
+    //This is called whenever the granularity or audio pushdown
+    //changes.  In this method we need to make sure that the
+    //granularity is results in at least 2 blocks being the min
+    //pushdown. If we are left with only one block, it can be hard to
+    //prevent underflow in the audio device. You don't have to
+    //increase the amount of PCM pushdown, just decrease the
+    //granularity.
     if (m_ulGranularity)
     {
- m_ulMinBlocksTobeQueued = (UINT32) (m_ulMinimumPushdown*1.0/m_ulGranularity);
-        if ((m_ulMinBlocksTobeQueued == 0) ||
- (m_ulMinBlocksTobeQueued*m_ulGranularity < m_ulMinimumPushdown))
-        {
-            m_ulMinBlocksTobeQueued++;
-        }
-
- if ((m_ulMinBlocksTobeQueued * m_ulGranularity) >= m_ulMinimumStartupPushdown)
-        {
- m_ulMinBlocksTobeQueuedAtStart = (UINT32) (m_ulMinimumStartupPushdown*1.0/m_ulGranularity);
-        }
-        else
-        {
-            m_ulMinBlocksTobeQueuedAtStart = m_ulMinBlocksTobeQueued;
-        }
+        //Basically, integer versions of 'ceil' function.
+ m_ulMinBlocksTobeQueued = (m_ulMinimumPushdown+m_ulGranularity-1)/m_ulGranularity; + m_ulMinBlocksTobeQueuedAtStart = (m_ulMinimumStartupPushdown+m_ulGranularity-1)/m_ulGranularity;

 #if defined(HELIX_FEATURE_PREFERENCES)
-        IHXBuffer* pBuffer = NULL;
-        if (m_pPreferences &&
- m_pPreferences->ReadPref("RestoreMinimumPushdown", pBuffer) == HXR_OK &&
-            pBuffer &&
-            ::atoi((char*) pBuffer->GetBuffer()) == 1)
+        HXBOOL bRestore = FALSE;
+ ReadPrefBOOL( m_pPreferences, "RestoreMinimumPushdown", bRestore );
+        if( bRestore)
         {
m_ulMinBlocksTobeQueuedAtStart = m_ulMinBlocksTobeQueued;
         }
+#endif

-        HX_RELEASE(pBuffer);
-#endif /* HELIX_FEATURE_PREFERENCES */
+        //Invarients to ensure glitch free audio playback.
+        HX_ASSERT( m_ulGranularity <= m_ulMinimumPushdown/2 );
+        HX_ASSERT( m_ulMinBlocksTobeQueued>1 );
+ HX_ASSERT( m_ulMinBlocksTobeQueued >= m_ulMinBlocksTobeQueuedAtStart ); + HX_ASSERT( m_ulMinimumPushdown >= m_ulMinimumStartupPushdown );
     }
 }

@@ -3527,65 +3510,17 @@
     }
     else
     {
- if ( (!m_bReplacedDev) && (((CHXAudioDevice*)m_pAudioDev)->IsWaveOutDevice()) )
-        {
- m_uNumToBePlayed = uNumBlocks = ((CHXAudioDevice*)m_pAudioDev)->NumberOfBlocksRemainingToPlay();
-
-
-
- /* Now that m_ulMinimumPushdown can be set by the user, it is possible
-             * for MIN_BLOCKS_TOBEQUEUED to be 0.
-             */
-            if (uNumBlocks == 0 ||
-                uNumBlocks < m_ulMinBlocksTobeQueued)
-            {
-                bPlay = TRUE;
-            }
-        }
-        else
-        {
-            ULONG32 ulCurTime = 0;
- if (m_pAudioDev->GetCurrentAudioTime(ulCurTime) == HXR_OK)
-            {
- UINT32 ulNumBlocksPlayed = (UINT32) ((double) ulCurTime / m_dGranularity);
-                if (m_ulBlocksWritten > ulNumBlocksPlayed)
-                {
- m_uNumToBePlayed = uNumBlocks = (UINT16) (m_ulBlocksWritten - ulNumBlocksPlayed);
-                }
-
- /* Now that m_ulMinimumPushdown can be set by the user, it is possible
-                 * for MIN_BLOCKS_TOBEQUEUED to be 0.
-                 */
-                if (uNumBlocks == 0 ||
-                    uNumBlocks < m_ulMinBlocksTobeQueued)
-                {
-                    bPlay = TRUE;
-                }
-            }
-        }
- HXLOGL4(HXLOG_ADEV, "CHXAudioSession[%p]::CheckToPlayMoreAudio(): block count = %lu (min to queue = %lu); play = '%s'", this, uNumBlocks, m_ulMinBlocksTobeQueued, bPlay ? "true" : "false");
-
+        m_uNumToBePushed = uNumBlocks = GetBlocksRemainingToPlay();
+        bPlay = (uNumBlocks<m_ulMinBlocksTobeQueued) ? TRUE : FALSE;
+        HXLOGL4( HXLOG_ADEV,
+ "CHXAudioSession[%p]::CheckToPlayMoreAudio(): block count = %lu",
+                 this,
+                 uNumBlocks);
     }

     if (bPlay)
     {
HX_ASSERT(!m_pAudioDev || m_ulMinBlocksTobeQueued > uNumBlocks);
-        /* Currently we break transcoding feature of jukwbox because:
-         * - overriden audio device plays much faster than realtime
- * - mp3 datatype does not implement drynotification interface. - * - we therefore play silence instead of halting the timeline
-         *   when we run out of data.
-         *
-         * Patch: revert back to old behavior: i.e. push only one
-         * block at a time for replaced audio device
-         *
- * correct fix: We should fix mp3 renderer to support drynotification
-         *
-         * XXXRA
-         *
- * Update Removing this hack for replaced devices since MP3 renderer
-         * now supports dry notification. -- RA 07/18/01:
-         */
         if (m_pAudioDev && m_ulMinBlocksTobeQueued > uNumBlocks)
         {
uNumBlocks = (UINT16) m_ulMinBlocksTobeQueued - uNumBlocks;
@@ -4138,7 +4073,7 @@
HXLOGL2( "IsRebufferRequired: num: %d start: %lu numblk()=%d",
                  m_uNumToBePlayed,
                  m_ulMinBlocksTobeQueuedAtStart,
- ((CHXAudioDevice*)m_pAudioDev)->NumberOfBlocksRemainingToPlay());
+                 GetBlocksRemainingToPlay());
     }

     return bRetVal;
Index: pub/hxaudses.h
===================================================================
RCS file: /cvsroot/client/audiosvc/pub/hxaudses.h,v
retrieving revision 1.18.6.2
diff -u -w -r1.18.6.2 hxaudses.h
--- pub/hxaudses.h      5 May 2005 09:33:29 -0000       1.18.6.2
+++ pub/hxaudses.h      16 Aug 2005 20:27:47 -0000
@@ -63,6 +63,52 @@
 #  define TLW_CLOSE    3
 #  define TLW_TIMESYNC 4

+
+// These defines control how much audio PCM data we push down into the +// audio device. MINIMUM_AUDIO_STARTUP_PUSHDOWN determines how much we
+// push before calling Resume() on the device (and starting playback)
+// and MINIMUM_AUDIO_PUSHDOWN determines how much PCM data we push
+// down during steady state playback. It is also important that the
+// granularity be less then or equal to MINIMUM_AUDIO_PUSHDOWN/2. If
+// not, underflows could result because only 1 block will be in the
+// audio device at any given time. Currently MINIMUM_AUDIO_GRANULARITY
+// is not used. In CHXAudioPlayer::Setup() hardcodes this:
+//
+//     m_ulGranularity = MAXIMUM_AUDIO_GRANULARITY;
+//
+// The CHECK_AUDIO_INTERVAL define tells the audio session how often
+// to check how much data we have pushed down in the audio device.
+// for min heap builds it is more important to check often because we
+// have very few blocks pushed down at any one time. The value for
+// this define is a percentage (0-100) of the granularity in
+// milliseconds. IE, 40 means 40% of whatever granulatiry is in use.
+//
+#ifdef HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES
+#  define MINIMUM_AUDIO_GRANULARITY       50
+#  define MAXIMUM_AUDIO_GRANULARITY       MINIMUM_AUDIO_GRANULARITY
+#  define MINIMUM_AUDIO_PUSHDOWN          100
+#  define MINIMUM_AUDIO_STARTUP_PUSHDOWN  MINIMUM_AUDIO_PUSHDOWN
+#  define CHECK_AUDIO_INTERVAL            40
+#else
+#  define MINIMUM_AUDIO_GRANULARITY       50
+#  define MAXIMUM_AUDIO_GRANULARITY       100
+#  define MINIMUM_AUDIO_PUSHDOWN          1000
+#  define MINIMUM_AUDIO_STARTUP_PUSHDOWN  100
+#  define CHECK_AUDIO_INTERVAL            90
+#endif
+


@@ -349,9 +395,7 @@
      */
virtual HX_RESULT CreateAudioPlayer(CHXAudioPlayer** ppAudioPlayer); HX_RESULT _CreateAudioPlayer(CHXAudioPlayer** ppAudioPlayer);
-
HX_RESULT CloseAudioPlayer( CHXAudioPlayer* pAudioPlayer);
-
     void            Close(void);

     /* The session object determines the audio device format based
@@ -362,7 +406,6 @@
     /* Open is called to open the audio device.
      */
     HX_RESULT       OpenAudio    (void);
-
     HX_RESULT       OpenDevice   (void);

     /* PlayAudio is called by Audio Player object.
@@ -383,8 +426,7 @@

     /* Seek is called by Audio Player object.
      */
-    HX_RESULT       Seek    (
-        CHXAudioPlayer* pPlayerToExclude,
+    HX_RESULT       Seek ( CHXAudioPlayer* pPlayerToExclude,
         const UINT32    ulSeekTime
         );

@@ -518,9 +560,10 @@
     friend class CHXAudioSession::HXDeviceSetupCallback;
   protected:
     ~CHXAudioSession(void);
-
     void _ConstructIfNeeded();

+    ULONG32 GetBlocksRemainingToPlay();
+
   private:

 #ifdef _MACINTOSH
@@ -606,8 +649,7 @@
     /* CheckAudioFormat Interface is called by audio player to
      * check resample audio format with audio device format.
      */
-    HX_RESULT               CheckAudioFormat(
-        HXAudioFormat* pAudioFormat );
+    HX_RESULT CheckAudioFormat( HXAudioFormat* pAudioFormat );

     /* Create the playback buffer.
      */
@@ -619,8 +661,7 @@


     /* Write audio data to post mix hooks. */
-    HX_RESULT               ProcessPostMixHooks(
-        CHXAudioPlayer* pPlayer,
+    HX_RESULT ProcessPostMixHooks( CHXAudioPlayer* pPlayer,
         IHXBuffer*&    pInBuffer,
         BOOL*           bDisableWrite,
         UINT32          ulBufTime,
@@ -631,7 +672,6 @@

     /* Convert 16-bit buffer to 8-bit */
     void                    ConvertToEight(void);
-
     BOOL                    IsAudioOnlyTrue(void);

     UINT32                  AnchorDeviceTime(UINT32 ulCurTime);


_______________________________________________
Audio-dev mailing list
Audio-dev@helixcommunity.org
http://lists.helixcommunity.org/mailman/listinfo/audio-dev





_______________________________________________
Audio-dev mailing list
Audio-dev@helixcommunity.org
http://lists.helixcommunity.org/mailman/listinfo/audio-dev

Reply via email to