dev sync#1107
Conversation
VPLAY-12070: protect stream abstraction in retune callback (#766) Reason for change: If a SetRate() is received during the retune callback, the stream abstraction can get deleted causing a segfault Test Procedure: Follow trickmode tests on ticket Risks: Low Signed-off-by: James Lofthouse <james_lofthouse@comcast.com> Co-authored-by: pstroffolino <Philip_Stroffolino@cable.comcast.com>
VPLAY-12806: Add timeout for each L1 test (#1085) Reason for change: Add timeout for each L1 test to avoid tests hanging indefinitely. Default value is 60s, can be configured via CTEST_TIMEOUT env variable of ./run.sh -t <timeout> Test Procedure: Make sure all L1 passes Risks: None Signed-off-by: Vinish100 <vinish.balan@gmail.com>
#1078) VPLAY-12746: Synchronize between fragment and manifest fetcher threads (#1078) Reason for change: Add synchronization between mpd downloader thread and fetcher loop to minimize delay in downloading new fragments. Clean up on base class functions used by HLS. Add debug logs to identify the delta between live window end time and wall clock time. Test Procedure: Test LLD and validate that the fragment downloads happen with <=200ms of a manifest download Risks: Medium Signed-off-by: Vinish100 <vinish.balan@gmail.com>
…ons (#1100) VPLAY-11339: [DOC] eAAMPConfig_NativeCCRendering and setTextStyleOptions Reason for change: Update documentation on CC related config and API Test Procedure: NA, documentation update Risks: None --------- Signed-off-by: Vinish100 <vinish.balan@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: pstroffolino <Philip_Stroffolino@cable.comcast.com>
…wableBuffer (#1088) VPLAY-12809 Replace calls to GetPtr with calls to data ready for AampGrowableBuffer removal Reason for Change: This PR replaces remaining AampGrowableBuffer::GetPtr() usage with data() and adjusts several interfaces (notably toward uint8_t*) to support eventual removal/refactoring of AampGrowableBuffer. - Replaces GetPtr() calls with data() across TS/MP4 processing codepaths and tests. - Updates several APIs to use uint8_t* / std::vector<uint8_t> for binary buffers. - Adjusts logging/formatting and a few local variable types (e.g., size_t vs int) to align with the new buffer types. Test Guidance: no L1/L2/L3 regressions nor regressions found in manual QA Risk: Low --------- Signed-off-by: Philip Stroffolino <philip_stroffolino@cable.comcast.com> Co-authored-by: pstroffolino <Philip_Stroffolino@cable.comcast.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Reason for change: Fix AAMP build failure in simulator Test Procedure: AAMP builds successfully using ./install-aamp.sh Risks: None Signed-off-by: Vinish100 <vinish.balan@gmail.com>
There was a problem hiding this comment.
Pull request overview
This PR primarily modernizes buffer access across the player by migrating from AampGrowableBuffer::GetPtr()/char* to AampGrowableBuffer::data()/uint8_t*, and introduces a counter-based “manifest update” wait/abort mechanism to prevent lost-wakeup races in fetch loops (HLS/DASH). It also updates unit tests/mocks/fakes accordingly and improves test tooling/docs.
Changes:
- Replace
GetPtr()usage withdata()and adjust APIs to useuint8_t*/const uint8_t*for binary buffers across TS/MPD/ISO-BMFF paths. - Add counter + condition-variable based manifest update synchronization (
GetManifestUpdateCounter/WaitForManifestUpdate(snapshot)/AbortWaitForManifestUpdate). - Update tests/mocks/fakes and add small test runner improvements (CTest timeout override) and CC rendering documentation.
Reviewed changes
Copilot reviewed 47 out of 48 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tsprocessor.cpp | Switch TS segment pointer handling to data() and tighten early-buffer validation. |
| tsFragmentProcessor.cpp | Use fragment.data() for TS processing base pointer. |
| tsDemuxer.cpp | Use AampGrowableBuffer::data() for ES buffer pointer access. |
| streamabstraction.cpp | Replace “fragment downloader wait” with counter-based manifest update wait/abort plumbing. |
| priv_aamp.cpp | Update chunk-injection buffer pointer type and add stream-abstraction change checks during retune scheduling. |
| mp4demux/AampMp4Demuxer.cpp | Use data() to validate and parse MP4 segments. |
| isobmff/isobmffprocessor.cpp | Use data() when restamping PTS. |
| isobmff/isobmffhelper.cpp | Use data() when parsing ISO-BMFF buffers. |
| isobmff/isobmffbuffer.h | Add setBuffer(const uint8_t*, size_t) overload for read-only buffers. |
| isobmff/isobmffbuffer.cpp | Implement read-only setBuffer overload via internal const-cast. |
| fragmentcollector_mpd.h | Add manifest-update wait/abort/counter APIs to MPD abstraction. |
| fragmentcollector_mpd.cpp | Use IDX.data() for SIDX parsing; replace sleep-based waits with manifest-update waits; wire aborts into callback/stop paths; use downloader-provided last playlist download time. |
| fragmentcollector_hls.cpp | Switch playlist parsing to playlist.data() and use new manifest-update wait API in refresh/track-switch flows. |
| drm/DrmInterface.cpp | Use mAesKeyBuf.data() for returning key buffer pointer. |
| admanager_mpd.cpp | Use manifest.data() for XML reader input and debug printing. |
| MetadataProcessor.hpp | Change ISO-BMFF ID3 processing API to accept const std::vector<uint8_t>&. |
| MetadataProcessor.cpp | Adapt ISO-BMFF ID3 processing to vector-based input and IsoBmffBuffer::setBuffer(const uint8_t*, ...). |
| ElementaryProcessor.h | Update signature to setTuneTimePTS(const uint8_t*, size_t, ...). |
| ElementaryProcessor.cpp | Call updated setTuneTimePTS with pBuffer->data(). |
| AampTSBSessionManager.cpp | Replace GetPtr() calls with fragment.data() for TSB store read/write and PTS recalculation. |
| AampMPDUtils.h | Update SIDX parsing helpers to use const uint8_t* and const uint8_t**. |
| AampMPDUtils.cpp | Implement updated uint8_t-based parsing helpers. |
| AampMPDParseHelper.cpp | Formatting/indentation cleanup in period duration logic. |
| AampConfig.h | Expand documentation for eAAMPConfig_NativeCCRendering. |
| main_aamp.cpp | Expand documentation for PlayerInstanceAAMP::SetNativeCCRendering. |
| AAMP-UVE-API.md | Clarify nativeCCRendering behavior by platform and document runtime CC control. |
| MediaStreamContext.h | Update CacheFragmentChunk signature to const uint8_t*. |
| MediaStreamContext.cpp | Update CacheFragmentChunk implementation to use const uint8_t* and add null-pointer guard/logging. |
| test/utests/tests/StreamAbstractionAAMP_MPD/FunctionalTests.cpp | Add/marshal mLastPlaylistDownloadTimeMs into manifest responses; adjust mock init ordering. |
| test/utests/tests/StreamAbstractionAAMP_MPD/FetcherLoopTests.cpp | Extend parameterized cases; add optional SIDX mocking; make fetch-loop exit deterministic via a flag. |
| test/utests/tests/StreamAbstractionAAMP_HLS/FunctionalTests.cpp | Remove unused/low-value tests and dead buffer code. |
| test/utests/tests/PrivateInstanceAAMP/ChunkedTransferTests.cpp | Use buffer.data() for string conversion. |
| test/utests/tests/PrivAampTests/PrivAampTests.cpp | Update CacheFragmentChunk expectations to uint8_t* pointer type. |
| test/utests/tests/MediaTrackTests/MediaTrackTests.cpp | Add manifest-update wait/abort/counter unit tests and required headers. |
| test/utests/tests/MediaStreamContextTests/MediaStreamContextTests.cpp | Change test data buffer to uint8_t[] to match API. |
| test/utests/tests/IsoBmffHelperTests/IsoBmffHelperTests.cpp | Update expected buffer pointer to buffer.data(). |
| test/utests/tests/IsoBmffConvertToKeyFrameTests/IsoBmffConvertToKeyFrameTests.cpp | Update buffer comparisons and pointers to data(). |
| test/utests/tests/AampTSBSessionManager/FunctionalTests.cpp | Use fragment.data() for store writes. |
| test/utests/run.sh | Add -t option and CTEST_TIMEOUT support for per-test timeout override. |
| test/utests/mocks/MockPrivateInstanceAAMP.h | Add LoadIDX mock method used by fetcher loop tests. |
| test/utests/mocks/MockMediaStreamContext.h | Update CacheFragmentChunk mock signature to const uint8_t*. |
| test/utests/fakes/FakeStreamAbstractionAamp.cpp | Add stubs for new MediaTrack manifest-update APIs. |
| test/utests/fakes/FakePrivateInstanceAAMP.cpp | Forward LoadIDX to mock when present. |
| test/utests/fakes/FakeMetadataProcessor.cpp | Update fake signature for ISO-BMFF ID3 processing. |
| test/utests/fakes/FakeMediaStreamContext.cpp | Update fake CacheFragmentChunk signature and forwarding. |
| test/utests/fakes/FakeFragmentCollector_MPD.cpp | Add stubs for new MPD manifest-update APIs. |
| test/utests/fakes/FakeAampMPDUtils.cpp | Update fake SIDX parsing helpers to uint8_t-based signatures. |
Comments suppressed due to low confidence (1)
MediaStreamContext.cpp:231
CacheFragmentChunkallowsptr == nullptrwhensize == 0, but later unconditionally doescachedFragment->fragment.assign(ptr, ptr + size). Even withsize == 0,ptr + sizeperforms pointer arithmetic on a null pointer, which is undefined behavior in C++. Handle the zero-length case explicitly (e.g., clear/resize the fragment without using pointer arithmetic) and prefernullptroverNULLin new code.
if (ptr == NULL && size > 0)
{
AAMPLOG_WARN("[%s] Null fragment pointer with non-zero size %zu", name, size);
return false;
}
bool ret = true;
if (WaitForCachedFragmentChunkInjected())
{
CachedFragment *cachedFragment = NULL;
cachedFragment = GetFetchChunkBuffer(true);
if (NULL == cachedFragment)
{
AAMPLOG_WARN("[%s] Something Went wrong - Can't get FetchChunkBuffer", name);
return false;
}
cachedFragment->absPosition = 0;
cachedFragment->type = actualType;
cachedFragment->downloadStartTime = dnldStartTime;
cachedFragment->fragment.assign(ptr, ptr + size);
cachedFragment->timeScale = fragmentDescriptor.TimeScale;
| // Take a local copy of the stream abstraction to check for tune | ||
| // NOTE - this copy is taken outside of the mutex protection as it is only used to see if it has changed while waiting | ||
| // for the mutex (i.e. checks to see if a 'retune' occurred). It should NOT be dereferenced as it may be invalid after the lock | ||
| const StreamAbstractionAAMP *oldStreamAbstraction = mpStreamAbstractionAAMP; | ||
| std::lock_guard<std::recursive_mutex> guard(mStreamLock); // protect mpStreamAbstractionAAMP (this must cover calls to AdditionalTuneFailLogEntries) | ||
|
|
||
| // Check that the stream abstraction has not changed while waiting for the mutex (we have not done some form of tune). | ||
| if (oldStreamAbstraction != mpStreamAbstractionAAMP) | ||
| { |
There was a problem hiding this comment.
mpStreamAbstractionAAMP is read into oldStreamAbstraction before acquiring mStreamLock. If another thread can update mpStreamAbstractionAAMP concurrently, that unsynchronized read is a data race (undefined behavior) even if the pointer is only compared and never dereferenced. Take the snapshot under mStreamLock (or make the pointer atomic / otherwise synchronize access) before comparing.
| // Take a local copy of the stream abstraction to check for tune | ||
| // NOTE - this copy is taken outside of the mutex protection as it is only used to see if it has changed while waiting | ||
| // for the mutex (i.e. checks to see if a 'retune' occurred). It should NOT be dereferenced as it may be invalid after the lock | ||
| const StreamAbstractionAAMP *oldStreamAbstraction = mpStreamAbstractionAAMP; | ||
| std::lock_guard<std::recursive_mutex> guard(mStreamLock); // protect mpStreamAbstractionAAMP (this must cover calls to AdditionalTuneFailLogEntries) | ||
|
|
||
| // Check that the stream abstraction has not changed while waiting for the mutex (we have not done some form of tune). | ||
| if (oldStreamAbstraction != mpStreamAbstractionAAMP) | ||
| { | ||
| AAMPLOG_WARN("PrivateInstanceAAMP: Ignore reTune due to stream changed"); | ||
| return; | ||
| } | ||
|
|
There was a problem hiding this comment.
Same data-race issue as above: oldStreamAbstraction snapshots mpStreamAbstractionAAMP before taking mStreamLock. This needs to be read under the same synchronization used for writers, otherwise the comparison itself has undefined behavior under concurrency.
| // Take a local copy of the stream abstraction to check for tune | |
| // NOTE - this copy is taken outside of the mutex protection as it is only used to see if it has changed while waiting | |
| // for the mutex (i.e. checks to see if a 'retune' occurred). It should NOT be dereferenced as it may be invalid after the lock | |
| const StreamAbstractionAAMP *oldStreamAbstraction = mpStreamAbstractionAAMP; | |
| std::lock_guard<std::recursive_mutex> guard(mStreamLock); // protect mpStreamAbstractionAAMP (this must cover calls to AdditionalTuneFailLogEntries) | |
| // Check that the stream abstraction has not changed while waiting for the mutex (we have not done some form of tune). | |
| if (oldStreamAbstraction != mpStreamAbstractionAAMP) | |
| { | |
| AAMPLOG_WARN("PrivateInstanceAAMP: Ignore reTune due to stream changed"); | |
| return; | |
| } | |
| std::lock_guard<std::recursive_mutex> guard(mStreamLock); // protect mpStreamAbstractionAAMP (this must cover calls to AdditionalTuneFailLogEntries) |
| std::thread manifestUpdateThread([&videoTrack]() { | ||
| videoTrack.WaitForManifestUpdate(); | ||
| }); | ||
|
|
||
| std::this_thread::sleep_for(std::chrono::milliseconds(200)); // Give the thread a moment to start and block on the wait | ||
| videoTrack.AbortWaitForManifestUpdate(); | ||
| manifestUpdateThread.join(); |
There was a problem hiding this comment.
WaitForManifestUpdateTest relies on a fixed sleep_for(200ms) to “give the thread a moment” to block. This is timing-dependent and can be flaky on slow/loaded CI. Prefer a deterministic synchronization point (e.g., a std::promise/std::future or condition variable) to confirm the background thread has entered WaitForManifestUpdate() before calling AbortWaitForManifestUpdate().
No description provided.