aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfritsch <Peter.Fruehberger@gmail.com>2023-02-13 20:33:13 +0100
committerfritsch <Peter.Fruehberger@gmail.com>2023-09-23 07:57:52 +0200
commitbe049ba900df39b9f2cef820a19088f8aa1ba7d2 (patch)
tree3080389543c577defad7bc341ba5abf90414b8b1
parentb90cc563c16ee5040b122b36d7f00d570178ef03 (diff)
AESinkAndroid: Watchdog HeadPosition movement
If the HeadPosition stops moving for too long an implicit error has happend under the hood. Take action based on the measurements and report error when the buffer stops moving for too long. Use-Case: Latest AMLogic BSP seems to have a bug, when opening IEC format it would under the hood reopen but not properly communicate that to outside world. Audio is heavily out of sync. v1: Initial v2: Relax AE's polling a bit by waiting 200 ms before indicating error
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp37
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h3
2 files changed, 40 insertions, 0 deletions
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp
index d7863c254b..a7fb55c9f2 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp
@@ -247,9 +247,12 @@ CAESinkAUDIOTRACK::CAESinkAUDIOTRACK()
m_sink_frameSize = 0;
m_encoding = CJNIAudioFormat::ENCODING_PCM_16BIT;
m_audiotrackbuffer_sec = 0.0;
+ m_audiotrackbuffer_sec_orig = 0.0;
m_at_jni = NULL;
m_duration_written = 0;
m_headPos = 0;
+ m_stuckCounter = 0;
+ m_headPosOld = 0;
m_timestampPos = 0;
m_sink_sampleRate = 0;
m_passthrough = false;
@@ -317,6 +320,8 @@ bool CAESinkAUDIOTRACK::Initialize(AEAudioFormat &format, std::string &device)
m_format = format;
m_headPos = 0;
+ m_stuckCounter = 0;
+ m_headPosOld = 0;
m_timestampPos = 0;
m_linearmovingaverage.clear();
m_pause_ms = 0.0;
@@ -572,6 +577,8 @@ bool CAESinkAUDIOTRACK::Initialize(AEAudioFormat &format, std::string &device)
"Created Audiotrackbuffer with playing time of {:f} ms min buffer size: {} bytes",
m_audiotrackbuffer_sec * 1000, m_min_buffer_size);
+ m_audiotrackbuffer_sec_orig = m_audiotrackbuffer_sec;
+
m_jniAudioFormat = m_encoding;
m_at_jni = CreateAudioTrack(stream, m_sink_sampleRate, atChannelMask,
m_encoding, m_min_buffer_size);
@@ -640,6 +647,7 @@ void CAESinkAUDIOTRACK::Deinitialize()
m_duration_written = 0;
m_headPos = 0;
+ m_headPosOld = 0;
m_timestampPos = 0;
m_stampTimer.SetExpired();
@@ -677,6 +685,14 @@ void CAESinkAUDIOTRACK::GetDelay(AEDelayStatus& status)
// clear lower 32 bit values, e.g. 0x0001 FFFF FFFF -> 0x0001 0000 0000
// and add head_pos which wrapped around, e.g. 0x0001 0000 0000 -> 0x0001 0000 0004
m_headPos = (m_headPos & UINT64_UPPER_BYTES) | (uint64_t)head_pos;
+ // check if sink is stuck
+ if (m_headPos == m_headPosOld)
+ m_stuckCounter++;
+ else
+ {
+ m_stuckCounter = 0;
+ m_headPosOld = m_headPos;
+ }
double gone = static_cast<double>(m_headPos) / m_sink_sampleRate;
@@ -820,6 +836,26 @@ unsigned int CAESinkAUDIOTRACK::AddPackets(uint8_t **data, unsigned int frames,
if (!IsInitialized())
return INT_MAX;
+ // If the sink did not move twice the buffer size in time it was opened
+ // take action. Some sinks open with e.g. 128 ms nicely but under the
+ // hood need a bit more samples to start moving on sink start.
+ // Simple equation: N x stime packages in ms > 2 configured audiotrack_buffer in ms
+ // will result in the error condition triggering.
+
+ const bool isRawPt = m_passthrough && !m_info.m_wantsIECPassthrough;
+ if (!isRawPt)
+ {
+ const double max_stuck_delay_ms = m_audiotrackbuffer_sec_orig * 2000.0;
+ const double stime_ms = 1000.0 * frames / m_format.m_sampleRate;
+
+ if (m_stuckCounter * stime_ms > max_stuck_delay_ms)
+ {
+ CLog::Log(LOGERROR, "Sink got stuck with {:f} ms - ask AE for reopening", max_stuck_delay_ms);
+ usleep(max_stuck_delay_ms * 1000);
+ return INT_MAX;
+ }
+ }
+
// for debugging only - can be removed if everything is really stable
uint64_t startTime = CurrentHostCounter();
@@ -978,6 +1014,7 @@ void CAESinkAUDIOTRACK::Drain()
}
m_duration_written = 0;
m_headPos = 0;
+ m_stuckCounter = 0;
m_timestampPos = 0;
m_linearmovingaverage.clear();
m_stampTimer.SetExpired();
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h
index d40b9a7c8e..6e9ec76a2e 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h
@@ -62,6 +62,8 @@ private:
double m_duration_written;
unsigned int m_min_buffer_size;
uint64_t m_headPos;
+ uint64_t m_headPosOld;
+ uint32_t m_stuckCounter;
uint64_t m_timestampPos = 0;
// Moving Average computes the weighted average delay over
// a fixed size of delay values - current size: 20 values
@@ -87,6 +89,7 @@ private:
unsigned int m_sink_sampleRate;
bool m_passthrough;
double m_audiotrackbuffer_sec;
+ double m_audiotrackbuffer_sec_orig;
int m_encoding;
double m_pause_ms = 0.0;
double m_delay = 0.0;