Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Video freeze when seekTo is called after midroll ads #10274

Closed
usopphammer opened this issue May 18, 2022 · 8 comments
Closed

Video freeze when seekTo is called after midroll ads #10274

usopphammer opened this issue May 18, 2022 · 8 comments
Assignees
Labels

Comments

@usopphammer
Copy link

Our QA team observes the same bug - #7161
When we call Player.seekTo() method a video freezes and the player doesn't react to any media event. It's very hard to reproduce, on my devices it happens 1 time out of 1000.

We use the latest 2.17 version of the Player. There are no deprecated classes in our code. Timeouts are set by default.
It happens for any ads, even for ads from this list https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/tags

Do you have any ideas about what can be a root cause? Any possible fix or workaround?

@icbaker
Copy link
Collaborator

icbaker commented May 19, 2022

Can you provide a little more information about your setup? Specifically:

  • Is the content between the ads protected with DRM?
    • If so, how do you configure the DRM playback? A sample code snippet of instantiating a MediaItem or MediaSource would be helpful here, as well as any direct DrmSessionManager configuration e.g. via DefaultDrmSessionManager.Builder.
  • Precisely how are you triggering Player.seekTo() 'after midroll ads'? Are you reacting to an event, e.g. from Player.Listener or AnalyticsListener or are you using just time-based triggering e.g. with ExoPlayer.createMessage?

@denis-solomko-deltatre
Copy link

denis-solomko-deltatre commented May 30, 2022

@icbaker

  1. Yes we use DRM

DRM creation

private fun buildDrmSessionManager(
        context: Context,
        drmSchemeUuid: UUID?,
        drmLicenseUrl: String
): DefaultDrmSessionManager {

        val drmCallback = HttpMediaDrmCallback(
            drmLicenseUrl,
            DefaultHttpDataSource.Factory().setUserAgent(getUserAgent(context))
        )

        releaseMediaDrm()

        try {
            frameworkMediaDrm = FrameworkMediaDrm.newInstance(drmSchemeUuid!!)
        } catch (exception: UnsupportedDrmException) {
            AxisLogger.instance().e(exception.message)
        }

        return DefaultDrmSessionManager.Builder()
            .setUuidAndExoMediaDrmProvider(drmSchemeUuid!!, FrameworkMediaDrm.DEFAULT_PROVIDER)
            .build(drmCallback)
}

MediaSource creation

 /**
   * Builds the [MediaSource] object containing the main video Media Source.
   *
   * @param videoUri the videoUrl
   * @return MediaSource instance
   */
private fun buildDASHMediaSource(
        uri: Uri,
        drmSessionManager: DrmSessionManager // a previously created DRM session manager
): MediaSource {
        return DashMediaSource.Factory(
            DefaultDashChunkSource.Factory(mediaDataSourceFactory!!),
            mediaDataSourceFactory
        )
            .setDefaultSettings(drmSessionManager, createLoadErrorPolicy())
            .createMediaSource(createMediaItem(uri))
}

AdsMediaSource creation

 private fun createAdsMediaSource(
        playerView: StyledPlayerView,
        mediaSource: MediaSource, // a previously created dash media source
        drmEngine: DrmSessionManager, // a previously created DRM session manager
        adTagUri: Uri,
): MediaSource {

        adsLoader = ImaAdsLoader.Builder(playerView.context).build().apply {
            setPlayer(playerView.player)
        }

        val adMediaSourceFactory = AdsMediaSourceFactory(this::buildDASHMediaSource)
            .setDrmSessionManagerProvider {drmEngine }

        return mediaSource.mediaItem.localConfiguration?.let {
            // this code duplicates DefaultMediaSourceFactory.maybeWrapWithAdsMediaSource
            val adTagDataSpec = DataSpec(adTagUri)
            val adsId = ImmutableList.of(mediaSource.mediaItem.mediaId, it.uri, adTagUri)
            AdsMediaSource(mediaSource, adTagDataSpec, adsId, adMediaSourceFactory, adsLoader!!, playerView)
        }
            ?: mediaSource
}

our AdsMediaSourceFactory

class AdsMediaSourceFactory(
    val buildMediaSourceFactoryMethod: (Uri, DrmSessionManager) -> MediaSource
) : MediaSource.Factory {

    private var drmSessionManagerProvider: DrmSessionManagerProvider? = null

    override fun setDrmSessionManagerProvider(drmSessionManagerProvider: DrmSessionManagerProvider?): MediaSource.Factory {
        this.drmSessionManagerProvider = drmSessionManagerProvider
        return this
    }

    override fun setLoadErrorHandlingPolicy(loadErrorHandlingPolicy: LoadErrorHandlingPolicy?): MediaSource.Factory {
        return this
    }

    override fun getSupportedTypes(): IntArray {
        return intArrayOf(C.TYPE_DASH, C.TYPE_OTHER)
    }

    override fun createMediaSource(mediaItem: MediaItem): MediaSource {
        val drmSessionManager = drmSessionManagerProvider?.get(mediaItem)
            ?: throw IllegalStateException("drmSessionManager is null")

        return mediaItem.localConfiguration?.uri
            ?.let {
                buildMediaSourceFactoryMethod(it, drmSessionManager)
            } ?: let {
                throw IllegalStateException("uri is null")
            }
    }
}
  1. we trigger seekTo in a button click listener

