androidx / media

Jetpack Media3 support libraries for media use cases, including ExoPlayer, an extensible media player for Android
https://developer.android.com/media/media3
Apache License 2.0
1.66k stars 395 forks source link

Allow client-side preroll ads with SSAI (DAI) stream #571

Open devno44 opened 1 year ago

devno44 commented 1 year ago

Hello,

I have a live content that need have to play both of Pre-Roll and Mid-Roll. So I have a question, How can I implement Pre-Roll and Mid-Roll at the same Player ? If possible, can you provide an example for the implementation ?

For SSAI, I want to use ImaServerSideAdInsertionMediaSource

The version of ExoPlayer that I am using is ExoPlayer 2.18.3. Streaming protocol is HLS.

Thank you

devno44 commented 1 year ago

Looks like ImaServerSideAdInsertionMediaSource doesn't support for CSAI right now.

Although I did as below but no success. There is no Pre-Roll is played. Just Mid-Roll.

     ....
     val adsTagUrl = "https://pubads.g.doubleclick.net/..."

      val contentUri = ImaServerSideAdInsertionUriBuilder()
            .setAssetKey(assetKey)
            .setFormat(C.CONTENT_TYPE_HLS) 
            .setAdTagParameters(adTags)
            .build()

       val mediaItem = MediaItem.Builder()
            .setUri(contentUri)
            .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(Uri.parse(adsTagUrl)).build())

      player.setMediaItem(mediaItem.build())
      player.prepare()
      ....
tonihei commented 1 year ago

@devno44 For client-side ad insertion, please use AdsMediaSource with ImaAdsLoader as explained here: https://developer.android.com/guide/topics/media/exoplayer/ad-insertion#client-side_ad_insertion

devno44 commented 1 year ago

@tonihei Thank you for your reply. But I mean, my live content have both of Pre-Roll and Mid-Roll. And I want to play them on the same live content. For example: Pre-Roll from the Ad tag url, and Mid-Roll from Google DAI. I tried follow the way bellow, but its not working. The player can play Mid-Roll only.

     ....
     val adsTagUrl = "https://pubads.g.doubleclick.net/..."

      val contentUri = ImaServerSideAdInsertionUriBuilder()
            .setAssetKey(assetKey)
            .setFormat(C.CONTENT_TYPE_HLS) 
            .setAdTagParameters(adTags)
            .build()

       val mediaItem = MediaItem.Builder()
            .setUri(contentUri)
            .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(Uri.parse(adsTagUrl)).build())

      player.setMediaItem(mediaItem.build())
      player.prepare()
      ....

Not only for client-side ad insertion or server-side ad insertion.

Is there any way to do it ? Thank you !

tonihei commented 1 year ago

Pre-Roll from the Ad tag url, and Mid-Roll from Google DAI.

Do I understand the problem correctly that you'd like to combined client-side ad insertion for the preroll with server-side ad insertion for the main stream?

So that the result looks something like:

[ pre-roll from CSAI adTagUrl ][[ live stream ... [ mid-roll from DAI ] ... live stream ... ]

Is this correct? If so, this is currently unsupported because our client-side AdsMediaSource does not expect the underlying stream to already have ads defined. I can mark as an enhancement to track support for this feature. Please let me know if I misunderstood the question though.

devno44 commented 1 year ago

@tonihei Thank for your reply. Yes, exactly what you said. I mean I want to do something like bellow (as you said). [ pre-roll from CSAI adTagUrl ][[ live stream ... [ mid-roll from DAI ] ... live stream ... ]

Please add this feature.

Thank you so much.

tonihei commented 1 year ago

There is a workaround where you add the pre-roll with a media item with 0 duration and the DAI source as different items in a playlist. Generating this empty source for the preroll requires you to use AdsMediaSource directly though:

player.addMediaSource(
    new AdsMediaSource(
        new SilenceMediaSource(/* durationUs= */ 0),
        new DataSpec(adTagUri),
        /* adsId= */ "preroll",
        new DefaultMediaSourceFactory(context),
        adsLoader,
        adViewProvider));
player.addMediaItem(daiMediaItem);

This should work for HLS streams already, but we discovered a bug for multi-period DASH that needs to be fixed first. Once the fix is in, this workaround also works for DASH streams.

devno44 commented 1 year ago

@tonihei Thank you. But I tried follow this way, but still there is no Pre-Roll. Just Mid-Roll is showed. Im using HLS stream.

Can you please check if is there something wrong on my implementation ?

....
     val adsTagUrl = "https://pubads.g.doubleclick.net/..."

      val contentUri = ImaServerSideAdInsertionUriBuilder()
            .setAssetKey(assetKey)
            .setFormat(C.CONTENT_TYPE_HLS) 
            .setAdTagParameters(adTags)
            .build()

       val mediaItem = MediaItem.Builder()
            .setUri(contentUri)
            //.setAdsConfiguration(MediaItem.AdsConfiguration.Builder(Uri.parse(adsTagUrl)).build())

           (adsLoader as? AdsLoader)?.let { adLoader ->
                    (player as? ExoPlayer)?.addMediaSource(
                        AdsMediaSource(
                            SilenceMediaSource(/* durationUs = */ 0),
                            DataSpec(Uri.parse(adsTagUrl)),
                            /* adsId = */ "preroll",
                            DefaultMediaSourceFactory(context),
                            adLoader,
                           /* adViewProvider = */ playerView
                        )
                    )
                }

      player.setMediaItem(mediaItem.build())
      player.prepare()
      ....
tonihei commented 1 year ago

I think the second item should use addMediaItem, because setMediaItem overrides the entire playlist.

devno44 commented 1 year ago

@tonihei I tried to use addMediaItem instead of setMediaItem. But still there is no pre-roll is displayed. And I checked on VAST side too, and there is no problem on VAST.

tonihei commented 1 year ago

This works without issues in the demo app. You should probably check the pre-roll AdsMediaSource on its own to see if it works and try out your streams in the demo app. If you think there is a bug, please provide more details about your actual strreams, so we can reproduce the issue. (You can send links to android-media-github@google.com with "Issue #571" in the subject if needed).