From d38aba92fe987e51f5bfe54ab5a0cb09b4e6592b Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 5 Nov 2024 09:39:34 -0800 Subject: [PATCH] Fix flakiness in HlsPlaybackTest and DashPlaybackTest The tests became more flaky after https://github.com/androidx/media/commit/76e4abe4282d0b17b2f71e2e09d6e0e4344ab695, likely because playback was able to start slightly earlier, exaggerating any existing race conditions. Fix the flakiness by letting all tests with subtitle parsing wait until all data is fully loaded before starting to play. PiperOrigin-RevId: 693380656 --- .../dash/e2etest/DashPlaybackTest.java | 55 ++++++++++++++++--- .../hls/e2etest/HlsPlaybackTest.java | 40 ++++++++++++-- 2 files changed, 84 insertions(+), 11 deletions(-) diff --git a/libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/e2etest/DashPlaybackTest.java b/libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/e2etest/DashPlaybackTest.java index 2ff2710072..6f71632ea1 100644 --- a/libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/e2etest/DashPlaybackTest.java +++ b/libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/e2etest/DashPlaybackTest.java @@ -94,8 +94,11 @@ public final class DashPlaybackTest { trackSelector.setParameters(trackSelector.buildUponParameters().setPreferredTextLanguage("en")); player.setMediaItem(MediaItem.fromUri("asset:///media/dash/standalone-webvtt/sample.mpd")); player.prepare(); + // Ensure media is fully buffered so that the first subtitle is ready at the start of playback. + run(player).untilBackgroundThreadCondition(() -> player.getBufferedPercentage() == 100); + run(player).untilLoadingIs(false); player.play(); - TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED); + run(player).untilState(Player.STATE_ENDED); player.release(); surface.release(); @@ -132,6 +135,11 @@ public final class DashPlaybackTest { trackSelector.setParameters(trackSelector.buildUponParameters().setPreferredTextLanguage("en")); player.setMediaItem(MediaItem.fromUri("asset:///media/dash/standalone-webvtt/sample.mpd")); player.prepare(); + // Ensure media is fully buffered so that the first subtitle is ready at the start of playback. + run(player) + .ignoringNonFatalErrors() + .untilBackgroundThreadCondition(() -> player.getBufferedPercentage() == 100); + run(player).ignoringNonFatalErrors().untilLoadingIs(false); player.play(); run(player).ignoringNonFatalErrors().untilState(Player.STATE_ENDED); player.release(); @@ -169,6 +177,11 @@ public final class DashPlaybackTest { trackSelector.setParameters(trackSelector.buildUponParameters().setPreferredTextLanguage("en")); player.setMediaItem(MediaItem.fromUri("asset:///media/dash/standalone-webvtt/sample.mpd")); player.prepare(); + // Ensure media is fully buffered so that the first subtitle is ready at the start of playback. + run(player) + .ignoringNonFatalErrors() + .untilBackgroundThreadCondition(() -> player.getBufferedPercentage() == 100); + run(player).ignoringNonFatalErrors().untilLoadingIs(false); player.play(); run(player).ignoringNonFatalErrors().untilState(Player.STATE_ENDED); player.release(); @@ -204,8 +217,11 @@ public final class DashPlaybackTest { trackSelector.setParameters(trackSelector.buildUponParameters().setPreferredTextLanguage("en")); player.setMediaItem(MediaItem.fromUri("asset:///media/dash/standalone-ttml/sample.mpd")); player.prepare(); + // Ensure media is fully buffered so that the first subtitle is ready at the start of playback. + run(player).untilBackgroundThreadCondition(() -> player.getBufferedPercentage() == 100); + run(player).untilLoadingIs(false); player.play(); - TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED); + run(player).untilState(Player.STATE_ENDED); player.release(); surface.release(); @@ -233,8 +249,11 @@ public final class DashPlaybackTest { trackSelector.setParameters(trackSelector.buildUponParameters().setPreferredTextLanguage("en")); player.setMediaItem(MediaItem.fromUri("asset:///media/dash/webvtt-in-mp4/sample.mpd")); player.prepare(); + // Ensure media is fully buffered so that the first subtitle is ready at the start of playback. + run(player).untilBackgroundThreadCondition(() -> player.getBufferedPercentage() == 100); + run(player).untilLoadingIs(false); player.play(); - TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED); + run(player).untilState(Player.STATE_ENDED); player.release(); surface.release(); @@ -261,8 +280,11 @@ public final class DashPlaybackTest { trackSelector.setParameters(trackSelector.buildUponParameters().setPreferredTextLanguage("en")); player.setMediaItem(MediaItem.fromUri("asset:///media/dash/ttml-in-mp4/sample.mpd")); player.prepare(); + // Ensure media is fully buffered so that the first subtitle is ready at the start of playback. + run(player).untilBackgroundThreadCondition(() -> player.getBufferedPercentage() == 100); + run(player).untilLoadingIs(false); player.play(); - TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED); + run(player).untilState(Player.STATE_ENDED); player.release(); surface.release(); @@ -299,6 +321,11 @@ public final class DashPlaybackTest { trackSelector.setParameters(trackSelector.buildUponParameters().setPreferredTextLanguage("en")); player.setMediaItem(MediaItem.fromUri("asset:///media/dash/ttml-in-mp4/sample.mpd")); player.prepare(); + // Ensure media is fully buffered so that the first subtitle is ready at the start of playback. + run(player) + .ignoringNonFatalErrors() + .untilBackgroundThreadCondition(() -> player.getBufferedPercentage() == 100); + run(player).ignoringNonFatalErrors().untilLoadingIs(false); player.play(); run(player).ignoringNonFatalErrors().untilState(Player.STATE_ENDED); player.release(); @@ -336,6 +363,11 @@ public final class DashPlaybackTest { trackSelector.setParameters(trackSelector.buildUponParameters().setPreferredTextLanguage("en")); player.setMediaItem(MediaItem.fromUri("asset:///media/dash/ttml-in-mp4/sample.mpd")); player.prepare(); + // Ensure media is fully buffered so that the first subtitle is ready at the start of playback. + run(player) + .ignoringNonFatalErrors() + .untilBackgroundThreadCondition(() -> player.getBufferedPercentage() == 100); + run(player).ignoringNonFatalErrors().untilLoadingIs(false); player.play(); run(player).ignoringNonFatalErrors().untilState(Player.STATE_ENDED); player.release(); @@ -378,8 +410,11 @@ public final class DashPlaybackTest { trackSelector.setParameters(trackSelector.buildUponParameters().setPreferredTextLanguage("en")); player.setMediaItem(MediaItem.fromUri("asset:///media/dash/cea608/manifest.mpd")); player.prepare(); + // Ensure media is fully buffered so that the first subtitle is ready at the start of playback. + run(player).untilBackgroundThreadCondition(() -> player.getBufferedPercentage() == 100); + run(player).untilLoadingIs(false); player.play(); - TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED); + run(player).untilState(Player.STATE_ENDED); player.release(); surface.release(); @@ -416,8 +451,11 @@ public final class DashPlaybackTest { trackSelector.setParameters(trackSelector.buildUponParameters().setPreferredTextLanguage("en")); player.setMediaItem(MediaItem.fromUri("asset:///media/dash/cea608/manifest.mpd")); player.prepare(); + // Ensure media is fully buffered so that the first subtitle is ready at the start of playback. + run(player).untilBackgroundThreadCondition(() -> player.getBufferedPercentage() == 100); + run(player).untilLoadingIs(false); player.play(); - TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED); + run(player).untilState(Player.STATE_ENDED); player.release(); surface.release(); @@ -651,8 +689,11 @@ public final class DashPlaybackTest { player.setMediaItem( MediaItem.fromUri("asset:///media/dash/multi-period-with-offset/sample.mpd")); player.prepare(); + // Ensure media is fully buffered to avoid flakiness from loading second period too late. + run(player).untilBackgroundThreadCondition(() -> player.getBufferedPercentage() == 100); + run(player).untilLoadingIs(false); player.play(); - TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED); + run(player).untilState(Player.STATE_ENDED); player.release(); surface.release(); diff --git a/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/e2etest/HlsPlaybackTest.java b/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/e2etest/HlsPlaybackTest.java index 0d6391f871..2ff17f3e05 100644 --- a/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/e2etest/HlsPlaybackTest.java +++ b/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/e2etest/HlsPlaybackTest.java @@ -84,8 +84,11 @@ public final class HlsPlaybackTest { player.setMediaItem( MediaItem.fromUri("asset:///media/hls/standalone-webvtt/multivariant_playlist.m3u8")); player.prepare(); + // Ensure media is fully buffered so that the first subtitle is ready at the start of playback. + run(player).untilBackgroundThreadCondition(() -> player.getBufferedPercentage() == 100); + run(player).untilLoadingIs(false); player.play(); - TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED); + run(player).untilState(Player.STATE_ENDED); player.release(); surface.release(); @@ -120,6 +123,11 @@ public final class HlsPlaybackTest { player.setMediaItem( MediaItem.fromUri("asset:///media/hls/standalone-webvtt/multivariant_playlist.m3u8")); player.prepare(); + // Ensure media is fully buffered so that the first subtitle is ready at the start of playback. + run(player) + .ignoringNonFatalErrors() + .untilBackgroundThreadCondition(() -> player.getBufferedPercentage() == 100); + run(player).ignoringNonFatalErrors().untilLoadingIs(false); player.play(); run(player).ignoringNonFatalErrors().untilState(Player.STATE_ENDED); player.release(); @@ -155,6 +163,11 @@ public final class HlsPlaybackTest { player.setMediaItem( MediaItem.fromUri("asset:///media/hls/standalone-webvtt/multivariant_playlist.m3u8")); player.prepare(); + // Ensure media is fully buffered so that the first subtitle is ready at the start of playback. + run(player) + .ignoringNonFatalErrors() + .untilBackgroundThreadCondition(() -> player.getBufferedPercentage() == 100); + run(player).ignoringNonFatalErrors().untilLoadingIs(false); player.play(); run(player).ignoringNonFatalErrors().untilState(Player.STATE_ENDED); player.release(); @@ -184,8 +197,11 @@ public final class HlsPlaybackTest { player.setMediaItem( MediaItem.fromUri("asset:///media/hls/ttml-in-mp4/multivariant_playlist.m3u8")); player.prepare(); + // Ensure media is fully buffered so that the first subtitle is ready at the start of playback. + run(player).untilBackgroundThreadCondition(() -> player.getBufferedPercentage() == 100); + run(player).untilLoadingIs(false); player.play(); - TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED); + run(player).untilState(Player.STATE_ENDED); player.release(); surface.release(); @@ -219,6 +235,11 @@ public final class HlsPlaybackTest { player.setMediaItem( MediaItem.fromUri("asset:///media/hls/ttml-in-mp4/multivariant_playlist.m3u8")); player.prepare(); + // Ensure media is fully buffered so that the first subtitle is ready at the start of playback. + run(player) + .ignoringNonFatalErrors() + .untilBackgroundThreadCondition(() -> player.getBufferedPercentage() == 100); + run(player).ignoringNonFatalErrors().untilLoadingIs(false); player.play(); run(player).ignoringNonFatalErrors().untilState(Player.STATE_ENDED); player.release(); @@ -253,6 +274,11 @@ public final class HlsPlaybackTest { player.setMediaItem( MediaItem.fromUri("asset:///media/hls/ttml-in-mp4/multivariant_playlist.m3u8")); player.prepare(); + // Ensure media is fully buffered so that the first subtitle is ready at the start of playback. + run(player) + .ignoringNonFatalErrors() + .untilBackgroundThreadCondition(() -> player.getBufferedPercentage() == 100); + run(player).ignoringNonFatalErrors().untilLoadingIs(false); player.play(); run(player).ignoringNonFatalErrors().untilState(Player.STATE_ENDED); player.release(); @@ -291,8 +317,11 @@ public final class HlsPlaybackTest { player.setMediaItem(MediaItem.fromUri("asset:///media/hls/cea608/manifest.m3u8")); player.prepare(); + // Ensure media is fully buffered so that the first subtitle is ready at the start of playback. + run(player).untilBackgroundThreadCondition(() -> player.getBufferedPercentage() == 100); + run(player).untilLoadingIs(false); player.play(); - TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED); + run(player).untilState(Player.STATE_ENDED); player.release(); surface.release(); @@ -325,8 +354,11 @@ public final class HlsPlaybackTest { player.setMediaItem(MediaItem.fromUri("asset:///media/hls/cea608/manifest.m3u8")); player.prepare(); + // Ensure media is fully buffered so that the first subtitle is ready at the start of playback. + run(player).untilBackgroundThreadCondition(() -> player.getBufferedPercentage() == 100); + run(player).untilLoadingIs(false); player.play(); - TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED); + run(player).untilState(Player.STATE_ENDED); player.release(); surface.release();