Shaka-player: player.load(manifest) never resolves, though manifest is loaded

Created on 9 May 2018  路  12Comments  路  Source: google/shaka-player

Have you read the FAQ and checked for duplicate open issues?: yes

What version of Shaka Player are you using?: 2.3.7

Can you reproduce the issue with our latest release version?: yes

Can you reproduce the issue with the latest code from master?: haven't tried to compile

Are you using the demo app or your own custom app?: custom

If custom app, can you reproduce the issue using our demo app?: haven't tried

What browser and OS are you using?: chrome 66 mac high sierra

What are the manifest and license server URIs?: http://yt-dash-mse-test.commondatastorage.googleapis.com/media/car-20120827-manifest.mpd

What did you do?

I'm writing a custom element that wraps shaka player. My method for loading manifests looks like this:

async loadManifest(manifestUrl, player = this.player) { // this.player is a handle on the shaka player instance
  if (!player) throw new Error('Could not load player');

  // If the player is already initialized, unload it's sources.
  if (player.getManifest()) player.unload();

  const loaded = await player.load(manifestUrl); // this promise is never resolving
  this.dispatchEvent(new CustomEvent('manifest-loaded', {detail:loaded})); // breakpoints set here never break
  return loaded;
}

The promise from player.load() never resolves. I never reach the breakpoint at this.dispatchEvent.

What did you expect to happen?
I expected the promise to resolve, the event to be dispatched, and the video to play

What actually happened?
Although the promise never resolves, If I run player.getManifest() in the js console, I do in fact see the parsed manifest, and I see that the manifest was loaded over the network by the browser. Nonetheless, when I try to videoElement.play() I get a DOMException: The element has no supported sources.

archived unable to reproduce

All 12 comments

I'm unable to reproduce this in our demo app:

https://shaka-player-demo.appspot.com/demo/#asset=https://yt-dash-mse-test.commondatastorage.googleapis.com/media/car-20120827-manifest.mpd;lang=en-US;build=uncompiled

This leads me to expect that it's something specific to your app or your wrapper.

I notice that you are explicitly calling unload(), and also not waiting on unload() to complete. unload() is an async method that returns a Promise.

But you shouldn't have to call unload() explicitly at all, since that is implied by a subsequent load() call. You can simply call load() again without unloading it first. What happens in your app if you drop the unload() call?

After looking into this, I'm sure it has something to do with a double call to load or unload. I removed the unload call and waited on any previous load promise, and that got things working again.
Could this be an area where a console warning would help users?

Thanks.

It could be a bug. We are supposed to tolerate all manner of calling patterns between load/unload/destroy.
With the caveat that after destroy, nothing else can be called, there's no need to necessarily wait between load/unload/destroy, and they can be called multiple times.

We have a bunch of automated tests to verify this, but it's possible we have a regression that the tests don't catch.

Let me see if I can reproduce it by mimicking your code above.

I'm fascinated that you're building a polymer element for Shaka! I think that's really cool.

I can't reproduce the issue, though, in a standalone app. I started with our basic usage tutorial, and I tried adding all the same things (except requestAnimationFrame) that you had in the broken commit:

async function initPlayer() {
  // Create a Player instance.
  var video = document.getElementById('video');
  var player = new shaka.Player(video);

  // Attach player to the window to make it easy to access in the JS console.
  window.player = player;

  // Listen for error events.
  player.addEventListener('error', onErrorEvent);

  console.log('PROBE 1');
  support = await shaka.Player.probeSupport();
  console.log(support);

  console.log('LOAD 1');
  try {
    player.load(manifestUri);
  } catch (error) {
    onError(error);
  }

  await delay(5);

  console.log('UNLOAD');
  video.pause();
  video.src = '';
  player.unload();

  console.log('PROBE 2');
  support = await shaka.Player.probeSupport();
  console.log(support);

  console.log('LOAD 2');
  try {
    await player.load(manifestUri);
  } catch (error) {
    onError(error);
  }
}

Did I miss something?

Also, I noticed that you're doing this in the working version on each new load:

    const support = await shaka.Player.probeSupport();
    const manifest = support.manifest.mpd ? dashManifest : hlsManifest;

You shouldn't need to call probeSupport(). It's a method that may cause user prompts while probing DRM support, and the manifest support you're checking for is decided at compile time. So if you are using a standard build of Shaka Player, or if you've customized it in a way that has both DASH and HLS, you know ahead of time what manifest types are supported.

Even if you're using did need to use probeSupport() to check for browser support for various DRM systems and codecs, you can still cache that result across playbacks. It won't change during the life of the page.

Could it be because I'm connecting multiple players to the soon at the same time? In my case, I had these part elements as children in a virtual-list. Multiple re renders via Lit-html. Could be a contributing factor.

I was using probesupport as it seemed the only way to check at runtime if dash is supported. Did I miss something?

There is no need to use probeSupport() for DASH support if you control the build of Shaka Player that is loaded. DASH & HLS support are determined at compile time, and are both on by default.

Ahhh perhaps I wasn't clear as to what I had in mind. My idea was to load hls on iPhones as video src instead of loading a dash manifest, and, preferring feature detection to UA parsing, I thought that probeSupport was the only reliable way to do that.

  1. Pass all available sources to element
  2. On init, element determines which are able to play
  3. Element prefers dash, then hls, then MP4, depending on UA support.

Do you recommend, for example, that I should do some UA parsing in app code before passing the manifest as a property to my element?

  1. App decides which manifest to load based on UA string parsing
  2. App passes manifest either as dashManifest, hlsManifest, or src property
  3. Element tries it's best, exposing an error event when needed.

First, we don't support iOS at all since it doesn't support MediaSource. We also do our own DASH and HLS parsing, we never pass it to the browser; this means we support them on all platforms equally. So we either support DASH and HLS or don't support anything (assuming the default build).

What you could do is use shaka.Player.isBrowserSupported to detect whether the browser is supported, then fall back to src=. Note that you should always use isBrowserSupported before creating the Player to ensure the browser supports everything we need.

if (shaka.Player.isBrowserSupported()) {
  let player = new shaka.Player(video);
  player.load(dashManifest);
} else {
  video.src = 'foo.mp4';  // or 'foo.m3u8' on iOS/Mac.
}

Instead of UA parsing, use shaka.Player.isBrowserSupported() as @TheModMaker suggests. If that returns true, you can pass either DASH or HLS, whichever you prefer.

That sounds great. thanks for the advice, I think that should do it. I'm going to close because it seems my problem is solved, but please consider adding some more descriptive errors.

Was this page helpful?
0 / 5 - 0 ratings