From 7cee052dcd5473448f882d67bb5bc9d8e9a1763c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Gangs=C3=B8?= Date: Tue, 4 May 2021 18:43:54 +0200 Subject: [PATCH 1/2] feat: Allow modifying the load request (#123, #141) Allow modifying the load request to make it possible to cast HLS video by using: ``` modifyLoadRequestFn: function (loadRequest) { loadRequest.media.hlsSegmentFormat = 'fmp4'; loadRequest.media.hlsVideoSegmentFormat = 'fmp4'; return loadRequest; } ``` --- README.md | 10 ++++++++++ src/js/tech/ChromecastTech.js | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/README.md b/README.md index 31b0f67..2b58963 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,9 @@ player.chromecast(); // initializes the Chromecast plugin If nothing is returned or if this option is not defined, no custom data will be sent. This option is intended to be used with a [custom receiver][custom-receiver] application to extend its default capabilities. + * **`chromecast.modifyLoadRequestFn`** - a function that this plugin calls before doing + the request to [load media][chromecast-load-media]. The function gets called with the + [LoadRequest][chromecast-load-request] object as argument and expects it in return. Here is an example configuration object that makes full use of all required and optional configuration: @@ -220,6 +223,11 @@ options = { }, requestCustomDataFn: function(source) { // Not required return customData[source.url]; + }, + modifyLoadRequestFn: function (loadRequest) { // HLS support + loadRequest.media.hlsSegmentFormat = 'fmp4'; + loadRequest.media.hlsVideoSegmentFormat = 'fmp4'; + return loadRequest; } }, plugins: { @@ -342,3 +350,5 @@ details. [player-source]: http://docs.videojs.com/Player.html#currentSource [custom-receiver]: https://developers.google.com/cast/docs/custom_receiver [contributing]: https://github.com/silvermine/silvermine-info#contributing +[chromecast-load-media]: https://developers.google.com/cast/docs/reference/web_sender/cast.framework.CastSession#loadMedia +[chromecast-load-request]: https://developers.google.com/cast/docs/reference/web_sender/chrome.cast.media.LoadRequest diff --git a/src/js/tech/ChromecastTech.js b/src/js/tech/ChromecastTech.js index 3dd89d4..663ea3e 100644 --- a/src/js/tech/ChromecastTech.js +++ b/src/js/tech/ChromecastTech.js @@ -75,6 +75,9 @@ module.exports = function(videojs) { this._requestTitle = options.requestTitleFn || function() { /* noop */ }; this._requestSubtitle = options.requestSubtitleFn || function() { /* noop */ }; this._requestCustomData = options.requestCustomDataFn || function() { /* noop */ }; + this._modifyLoadRequestFn = options.modifyLoadRequestFn || function(request) { + return request; + }; // See `currentTime` function this._initialStartTime = options.startTime || 0; @@ -209,6 +212,7 @@ module.exports = function(videojs) { request = new chrome.cast.media.LoadRequest(mediaInfo); request.autoplay = true; request.currentTime = startTime; + request = this._modifyLoadRequestFn(request); this._isMediaLoading = true; this._hasPlayedCurrentItem = false; From 2f799f234d573c3ecc838d8629fe77ba69ee165f Mon Sep 17 00:00:00 2001 From: kontrollanten <6680299+kontrollanten@users.noreply.github.com> Date: Fri, 1 Sep 2023 06:38:30 +0200 Subject: [PATCH 2/2] test: verify modifyLoadRequestFn has accurate default value --- tests/ChromcastTech.test.js | 94 ++++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/tests/ChromcastTech.test.js b/tests/ChromcastTech.test.js index 4a8440d..f554ac6 100644 --- a/tests/ChromcastTech.test.js +++ b/tests/ChromcastTech.test.js @@ -1,13 +1,56 @@ 'use strict'; -var expect = require('expect.js'); +const expect = require('expect.js'); + +const sinon = require('sinon'); const chromecastTech = require('../src/js/tech/ChromecastTech'); class TechComponentStub { + constructor() { + this._ui = { + getPoster: () => {}, + updatePoster: () => {}, + updateSubtitle: () => {}, + updateTitle: () => {}, + }; + this.trigger = () => {}; + } + on() {} + ready() {} } describe('ChromecastTech', function() { + let originalCast, + originalChrome; + + this.beforeEach(() => { + originalCast = global.cast; + global.cast = { + framework: { + RemotePlayerEventType: {}, + }, + }; + + originalChrome = global.chrome; + global.chrome = { + cast: { + media: { + GenericMediaMetadata: function() {}, + LoadRequest: function() {}, + MediaInfo: function() {}, + MetadataType: {}, + StreamType: {}, + }, + }, + }; + }); + + this.afterEach(() => { + global.cast = originalCast; + global.chrome = originalChrome; + }); + it('should not call videojs.extend', function() { const videoJsSpy = { extend: function() { @@ -23,4 +66,53 @@ describe('ChromecastTech', function() { chromecastTech(videoJsSpy); }); + + it('should call castSession.loadMedia with accurate req from chrome.cast.media.LoadRequest', function() { + let ChromecastTech; + + const loadMediaSpy = sinon.stub().returns(Promise.resolve()); + + const videoJsSpy = () => { + return { + chromecastSessionManager: { + getCastContext: () => { + return { + getCurrentSession: () => { + return { + loadMedia: loadMediaSpy, + }; + }, + }; + }, + getRemotePlayer: () => {}, + getRemotePlayerController: () => { + return { + addEventListener: () => {}, + }; + }, + }, + poster: () => {}, + }; + }; + + videoJsSpy.getComponent = () => { + return TechComponentStub; + }; + videoJsSpy.registerTech = (_, component) => { + ChromecastTech = component; + }; + + const fakeRequest = {}; + + sinon.stub(global.chrome.cast.media, 'LoadRequest').returns(fakeRequest); + + chromecastTech(videoJsSpy); + + // eslint-disable-next-line no-new + new ChromecastTech({ + source: 'source.url', + }); + + expect(loadMediaSpy.calledWith(fakeRequest)).to.be(true); + }); });