@icbaker
Copy link
Collaborator

icbaker commented May 30, 2022

Are you able to try depending on ExoPlayer locally? If so please try applying this patch on top of r2.17.1 and see if it fixes the issue.

We think there's a theoretical problem with the way we handle seeking after a format switch (like ad -> content) in DRM content - but we've not been able to reproduce a problem at all in our demo app. We're reluctant to submit the fix to the library without being able to directly see it fix something - so since you seem to have a repro case it would be great if you could report back with your findings (either to let us know that it worked, or that it didn't make a difference (or that it made things worse!)). Thanks!

marcbaechinger pushed a commit to androidx/media that referenced this issue Jun 13, 2022
`codecDrainAction` is set to `DRAIN_ACTION_NONE` in 3 places in
`MediaCodecRenderer`:
* The constructor (so there's no prior state to worry about)
* `updateDrmSessionV23()`: Where `mediaCrypto` is reconfigured based
  on `sourceDrmSession` and `codecDrmSession` is also updated to
  `sourceDrmSession`.
* `resetCodecStateForFlush()`: Where (before this change) the action
  is unconditionally set back to `DRAIN_ACTION_NONE` and so any
  required updated implied by
  `DRAIN_ACTION_FLUSH_AND_UPDATE_DRM_SESSION` is not done.

This change ensures that `flushOrReleaseCodec()` handles
`DRAIN_ACTION_FLUSH_AND_UPDATE_DRM_SESSION` before calling .

This probably also resolves Issue: google/ExoPlayer#10274

#minor-release

PiperOrigin-RevId: 454114428
marcbaechinger pushed a commit that referenced this issue Jun 13, 2022
`codecDrainAction` is set to `DRAIN_ACTION_NONE` in 3 places in
`MediaCodecRenderer`:
* The constructor (so there's no prior state to worry about)
* `updateDrmSessionV23()`: Where `mediaCrypto` is reconfigured based
  on `sourceDrmSession` and `codecDrmSession` is also updated to
  `sourceDrmSession`.
* `resetCodecStateForFlush()`: Where (before this change) the action
  is unconditionally set back to `DRAIN_ACTION_NONE` and so any
  required updated implied by
  `DRAIN_ACTION_FLUSH_AND_UPDATE_DRM_SESSION` is not done.

This change ensures that `flushOrReleaseCodec()` handles
`DRAIN_ACTION_FLUSH_AND_UPDATE_DRM_SESSION` before calling .

This probably also resolves Issue: #10274

#minor-release

PiperOrigin-RevId: 454114428
@icbaker
Copy link
Collaborator

icbaker commented Jun 15, 2022

I'm closing this because I hope it's fixed with the commit linked above, which will be included in the next release.

@denis-solomko-deltatre
Copy link

@icbaker I sent a build for our qa team, but unfortunately, they haven't checked it yet as they have a lot of other work to do. They will be able to test it only next week. Please don't close the ticket now, I will write an update later.

marcbaechinger pushed a commit that referenced this issue Jun 15, 2022
`codecDrainAction` is set to `DRAIN_ACTION_NONE` in 3 places in
`MediaCodecRenderer`:
* The constructor (so there's no prior state to worry about)
* `updateDrmSessionV23()`: Where `mediaCrypto` is reconfigured based
  on `sourceDrmSession` and `codecDrmSession` is also updated to
  `sourceDrmSession`.
* `resetCodecStateForFlush()`: Where (before this change) the action
  is unconditionally set back to `DRAIN_ACTION_NONE` and so any
  required updated implied by
  `DRAIN_ACTION_FLUSH_AND_UPDATE_DRM_SESSION` is not done.

This change ensures that `flushOrReleaseCodec()` handles
`DRAIN_ACTION_FLUSH_AND_UPDATE_DRM_SESSION` before calling .

This probably also resolves Issue: #10274

#minor-release

PiperOrigin-RevId: 454114428
(cherry picked from commit c736a72)
marcbaechinger pushed a commit to androidx/media that referenced this issue Jun 15, 2022
`codecDrainAction` is set to `DRAIN_ACTION_NONE` in 3 places in
`MediaCodecRenderer`:
* The constructor (so there's no prior state to worry about)
* `updateDrmSessionV23()`: Where `mediaCrypto` is reconfigured based
  on `sourceDrmSession` and `codecDrmSession` is also updated to
  `sourceDrmSession`.
* `resetCodecStateForFlush()`: Where (before this change) the action
  is unconditionally set back to `DRAIN_ACTION_NONE` and so any
  required updated implied by
  `DRAIN_ACTION_FLUSH_AND_UPDATE_DRM_SESSION` is not done.

This change ensures that `flushOrReleaseCodec()` handles
`DRAIN_ACTION_FLUSH_AND_UPDATE_DRM_SESSION` before calling .

This probably also resolves Issue: google/ExoPlayer#10274

#minor-release

PiperOrigin-RevId: 454114428
(cherry picked from commit 222faa9)
@denis-solomko-deltatre
Copy link

@icbaker I've received info from ous QAs. The bug is not reproducible with this approach. Thanks!

@denis-solomko-deltatre
Copy link

@icbaker Could you tell me when the next release will be?

@icbaker
Copy link
Collaborator

icbaker commented Jun 20, 2022

@google google locked and limited conversation to collaborators Aug 15, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

3 participants