Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chromecast crashes when using serviceWorkers? #2205

Closed
Fenny opened this issue Oct 21, 2019 · 19 comments
Closed

Chromecast crashes when using serviceWorkers? #2205

Fenny opened this issue Oct 21, 2019 · 19 comments
Assignees
Labels
status: archived Archived and locked; will not be updated type: question A question from the community

Comments

@Fenny
Copy link

Fenny commented Oct 21, 2019

Are serviceWorkers disabled on the chromecast, the app instantly crashed when called:

try {
    if ('serviceWorker' in navigator) {
        navigator.serviceWorker.getRegistrations().then(function(registrations) {
            for(let registration of registrations) {  
                registration.unregister();
                console.log('Unregister', registration)
            }
    	})
        navigator.serviceWorker.register('sw.js', {scope: './'}).then(function() {
          console.log('Success!')
        }).catch(function(err) {
            console.log(err);
        });
    } else {
        console.log('Service worker not supported')
    }
} catch (err) {
	console.log(err)
}
@Fenny Fenny added the type: question A question from the community label Oct 21, 2019
@joeyparrish
Copy link
Member

I don't believe Google removed service workers. They are still working in the Shaka Player Demo.

Is your page running in a "secure context"? (That means either https or localhost.) Service workers are spec'd to require a secure context. So you may have seen an update to the browser that started enforcing this requirement.

Quoting MDN's "Using Service Workers" article:

You’ll also need to serve your code via HTTPS — Service workers are restricted to running across HTTPS for security reasons. GitHub is therefore a good place to host experiments, as it supports HTTPS. In order to facilitate local development, localhost is considered a secure origin by browsers as well.

Does this help?

@Fenny
Copy link
Author

Fenny commented Oct 21, 2019

@joeyparrish You are right, serviceWorker still exist in the navigator on localhost and https.
I tested with ngrok and can confirm that any chromecast instantly crashes on calling the serviceWorker register function

However, chromecast seems to crash right after I launch a serviceWorker, same code I used for years.

receiver.js

const ctx = cast.framework.CastReceiverContext.getInstance();
ctx.start()
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('serviceWorker.js', { scope: './' }).then(() => {
    console.log('serviceWorker ready!);
  })
}

serviceWorker.js

// Call skipWaiting and claim to take control immediately.
self.addEventListener('install', () => {
  self.skipWaiting();
});
self.addEventListener('activate', () => {
  clients.claim();
});
// Intercept fetch requests and log url
self.addEventListener('fetch', async (e) => {
  console.log(e.request.url)
  return;
})

This code works fine, except on the chromecast.
After it launches the serviceWorker it crashes with the message "Something went wrong" and goes back to the homescreen after some seconds.

Any idea's why?

@Fenny Fenny changed the title Update disabled serviceWorkers? Update causes crash when using serviceWorkers? Oct 21, 2019
@Fenny Fenny changed the title Update causes crash when using serviceWorkers? Chromecast crashes when using serviceWorkers? Oct 21, 2019
@joeyparrish
Copy link
Member

I'm not sure why the cast receiver would crash with a service worker. It shouldn't. You should file a bug with the Chromecast team, since that sounds like a c++ bug somewhere in the firmware of the device.

In the mean time, you can check if the device is a Chromecast and bypass the service worker.

@Fenny
Copy link
Author

Fenny commented Oct 21, 2019

Could you point me in the right direction to contact the Chromecast developers?

@joeyparrish
Copy link
Member

Also, you edited your original post such that this thread no longer makes sense. Please don't do that.

Now that I've read the original post again, I can see that you're using the service worker to intercept range requests and send them over WebRTC. You don't need a service worker for this if you're using Shaka Player. Instead, you can implement a "scheme plugin". This allows you to handle all network requests for a certain URL scheme. For example, you could register your plugin for the "http" and "https" schemes. Then all http(s) traffic from Shaka Player would go through your plugin. If you want to handle some requests over WebRTC, but not others, you can delegate certain requests to the default HTTP scheme plugin.

