shaka-player icon indicating copy to clipboard operation
shaka-player copied to clipboard

Recover player after HTTP_ERROR

Open jakubkrolikowski opened this issue 2 years ago • 12 comments

Have you read the Tutorials? yes

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

What version of Shaka Player are you using? 3.1.x

Please ask your question When the Shaka player cannot connect to the media server on fetching new data, even for a very short time, the player stops with error HTTP_ERROR 1002, with severity CRITICAL, which means the manifest needs to be reloaded. Error looks like this:

{
  "severity": 2,
  "category": 1,
  "code": 1002,
  "data": ["https://......mp4", {
    "name": "TypeError",
    "message": "NetworkError when attempting to fetch resource.",
    "stack": ""
  }

This is a very serious reaction to a common problem, which is a short break in internet connection.

I wonder if there is an easy way to recover the player after HTTP_ERROR? Can I configure Shaka player to react more friendly in this kind of situation and for example, wait for new content in "loading" state for N seconds and then try again? How do you deal with critical HTTP_ERROR?

jakubkrolikowski avatar Aug 23 '21 14:08 jakubkrolikowski

OK, I think I found a proper combination of settings. I have significantly increased "maxAttempts" setting.

Could you please explain the difference between "timeout" and "connectionTimeout" settings? 20 seconds for timeout isn't too short? My current configuration:

player.configure({
    drm: {
      servers: supportedservers,
      retryParameters: {
        maxAttempts: 25
      }
    },
    streaming: {
      bufferingGoal: 25, 
      rebufferingGoal: 3, 
      bufferBehind: 10, 
      retryParameters: {
        timeout: 20000,
        stallTimeout: 6000, 
        connectionTimeout: 15000,       
        maxAttempts: 120,   
        baseDelay: 1000,  
        backoffFactor: 2, 
        fuzzFactor: 0.5,  
      }
    },
    abr: {
      bandwidthDowngradeTarget: 0.95,
      bandwidthUpgradeTarget: 0.85,
      defaultBandwidthEstimate: 10000,
     
      enabled: true,
      switchInterval: 5
    }
  })

jakubkrolikowski avatar Aug 23 '21 15:08 jakubkrolikowski

connectionTimeout is for establishing the HTTP connection, not counting the request and response time.

timeout is for entire transfer.

As for recovery, there is a streaming error callback you can use. See https://shaka-player-demo.appspot.com/docs/api/shaka.extern.html#.StreamingConfiguration and use streaming.failureCallback.

A callback to decide what to do on a streaming failure. Default behavior is to retry on live streams and not on VOD.

But that description is a bit lacking. We should add more detail. If you want to continue streaming in spite of a streaming error, call player.retryStreaming(). Here's what the default callback looks like in Player:

https://github.com/google/shaka-player/blob/d5769eeda47524998a714a3d701604561d761b6d/lib/player.js#L4832-L4849

Does this help?

joeyparrish avatar Aug 24 '21 04:08 joeyparrish

Great! Thank you, I missed this feature, it's very useful!

jakubkrolikowski avatar Aug 24 '21 09:08 jakubkrolikowski

Glad this helped! I'm going to reopen the issue, tag it "docs", and convert it to a tracking bug to improve the documentation on this. Thanks!

joeyparrish avatar Aug 25 '21 22:08 joeyparrish

Hi ! I downloaded and built the files today itself and ran into the same problem . I was checking out the code given in the Tutorials under the Basic Usage Section. Upon encountering the problem and viewing the above mentioned solution I tried to use player.retryStreaming() in the following manner :

   // Try to load a manifest.
   // This is an asynchronous process.
   try {
       await player.load(manifestUri);
       // This runs if the asynchronous load is successful.
       console.log('The video has now been loaded!');
   } catch (e) {
       // onError is executed if the asynchronous load fails.
       // shaka.log.warning('Live streaming error.  Retrying automatically...'); 
       console.log(player.retryStreaming());
       onError(e);
   }

And I still receive this error even though player.retryStreaming() is returning true

I would be grateful if you could kindly suggest a solution to this problem . I would also love to update the documentation once this problem is solved.

Thank You

Ansh-Sarkar avatar Sep 04 '21 10:09 Ansh-Sarkar

If load fails, you need to call it again. retryStreaming is only for errors that happen after playback has started. So this only makes sense in error events.

player.addEventListener('error', () => {
  // Error during playback, try to recover.
  player.retryStreaming();
});

TheModMaker avatar Sep 04 '21 18:09 TheModMaker

Oh ! Ok . Got it . Will try this out and then update the docs for the retryStreaming( ) function . Thank You for the help

Ansh-Sarkar avatar Sep 06 '21 04:09 Ansh-Sarkar

Yup . Thank you for the suggestion @TheModMaker . This code works . It retrys loading the manifestUri every 5 seconds . The player no longer needs to be reloaded after every failure .

const manifestUri =
    'https://storage.googleapis.com/shaka-demo-assets/angel-one/dash.mpd';

function initApp() {
    // Install built-in polyfills to patch browser incompatibilities.
    shaka.polyfill.installAll();

    // Check to see if the browser supports the basic APIs Shaka needs.
    if (shaka.Player.isBrowserSupported()) {
        // Everything looks good!
        initPlayer();
    } else {
        // This browser does not have the minimum set of APIs we need.
        console.error('Browser not supported!');
    }
}

async function initPlayer() {
    // Create a Player instance.
    const video = document.getElementById('video');
    const 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);

    // Try to load a manifest.
    // This is an asynchronous process.
    try {
        await player.load(manifestUri);
        // This runs if the asynchronous load is successful.
        console.log('The video has now been loaded!');
    } catch (e) {
        // onError is executed if the asynchronous load fails.
        // shaka.log.warning('Live streaming error.  Retrying automatically...'); 
        onError(e);
    }
}

function sleep(milliseconds) {
    const date = Date.now();
    let currentDate = null;
    do {
        currentDate = Date.now();
    } while (currentDate - date < milliseconds);
}

function onErrorEvent(event) {
    // Extract the shaka.util.Error object from the event.
    onError(event.detail);
    // in case of errors 
    player.retryStreaming();
}

async function onError(error) {
    // in case of failure of the asynchronous load function
    console.log("Load failed . Trying to reload manifestUri . . . in 3 seconds ");
    sleep(5000);
    if(error.code == 1002)
        await player.load(manifestUri);
    console.error('Error code', error.code, 'object', error.detail);
}

document.addEventListener('DOMContentLoaded', initApp);

Ansh-Sarkar avatar Sep 09 '21 13:09 Ansh-Sarkar

Also do you think it would be a good idea to modify the documentation for the retryStreaming( ) function ? I think mentioning the difference between , when to use retryStreaming( ) and when to use the load( ) function could help future developers getting started more smoothly . Kindly provide your suggestions as to whether this should be done .

Thank You

Ansh-Sarkar avatar Sep 09 '21 13:09 Ansh-Sarkar

Yes, we should improve the docs. This issue is being kept open to track docs improvements. Here are my suggestions:

  1. failureCallback should explain how it works (received error object, callback makes decision) and point to retryStreaming docs
  2. retryStreaming should explain when and how to use it (and when not to use it, such as when load() fails)

joeyparrish avatar Sep 09 '21 15:09 joeyparrish

Yes . Agree with both the points . Especially the second one . I was trying to call retryStreaming( ) everytime load( ) was failing . I would like to make the necessary changes and contribute to the documentation . Will notify once the necessary changes have been made so that they can be reviewed and corrected if required . Really appreciate the suggestions .

Thank You

Ansh-Sarkar avatar Sep 09 '21 17:09 Ansh-Sarkar

Hi there, I just set up the dev environment today and ran the tests. Everything worked completely fine until I tried to change the manifestUri in myapp.js in order to see how the errors are being handled. Looked for failureCallback in player_configuration.js and tried to understand how it works. I'm a newbie to open source and would like to contribute to improve the docs by making the two changes you suggested. @joeyparrish

Yes, we should improve the docs. This issue is being kept open to track docs improvements. Here are my suggestions:

  1. failureCallback should explain how it works (received error object, callback makes decision) and point to retryStreaming docs
  2. retryStreaming should explain when and how to use it (and when not to use it, such as when load() fails)

abhinavvsinhaa avatar Sep 19 '21 15:09 abhinavvsinhaa

Fixed in https://github.com/shaka-project/shaka-player/pull/4983

avelad avatar May 08 '24 12:05 avelad