时雨小径 May the Spirit be with you

Fix Chromecast DASH-MPEG playback issue

Recently in a chromecast project which requires to play MPEG-DASH format, we found that current official Media Player Library has some limitation on retrieving license, some other developers also have this similar issue and they have complained at chromecast developer forum, unfortunately, nothing is indicating there would
be a fix soon.

Based on the response of someone from google, they suggest developers to skip the request to make their own license requests, however, without having access to the Message Event fired by the media library, we won't be able to construct necessary license request, that's I say it's limited.

But this thread actually leads me to the correct solution, which is to add a simple workaround to the original media player library to make it support updating license request URL, and also make it support GET method. (by default it only support POST)

The original code in official media player library:

  this.g.Rd = a.withCredentials;
  this.g.Xb = Math.max(0, a.timeoutInterval);
  this.g.send(a.url, "POST", a.content,
      a.headers);

After modification:

  if (this.a.requestFilter) {
    a.url += this.a.requestFilter(a.content);
  }
  var method = a.method || "POST";
  this.g.Rd = a.withCredentials;
  this.g.Xb = Math.max(0, a.timeoutInterval);
  this.g.send(a.url, method, a.content,
      a.headers);

Here I need a.content which is the request body to create my parameter for license request URL, and variable a is RequestInfo object we need to overwrite using mediaHost's updateLicenseRequestInfo method.

In my receiver application, I've added following modification:

  _mediaHost.requestFilter = function (content) {
    var rawLicenseRequestBase64 = encodeURIComponent(_this.arrayTob64String(new Uint8Array(content)));
    return rawLicenseRequestBase64;
  };

  _mediaHost.processLicense = function (data) {
    var wrappedString = String.fromCharCode.apply(null, new Uint8Array(data));
    var wrapped = JSON.parse(wrappedString);
    var licenseBase64 = wrapped.getWidevineLicenseResponse.license;
    return _this.b64StringToArray(licenseBase64);
  };

  _mediaHost.updateLicenseRequestInfo = function (requestInfo) {
    requestInfo.method = 'GET';
  };

After I made this change, the receiver application is able to play DASH stream, however, there is still a weird issue on chromecast V1, that although I can cast a video to the device and play, when I try to cast second video, it hangs and keep buffering.

When I look at the log, I found that in the media player library, there is line of code to use mediaKeys to create session, and this object will be set to null at some moment when switching streams, but since there is no null checking on the line of creating session, it will just break unexpectedly.

Original code:

  this.h = this.a.mediaElement;
  this.Eb = a;
  this.nc = a = this.h.mediaKeys.createSession();
  E(this.nc, "message", this.lj, !1, this);
  a.generateRequest("cenc", b.buffer).catch(this.jj.bind(this))

After added null checking:

  this.h = this.a.mediaElement;
  this.Eb = a;
  if (this.h.mediaKeys) {
    this.nc = a = this.h.mediaKeys.createSession();
    E(this.nc, "message", this.lj, !1, this);
    a.generateRequest("cenc", b.buffer).catch(this.jj.bind(this))
  }

As so far, the two issues are all fixed by updating the media player library, previously I have also fixed a bug related to subtitle parsing bug, while sadly there is no open-source community available for this library, only a developer forum to raise issues, which seems to be not actively maintained, a issue I raised 10 month ago was marked as Acknowledged, then there isn't any update yet.

Anyway, I have post another issue on the forum, see if they want to fix it or not.