Skip to content
Permalink
Browse files

move audio sync to AE - WIP

  • Loading branch information...
FernetMenta authored and popcornmix committed Sep 6, 2015
1 parent 0be229c commit 27345e3f2400b377fbf81eaeec70dcb59979eba5
@@ -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()
@@ -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<std::string, std::string> > &list, std::string &current, void *data);
@@ -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)
@@ -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);
@@ -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()
@@ -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;
};
}

@@ -35,6 +35,7 @@ class IAEStream;
class IAESound;
class IAEPacketizer;
class IAudioCallback;
class IAEClockCallback;

/* sound options */
#define AE_SOUND_OFF 0 /* disable sounds */
@@ -157,15 +158,15 @@ 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.
* For OSX/IOS this is essential to reconfigure the audio output.
* @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
@@ -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
*/
@@ -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;
}
@@ -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;
};
@@ -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;

0 comments on commit 27345e3

Please sign in to comment.
You can’t perform that action at this time.