diff options
author | fritsch <Peter.Fruehberger@gmail.com> | 2023-02-13 20:33:13 +0100 |
---|---|---|
committer | fritsch <Peter.Fruehberger@gmail.com> | 2023-09-23 07:57:52 +0200 |
commit | be049ba900df39b9f2cef820a19088f8aa1ba7d2 (patch) | |
tree | 3080389543c577defad7bc341ba5abf90414b8b1 | |
parent | b90cc563c16ee5040b122b36d7f00d570178ef03 (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.cpp | 37 | ||||
-rw-r--r-- | xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h | 3 |
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; |