diff --git a/xbmc/cores/AudioEngine/AEFactory.cpp b/xbmc/cores/AudioEngine/AEFactory.cpp index 7b80501541ce8..56b7e3d7814b5 100644 --- a/xbmc/cores/AudioEngine/AEFactory.cpp +++ b/xbmc/cores/AudioEngine/AEFactory.cpp @@ -271,20 +271,20 @@ void CAEFactory::Shutdown() } IAEStream *CAEFactory::MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, - unsigned int encodedSampleRate, CAEChannelInfo channelLayout, unsigned int options) + unsigned int encodedSampleRate, CAEChannelInfo channelLayout, unsigned int options, IAEClockCallback *clock) { if(AE) - return AE->MakeStream(dataFormat, sampleRate, encodedSampleRate, channelLayout, options); + return AE->MakeStream(dataFormat, sampleRate, encodedSampleRate, channelLayout, options, clock); return NULL; } -IAEStream *CAEFactory::FreeStream(IAEStream *stream) +bool CAEFactory::FreeStream(IAEStream *stream) { if(AE) return AE->FreeStream(stream); - return NULL; + return false; } void CAEFactory::GarbageCollect() diff --git a/xbmc/cores/AudioEngine/AEFactory.h b/xbmc/cores/AudioEngine/AEFactory.h index 04a41a1afe19c..d1e524481e391 100644 --- a/xbmc/cores/AudioEngine/AEFactory.h +++ b/xbmc/cores/AudioEngine/AEFactory.h @@ -59,8 +59,8 @@ class CAEFactory static void SetVolume(const float volume); static void Shutdown(); static IAEStream *MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, - unsigned int encodedSampleRate, CAEChannelInfo channelLayout, unsigned int options = 0); - static IAEStream *FreeStream(IAEStream *stream); + unsigned int encodedSampleRate, CAEChannelInfo channelLayout, unsigned int options = 0, IAEClockCallback *clock = NULL); + static bool FreeStream(IAEStream *stream); static void GarbageCollect(); static void SettingOptionsAudioDevicesFiller(const CSetting *setting, std::vector< std::pair > &list, std::string ¤t, void *data); diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp index 6d34e257551c2..2610f5fa129d6 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp @@ -304,6 +304,7 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg) CActiveAEStream *stream; stream = *(CActiveAEStream**)msg->data; DiscardStream(stream); + msg->Reply(CActiveAEDataProtocol::ACC); return; case CActiveAEDataProtocol::FREESOUND: sound = *(CActiveAESound**)msg->data; @@ -519,6 +520,8 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg) case CActiveAEControlProtocol::RESUMESTREAM: stream = *(CActiveAEStream**)msg->data; stream->m_paused = false; + stream->m_syncClock = true; + stream->m_syncError.Flush(100); streaming = true; m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::STREAMING, &streaming, sizeof(bool)); m_extTimeout = 0; @@ -638,6 +641,7 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg) case CActiveAEDataProtocol::FREESTREAM: stream = *(CActiveAEStream**)msg->data; DiscardStream(stream); + msg->Reply(CActiveAEDataProtocol::ACC); if (m_streams.empty()) { if (m_extKeepConfig) @@ -762,6 +766,8 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg) CActiveAEStream *stream; stream = *(CActiveAEStream**)msg->data; stream->m_paused = false; + stream->m_syncClock = true; + stream->m_syncError.Flush(100); m_state = AE_TOP_CONFIGURED_PLAY; m_extTimeout = 0; return; @@ -1307,6 +1313,8 @@ CActiveAEStream* CActiveAE::CreateStream(MsgStreamNew *streamMsg) stream->m_bypassDSP = true; } + stream->m_pClock = streamMsg->clock; + m_streams.push_back(stream); return stream; @@ -1351,6 +1359,8 @@ void CActiveAE::SFlushStream(CActiveAEStream *stream) stream->m_streamPort->Purge(); stream->m_bufferedTime = 0.0; stream->m_paused = false; + stream->m_syncClock = true; + stream->m_syncError.Flush(100); // flush the engine if we only have a single stream if (m_streams.size() == 1) @@ -1799,6 +1809,31 @@ bool CActiveAE::RunStages() if (m_stats.GetWaterLevel() < MAX_WATER_LEVEL && (m_mode != MODE_TRANSCODE || (m_encoderBuffers && !m_encoderBuffers->m_freeSamples.empty()))) { + // calculate sync error + for (it = m_streams.begin(); it != m_streams.end(); ++it) + { + if ((*it)->m_paused || !(*it)->m_started || !(*it)->m_resampleBuffers || !(*it)->m_pClock) + continue; + + if ((*it)->m_resampleBuffers->m_outputSamples.empty()) + continue; + + CSampleBuffer *buf = (*it)->m_resampleBuffers->m_outputSamples.front(); + if (buf->timestamp) + { + AEDelayStatus status; + m_stats.GetDelay(status); + double pts = buf->timestamp - (buf->pkt_start_offset / buf->pkt->config.sample_rate * 1000); + double delay = status.GetDelay() * 1000; + double playingPts = pts - delay; + if (playingPts < 0) + playingPts = 0; + double error = playingPts - (*it)->m_pClock->GetClock(); + + (*it)->m_syncError.Add(error); + } + } + // mix streams and sounds sounds if (m_mode != MODE_RAW) { @@ -1840,6 +1875,7 @@ bool CActiveAE::RunStages() if (!(*it)->m_resampleBuffers->m_outputSamples.empty()) { (*it)->m_started = true; + (*it)->m_syncError.Flush(100); if (!out) { @@ -2854,7 +2890,7 @@ bool CActiveAE::ResampleSound(CActiveAESound *sound) // Streams //----------------------------------------------------------------------------- -IAEStream *CActiveAE::MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo& channelLayout, unsigned int options) +IAEStream *CActiveAE::MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo& channelLayout, unsigned int options, IAEClockCallback *clock) { if (IsSuspended()) return NULL; @@ -2873,6 +2909,7 @@ IAEStream *CActiveAE::MakeStream(enum AEDataFormat dataFormat, unsigned int samp MsgStreamNew msg; msg.format = format; msg.options = options; + msg.clock = clock; Message *reply; if (m_dataPort.SendOutMessageSync(CActiveAEDataProtocol::NEWSTREAM, @@ -2893,10 +2930,22 @@ IAEStream *CActiveAE::MakeStream(enum AEDataFormat dataFormat, unsigned int samp return NULL; } -IAEStream *CActiveAE::FreeStream(IAEStream *stream) +bool CActiveAE::FreeStream(IAEStream *stream) { - m_dataPort.SendOutMessage(CActiveAEDataProtocol::FREESTREAM, &stream, sizeof(IAEStream*)); - return NULL; + Message *reply; + if (m_dataPort.SendOutMessageSync(CActiveAEDataProtocol::FREESTREAM, + &reply,1000, + &stream, sizeof(IAEStream*))) + { + bool success = reply->signal == CActiveAEControlProtocol::ACC; + reply->Release(); + if (success) + { + return true; + } + } + CLog::Log(LOGERROR, "CActiveAE::FreeStream - failed"); + return false; } void CActiveAE::FlushStream(CActiveAEStream *stream) diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h index e5406b619d60e..8413777fcbc8a 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h @@ -133,6 +133,7 @@ struct MsgStreamNew { AEAudioFormat format; unsigned int options; + IAEClockCallback *clock; }; struct MsgStreamSample @@ -234,8 +235,8 @@ class CActiveAE : public IAE, private CThread virtual void SetSoundMode(const int mode); /* returns a new stream for data in the specified format */ - virtual IAEStream *MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo& channelLayout, unsigned int options = 0); - virtual IAEStream *FreeStream(IAEStream *stream); + virtual IAEStream *MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo& channelLayout, unsigned int options = 0, IAEClockCallback *clock = NULL); + virtual bool FreeStream(IAEStream *stream); /* returns a new sound object */ virtual IAESound *MakeSound(const std::string& file); diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp index 01ac1129abac8..e5a3556e2b7d4 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp @@ -64,6 +64,7 @@ CActiveAEStream::CActiveAEStream(AEAudioFormat *format) m_profile = 0; m_matrixEncoding = AV_MATRIX_ENCODING_NONE; m_audioServiceType = AV_AUDIO_SERVICE_TYPE_MAIN; + m_pClock = NULL; } CActiveAEStream::~CActiveAEStream() diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h index 0e08eed75e637..73a3030bcc391 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h @@ -26,6 +26,52 @@ namespace ActiveAE { +class CSyncError +{ +public: + CSyncError() + { + Flush(); + } + void Add(double error) + { + m_buffer += error; + m_count++; + } + + void Flush(int interval = 100) + { + m_buffer = 0.0f; + m_count = 0; + m_timer.Set(interval); + } + + bool Get(double& error, int interval = 100) + { + if(m_timer.IsTimePast()) + { + error = Get(); + Flush(interval); + return true; + } + else + return false; + } + +protected: + double Get() + { + if(m_count) + return m_buffer / m_count; + else + return 0.0; + } + double m_buffer; + int m_count; + XbmcThreads::EndTime m_timer; +}; + + class CActiveAEStream : public IAEStream { protected: @@ -128,6 +174,9 @@ class CActiveAEStream : public IAEStream enum AVMatrixEncoding m_matrixEncoding; enum AVAudioServiceType m_audioServiceType; bool m_forceResampler; + IAEClockCallback *m_pClock; + CSyncError m_syncError; + bool m_syncClock; }; } diff --git a/xbmc/cores/AudioEngine/Interfaces/AE.h b/xbmc/cores/AudioEngine/Interfaces/AE.h index 7ec305351ec52..da0df23ea6abb 100644 --- a/xbmc/cores/AudioEngine/Interfaces/AE.h +++ b/xbmc/cores/AudioEngine/Interfaces/AE.h @@ -35,6 +35,7 @@ class IAEStream; class IAESound; class IAEPacketizer; class IAudioCallback; +class IAEClockCallback; /* sound options */ #define AE_SOUND_OFF 0 /* disable sounds */ @@ -157,7 +158,7 @@ class IAE * @param options A bit field of stream options (see: enum AEStreamOptions) * @return a new IAEStream that will accept data in the requested format */ - virtual IAEStream *MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo& channelLayout, unsigned int options = 0) = 0; + virtual IAEStream *MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo& channelLayout, unsigned int options = 0, IAEClockCallback *clock = NULL) = 0; /** * This method will remove the specifyed stream from the engine. @@ -165,7 +166,7 @@ class IAE * @param stream The stream to be altered * @return NULL */ - virtual IAEStream *FreeStream(IAEStream *stream) = 0; + virtual bool FreeStream(IAEStream *stream) = 0; /** * Creates a new IAESound that is ready to play the specified file diff --git a/xbmc/cores/AudioEngine/Interfaces/AEStream.h b/xbmc/cores/AudioEngine/Interfaces/AEStream.h index 54e83719e16bf..2c3e1e31d5c12 100644 --- a/xbmc/cores/AudioEngine/Interfaces/AEStream.h +++ b/xbmc/cores/AudioEngine/Interfaces/AEStream.h @@ -38,6 +38,15 @@ enum AEStreamOptions AESTREAM_BYPASS_ADSP = 0x08 /* if this option is set the ADSP-System is bypassed and raw stream will be passed through IAESink */ }; +/** + * Callback interafce for VideoPlayer clock needed by AE for sync + */ +class IAEClockCallback +{ +public: + virtual double GetClock() = 0; +}; + /** * IAEStream Stream Interface for streaming audio */ diff --git a/xbmc/cores/VideoPlayer/DVDAudio.cpp b/xbmc/cores/VideoPlayer/DVDAudio.cpp index f420300ff0e5c..36eb7cce28fc5 100644 --- a/xbmc/cores/VideoPlayer/DVDAudio.cpp +++ b/xbmc/cores/VideoPlayer/DVDAudio.cpp @@ -27,8 +27,7 @@ #include "cores/AudioEngine/Interfaces/AEStream.h" #include "settings/MediaSettings.h" -CDVDAudio::CDVDAudio(volatile bool &bStop) - : m_bStop(bStop) +CDVDAudio::CDVDAudio(volatile bool &bStop, CDVDClock *clock) : m_bStop(bStop), m_pClock(clock) { m_pAudioStream = NULL; m_bPassthrough = false; @@ -67,7 +66,8 @@ bool CDVDAudio::Create(const DVDAudioFrame &audioframe, AVCodecID codec, bool ne audioframe.sample_rate, audioframe.encoded_sample_rate, audioframe.channel_layout, - options + options, + this ); if (!m_pAudioStream) return false; @@ -125,7 +125,7 @@ unsigned int CDVDAudio::AddPackets(const DVDAudioFrame &audioframe) unsigned int offset = 0; do { - unsigned int copied = m_pAudioStream->AddData(audioframe.data, offset, frames); + unsigned int copied = m_pAudioStream->AddData(audioframe.data, offset, frames, audioframe.pts / DVD_TIME_BASE * 1000); offset += copied; frames -= copied; if (frames <= 0) @@ -289,3 +289,12 @@ double CDVDAudio::GetPlayingPts() m_playingPts += played; return m_playingPts; } + +double CDVDAudio::GetClock() +{ + double absolute; + if (m_pClock) + return m_pClock->GetClock(absolute) / DVD_TIME_BASE * 1000; + else + return 0.0; +} \ No newline at end of file diff --git a/xbmc/cores/VideoPlayer/DVDAudio.h b/xbmc/cores/VideoPlayer/DVDAudio.h index 16c26b2985782..825cb8972a8c5 100644 --- a/xbmc/cores/VideoPlayer/DVDAudio.h +++ b/xbmc/cores/VideoPlayer/DVDAudio.h @@ -27,7 +27,7 @@ #include "PlatformDefs.h" #include "cores/AudioEngine/Utils/AEChannelInfo.h" -class IAEStream; +#include "cores/AudioEngine/Interfaces/AEStream.h" extern "C" { #include "libavcodec/avcodec.h" @@ -36,11 +36,12 @@ extern "C" { typedef struct stDVDAudioFrame DVDAudioFrame; class CSingleLock; +class CDVDClock; -class CDVDAudio +class CDVDAudio : IAEClockCallback { public: - CDVDAudio(volatile bool& bStop); + CDVDAudio(volatile bool& bStop, CDVDClock *clock); ~CDVDAudio(); void SetVolume(float fVolume); @@ -64,7 +65,9 @@ class CDVDAudio void SetSpeed(int iSpeed); void SetResampleRatio(double ratio); + double GetClock(); IAEStream *m_pAudioStream; + protected: double m_playingPts; double m_timeOfPts; @@ -78,6 +81,5 @@ class CDVDAudio bool m_bPaused; volatile bool& m_bStop; - //counter that will go from 0 to m_iSpeed-1 and reset, data will only be output when speedstep is 0 - //int m_iSpeedStep; + CDVDClock *m_pClock; }; diff --git a/xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp b/xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp index 12a443867704b..5583bdb23d5d9 100644 --- a/xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp +++ b/xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp @@ -100,7 +100,7 @@ CVideoPlayerAudio::CVideoPlayerAudio(CDVDClock* pClock, CDVDMessageQueue& parent : CThread("VideoPlayerAudio") , m_messageQueue("audio") , m_messageParent(parent) -, m_dvdAudio((bool&)m_bStop) +, m_dvdAudio((bool&)m_bStop, pClock) { m_pClock = pClock; m_pAudioCodec = NULL;