See lib/net/http_fetch_plugin.js in the sources. You can delegate to this for requests you don't want to handle, and use it as a template to build and register your own plugin.

@joeyparrish
Copy link
Member

Chromecast issues can be filed here: https://issuetracker.google.com/issues/new?component=190205&template=814901

@joeyparrish
Copy link
Member

Does this help?

@Fenny
Copy link
Author

Fenny commented Oct 21, 2019

@joeyparrish Thanks, I will create a thread!

I thought the current title is more fitting to the actual problem, but I understand what you mean.

PS: Should we keep this issue open until its solved by the cast developers?

@joeyparrish
Copy link
Member

Editing the title was no problem. But changing the entire contents of the original post so that the replies sound like nonsense is a bit jarring, and it makes it difficult for us to locate important details, such as your use of service worker specifically to route over WebRTC.

@joeyparrish
Copy link
Member

There's nothing my team can do for you regarding the Cast issue, since your service worker is at the application level, and we can't influence this cast bug in any way. But please link back to your cast issue here, so that we can track it and offer assistance to the cast team if necessary. Thanks!

@Fenny
Copy link
Author

Fenny commented Oct 21, 2019

Also, you edited your original post such that this thread no longer makes sense. Please don't do that.

Now that I've read the original post again, I can see that you're using the service worker to intercept range requests and send them over WebRTC. You don't need a service worker for this if you're using Shaka Player. Instead, you can implement a "scheme plugin". This allows you to handle all network requests for a certain URL scheme. For example, you could register your plugin for the "http" and "https" schemes. Then all http(s) traffic from Shaka Player would go through your plugin. If you want to handle some requests over WebRTC, but not others, you can delegate certain requests to the default HTTP scheme plugin.

See lib/net/http_fetch_plugin.js in the sources. You can delegate to this for requests you don't want to handle, and use it as a template to build and register your own plugin.

I used a serviceWorker to catch the range request and retrieve the chunks from the webtorrent object (sender) back to the receiver and serviceWorker to convert the buffer to a blob and serve the request as a regular stream. Can I achieve the same with the scheme plugin? Intercept range requests and communicate with the sender before proxy the request back to the shaka player?

PS: Created the serviceWorker issue https://issuetracker.google.com/issues/143057613

@joeyparrish
Copy link
Member

Yes, that's correct. Your plugin would accept a Request object containing a URL and return a Promise to a Response object containing an ArrayBuffer of data.

@Fenny
Copy link
Author

Fenny commented Oct 21, 2019

That sounds exactly what I'm looking for, so theoretically we could cast local content from the browser without extentions? Is there already a "scheme plugin" out there, I'm new to the shaka player :sadface:

@joeyparrish
Copy link
Member

Yes, all of our networking capabilities are in terms of our plugin interface. For example, see:

Those are implementations of the scheme plugin interface for http/https and data URIs respectively.

@Fenny
Copy link
Author

Fenny commented Oct 23, 2019

@joeyparrish Thanks for the examples.

Since there are 17 open issues regarding the cast sdk on the google issuetracker that are still unanswered since oct 3, I have low hopes that they will fix the serviceWorker bug anytime soon.

Therefor I would give shaka a try to cast local content in the browser without extensions.

Could you help me how I could play media using the file.createReadStream(start, end) function?
Previously I used a serviceWorker to intercept the range requests and call the readStream function to get the correct buffer and turn it into a 'octet/stream' blob.

Something like this

function getNextBlob(start) {
  return new Promise((res, reject) => {
    const SEGMENT_SIZE = 64 * 1000;
    const stream = media.createReadStream({ 
      start:  start, 
      end:    start + SEGMENT_SIZE - 1 
    });
    stream.once('data', data => {
      const buffer  = data.slice(0, SEGMENT_SIZE);
      const blob    = new Blob([resp.buffer], { type: 'octet/stream' });
      res(blob)
    });
    stream.once('error', reject);
  })
}

How can I make shaka work with a readStream, could you give me an example?

Thank you for your time!

