GetPositionSeconds(&tm) returns the clock time timestamp associated with the
returned sound time. This is tricky: we may be interrupted, causing timing error. We tried working around this by trying to hint the scheduler that we're in a period where we don't want to be interrupted, even though we're in a thread that's not normally high priority, by boosting the priority temporarily. This worked in Windows, but not in general; it's too far out of the expectations of schedulers and generally just made things worse. Let's look at this like an interruption-based lockless algorithm: try it, see if it succeeded, and if it failed, try again. Retrying even once should be a rare exception, but failsafe anyway, so a bug in a sound driver won't hang.
This commit is contained in:
@@ -26,7 +26,6 @@
|
|||||||
#include "RageUtil.h"
|
#include "RageUtil.h"
|
||||||
#include "RageLog.h"
|
#include "RageLog.h"
|
||||||
#include "PrefsManager.h"
|
#include "PrefsManager.h"
|
||||||
#include "arch/ArchHooks/ArchHooks.h"
|
|
||||||
#include "RageSoundUtil.h"
|
#include "RageSoundUtil.h"
|
||||||
|
|
||||||
#include "RageSoundReader_Pan.h"
|
#include "RageSoundReader_Pan.h"
|
||||||
@@ -656,18 +655,40 @@ float RageSound::GetPositionSeconds( bool *bApproximate, RageTimer *pTimestamp )
|
|||||||
{
|
{
|
||||||
LockMut( m_Mutex );
|
LockMut( m_Mutex );
|
||||||
|
|
||||||
if( pTimestamp )
|
if( pTimestamp == NULL )
|
||||||
{
|
{
|
||||||
HOOKS->EnterTimeCriticalSection();
|
const int64_t iPositionFrames = GetPositionSecondsInternal( bApproximate );
|
||||||
pTimestamp->Touch();
|
return iPositionFrames / float(samplerate());
|
||||||
}
|
}
|
||||||
|
|
||||||
const int64_t iPositionFrames = GetPositionSecondsInternal( bApproximate );
|
/*
|
||||||
const float fPosition = iPositionFrames / float(samplerate());
|
* We may have unpredictable scheduling delays between updating the timestamp
|
||||||
if( pTimestamp )
|
* and reading the sound position. If we're preempted while doing this and
|
||||||
HOOKS->ExitTimeCriticalSection();
|
* it may have caused the timestamp to not match the returned time, retry.
|
||||||
|
*
|
||||||
|
* As a failsafe, only allow a few attempts. If this has to try more than
|
||||||
|
* a few times, then probably we have thread contention that's causing more
|
||||||
|
* severe performance problems, anyway.
|
||||||
|
*/
|
||||||
|
int iTries = 3;
|
||||||
|
int64_t iPositionFrames;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
pTimestamp->Touch();
|
||||||
|
iPositionFrames = GetPositionSecondsInternal( bApproximate );
|
||||||
|
} while( --iTries && pTimestamp->Ago() > 0.002f );
|
||||||
|
|
||||||
return fPosition;
|
if( iTries == 0 )
|
||||||
|
{
|
||||||
|
static bool bLogged = false;
|
||||||
|
if( !bLogged )
|
||||||
|
{
|
||||||
|
bLogged = true;
|
||||||
|
LOG->Warn( "RageSound::GetPositionSeconds: too many tries" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return iPositionFrames / float(samplerate());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user