Modified by: d...@real.com
Date: 7/7/2009
Project: RealPlayer for Netbook
Synopsis:
Imlemented New Helix Audio Device Simple Fake Timeline And Drift
Detection
Overview:
When I was "bootstrapping" PulseAudio support implementation,
I wanted to test pushing of audio data, pa_xxxxxx_write(),
before I knew how accurate audio timing can be implemented.
So, I needed fake timeline support to drive the (rest of the)
Helix client engine to make available audio data
to enable the push model.
However, I found that if a clip contains an audio stream (necessary),
it is very difficult to get the Original Helix Fake Timeline support
working.
It is impossible to fake the audio timing
by incrementing it by a constant.
So, this HX_GET_TICKCOUNT() based fake timeline is necessary
to bootstrap an audio device support implementation.
New Helix Audio Device Simple Fake Timeline:
--------------------------------------------
I documented this New Helix Audio Device Simple Fake Timeline here:
https://audio.helixcommunity.org/2009/devdocs/HelixAudioDeviceFakeTimeline
To compile this New Helix Audio Device Simple Fake Timeline support
into hxmedplyeng, the macro:
HELIX_FEATURE_FAKE_AUDIO_DEVICE_TIMELINE
must be defined
In scenarios where this New Helix Audio Device Simple Fake Timeline
is useful, it can be turned on by setting the following Helix
Preference:
FakeHelixAudioDeviceTimeline=1
Drift Detection:
----------------
Even when this New Helix Audio Device Simple Fake Timeline
isn't turned on (the default):
FakeHelixAudioDeviceTimeline=0
this implementation offers actual audio device timeline drift
detection,
by comparing the actual audio device timeline against
HX_GET_TICKCOUNT().
If a full second of timeline drift is detected
(which will prevent playback from functioning normally),
a throttled message is shown (in the terminal).
A seek operation will restart the drift detection and
playback often recovers (from the stuck timeline.)
Files Modified:
audio/device/platform/unix/audUnix.cpp
audio/device/pub/platform/unix/audUnix.h
Image Size and Heap Use impact (Client -Only):
None.
Platforms and Profiles Affected:
Linux
Distribution Libraries Affected:
None.
Distribution library impact and planned action:
None.
Platforms and Profiles Build Verified:
Profile: helix_client_moblin
Platform: linux-2.2-libc6-gcc32-i586
Platforms and Profiles Functionality verified:
Profile: helix_client_moblin
Platform: linux-2.2-libc6-gcc32-i586
Branch: 347Atlas, 310Atlas.
Copyright assignment: I am a RealNetworks employee.
--
Daniel Yek.
Index: audio/device/platform/unix/audUnix.cpp
===================================================================
RCS file: /cvsroot/audio/device/platform/unix/audUnix.cpp,v
retrieving revision 1.12.2.3.14.1
diff -u -w -r1.12.2.3.14.1 audUnix.cpp
--- audio/device/platform/unix/audUnix.cpp 29 Jan 2009 09:57:09
-0000 1.12.2.3.14.1
+++ audio/device/platform/unix/audUnix.cpp 22 Jun 2009 23:13:51 -0000
@@ -69,15 +69,16 @@
#include <errno.h>
-#if defined(_THREADED_AUDIO) && defined(_UNIX_THREADS_SUPPORTED)
#include "hxprefs.h"
-#endif
+#include "hxprefutil.h"
#include "hxtlogutil.h"
#include "ihxtlogsystem.h"
#include "baseobj.h"
#include "nestbuff.h"
+#include "thrdutil.h"
+
//-1 is usually considered to be no file descriptor.
const int CAudioOutUNIX::NO_FILE_DESCRIPTOR = -1;
@@ -96,16 +100,22 @@
m_pPlaybackCountCBTime(0),
m_PendingCallbackID (0),
m_bCallbackPending(FALSE),
+#ifdef HELIX_FEATURE_FAKE_AUDIO_DEVICE_TIMELINE
+ m_bEnableFakeHelixAudioDeviceTimeline(FALSE),
+ m_ulFakeHelixAudioDeviceStartTime(0),
+ m_ulFakeHelixAudioDeviceCurrentTime(0),
+ m_ulTimelinesDeltaSecs(0),
+#endif // HELIX_FEATURE_FAKE_AUDIO_DEVICE_TIMELINE
m_pWriteList(NULL),
m_wLastError( RA_AOE_NOERR ),
m_ulDeviceBufferSize(0),
m_pRollbackBuffer(NULL),
@@ -521,18 +587,19 @@
m_wState = RA_AOS_OPEN_PLAYING;
UNLOCK(m_mtxWriteListPlayStateLock);
- //XXXgfw If the two branches of the if are the same maybe get
rid of one????
- if( !_HardwarePauseSupported() )
+#ifdef HELIX_FEATURE_FAKE_AUDIO_DEVICE_TIMELINE
+ // No harm setting.
+ m_ulFakeHelixAudioDeviceStartTime = HX_GET_TICKCOUNT();
+ m_ulTimelinesDeltaSecs = 0;
+
+ if (m_pContext)
{
- _Resume();
- _Imp_Write(NULL);
+ ReadPrefBOOL(m_pContext, "FakeHelixAudioDeviceTimeline",
m_bEnableFakeHelixAudioDeviceTimeline);
}
- else
- {
- //The hardware device handles the Pause/Resume.
+#endif // HELIX_FEATURE_FAKE_AUDIO_DEVICE_TIMELINE
+
_Resume();
_Imp_Write(NULL);
- }
m_wLastError = HXR_OK;
return m_wLastError;
@@ -560,6 +627,10 @@
m_ulLastNumBytes = 0;
}
+#ifdef HELIX_FEATURE_FAKE_AUDIO_DEVICE_TIMELINE
+ m_ulTimelinesDeltaSecs = 0;
+#endif // HELIX_FEATURE_FAKE_AUDIO_DEVICE_TIMELINE
+
m_wLastError = retCode;
return m_wLastError;
}
@@ -607,6 +678,77 @@
return m_wLastError;
}
+
+#ifdef HELIX_FEATURE_FAKE_AUDIO_DEVICE_TIMELINE
+
+// Time unit: msec.
+HX_RESULT CAudioOutUNIX::_Imp_GetCurrentTime( ULONG32&
ulCurrentTime )
+{
+ if (m_bEnableFakeHelixAudioDeviceTimeline)
+ {
+ // When Helix Preference, FakeHelixAudioDeviceTimeline, is
set to 1,
+ // Helix Audio Device fake timeline feature is enabled.
+ ulCurrentTime = m_ulFakeHelixAudioDeviceCurrentTime =
(HX_GET_TICKCOUNT() - m_ulFakeHelixAudioDeviceStartTime);
+
+ HXLOGL4 (HXLOG_ADEV, "CAudioOutUNIX::_Imp_GetCurrentTime()
= %i.", ulCurrentTime);
+
+ m_wLastError = HXR_OK;
+ return HXR_OK;
+ }
+ else
+ {
+ ULONG32 ulTime = 0;
+ UINT64 ulBytes = 0;
+
+ // Locking WriteListPlayStateLock first appears to cause
deadlock in PulseAudio mainloop lock.
+ //LOCK(m_mtxWriteListPlayStateLock);
+ ulBytes = _GetBytesActualyPlayed();
+ //UNLOCK(m_mtxWriteListPlayStateLock);
+
+ ulTime = (ULONG32)(( ( (double)ulBytes/(double)
m_uSampFrameSize)/(double)m_unSampleRate) * 1000.0 / (double)
m_unNumChannels);
+
+ // XXXdyek:
+ // When Helix Preference, FakeHelixAudioDeviceTimeline, is
set to 0,
+ // Helix Audio Device fake-timeline feature is disabled.
+ // However, in this case, the feature implements checking of
+ // timeline from real sound card driver
+ // against HX_GET_TICKCOUNT() reference.
+ // This enables easy runtime troubleshooting of timing
information from sound card driver.
+ // This is likely to produce noise if PlaybackVelocity is
used.
+ // To disable check once PlaybackVelocity is employed.
+ UINT32 delta_secs = 0;
+ m_ulFakeHelixAudioDeviceCurrentTime = (HX_GET_TICKCOUNT() -
m_ulFakeHelixAudioDeviceStartTime);
+
+ delta_secs = abs(ulTime -
m_ulFakeHelixAudioDeviceCurrentTime) / 1000 ;
+
+ if (!m_ulTimelinesDeltaSecs)
+ {
+ m_ulTimelinesDeltaSecs = delta_secs; // Suppress
messages for pause and resume.
+ }
+
+ if ( delta_secs > m_ulTimelinesDeltaSecs &&
+ ulTime // Avoid the spurious case where
m_ulTimelinesDeltaSecs isn't reset in _Imp_Resume() yet.
+ )
+ {
+ fprintf(stderr, "Audio time line drifted %lu secs. from
%lu ms to %lu ms\n", delta_secs,
m_ulFakeHelixAudioDeviceCurrentTime, ulTime);
+ HXLOGL2 (HXLOG_ADEV, "CAudioOutUNIX::_Imp_GetCurrentTime
() Audio time line drifted %lu secs. from %lu ms to %lu ms",
delta_secs, m_ulFakeHelixAudioDeviceCurrentTime, ulTime);
+ m_ulTimelinesDeltaSecs = delta_secs;
+ }
+
+ // Not used anywhere but belongs to CHXAudioDevice so we
must set it.
+ m_ulCurrentTime = ulTime;
+
+ // Set the answer.
+ ulCurrentTime = ulTime;
+
+ m_wLastError = HXR_OK;
+ return HXR_OK;
+ }
+}
+
+#else // HELIX_FEATURE_FAKE_AUDIO_DEVICE_TIMELINE
+
+// Original implementation.
HX_RESULT CAudioOutUNIX::_Imp_GetCurrentTime( ULONG32& ulCurrentTime )
{
ULONG32 ulTime = 0;
@@ -629,6 +771,9 @@
}
+#endif // HELIX_FEATURE_FAKE_AUDIO_DEVICE_TIMELINE
+
+
void CAudioOutUNIX::DoTimeSyncs()
{
ReschedPlaybackCheck();
Index: audio/device/pub/platform/unix/audUnix.h
===================================================================
RCS file: /cvsroot/audio/device/pub/platform/unix/audUnix.h,v
retrieving revision 1.8.2.2.14.1
diff -u -w -r1.8.2.2.14.1 audUnix.h
--- audio/device/pub/platform/unix/audUnix.h 29 Jan 2009 10:08:57
-0000 1.8.2.2.14.1
+++ audio/device/pub/platform/unix/audUnix.h 22 Jun 2009 23:13:51
-0000
@@ -256,6 +265,18 @@
ULONG32 m_PendingCallbackID; // Used for fake time
sync
HXBOOL m_bCallbackPending; // Used for fake time
sync
+
+#ifdef HELIX_FEATURE_FAKE_AUDIO_DEVICE_TIMELINE
+ // Used to implement fake Helix Audio Device Timeline.
+ // This implementation allows easy identification of
+ // broken timing information in sound card driver.
+ HXBOOL m_bEnableFakeHelixAudioDeviceTimeline;
+ UINT32 m_ulFakeHelixAudioDeviceStartTime;
+ UINT32 m_ulFakeHelixAudioDeviceCurrentTime;
+ UINT32 m_ulTimelinesDeltaSecs; // Compare actual
time line with fake Helix Audio Device timeline
+
+#endif // HELIX_FEATURE_FAKE_AUDIO_DEVICE_TIMELINE
+
CHXSimpleList* m_pWriteList;
UINT32 m_unSampleRate;
UINT32 m_unNumChannels;
_______________________________________________
Audio-dev mailing list
Audio-dev@helixcommunity.org
http://lists.helixcommunity.org/mailman/listinfo/audio-dev