HLS options not being passed in mobile
I have a HLS stream with amazon signed cookies that will work on normal chrome browser on a laptop, if I change to a mobile device either by an actual device or by toggling device mode in the dev tools, the stream will no longer work. It appears to still be sending the correct cookie headers, but not the correct Cors header : sec-fetch-mode: no-cors
This is my config for React-Player config={{ file: { hlsOptions: { xhrSetup: function(xhr, url) { xhr.withCredentials = true // send cookies }, forceHLS: true, } } }}
I added forceHLS: true to make sure it wasn't somehow switching players on me, but that was just a guess. I put a console log in there to see whether options were being run both times and it appears that they are only run on the standard browser. Although that is not reliable as the Cors errors don't seem to appear properly in device mode, so maybe logs don't either.
It is hard to understand whether this is a React Player issue or a HLS issue, Since it could be that the xhr.withCredentials config might not be making it to the player in device mode i felt like that could make it a React-player issue rather than a HLS.js issue, but i don't know why either should behave differently in a PC versus a mobile device.
Thank you for any help in advance.
Using react-player 2.9.0
So on further experimentation it seems very likely that this is a react-player issue. I have implemented a direct Hls.js approach and it does not have any issues with headers or cookies in either state. So i suspect something is interrupting these headers somewhere in the transition in react-player.
It could be a number of things, I saw something about updating to the latest HLS version in react-player, which might be the issue. But otherwise it could be the options not making it to the player for some reason when the player is in a mobile environment. Or it could be that the headers are being over written by something else when the player moves into mobile, This is an option as the cookies are still being passed with the request when the player fails, but the accompanying sec-fetch-mode header is no-cors, which could mean that something reset those headers without removing the cookies.
I dont know, i am just exploring possibilities. Hope this helps.
You can update the hls.js version you are using with config={{ file: { hlsVersion: 'x.x.x' } }}. Try matching the version with your direct HLS.js example that works, and see if you still get problems.
I gave that a try, yarn tells me that i am using Hls.js 1.0.4, looks to be latest version. Same issue occurs here.
I don't really need this issue fixed at the moment, as i only need one working player so i am happy to stick to my implementation of Hls.js, however i appreciate that setting up a signed cookie environment is no small task so i am happy to test out a few things for you if you would like me to. Or if you think this issue is niche enough not to be urgent then put it on the backburner by all means.
I've got the same issue. The m3u8 file loads perfectly fine on the desktop browser but it doesn't work on mobile. Definitely a react-player issue as it works via hls.js. Has anyone found a solution as I'd like to keep using this module? Thanks!
There are two things here @zammitjames. If HLS library doesn't load properly due to cookies or anything, just bring it in from your own CDN right before you need it. You can call this as many times you start the HLS player cause will only get the library if it doesn't exist:
let requestedHLS = false
const loadHls = () => {
if (!window.Hls && !requestedHLS) {
requestedHLS = true
const script = document.createElement('script')
script.src = 'https://your cdn.com/cdn/js/hls_v2.js'
script.type = 'text/javascript'
// script.integrity = integritySet.shaHLSJS
// script.crossOrigin = 'anonymous'
document.body.appendChild(script)
}
}
If by mobile you mean IOS, true, it is not supposed to work in IOS. That's why in your react player config you check for the browser. IOS plays HLS 'natively':
My options for mobile (Android):
const hlsOptions = {
maxBufferLength: 1,
maxMaxBufferLength: 2,
maxBufferSize: 1000000,
maxLoadingDelay: 2,
capLevelToPlayerSize: true,
liveSyncDuration: 1
}
const config = {
file: {
hlsOptions: window.innerWidth > 575 ? {} : hlsOptions,
forceHLS: !(isSafari || isIOS), // It might be that react-player checks for this maybe even automatically selects the HLS player ... I lost track with the updates, I just use my own check.
forceVideo: true,
attributes: {
disablePictureInPicture: true
}
}
}
We had the same issue with signed cookies not being picked up in iOS alone. The trick to get this to work was to set the crossOrigin config to use-credentials in attributes, on top of setting xhr.withCredentials to true in hlsOptions config.
My understanding is that setting xhr.withCredentials to true helps in environments where hls.js is playing the HLS video. However, in iOS, since the native player kicks in, the withCredentials config does not help. When the native player kicks in, it uses a default value of anonymous for the crossOrigin config, which in turn causes it to ignore cookies while fetching HLS manifests. Adding the crossOrigin config to attributes tells the native player to send cookies.
The setting that worked for us was as follows:
config={{
file: {
attributes: {
crossOrigin: "use-credentials"
},
forceVideo: true,
hlsOptions: {
xhrSetup: function(xhr, videoFileSrc) {
xhr.withCredentials = true;
}
},
hlsVersion: "1.4.12"
},
}}
More on how native player uses the crossorigin config is here. Note that the name of the config when passed through react-player has a capital O in it. An example is shown in this fiddle.