shaka-project / shaka-player-embedded

Shaka Player in a C++ Framework
Apache License 2.0
239 stars 62 forks source link

Widevine PSSH not found #158

Closed OmarPedraza closed 3 years ago

OmarPedraza commented 3 years ago

Hi here, I'm having problems while trying to download a content.

This is the current status of our code:

class DownloadManager: NSObject {

    // MARK: - Properties

    private var player: ShakaPlayer?
    private var storage: ShakaPlayerStorage?

    // MARK: - Lifecycle methods

    override init() {
        super.init()

        player = try? ShakaPlayer()
        storage = try? ShakaPlayerStorage(player: player)
    }
}

extension DownloadManager {

    // MARK: - Public methods

    func download(element: PlayableElement, completion: ((AlertError?) -> Void)?) {
        if userStatus.userIsSubscribed {
            showOfflineConfiguration(force: false) {
                if let player = self.player, let storage = self.storage {
                    element.getAsset(forOffline: true) { (asset, error) in
                        if error == nil, let asset = asset as? DRMAsset, case .widevine(let releasePID) = asset.security {
                            var server = self.playbackConfiguration.widevineLicenseServer
                            server.add(parameters: ["_releasePid": releasePID])
                            player.configure(ShakaPlayerLicenseServerConfig(Constants.Downloads.widevineServerName), with: server)

                            storage.store(asset.url.absoluteString) { (content, failure) in
                                if let failure = failure {
                                    print(failure)
                                } else {
                                    print(content)
                                }
                            }
                        } else {
                            completion?(error)
                        }
                    }
                } else {
                    completion?(AlertError.downloadsError(ofType: .missingShakaPlayerStorage))
                }
            }
        } else {
            completion?(AlertError.downloadsError(ofType: .unsubscribedUser))
        }
    }

    func startManager() {
        player?.add(self)

        player?.configure(ShakaPlayerAdvancedDrmConfig(Constants.Downloads.widevineServerName, "persistentStateRequired"), with: true)

        storage?.client = self
    }
}

extension DownloadManager: ShakaPlayerNetworkFilter {
    func onPlayer(_ player: ShakaPlayer, networkRequest request: ShakaPlayerRequest, of type: ShakaPlayerRequestType, with block: @escaping ShakaPlayerAsyncBlock) {
        switch type {
        case .license:
            if var uri = request.uris.firstObject as? String {
                if let body = request.body {
                    getMPXToken {
                        if $1 == nil, let mpx = $0 {
                            let base64String = body.base64EncodedString(options: .endLineWithLineFeed)
                            if let escapedString = base64String.unescape(charactersToLeaveEscaped: Constants.Downloads.widevineChallengeLeaveEscapedCharacters) {
                                request.body = nil
                                request.method = "GET"

                                uri.add(parameters: ["_widevineChallenge": escapedString, "account": self.playbackConfiguration.mpxAccountID, "form": "json", "schema": "1.0", "token": mpx.token])
                                request.uris = [uri]

                                block(nil)
                            } else {
                                block(ShakaPlayerError.incorrectRequestBodyError)
                            }
                        } else {
                            block(ShakaPlayerError.missingMPXTokenError)
                        }
                    }
                } else {
                    block(ShakaPlayerError.missingRequestBodyError)
                }
            } else {
                block(ShakaPlayerError.missingLicenseServerURL)
            }
        default:
            block(nil)
        }
    }

    func onPlayer(_ player: ShakaPlayer, networkResponse response: ShakaPlayerResponse, of type: ShakaPlayerRequestType, with block: @escaping ShakaPlayerAsyncBlock) {
        switch type {
        case .license:
            if let data = response.data {
                if let license = getWidevineLicense(from: data) {
                    response.data = license

                    block(nil)
                } else {
                    block(ShakaPlayerError.incorrectResponseDataError)
                }
            } else {
                block(ShakaPlayerError.missingResponseDataError)
            }
        default:
            block(nil)
        }
    }
}

A few seconds after starting the download, the following errors appear:

