diff --git a/src/services/Chromecast/Chromecast.js b/src/services/Chromecast/Chromecast.js new file mode 100644 index 000000000..1e3832710 --- /dev/null +++ b/src/services/Chromecast/Chromecast.js @@ -0,0 +1,133 @@ +// Copyright (C) 2017-2020 Smart code 203358507 + +const EventEmitter = require('events'); + +const RECEIVER_APPLICATION_ID = '1634F54B'; +const CUSTOM_MESSAGE_NAMESPACE = 'urn:x-cast:com.stremio'; + +let castAPIAvailable = null; +const castAPIEvents = new EventEmitter(); +window['__onGCastApiAvailable'] = function(available) { + delete window['__onGCastApiAvailable']; + castAPIAvailable = available; + castAPIEvents.emit('availabilityChanged'); +}; + +function Chromecast() { + let active = false; + let error = null; + let starting = false; + + const events = new EventEmitter(); + events.on('error', () => { }); + + function onCastAPIAvailabilityChange() { + if (castAPIAvailable) { + active = true; + error = null; + } else { + active = false; + error = new Error('Google Cast API not available'); + } + + starting = false; + onStateChanged(); + } + function onStateChanged() { + if (active) { + const context = cast.framework.CastContext.getInstance(); + context.setOptions({ + autoJoinPolicy: chrome.cast.AutoJoinPolicy.PAGE_SCOPED, + // TODO language: '' + receiverApplicationId: RECEIVER_APPLICATION_ID, + resumeSavedSession: false + }); + // context.addEventListener(cast.framework.CastContextEventType.SESSION_STATE_CHANGED, onSessionStateChange); + } else if (castAPIAvailable) { + const context = cast.framework.CastContext.getInstance(); + context.setOptions({ + autoJoinPolicy: chrome.cast.AutoJoinPolicy.PAGE_SCOPED, + // TODO language: '' + receiverApplicationId: chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID, + resumeSavedSession: false + }); + // context.removeEventListener(cast.framework.CastContextEventType.SESSION_STATE_CHANGED, onSessionStateChange); + // context.removeEventListener(cast.framework.CastContextEventType.CAST_STATE_CHANGED, onSessionStateChange); + } + + events.emit('stateChanged'); + } + function start() { + if (active || error instanceof Error || starting) { + return; + } + + starting = true; + if (castAPIAvailable !== null) { + onCastAPIAvailabilityChange(); + } else { + castAPIEvents.on('availabilityChanged', onCastAPIAvailabilityChange); + } + } + function stop() { + castAPIEvents.off('availabilityChanged', onCastAPIAvailabilityChange); + active = false; + error = null; + starting = false; + onStateChanged(); + } + function on(name, listener) { + events.on(name, listener); + } + function off(name, listener) { + events.off(name, listener); + } + function dispatch(action) { + if (!active || !action) { + return; + } + + switch (action.type) { + case 'message': { + const castSession = cast.framework.CastContext.getInstance().getCurrentSession(); + if (castSession) { + castSession.sendMessage(CUSTOM_MESSAGE_NAMESPACE, action.message); + } + + return; + } + } + } + + Object.defineProperties(this, { + active: { + configurable: false, + enumerable: true, + get: function() { + return active; + } + }, + error: { + configurable: false, + enumerable: true, + get: function() { + return error; + } + }, + starting: { + configurable: false, + enumerable: true, + get: function() { + return starting; + } + } + }); + + this.start = start; + this.stop = stop; + this.on = on; + this.off = off; + this.dispatch = dispatch; +} + +module.exports = Chromecast; diff --git a/src/services/Chromecast/index.js b/src/services/Chromecast/index.js new file mode 100644 index 000000000..a4d3d8e8f --- /dev/null +++ b/src/services/Chromecast/index.js @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2020 Smart code 203358507 + +const Chromecast = require('./Chromecast'); + +module.exports = Chromecast; diff --git a/src/services/index.js b/src/services/index.js index 726939d0f..3c4c75556 100644 --- a/src/services/index.js +++ b/src/services/index.js @@ -1,11 +1,13 @@ // Copyright (C) 2017-2020 Smart code 203358507 +const Chromecast = require('./Chromecast'); const Core = require('./Core'); const KeyboardNavigation = require('./KeyboardNavigation'); const { ServicesProvider, useServices } = require('./ServicesContext'); const Shell = require('./Shell'); module.exports = { + Chromecast, Core, KeyboardNavigation, ServicesProvider,