@joeyparrish
Copy link
Member

I'm sorry, but I'm not familiar with file.readStream().

In principle, you must create a function with the following signature to implement the scheme plugin interface. This is taken from the data URI plugin I mentioned before.

 /**
   * @param {string} uri
   * @param {shaka.extern.Request} request
   * @param {shaka.net.NetworkingEngine.RequestType} requestType
   * @param {shaka.extern.ProgressUpdated} progressUpdated Called when a
   *   progress event happened.
   * @return {!shaka.extern.IAbortableOperation.<shaka.extern.Response>}
   * @export
   */
  mySchemePlugin(uri, request, requestType, progressUpdated) {
    // ...
  }

You can ignore progressUpdated for your purposes.

Read the uri, request, and requestType arguments and decide if you want to handle the request. If not, just delegate to the standard HTTP scheme plugin:

return shaka.net.HttpFetchPlugin.parse(uri, request, requestType, progressUpdated);

If you do want to handle the request, you return an instance of shaka.util.AbortableOperation. If your handler cannot be aborted, use the static method shaka.util.AbortableOperation.notAbortable instead of the constructor.

AbortableOperation takes a Promise to a shaka.extern.Response object. The data field of the Response contains the response data as an ArrayBuffer. So if you can get an ArrayBuffer for your content through file.readStream(), this shouldn't be too hard. The headers object can be empty. The uri and originalUri fields are required. The rest are optional. You can refer to the Response docs for more detail.

Finally, you will register your plugin like so:

shaka.net.NetworkingEngine.registerScheme('http', mySchmePlugin);
shaka.net.NetworkingEngine.registerScheme('https', mySchmePlugin);

Does this help?

@Fenny
Copy link
Author

Fenny commented Oct 23, 2019

Thanks @joeyparrish , your help is much appreciated!

After a day of errors I managed to get something to work, but I still need some help regarding the Response. I can't get that to work, but I thought I should create another topic for that since its not related to the current one.

If we could continue on Issue 2213, that would be great!

Thank you so much for being so responsive! 👍👍

@joeyparrish
Copy link
Member

Sounds good. I'll mention this briefly here, then close the issue and take the conversation to the new issue:

I've just discovered that a small bug in the code prevents you from delegating to the fetch plugin as I recommended. It should be very easy to fix, though you would have to build the player from source to see the fix. If you're loading from cdnjs, you won't see it until a new release it out.

shaka-bot pushed a commit that referenced this issue Oct 23, 2019
Without this, custom scheme plugins can't delegate to this standard
one.

Issue #2205
Issue #2213

Change-Id: I13e9762e75ba9afe9fd7f804404ffb1d2e684435
@Fenny
Copy link
Author

Fenny commented Oct 28, 2019

@joeyparrish , unfortunately nobody responded to the issue yet.
https://issuetracker.google.com/issues/143057613
https://support.google.com/chromecast/thread/17509737?hl=en

To make sure it's not on my end, I looked for multiple receiver snippets on github that also used service workers.
I tried to run them on my receiver and I can confirm they also crashed, the newest repository using service workers on a receiver was 12 months old.

You said in issue 2205

I don't believe Google removed service workers. They are still working in the Shaka Player Demo.

Can you confirm that shaka player executes the

navigator.serviceWorker.register()

function on the receiver end?

If this is the case, this means it's not the actual function call that makes the chromecast crash.

I also found this on the chromium forum, I'm not sure if it has anything to do with the serviceWorker support on the chromecast:

Chromecast devtools API fixes. (issue 505393002)
Side by Side Diff: chromecast/shell/browser/devtools/cast_dev_tools_delegate.cc

I'm not giving up 😉, maybe you could shine some extra light on this matter.

@shaka-project shaka-project locked and limited conversation to collaborators Dec 22, 2019
@shaka-bot shaka-bot added the status: archived Archived and locked; will not be updated label Apr 15, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
status: archived Archived and locked; will not be updated type: question A question from the community
Projects
None yet
Development

No branches or pull requests

3 participants