diff --git a/RELEASENOTES.md b/RELEASENOTES.md index e0dd6991ab..abfcc3a15b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -48,6 +48,8 @@ * Effect: * Muxers: * IMA extension: + * Fix issue where DASH and HLS ads without the appropriate file extension + can't be played. * Session: * Put the custom keys and values in `MediaMetadataCompat` to `MediaMetadata.extras` diff --git a/libraries/exoplayer_ima/src/main/java/androidx/media3/exoplayer/ima/AdTagLoader.java b/libraries/exoplayer_ima/src/main/java/androidx/media3/exoplayer/ima/AdTagLoader.java index cf99362415..a0409dddde 100644 --- a/libraries/exoplayer_ima/src/main/java/androidx/media3/exoplayer/ima/AdTagLoader.java +++ b/libraries/exoplayer_ima/src/main/java/androidx/media3/exoplayer/ima/AdTagLoader.java @@ -183,6 +183,9 @@ import java.util.Map; /** Whether IMA has been notified that playback of content has finished. */ private boolean sentContentComplete; + /** The MIME type of the ad pod that is next requested via an {@link AdEventType#LOADED} event. */ + @Nullable private String pendingAdMimeType; + // Fields tracking the player/loader state. /** Whether the player is playing an ad. */ @@ -775,6 +778,9 @@ import java.util.Map; String message = "AdEvent: " + adData; Log.i(TAG, message); break; + case LOADED: + pendingAdMimeType = adEvent.getAd().getContentType(); + break; default: break; } @@ -981,6 +987,10 @@ import java.util.Map; } MediaItem.Builder adMediaItem = new MediaItem.Builder().setUri(adMediaInfo.getUrl()); + if (pendingAdMimeType != null) { + adMediaItem.setMimeType(pendingAdMimeType); + pendingAdMimeType = null; + } adPlaybackState = adPlaybackState.withAvailableAdMediaItem( adInfo.adGroupIndex, adInfo.adIndexInAdGroup, adMediaItem.build()); diff --git a/libraries/exoplayer_ima/src/test/java/androidx/media3/exoplayer/ima/ImaAdsLoaderTest.java b/libraries/exoplayer_ima/src/test/java/androidx/media3/exoplayer/ima/ImaAdsLoaderTest.java index 895ae72f8e..8523ebad3c 100644 --- a/libraries/exoplayer_ima/src/test/java/androidx/media3/exoplayer/ima/ImaAdsLoaderTest.java +++ b/libraries/exoplayer_ima/src/test/java/androidx/media3/exoplayer/ima/ImaAdsLoaderTest.java @@ -283,6 +283,31 @@ public final class ImaAdsLoaderTest { adsMediaSource, /* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, new IOException()); } + @Test + public void loadAd_withAdContentTypeSet_setsMimeTypeInAdPlaybackState() { + // Load the preroll ad with content type set. Intentionally use all lower-case HLS MIME type as + // this is what the IMA SDK sets. + when(mockPrerollSingleAd.getContentType()).thenReturn("application/x-mpegurl"); + imaAdsLoader.start( + adsMediaSource, TEST_DATA_SPEC, TEST_ADS_ID, adViewProvider, adsLoaderListener); + + adEventListener.onAdEvent(getAdEvent(AdEventType.LOADED, mockPrerollSingleAd)); + videoAdPlayer.loadAd(TEST_AD_MEDIA_INFO, mockAdPodInfo); + + // Verify that the preroll ad has been marked with the expected MIME type. + assertThat(getAdPlaybackState(/* periodIndex= */ 0)) + .isEqualTo( + new AdPlaybackState(TEST_ADS_ID, /* adGroupTimesUs...= */ 0) + .withContentDurationUs(CONTENT_PERIOD_DURATION_US) + .withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1) + .withAvailableAdMediaItem( + /* adGroupIndex= */ 0, + /* adIndexInAdGroup= */ 0, + TEST_MEDIA_ITEM.buildUpon().setMimeType(MimeTypes.APPLICATION_M3U8).build()) + .withAdDurationsUs(new long[][] {{TEST_AD_DURATION_US}}) + .withAdResumePositionUs(/* adResumePositionUs= */ 0)); + } + @Test public void playback_withPrerollAd_marksAdAsPlayed() { // Load the preroll ad.