[ERROR:/var/lib/jenkins/workspace/CDM_Arxan_Create_Release/oemcrypto-arxan/third_party/cdm/core/src/initialization_data.cpp(126):SelectWidevinePssh] InitializationData::SelectWidevinePssh: The concatenated PSSH boxes could be parsed, but no Widevine PSSH was found.
[ERROR:/var/lib/jenkins/workspace/CDM_Arxan_Create_Release/oemcrypto-arxan/third_party/cdm/core/src/initialization_data.cpp(81):InitializationData] InitializationData: Unable to select a supported Widevine PSSH from the init data.
[ERROR:/var/lib/jenkins/workspace/CDM_Arxan_Create_Release/oemcrypto-arxan/third_party/cdm/cdm/src/cdm.cpp(667):generateRequest] Failed to parse init data, may not contain a Widevine PSSH.

Nevertheless, when I tried to play the same .mpd file online using the same ShakaPlayerNetworkFilter code and server configuration, that error disappeared, load() method did not return any error but playback didn't start, displaying continuously the following errors:

[ERROR:/var/lib/jenkins/workspace/CDM_Arxan_Create_Release/oemcrypto-arxan/third_party/cdm/core/src/cdm_engine.cpp(1712):Decrypt] CdmEngine::Decrypt: session not found: Empty session ID
[ERROR:/var/lib/jenkins/workspace/CDM_Arxan_Create_Release/oemcrypto-arxan/third_party/cdm/cdm/src/cdm.cpp(1203):decrypt] Key not available.

We've checked that that .mpd file works on our Android app, which uses ExoPlayer for both online and offline, do we have to change anything for doing it work for Shaka Player? Are we missing anything?

The .mpd is the following one:

