Monday 5 October 2020

AWS S3 signing for HLS Videos on iOS Safari

I'm using HLS.js to handle HLS streams and I've been able to get it working fine on Android. The issue is that Safari iOS has HLS support built in, so it doesn't support Media Source Extensions (MSE). This means that I can't use the custom loader to sign each file chunks URL so it can access that file chunk on S3. Each user has their own cognito access and can only access their folder in the S3 bucket. This stops users from viewing other peoples videos. This is why a generic signing of the playlist file isn't enough as the playlist file could be signed, but as soon as the stream tries to access the file chunks, it's block because they're not signed.

if (Hls.isSupported()) {
                        class loader extends Hls.DefaultConfig.loader {
                            constructor(config) {
                                super(config);
                                var load = this.load.bind(this);
                                this.load = async function(context, config, callbacks) {
                                    let signedVideoPlaylistUrl = await new Promise((resolve, reject) => {
                                        s3.getSignedUrl('getObject', {
                                            Bucket: 'bucket-name',
                                            // Pass the URL and get the S3 key
                                            Key: context.url.split("s3.amazonaws.com/")[1],
                                            Expires: 60 * 60 * 1 // 1 hour
                                        }, function(error, result){
                                            if(error){
                                                console.error(error);
                                                reject(error);
                                            } else {
                                                resolve(result);
                                            }
                                        })
                                    });
                                    context.url = signedVideoPlaylistUrl;
                                    load(context, config, callbacks);
                                };
                            }
                        }
                        var hls = new Hls({
                            loader: loader
                        });
                        hls.attachMedia(video);
                        hls.on(Hls.Events.MEDIA_ATTACHED, function(event, data) {
                            console.log(event, data);
                        });
                        hls.on(Hls.Events.MANIFEST_PARSED, function() {
                            console.log(event, data);
                            //video.play();
                        });
                        hls.loadSource(`"https://bucket-name.s3.amazonaws.com/users/random-user-id/category/video_hls/recordingId.m3u8`);
                    }
                    // hls.js is not supported on platforms that do not have Media Source Extensions (MSE) enabled.
                    // When the browser has built-in HLS support (check using `canPlayType`), we can provide an HLS manifest (i.e. .m3u8 URL) directly to the video element through the `src` property.
                    // This is using the built-in support of the plain video element, without using hls.js.
                    // Note: it would be more normal to wait on the 'canplay' event below however on Safari (where you are most likely to find built-in HLS support) the video.src URL must be on the user-driven
                    // white-list before a 'canplay' event will be emitted; the last video event that can be reliably listened-for when the URL is not on the white-list is 'loadedmetadata'.
                    else if (video.canPlayType('application/vnd.apple.mpegurl')) {
                        //THIS IS WHERE I'M STUCK
                        throw new Meteor.Error("Not Supported");
                        video.src = signedVideoPlaylistUrl;
                        video.addEventListener('loadedmetadata', function() {
                            video.play();
                        });
                    }
                }

Since Safari on iOS doesn't support HLS.js, I can't intercept the URL like I can with the code above. Does anyone know if it's possible to do this? I haven't been able to find a way to do it with native HTML with the video tag.

Thanks!



from AWS S3 signing for HLS Videos on iOS Safari

No comments:

Post a Comment