As the title says I have some video saved on an s3 bucket. I set my nodejs to stream it on my react app. It works fine on all devices except iOS. I did some searches and I can't find the issue. The server is returning the initial bytes request as 206. I checked the headers but I can't find the issue: Here is my nodejs: After it reaches the path:
if (!range) {
res.status(400).send("returning err!");
return;
}
s3.headObject({
Bucket: process.env.AWS_BUCKET_NAME,
Key: req.params.key
}, function (err, data) {
if (err) {
// an error occurred
console.error(err);
return res.status(500).send("returning err");
}
const videoSize = Number(data.ContentLength);
const CHUNK_SIZE = 10 ** 6; // 1MB
const start = Number(range.replace(/\D/g, ""));
const end = Math.min(start + CHUNK_SIZE, videoSize - 1);
var params = {
Bucket: process.env.AWS_BUCKET_NAME,
Key: req.params.key,
Range: range,
};
var stream = s3.getObject(params).createReadStream();
res.status(206);
res.set('Content-Type', data.ContentType);
res.set('Content-Disposition','inline');
res.set('Accept-Ranges','bytes');
res.set('Accept-Encoding', 'Identity');
res.set('Content-Range', 'bytes ' + start + '-' + end + '/' + videoSize);
res.set('Content-Length', data.ContentLength);
res.set('X-Playback-Session-Id', req.header('X-Playback-Session-Id')); // Part of the attempt to fix
res.set('Connection', 'keep-alive');
res.set('Last-Modified', data.LastModified);
res.set('ETag', data.ETag);
stream.pipe(res);
Here is my Frontend React player code:
<ReactPlayer
ref={player}
// onProgress={onProgress}
playsinline={true}
url={[{ src: source, type: 'video/mp4;' }]} // video location
controls // gives the front end video controls
width='100%'
className='react-player'
height='100%'
allow='autoplay; encrypted-media'
allowFullScreen
// muted={true}
playing={playing}
onPlay={() => setPlaying(true)}
// onPause={() => setPlaying(false)} //part of the attempt to fix
// onSeek={(seek) => playerSeeker(seek)} //part of the attempt to fix
config={{
file: {
attributes: {
controlsList: 'nodownload'
}
}
}}
onContextMenu={e => e.preventDefault()}
onEnded={(e) => onVideoEnded(e)}
onError={(e) => onVideoError(e)}
/>
Again, the first request on iOS is returning a 206 success but node always ends the stream before it even start playing.
Turns out It was just the
res.set('Content-Length', data.ContentLength);
Instead of sending the full length for the video, I needed to return the length of the calculated range.