void PAPlayer::Process() { if (!m_startEvent.WaitMSec(100)) { CLog::Log(LOGDEBUG, "PAPlayer::Process - Failed to receive start event"); return; } CLog::Log(LOGDEBUG, "PAPlayer::Process - Playback started"); while(m_isPlaying && !m_bStop) { /* this needs to happen outside of any locks to prevent deadlocks */ if (m_signalSpeedChange) { m_callback.OnPlayBackSpeedChanged(m_playbackSpeed); m_signalSpeedChange = false; } double delay = 100.0; double buffer = 100.0; ProcessStreams(delay, buffer); double watermark = buffer * 0.5; if (delay < buffer && delay > watermark) CThread::Sleep(MathUtils::round_int((delay - watermark) * 1000.0)); GetTimeInternal(); //update for GUI } }
void PAPlayer::Process() { if (!m_startEvent.WaitMSec(100)) { CLog::Log(LOGDEBUG, "PAPlayer::Process - Failed to receive start event"); return; } CLog::Log(LOGDEBUG, "PAPlayer::Process - Playback started"); while(m_isPlaying && !m_bStop) { /* this needs to happen outside of any locks to prevent deadlocks */ if (m_signalSpeedChange) { m_callback.OnPlayBackSpeedChanged(m_playbackSpeed); m_signalSpeedChange = false; } double freeBufferTime = 0.0; ProcessStreams(freeBufferTime); // if none of our streams wants at least 10ms of data, we sleep if (freeBufferTime < 0.01) { CThread::Sleep(10); } GetTimeInternal(); //update for GUI } if(m_isFinished && !m_bStop) m_callback.OnPlayBackEnded(); else m_callback.OnPlayBackStopped(); }
static void CALLBACK AdvisePeriodicCallback (UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) { HANDLE hSemaphore = (HANDLE)dwUser; UINT startTime = *((UINT*)hSemaphore); if((LONGLONG)startTime * 10000 - GetTimeInternal() < 0) return; // not yet ReleaseSemaphore(hSemaphore, 1, nullptr); }
static HRESULT STDMETHODCALLTYPE MyGetTime (IReferenceClock* pThis, REFERENCE_TIME *pTime) { //return GetTime(pThis, pTime); if(!pTime) return E_POINTER; *pTime = GetTimeInternal(); debuglog(LCF_TIMERS|LCF_TIMEGET|LCF_FREQUENT, __FUNCTION__ " called (%d).\n", (DWORD)*pTime); return S_OK; }
static HRESULT STDMETHODCALLTYPE MyGetTime(IReferenceClock* pThis, REFERENCE_TIME *pTime) { //return GetTime(pThis, pTime); if (!pTime) return E_POINTER; *pTime = GetTimeInternal(); ENTER(*pTime); return S_OK; }
void PAPlayer::Process() { if (!m_startEvent.WaitMSec(100)) { CLog::Log(LOGDEBUG, "PAPlayer::Process - Failed to receive start event"); return; } CLog::Log(LOGDEBUG, "PAPlayer::Process - Playback started"); while(m_isPlaying && !m_bStop) { /* this needs to happen outside of any locks to prevent deadlocks */ if (m_signalSpeedChange) { m_callback.OnPlayBackSpeedChanged(m_playbackSpeed); m_signalSpeedChange = false; } double delay = 100.0; double buffer = 100.0; ProcessStreams(delay, buffer); double watermark = buffer * 0.5; #if defined(TARGET_DARWIN) // In CoreAudio the delay can be bigger then the buffer // because of delay from the HAL/Hardware // This is the case when the buffer is full (e.x. 1 sec) // and there is a HAL-Delay. In that case we would never sleep // but load one cpu core up to 100% (happens on osx/ios whenever // the first stream is finished and a prebuffered second stream // starts to play. A BIG FIXME HERE. if ((delay < buffer || buffer == 1) && delay > watermark) #else if ((delay < buffer) && delay > watermark) #endif CThread::Sleep(MathUtils::round_int((delay - watermark) * 1000.0)); GetTimeInternal(); //update for GUI } // wait for any pending jobs to complete { CSharedLock lock(m_streamsLock); while (m_jobCounter > 0) { lock.Leave(); m_jobEvent.WaitMSec(100); lock.Enter(); } } if(m_isFinished && !m_bStop) m_callback.OnPlayBackEnded(); else m_callback.OnPlayBackStopped(); }
void PAPlayer::SeekTime(int64_t iTime /*=0*/) { if (!CanSeek()) return; CSharedLock lock(m_streamsLock); if (!m_currentStream) return; int seekOffset = (int)(iTime - GetTimeInternal()); if (m_playbackSpeed != 1) ToFFRW(1); m_currentStream->m_seekFrame = (int)((float)m_currentStream->m_sampleRate * ((float)iTime + (float)m_currentStream->m_startOffset) / 1000.0f); m_callback.OnPlayBackSeek((int)iTime, seekOffset); }
static HRESULT STDMETHODCALLTYPE MyAdviseTime (IReferenceClock* pThis, REFERENCE_TIME rtBaseTime, REFERENCE_TIME rtStreamTime, HANDLE hEvent, LPDWORD pdwAdviseCookie) { debuglog(LCF_TIMERS, __FUNCTION__ "(rtBaseTime=%d, rtStreamTime=%d) called.\n", (DWORD)(rtBaseTime/10000), (DWORD)(rtStreamTime/10000)); //return AdviseTime(pThis, rtBaseTime, rtStreamTime, hEvent, pdwAdviseCookie); REFERENCE_TIME time = rtBaseTime + rtStreamTime; // if((ULONGLONG)time >= 86400000L) // return E_INVALIDARG; if(!pdwAdviseCookie) return E_POINTER; time -= GetTimeInternal(); time /= 10000; *pdwAdviseCookie = (DWORD)MytimeSetEvent((UINT)time, 0, (LPTIMECALLBACK)hEvent, 0, TIME_ONESHOT | TIME_CALLBACK_EVENT_SET); if(!*pdwAdviseCookie) return E_OUTOFMEMORY; return S_OK; }
static HRESULT STDMETHODCALLTYPE MyAdvisePeriodic (IReferenceClock* pThis, REFERENCE_TIME rtStartTime, REFERENCE_TIME rtPeriodTime, HANDLE hSemaphore, LPDWORD pdwAdviseCookie) { debuglog(LCF_TIMERS|LCF_DESYNC|LCF_UNTESTED, __FUNCTION__ "(rtStartTime=%d, rtPeriodTime=%d) called.\n", (DWORD)(rtStartTime/10000), (DWORD)(rtPeriodTime/10000)); return AdvisePeriodic(pThis, rtStartTime, rtPeriodTime, hSemaphore, pdwAdviseCookie); // following is NYI (or at least, not tested so it's probably broken) // if((ULONGLONG)rtStartTime >= 86400000L) // return E_INVALIDARG; if(!pdwAdviseCookie || !hSemaphore) return E_POINTER; rtStartTime -= GetTimeInternal(); rtStartTime /= 10000; rtPeriodTime /= 10000; *((UINT*)hSemaphore) = (UINT)rtStartTime; // kind of evil... stuff the start time in the "int unused" field of the HANDLE struct, since I can't dynamically allocate the data since I don't know what to hook to clean up when Unadvice doesn't get called. *pdwAdviseCookie = (DWORD)MytimeSetEvent((UINT)rtPeriodTime, 0, (LPTIMECALLBACK)AdvisePeriodicCallback, (DWORD_PTR)hSemaphore, TIME_PERIODIC | TIME_CALLBACK_FUNCTION); if(!*pdwAdviseCookie) return E_OUTOFMEMORY; return S_OK; }