media icon indicating copy to clipboard operation
media copied to clipboard

Preacquire DRM session/download License

Open changxiangzhong opened this issue 2 years ago • 1 comments

Our use case is a bit special.

  • We have setup and prepared() everything, ExoPlayer, DataSource, TrackSelector and DefaultDrmSessionManager
  • playWhenReady is set to true
  • But we DISABLE all the renders by the following code.
        for (int i = 0; i < getRendererCount(); i++) {
            trackSelector.setParameters(trackSelector.buildUponParameters().setRendererDisabled(i, disabled).build());
        }

The manifest URL is a dash live stream. So we do see dash manifest gets updated periodically. So everything works as expected except we are using DRMToday's Upfront token. I've noticed when both audio & video renderers are disabled, DRM License download won't be triggered. The expiration period of Upfront token is only 10 minutes. So we are trying to manually/force trigger the DRM License downloading (renderers could remain disabled for hours). We are planning to use DefaultDrmSessionManager.preacquireSession()

Our plan is

  • When onTracksChanged() gets called, loop through all the tracks and find the Widevine DrmInitData
  • Use the DrmInitData as a param to call DefaultDrmSessionManager.preacquireSession() to manually trigger the DRM license downloading. Here are the source code.
Source code
    private void onTracksChanged(Tracks tracks) {
        String drmSvrUrl = "...";
      
        DrmInitData.SchemeData widevineSchemeData = null;
        outerLoop:
        for (Tracks.Group group: tracks.getGroups()) {
            if (group.getType() != C.TRACK_TYPE_VIDEO) {
                continue;
            }
            for(int i = 0; i < group.length; i++) {
                DrmInitData initData = group.getTrackFormat(i).drmInitData;
                if (initData == null) {
                    continue;
                }
                for (int j = 0; j < initData.schemeDataCount; j++) {
                    DrmInitData.SchemeData schemeData = initData.get(j);
                    if (C.WIDEVINE_UUID.equals(schemeData.uuid)
                            && !TextUtils.isEmpty(schemeData.mimeType)
                            && schemeData.data != null
                            && schemeData.data.length != 0
                    ) {
                        widevineSchemeData = new DrmInitData.SchemeData(
                                schemeData.uuid,
                                drmSvrUrl,
                                schemeData.mimeType,
                                schemeData.data);
                        break outerLoop;
                    }
                }
            }
        }

        if (widevineSchemeData == null) {
            Log.d(TAG, "no valid drmInitData found. quitting preacquire()");
            return;
        }
        // Release it when playback is done
        drmSessionRef = drmSessionManager.preacquireSession(new DrmSessionEventListener.EventDispatcher(),
                new Format.Builder()
                        .setSampleMimeType(widevineSchemeData.mimeType)
                        .setDrmInitData(new DrmInitData(widevineSchemeData))
                        .build()
        );

    }

We have made a POC, it proves to work. The whole flow is as following

  • Playback gets started, all renders are disabled. But dash manifest gets refreshed
  • The drm license downloading(preacquireSession()) was triggered in onTracksChanged()
  • Wait for 11 minutes
  • Enable all renders
  • The video/audio gets output as expected. Everything works fine.

Our questions are

  • Do you see any pitfalls with this implementation?
  • Should we tweak the DefaultDrmSessionManager.Builder.setSessionKeepaliveMs() to make sure the session remained open long enough?

changxiangzhong avatar Jan 16 '24 15:01 changxiangzhong

  • Do you see any pitfalls with this implementation?

You don't mention when you will release the preacquired session. You need to explicitly do this, otherwise the underlying resources will be held for longer than necessary.

  • Should we tweak the DefaultDrmSessionManager.Builder.setSessionKeepaliveMs() to make sure the session remained open long enough?

Based on your description, you shouldn't need to rely on session keep-alive, since you're explicitly holding references to preacquired sessions, which will keep the underlying session open even if keep-alive is disabled (hence the need to explicitly release these preacquired sessions) - unless a contention for underlying resources causes DefaultDrmSessionManager to eagerly release sessions, in which case it will release both preacquired and kept-alive sessions - so no real difference/benefit to keep-alive.


Note that the only difference between 'preacquired' sessions and normal ones is that DefaultDrmSessionManager will eagerly release preacquired ones when it encounters a shortage of sessions in the underlying hardware (and therefore an owner of a preacquired session can't rely on it being available for decoding, but in the normal case it will remain open).

icbaker avatar Feb 08 '24 15:02 icbaker

Closing due to inactivity.

icbaker avatar Mar 25 '24 18:03 icbaker