<?xml version="1.0"?>
<!-- MPD file Generated with GPAC version 0.6.1-rev1-g35849be-dash_relax_ar_in_as  at 2016-07-05T00:08:09.368Z-->
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" minBufferTime="PT1.500S" type="static" mediaPresentationDuration="PT0H22M19.570S" maxSegmentDuration="PT0H0M3.994S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" xmlns:cenc="urn:mpeg:cenc:2013">
  <ProgramInformation moreInformationURL="http://gpac.sourceforge.net">
    <Title> --- Hidden --- </Title>
  </ProgramInformation>
  <Period duration="PT0H22M19.570S">
    <AdaptationSet segmentAlignment="true" maxWidth="640" maxHeight="480" maxFrameRate="30000/1001" par="4:3" lang="und" subsegmentAlignment="true" subsegmentStartsWithSAP="1">
      <ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc" cenc:default_KID="139879bd-5002-577e-8a18-104386b10cef" />
      <Representation id="video_1_1" mimeType="video/mp4" codecs="avc1.42c01e" width="640" height="480" frameRate="30000/1001" sar="1:1" startWithSAP="1" bandwidth="1633160">
        <BaseURL> --- Hidden --- </BaseURL>
        <SegmentBase indexRangeExact="true" indexRange="972-9031">
          <Initialization range="0-971" />
        </SegmentBase>
      </Representation>
      <Representation id="video_3_1" mimeType="video/mp4" codecs="avc1.42c01e" width="640" height="480" frameRate="30000/1001" sar="1:1" startWithSAP="1" bandwidth="1231975">
        <BaseURL> --- Hidden --- </BaseURL>
        <SegmentBase indexRangeExact="true" indexRange="972-9031">
          <Initialization range="0-971" />
        </SegmentBase>
      </Representation>
      <Representation id="video_5_1" mimeType="video/mp4" codecs="avc1.42c01e" width="640" height="480" frameRate="30000/1001" sar="1:1" startWithSAP="1" bandwidth="830431">
        <BaseURL> --- Hidden --- </BaseURL>
        <SegmentBase indexRangeExact="true" indexRange="972-9031">
          <Initialization range="0-971" />
        </SegmentBase>
      </Representation>
      <Representation id="video_7_1" mimeType="video/mp4" codecs="avc1.42c01e" width="600" height="452" frameRate="30000/1001" sar="1:1" startWithSAP="1" bandwidth="629425">
        <BaseURL> --- Hidden --- </BaseURL>
        <SegmentBase indexRangeExact="true" indexRange="973-9032">
          <Initialization range="0-972" />
        </SegmentBase>
      </Representation>
      <Representation id="video_9_1" mimeType="video/mp4" codecs="avc1.42c015" width="400" height="300" frameRate="30000/1001" sar="1:1" startWithSAP="1" bandwidth="428449">
        <BaseURL> --- Hidden --- </BaseURL>
        <SegmentBase indexRangeExact="true" indexRange="972-9031">
          <Initialization range="0-971" />
        </SegmentBase>
      </Representation>
      <Representation id="video_11_1" mimeType="video/mp4" codecs="avc1.42c015" width="400" height="300" frameRate="30000/1001" sar="1:1" startWithSAP="1" bandwidth="282631">
        <BaseURL> --- Hidden --- </BaseURL>
        <SegmentBase indexRangeExact="true" indexRange="972-9031">
          <Initialization range="0-971" />
        </SegmentBase>
      </Representation>
      <Representation id="video_13_1" mimeType="video/mp4" codecs="avc1.42c015" width="400" height="300" frameRate="30000/1001" sar="1:1" startWithSAP="1" bandwidth="237382">
        <BaseURL> --- Hidden --- </BaseURL>
        <SegmentBase indexRangeExact="true" indexRange="972-9031">
          <Initialization range="0-971" />
        </SegmentBase>
      </Representation>
    </AdaptationSet>
    <AdaptationSet segmentAlignment="true" lang="eng" subsegmentAlignment="true" subsegmentStartsWithSAP="1">
      <Representation id="audio_2_1" mimeType="audio/mp4" codecs="mp4a.40.2" audioSamplingRate="22050" startWithSAP="1" bandwidth="76953">
        <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
        <BaseURL> --- Hidden --- </BaseURL>
        <SegmentBase indexRangeExact="true" indexRange="839-4902">
          <Initialization range="0-838" />
        </SegmentBase>
      </Representation>
      <Representation id="audio_4_1" mimeType="audio/mp4" codecs="mp4a.40.2" audioSamplingRate="22050" startWithSAP="1" bandwidth="76953">
        <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
        <BaseURL> --- Hidden --- </BaseURL>
        <SegmentBase indexRangeExact="true" indexRange="839-4902">
          <Initialization range="0-838" />
        </SegmentBase>
      </Representation>
      <Representation id="audio_6_1" mimeType="audio/mp4" codecs="mp4a.40.2" audioSamplingRate="22050" startWithSAP="1" bandwidth="76953">
        <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
        <BaseURL> --- Hidden --- </BaseURL>
        <SegmentBase indexRangeExact="true" indexRange="839-4902">
          <Initialization range="0-838" />
        </SegmentBase>
      </Representation>
      <Representation id="audio_8_1" mimeType="audio/mp4" codecs="mp4a.40.2" audioSamplingRate="44100" startWithSAP="1" bandwidth="97613">
        <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
        <BaseURL> --- Hidden --- </BaseURL>
        <SegmentBase indexRangeExact="true" indexRange="839-4902">
          <Initialization range="0-838" />
        </SegmentBase>
      </Representation>
      <Representation id="audio_10_1" mimeType="audio/mp4" codecs="mp4a.40.2" audioSamplingRate="44100" startWithSAP="1" bandwidth="97613">
        <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
        <BaseURL> --- Hidden --- </BaseURL>
        <SegmentBase indexRangeExact="true" indexRange="839-4902">
          <Initialization range="0-838" />
        </SegmentBase>
      </Representation>
      <Representation id="audio_12_1" mimeType="audio/mp4" codecs="mp4a.40.2" audioSamplingRate="44100" startWithSAP="1" bandwidth="60639">
        <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
        <BaseURL> --- Hidden --- </BaseURL>
        <SegmentBase indexRangeExact="true" indexRange="839-4902">
          <Initialization range="0-838" />
        </SegmentBase>
      </Representation>
      <Representation id="audio_14_1" mimeType="audio/mp4" codecs="mp4a.40.2" audioSamplingRate="44100" startWithSAP="1" bandwidth="97613">
        <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2" />
        <BaseURL> --- Hidden --- </BaseURL>
        <SegmentBase indexRangeExact="true" indexRange="839-4902">
          <Initialization range="0-838" />
        </SegmentBase>
      </Representation>
    </AdaptationSet>
  </Period>
</MPD>
TheModMaker commented 3 years ago

Could you send us a manifest URL? You can send it privately to shaka-player-issues@google.com if you want. Your manifest doesn't include the PSSH info in it and doesn't explicitly list Widevine, just that it is encrypted. What may be happening is the content is encrypted with something else that ExoPlayer is handling. Or it could be a bug in our media parsing causing us to not find the correct PSSH data in the media. But we won't be able to see this without the media itself.

OmarPedraza commented 3 years ago

@TheModMaker, I've just sent you an email with more information about the issue. Do not hesitate to reach me if it's not enough.

Thanks!

OmarPedraza commented 3 years ago

Working fine!

Thanks @TheModMaker!