Browse files

Improve timestamp calculation leading to better A/V Sync (ALSA and Pu…

…lse only so far)

GetBufferedOnSoundCard should return the length of audio in the buffer including latency ; it was only returning the latency. Also in pulse, is some cases the end calculation could overflow leading to incorrect value. Changed it to 64 bits int
  • Loading branch information...
1 parent 3fbe948 commit 5eac843595d117bad9d6b6409573dc0bd745fbdd @jyavenard jyavenard committed Dec 17, 2010
View
31 mythtv/libs/libmyth/audio/audiooutputalsa.cpp
@@ -562,22 +562,43 @@ void AudioOutputALSA::WriteAudio(uchar *aubuf, int size)
int AudioOutputALSA::GetBufferedOnSoundcard(void) const
{
+
if (pcm_handle == NULL)
{
VBERROR("getBufferedOnSoundcard() called with pcm_handle == NULL!");
return 0;
}
- snd_pcm_sframes_t delay = 0;
+ snd_pcm_sframes_t delay = 0, buffered = 0;
+
+ if (snd_pcm_avail_delay(pcm_handle, &buffered, &delay) < 0)
+ {
+ return 0;
+ }
snd_pcm_state_t state = snd_pcm_state(pcm_handle);
+
if (state == SND_PCM_STATE_RUNNING || state == SND_PCM_STATE_DRAINING)
- snd_pcm_delay(pcm_handle, &delay);
+ {
+ delay *= output_bytes_per_frame;
+ }
+ else
+ {
+ delay = 00;
+ }
- if (delay <= 0)
- return 0;
+ if (buffered < 0)
+ {
+ buffered = 0;
+ }
+
+ buffered *= output_bytes_per_frame;
+ if (buffered > soundcard_buffer_size)
+ {
+ buffered = soundcard_buffer_size;
+ }
- return delay * output_bytes_per_frame;
+ return delay + buffered;
}
/*
View
7 mythtv/libs/libmyth/audio/audiooutputbase.h
@@ -111,6 +111,10 @@ class AudioOutputBase : public AudioOutput, public QThread
virtual bool OpenDevice(void) = 0;
virtual void CloseDevice(void) = 0;
virtual void WriteAudio(uchar *aubuf, int size) = 0;
+ /*
+ * Return the size in bytes of frames currently in the audio buffer adjusted
+ * with the audio playback latency
+ */
virtual int GetBufferedOnSoundcard(void) const = 0;
// Default implementation only supports 2ch s16le at 48kHz
virtual AudioOutputSettings* GetOutputSettings(void)
@@ -122,7 +126,8 @@ class AudioOutputBase : public AudioOutput, public QThread
virtual bool StartOutputThread(void);
virtual void StopOutputThread(void);
- int GetAudioData(uchar *buffer, int buf_size, bool fill_buffer, int *local_raud = NULL);
+ int GetAudioData(uchar *buffer, int buf_size, bool fill_buffer,
+ int *local_raud = NULL);
void OutputAudioLoop(void);
View
31 mythtv/libs/libmyth/audio/audiooutputpulse.cpp
@@ -226,10 +226,6 @@ void AudioOutputPulseAudio::WriteAudio(uchar *aubuf, int size)
QString fn_log_tag = "WriteAudio, ";
pa_stream_state_t sstate = pa_stream_get_state(pstream);
- // Do not write anything to pulse server if we are in pause mode
- if (IsPaused())
- return;
-
VBAUDIOTS(fn_log_tag + QString("writing %1 bytes").arg(size));
/* NB This "if" check can be replaced with PA_STREAM_IS_GOOD() in
@@ -299,21 +295,40 @@ void AudioOutputPulseAudio::WriteAudio(uchar *aubuf, int size)
int AudioOutputPulseAudio::GetBufferedOnSoundcard(void) const
{
- pa_usec_t latency;
+ pa_usec_t latency = (pa_usec_t) -1;
+ size_t buffered = 0;
if (!pcontext || pa_context_get_state(pcontext) != PA_CONTEXT_READY)
return 0;
if (!pstream || pa_stream_get_state(pstream) != PA_STREAM_READY)
return 0;
+ const pa_buffer_attr *buf_attr = pa_stream_get_buffer_attr(pstream);
+ size_t bfree = pa_stream_writable_size(pstream);
+ buffered = buf_attr->tlength - bfree;
+
pa_threaded_mainloop_lock(mainloop);
- if(pa_stream_get_latency(pstream, &latency, NULL) < 0)
- latency = 0;
+ while (pa_stream_get_latency(pstream, &latency, NULL) < 0)
+ {
+ if (pa_context_errno(pcontext) != PA_ERR_NODATA)
+ {
+ latency = 0;
+ break;
+ }
+ pa_threaded_mainloop_wait(mainloop);
+ }
pa_threaded_mainloop_unlock(mainloop);
- return (int)latency * samplerate * output_bytes_per_frame / 1000000;
+
+ if (latency < 0)
+ {
+ latency = 0;
+ }
+
+ return ((uint64_t)latency * samplerate *
+ output_bytes_per_frame / 1000000) + buffered;
}
int AudioOutputPulseAudio::GetVolumeChannel(int channel) const

0 comments on commit 5eac843

Please sign in to comment.