├── .gitignore ├── .jshintrc ├── Gruntfile.js ├── LICENSE ├── README.md ├── bower.json ├── chromecast.js ├── examples ├── receiver.html └── sender.html ├── package.json └── src └── chromecast.js /.gitignore: -------------------------------------------------------------------------------- 1 | /.settings 2 | /.project 3 | /bower_components 4 | /node_modules 5 | .DS_Store 6 | /docs 7 | /chromecast-bundle.js 8 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "camelcase": false, 6 | "curly": true, 7 | "eqeqeq": true, 8 | "immed": true, 9 | "indent": 4, 10 | "latedef": true, 11 | "newcap": true, 12 | "noarg": true, 13 | "quotmark": "single", 14 | "regexp": true, 15 | "undef": true, 16 | "unused": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "white": true, 21 | "globals": { 22 | "chrome": true, 23 | "window": true, 24 | "cast": true, 25 | "define": true 26 | } 27 | } -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | 'use strict'; 3 | 4 | var _ = require('lodash'); 5 | var Q = require('q'); 6 | 7 | require('load-grunt-tasks')(grunt); 8 | grunt.initConfig({ 9 | pkg: grunt.file.readJSON('package.json'), 10 | 11 | watch: { 12 | dev: { 13 | files: [ 14 | 'src/*.js', 'examples/*.html' 15 | ], 16 | tasks: [ 17 | 'test' 18 | ], 19 | options: { 20 | nospawn: true, 21 | livereload: '<%= portscanner.portLiveReload %>' 22 | } 23 | } 24 | }, 25 | 26 | jshint: { 27 | options: grunt.file.readJSON('./.jshintrc'), 28 | test: { 29 | files: { 30 | src: [ 31 | 'src/*.js' 32 | ] 33 | }, 34 | } 35 | }, 36 | 37 | open: { 38 | dev: { 39 | path: 'http://localhost:<%= portscanner.port %>/examples/sender.html' 40 | }, 41 | docs: { 42 | path: 'http://localhost:<%= portscanner.port %>/docs/readme.html' 43 | } 44 | }, 45 | 46 | docco: { 47 | docs: { 48 | src: [ 49 | 'README.md', 'src/*.js' 50 | ], 51 | options: { 52 | output: 'docs/' 53 | } 54 | } 55 | }, 56 | 57 | connect: { 58 | dev: { 59 | options: { 60 | port: '<%= portscanner.port %>', 61 | base: '', 62 | middleware: function (connect) { 63 | var connectLiveReload = require('connect-livereload'); 64 | 65 | return [ 66 | connectLiveReload({ 67 | port: grunt.config('portscanner.portLiveReload') 68 | }), 69 | connect.static(require('path').resolve('./')) 70 | ]; 71 | } 72 | } 73 | } 74 | }, 75 | 76 | uglify: { 77 | dist: { 78 | files: { 79 | 'chromecast.js': ['chromecast-bundle.js'] 80 | } 81 | } 82 | }, 83 | 84 | browserify: { 85 | dist: { 86 | files: { 87 | 'chromecast-bundle.js': ['src/chromecast.js'] 88 | } 89 | } 90 | } 91 | }); 92 | 93 | grunt.registerTask('portscanner', 'find a free tcp port', function () { 94 | var done = this.async(); 95 | var Task = { 96 | initialize: function () { 97 | this.deferred = new Q(); 98 | 99 | return this; 100 | }, 101 | findPort: function (name) { 102 | var portscanner = require('portscanner'); 103 | var deferred = Q.defer(); 104 | 105 | this.deferred = this.deferred.then(function (p_port) { 106 | var port = p_port || 5000; 107 | 108 | portscanner.findAPortNotInUse(port, 6000, 'localhost', _.bind(function (error, port) { 109 | grunt.config.set(name, port); 110 | 111 | console.log(name, port); 112 | deferred.resolve(port + 1); 113 | }, this)); 114 | 115 | return deferred.promise; 116 | }); 117 | 118 | return this; 119 | }, 120 | execute: function () { 121 | this.findPort('portscanner.port').findPort('portscanner.portLiveReload'); 122 | 123 | return this.deferred; 124 | } 125 | }; 126 | 127 | Object.create(Task).initialize().execute().then(function () { 128 | done(); 129 | }); 130 | }); 131 | 132 | 133 | grunt.registerTask('test', [ 134 | 'jshint:test', 'compile' 135 | ]); 136 | grunt.registerTask('default', [ 137 | 'test' 138 | ]); 139 | grunt.registerTask('serverdev', [ 140 | 'docco:docs', 'portscanner', 'connect:dev', 'open:docs', 'open:dev', 'watch' 141 | ]); 142 | grunt.registerTask('compile', [ 143 | 'browserify:dist', 'uglify:dist' 144 | ]); 145 | }; 146 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Marc Buils 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # chromecastjs 2 | 3 | ## Current version 4 | 5 | v0.1.0 6 | 7 | ## Licence 8 | 9 | MIT 10 | 11 | ## Author 12 | 13 | Marc Buils from Marc Buils Consultant Compagny (France) 14 | 15 | (and sorry for my english. I work it, but currently it is very bad...) 16 | 17 | 18 | ## Description 19 | 20 | JavaScript project based on ChromeCast API to build ChromeCast apps very easy 21 | 22 | AMD and CommonJS compatible 23 | 24 | Here all the requirements you need before to build the output files or to launch the dev mode: 25 | 26 | - [NodeJS](http://nodejs.org/download/) 27 | - [Grunt](http://gruntjs.com/) ```npm install -g grunt-cli``` 28 | - [PhantomJS](http://phantomjs.org/download.html) ```npm install -g phantomjs``` 29 | - [Bower](http://bower.io/) ```npm install -g bower``` 30 | 31 | 32 | ## Getting Started 33 | 34 | A Chromecast app is composed by 35 | - Sender application to start your application from a device (on Google Chrome with ChromeCast plugin) 36 | - Receiver application open on chromecast 37 | 38 | ### Install 39 | 40 | - Bower 41 | > bower install --save-dev chromecastjs 42 | 43 | ### Sender example 44 | ```html 45 | 46 | 47 | 48 | Hello World 49 | 50 | 51 | 52 | 53 | 58 | 59 |
54 |
55 | 56 |
57 |
60 | 61 | 62 | 83 | 84 | 85 | ``` 86 | 87 | 88 | ### Receiver example 89 | ```html 90 | 91 | 92 | 93 | Cast Hello Text 94 | 95 | 96 |
Talk to me
97 | 98 | 111 | 112 | 113 | ``` 114 | 115 | ## Usage 116 | 117 | > chromecast.createSender({options}) 118 | 119 | Create a chromecastjs sender instance 120 | 121 | > chromecast.createReceiver({options}) 122 | 123 | Create a chromecastjs receiver instance 124 | 125 | 126 | ### Sender 127 | 128 | _WARNING: no message can be sent during the first second after initialize_ 129 | 130 | 131 | #### API 132 | 133 | > on({event name}, {callback}) 134 | 135 | Register an event (see Getting Started / Sender / API / Events) 136 | 137 | 138 | > sendMessage({message}) 139 | 140 | Send a message to the receiver app 141 | 142 | 143 | #### Events 144 | 145 | - message 146 | - session 147 | - initSuccess 148 | - error 149 | - success 150 | - stopappsuccess 151 | - sessionupdatelistener 152 | - listener 153 | 154 | 155 | ### Receiver 156 | 157 | #### API 158 | 159 | > on({event name}, {callback}) 160 | 161 | Register an event (see Getting Started / Sender / API / Events) 162 | 163 | 164 | > sendMessage({message}) 165 | 166 | Send a message to the receiver app 167 | 168 | 169 | > getSenders() 170 | 171 | Get list of senders 172 | 173 | 174 | > disconnect() 175 | 176 | Close the app 177 | 178 | 179 | #### Events 180 | 181 | - message 182 | - ready 183 | - senderconnected 184 | - senderdisconnected 185 | - systemvolumechanged 186 | 187 | 188 | ## Development 189 | 190 | ### Getting sources 191 | 192 | This is how to launch the app quickly in dev mode: 193 | 194 | > * clone the git repository: 195 | > ```bash 196 | > git clone https://github.com/marcbuils/chromecastjs.git 197 | > ``` 198 | > 199 | > * Run in chromecastjs folder: 200 | > 201 | > ```bash 202 | > # Dependencies 203 | > npm install; bower install 204 | > # Start watcher for development 205 | > grunt start 206 | > ``` 207 | 208 | ### Sending pull request 209 | 210 | This is how to send a pull request: 211 | - Fork the project on your github account 212 | - Clone the project on local (see Development/Getting sources) 213 | - Add feature / bugfixed 214 | - Start test 215 | 216 | > * Run in chromecastjs folder: 217 | > 218 | > ```bash 219 | > grunt test 220 | > ``` 221 | 222 | - Commit and create a pull request with description of your modification 223 | 224 | (: THANKS FOR YOUR PARTICIPATION :) 225 | 226 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chromecastjs", 3 | "version": "0.1.0", 4 | "homepage": "https://github.com/marcbuils/chromecastjs", 5 | "authors": [ 6 | "marc.buils " 7 | ], 8 | "description": "JavaScript project based on ChromeCast API to build ChromeCast apps very easy", 9 | "main": "chromecast.js", 10 | "moduleType": [ 11 | "amd", 12 | "globals" 13 | ], 14 | "keywords": [ 15 | "chromecast", 16 | "google", 17 | "chrome", 18 | "cast", 19 | "js", 20 | "javascript", 21 | "api" 22 | ], 23 | "license": "MIT", 24 | "ignore": [ 25 | "**/.*", 26 | "node_modules", 27 | "bower_components", 28 | "test", 29 | "tests" 30 | ], 31 | "devDependencies": { 32 | "cast_sender": "http://www.gstatic.com/cv/js/sender/v1/cast_sender.js", 33 | "cast_receiver": "http://www.gstatic.com/cast/sdk/libs/receiver/2.0.0/cast_receiver.js" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /chromecast.js: -------------------------------------------------------------------------------- 1 | !function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g")&&(a=a.replace(r,">")),-1!=a.indexOf('"')&&(a=a.replace(s,""")),-1!=a.indexOf("'")&&(a=a.replace(t,"'")),a):a},p=/&/g,q=//g,s=/"/g,t=/'/g,u=/[&<>"']/,v=function(a,b){return b>a?-1:a>b?1:0},w=function(a,b){b.unshift(a),m.call(this,n.apply(null,b)),b.shift()};l(w,m),w.prototype.name="AssertionError";var x,y,z,A,B=function(a,b){if(!a){var c="Assertion failed";if(b)var c=c+(": "+b),d=Array.prototype.slice.call(arguments,2);throw new w(""+c,d||[])}},C=function(a){throw new w("Failure"+(a?": "+a:""),Array.prototype.slice.call(arguments,1))},D=Array.prototype,E=D.indexOf?function(a,b,c){return B(null!=a.length),D.indexOf.call(a,b,c)}:function(a,b,c){if(c=null==c?0:0>c?Math.max(0,a.length+c):c,e(a))return e(b)&&1==b.length?a.indexOf(b,c):-1;for(;c0){for(var c=Array(b),d=0;b>d;d++)c[d]=a[d];return c}return[]},G=function(a){var b,c=[],d=0;for(b in a)c[d++]=b;return c},H=function(a){var b,c={};for(b in a)c[b]=a[b];return c},I="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),J=function(a){for(var b,c,d=1;dparseFloat(U)){N=String(X);break a}}N=U}var Y=N,Z={},$=function(a){var b;if(!(b=Z[a])){b=0;for(var c=String(Y).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),d=String(a).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split("."),e=Math.max(c.length,d.length),f=0;0==b&&e>f;f++){var g=c[f]||"",h=d[f]||"",i=/(\d*)(\D*)/g,j=/(\d*)(\D*)/g;do{var k=i.exec(g)||["","",""],l=j.exec(h)||["","",""];if(0==k[0].length&&0==l[0].length)break;b=v(0==k[1].length?0:parseInt(k[1],10),0==l[1].length?0:parseInt(l[1],10))||v(0==k[2].length,0==l[2].length)||v(k[2],l[2])}while(0==b)}b=Z[a]=b>=0}return b},_=b.document,ab=_&&P?S()||("CSS1Compat"==_.compatMode?parseInt(Y,10):5):void 0,bb=function(a){return cb(a||arguments.callee.caller,[])},cb=function(a,b){var c=[];if(0<=E(b,a))c.push("[...circular reference...]");else if(a&&50>b.length){c.push(db(a)+"(");for(var d=a.arguments,e=0;e0&&c.push(", ");var f;switch(f=d[e],typeof f){case"object":f=f?"object":"null";break;case"string":break;case"number":f=String(f);break;case"boolean":f=f?"true":"false";break;case"function":f=(f=db(f))?f:"[fn]";break;default:f=typeof f}40=tb(this).value)for("function"==d(c)&&(c=c()),a=this.Db(a,c,e),c="log:"+a.Ha,b.console&&(b.console.timeStamp?b.console.timeStamp(c):b.console.markTimeline&&b.console.markTimeline(c)),b.msWriteProfilerMark&&b.msWriteProfilerMark(c),c=this;c;){e=c;var f=a;if(e.T)for(var g=0,h=void 0;h=e.T[g];g++)h(f);c=c.getParent()}},hb.prototype.Db=function(a,d,f){var g=new fb(a,String(d),this.Ua);if(f){g.ra=f;var h,i=arguments.callee.caller;try{var j,k=c("window.location.href");if(e(f))j={message:f,name:"Unknown error",lineNumber:"Not available",fileName:k,stack:"Not available"};else{var l,m,n=!1;try{l=f.lineNumber||f.Ob||"Not available"}catch(p){l="Not available",n=!0}try{m=f.fileName||f.filename||f.sourceURL||b.$googDebugFname||k}catch(q){m="Not available",n=!0}j=!n&&f.lineNumber&&f.fileName&&f.stack&&f.message&&f.name?f:{message:f.message||"Not available",name:f.name||"UnknownError",lineNumber:l,fileName:m,stack:f.stack||"Not available"}}h="Message: "+o(j.message)+'\nUrl: '+j.fileName+"\nLine: "+j.lineNumber+"\n\nBrowser stack:\n"+o(j.stack+"-> ")+"[end]\n\nJS stack traversal:\n"+o(bb(i)+"-> ")}catch(r){h="Exception trying to expose exception! You win, we lose. "+r}g.qa=h}return g};var ub=function(a,b,c){a.log(kb,b,c)};hb.prototype.info=function(a,b){this.log(mb,a,b)};var vb=function(a,b){a.log(ob,b,void 0)},wb=function(a,b){a.log(pb,b,void 0)},xb={},yb=null,zb=function(){yb||(yb=new hb(""),xb[""]=yb,yb.ya(nb))},Ab=function(a){zb();var b;if(!(b=xb[a])){b=new hb(a);var c=a.lastIndexOf("."),d=a.substr(c+1),c=Ab(a.substr(0,c));c.xa||(c.xa={}),c.xa[d]=b,b.da=c,xb[a]=b}return b},Bb=function(){};Bb.prototype.Ta=!1,Bb.prototype.G=function(){this.Ta||(this.Ta=!0,this.d())};var Cb=function(a,b){a.V||(a.V=[]),a.V.push(h(b,void 0))};Bb.prototype.d=function(){if(this.V)for(;this.V.length;)this.V.shift()()};var Db=function(a){a&&"function"==typeof a.G&&a.G()},Eb=function(a,b){this.type=a,this.currentTarget=this.target=b,this.defaultPrevented=this.B=!1,this.Qa=!0};Eb.prototype.d=function(){},Eb.prototype.G=function(){},Eb.prototype.stopPropagation=function(){this.B=!0},Eb.prototype.preventDefault=function(){this.defaultPrevented=!0,this.Qa=!1},k("cast.receiver.VERSION","2.0.0");var Fb=Ab("cast");k("cast.receiver.logger",Fb),k("cast.receiver.LoggerLevel",{DEBUG:0,VERBOSE:400,INFO:800,ERROR:1e3,NONE:1500}),Fb.Wa=function(a){Fb.ya(sb(a))},Fb.setLevelValue=Fb.Wa,Fb.Wa(1e3);var Gb=function(){this.Va=j()},Hb=new Gb;Gb.prototype.set=function(a){this.Va=a},Gb.prototype.reset=function(){this.set(j())},Gb.prototype.get=function(){return this.Va};var Ib=function(a){this.rb=a||"",this.sb=Hb};a=Ib.prototype,a.tb=!0,a.La=!0,a.vb=!0,a.ub=!0,a.Ma=!1,a.wb=!1;var Jb=function(a){return 10>a?"0"+a:String(a)},Kb=function(a,b){var c=(a.Pa-b)/1e3,d=c.toFixed(3),e=0;if(1>c)e=2;else for(;100>c;)e++,c*=10;for(;0=9);var Rb=Qb,Sb=P&&!$("9");!R||$("528"),Q&&$("1.9b")||P&&$("8")||O&&$("9.5")||R&&$("528"),Q&&!$("8")||P&&$("9");var Tb=function(a,b){if(Eb.call(this,a?a.type:""),this.relatedTarget=this.currentTarget=this.target=null,this.charCode=this.keyCode=this.button=this.screenY=this.screenX=this.clientY=this.clientX=this.offsetY=this.offsetX=0,this.metaKey=this.shiftKey=this.altKey=this.ctrlKey=!1,this.U=this.state=null,a){var c=this.type=a.type;this.target=a.target||a.srcElement,this.currentTarget=b;var d=a.relatedTarget;if(d){if(Q){var e;a:{try{Pb(d.nodeName),e=!0;break a}catch(f){}e=!1}e||(d=null)}}else"mouseover"==c?d=a.fromElement:"mouseout"==c&&(d=a.toElement);this.relatedTarget=d,this.offsetX=R||void 0!==a.offsetX?a.offsetX:a.layerX,this.offsetY=R||void 0!==a.offsetY?a.offsetY:a.layerY,this.clientX=void 0!==a.clientX?a.clientX:a.pageX,this.clientY=void 0!==a.clientY?a.clientY:a.pageY,this.screenX=a.screenX||0,this.screenY=a.screenY||0,this.button=a.button,this.keyCode=a.keyCode||0,this.charCode=a.charCode||("keypress"==c?a.keyCode:0),this.ctrlKey=a.ctrlKey,this.altKey=a.altKey,this.shiftKey=a.shiftKey,this.metaKey=a.metaKey,this.state=a.state,this.U=a,a.defaultPrevented&&this.preventDefault()}};l(Tb,Eb),Tb.prototype.stopPropagation=function(){Tb.n.stopPropagation.call(this),this.U.stopPropagation?this.U.stopPropagation():this.U.cancelBubble=!0},Tb.prototype.preventDefault=function(){Tb.n.preventDefault.call(this);var a=this.U;if(a.preventDefault)a.preventDefault();else if(a.returnValue=!1,Sb)try{(a.ctrlKey||112<=a.keyCode&&123>=a.keyCode)&&(a.keyCode=-1)}catch(b){}},Tb.prototype.d=function(){};var Ub="closure_listenable_"+(1e6*Math.random()|0),Vb=function(a){try{return!(!a||!a[Ub])}catch(b){return!1}},Wb=0,Xb=function(a,b,c,d,e){this.w=a,this.ca=null,this.src=b,this.type=c,this.$=!!d,this.ba=e,this.key=++Wb,this.J=this.aa=!1},Yb=function(a){a.J=!0,a.w=null,a.ca=null,a.src=null,a.ba=null},Zb=function(a){this.src=a,this.g={},this.S=0};Zb.prototype.add=function(a,b,c,d,e){var f=this.g[a];f||(f=this.g[a]=[],this.S++);var g=_b(f,b,d,e);return g>-1?(a=f[g],c||(a.aa=!1)):(a=new Xb(b,this.src,a,!!d,e),a.aa=c,f.push(a)),a},Zb.prototype.remove=function(a,b,c,d){if(!(a in this.g))return!1;var e=this.g[a];return b=_b(e,b,c,d),b>-1?(Yb(e[b]),B(null!=e.length),D.splice.call(e,b,1),0==e.length&&(delete this.g[a],this.S--),!0):!1};var $b=function(a,b){var c=b.type;if(c in a.g){var d,e=a.g[c],f=E(e,b);(d=f>=0)&&(B(null!=e.length),D.splice.call(e,f,1)),d&&(Yb(b),0==a.g[c].length&&(delete a.g[c],a.S--))}};Zb.prototype.wa=function(a,b,c,d){a=this.g[a];var e=-1;return a&&(e=_b(a,b,c,d)),e>-1?a[e]:null};var _b=function(a,b,c,d){for(var e=0;ed.keyCode||void 0!=d.returnValue)){a:{var g=!1;if(0==d.keyCode)try{d.keyCode=-1;break a}catch(h){g=!0}(g||void 0==d.returnValue)&&(d.returnValue=!0)}for(d=[],g=e.currentTarget;g;g=g.parentNode)d.push(g);for(var g=a.type,i=d.length-1;!e.B&&i>=0;i--)e.currentTarget=d[i],f&=hc(d[i],g,!0,e);for(i=0;!e.B&&i>>0),mc=function(a){return B(a,"Listener can not be null."),"function"==d(a)?a:(B(a.handleEvent,"An object listener must have handleEvent method."),a[lc]||(a[lc]=function(b){return a.handleEvent(b)}))},nc=function(){this.r=new Zb(this),this.Cb=this};l(nc,Bb),nc.prototype[Ub]=!0,a=nc.prototype,a.sa=null,a.addEventListener=function(a,b,c,d){dc(this,a,b,c,d)},a.removeEventListener=function(a,b,c,d){fc(this,a,b,c,d)},a.dispatchEvent=function(a){pc(this);var b,c=this.sa;if(c){b=[];for(var d=1;c;c=c.sa)b.push(c),B(1e3>++d,"infinite loop")}if(c=this.Cb,d=a.type||a,e(a))a=new Eb(a,c);else if(a instanceof Eb)a.target=a.target||c;else{var f=a;a=new Eb(d,c),J(a,f)}var g,f=!0;if(b)for(var h=b.length-1;!a.B&&h>=0;h--)g=a.currentTarget=b[h],f=oc(g,d,!0,a)&&f;if(a.B||(g=a.currentTarget=c,f=oc(g,d,!0,a)&&f,a.B||(f=oc(g,d,!1,a)&&f)),b)for(h=0;!a.B&&h2147483647?-1:b.setTimeout(a,c||0)},sc=function(a,b){nc.call(this),this.lb=void 0!==a?a:!0,this.ia=b||vc,this.Z=this.ia(this.Q)};l(sc,nc),a=sc.prototype,a.i=null,a.q=null,a.F=void 0,a.ja=!1,a.Q=0;var tc=sc.prototype,uc=Ab("goog.net.WebSocket");tc.a=uc;var vc=function(a){return Math.min(1e3*Math.pow(2,a),6e4)};a=sc.prototype,a.open=function(a,c){B(b.WebSocket,"This browser does not support WebSocket"),B(!this.P(),"The WebSocket is already open"),null!=this.D&&b.clearTimeout(this.D),this.D=null,this.q=a,(this.F=c)?(qc(this.a,"Opening the WebSocket on "+this.q+" with protocol "+this.F),this.i=new WebSocket(this.q,this.F)):(qc(this.a,"Opening the WebSocket on "+this.q),this.i=new WebSocket(this.q)),this.i.onopen=h(this.nb,this),this.i.onclose=h(this.mb,this),this.i.onmessage=h(this.K,this),this.i.onerror=h(this.ga,this)},a.close=function(){null!=this.D&&b.clearTimeout(this.D),this.D=null,this.i&&(qc(this.a,"Closing the WebSocket."),this.ja=!0,this.i.close(),this.i=null)},a.send=function(a){B(this.P(),"Cannot send without an open socket"),this.i.send(a)},a.P=function(){return!!this.i&&1==this.i.readyState},a.nb=function(){qc(this.a,"WebSocket opened on "+this.q),this.dispatchEvent("d"),this.Q=0,this.Z=this.ia(this.Q)},a.mb=function(a){if(qc(this.a,"The WebSocket on "+this.q+" closed."),this.dispatchEvent("a"),this.i=null,this.ja)qc(this.a,"The WebSocket closed normally."),this.q=null,this.F=void 0;else{var b=this.a;b&&ub(b,"The WebSocket disconnected unexpectedly: "+a.data,void 0),this.lb&&(qc(this.a,"Seconds until next reconnect attempt: "+Math.floor(this.Z/1e3)),this.D=rc(h(this.open,this,this.q,this.F),this.Z,this),this.Q++,this.Z=this.ia(this.Q))}this.ja=!1},a.K=function(a){this.dispatchEvent(new wc(a.data))},a.ga=function(a){a=a.data;var b=this.a;b&&ub(b,"An error occurred: "+a,void 0),this.dispatchEvent(new xc(a))},a.d=function(){sc.n.d.call(this),this.close()};var wc=function(a){Eb.call(this,"c"),this.message=a};l(wc,Eb);var xc=function(a){Eb.call(this,"b"),this.data=a};l(xc,Eb);var yc=function(a,b){nc.call(this),this.u=b,this.la=!0,this.I=a,this.onClose=this.onMessage=null,dc(this.I,this.u,this.ua,!1,this)};l(yc,nc),k("cast.receiver.CastChannel",yc),yc.EventType={MESSAGE:"message",CLOSE:"close"};var zc=function(a,b){Eb.call(this,a),this.message=b};l(zc,Eb),yc.Event=zc,yc.prototype.a=Ab("cast.receiver.CastChannel"),yc.prototype.s=function(){return"CastChannel["+this.u+" "+this.I.v()+"]"},yc.prototype.v=function(){return this.I.v()},yc.prototype.getNamespace=yc.prototype.v,yc.prototype.Ib=function(){return this.u},yc.prototype.getSenderId=yc.prototype.Ib,yc.prototype.ua=function(a){wb(this.a,"Dispatching CastChannel message ["+this.I.v()+", "+this.u+"]: "+a.data),a=new zc("message",a.data),this.onMessage&&this.onMessage(a),this.dispatchEvent(a)},yc.prototype.close=function(){if(this.la){this.la=!1,this.a.info("Closing CastChannel ["+this.I.v()+", "+this.u+"]");var a=new zc("close",this.u);this.onClose&&this.onClose(a),this.dispatchEvent(a),this.G()}},yc.prototype.send=function(a){if(!this.la)throw Error("Invalid state, socket not open");this.I.send(this.u,a)},yc.prototype.send=yc.prototype.send,yc.prototype.d=function(){yc.n.d.call(this),wb(this.a,"Disposed "+this.s())},k("cast.receiver.system.NAMESPACE_PREFIX","urn:x-cast:"),k("cast.receiver.system.ApplicationData",function(){this.name=this.id="",this.sessionId=0,this.namespaces=[],this.launchingSenderId=""}),k("cast.receiver.system.Sender",function(){this.userAgent=this.id=""});var Ac=function(){nc.call(this),this.j=null;var a=new sc(!0);this.j&&this.j.G(),this.j=a,Cb(this,i(Db,this.j)),dc(this.j,"d",this.Ab,!1,this),dc(this.j,"a",this.zb,!1,this),dc(this.j,"b",this.ga,!1,this),dc(this.j,"c",this.K,!1,this)};l(Ac,nc);var Bc=function(a,b,c){Eb.call(this,a),this.senderId=b,this.data=c};l(Bc,Eb),Ac.prototype.a=Ab("cast.receiver.IpcChannel");var Cc=function(a,b){vb(a.a,"IpcChannel "+b),a.dispatchEvent(new Bc("urn:x-cast:com.google.cast.system","SystemSender",JSON.stringify({type:b})))};a=Ac.prototype,a.Ab=function(){Cc(this,"opened")},a.zb=function(){Cc(this,"closed")},a.ga=function(){Cc(this,"error")},a.K=function(a){vb(this.a,"Received message: "+a.message);var b=(a=JSON.parse(a.message))&&a.namespace;a&&b&&a.senderId&&a.data?this.dispatchEvent(new Bc(b,a.senderId,a.data)):ub(this.a,"IpcChannel Message received is invalid")},a.open=function(){this.a.info("Opening message bus websocket"),this.j.open("ws://localhost:8008/v2/ipc")},a.close=function(){this.a.info("Closing message bus websocket"),this.j.close()},a.P=function(){return this.j.P()},a.send=function(a,b,c){if(!this.P)throw Error("Underlying websocket is not open");a=JSON.stringify({namespace:a,senderId:b,data:c}),vb(this.a,"IPC message sent: "+a),this.j.send(a)},a.d=function(){Ac.n.d.call(this),wb(this.a,"Disposed IpcChannel")};var Dc=function(a,b,c,d){for(nc.call(this),this.p=a,this.t=b,this.R=d||"STRING",this.onMessage=null,this.serializeMessage=this.yb,this.deserializeMessage=this.xb,this.e={},a=0;aa.maxInactivity)throw Error("config.maxInactivity must be greater than or equal to 5 seconds.");J(this.N,a||{})}this.Ia=!0,this.t.open()},Fc.prototype.start=Fc.prototype.start,Fc.prototype.stop=function(){this.G(),window.close()},Fc.prototype.stop=Fc.prototype.stop,Fc.prototype.Kb=function(){return this.Y},Fc.prototype.isSystemReady=Fc.prototype.Kb,Fc.prototype.Jb=function(){return G(this.o)},Fc.prototype.getSenders=Fc.prototype.Jb,Fc.prototype.Hb=function(a){return this.o[a]?H(this.o[a]):null},Fc.prototype.getSender=Fc.prototype.Hb,Fc.prototype.Eb=function(){return this.ha},Fc.prototype.getApplicationData=Fc.prototype.Eb,Fc.prototype.Lb=function(a){if(this.Y){var b={type:"setappstate"};void 0!=a&&(b.statusText=a),this.O.send("SystemSender",b)}else this.N.statusText=a},Fc.prototype.setApplicationState=Fc.prototype.Lb,Fc.prototype.Ca=function(a,b){if("urn:x-cast:com.google.cast.system"==a)throw Error("Protected namespace");if(0!=a.lastIndexOf("urn:x-cast:",0))throw Error("Invalid namespace prefix");if(!this.k[a]){if(this.Ia)throw Error("New namespaces can not be requested after start has been called");this.k[a]=new Dc(a,this.t,G(this.o),b),Cb(this,i(Db,this.k[a]))}if(b&&this.k[a].Sa()!=b)throw Error("Invalid messageType for the namespace");return this.k[a]},Fc.prototype.getCastMessageBus=Fc.prototype.Ca,Fc.prototype.qb=function(a){var b=a.data;switch(wb(this.a,"CastReceiverManager message received: "+a.data),b.type){case"opened":this.a.info("Underlying message bus is open");var c=G(this.k),d=this.N.statusText;a={type:"ready"},d&&(a.statusText=d),a.activeNamespaces=c,a.version="2.0.0",a.messagesVersion="1.0",this.O.send("SystemSender",a),this.N.maxInactivity&&this.O.send("SystemSender",{type:"startheartbeat",maxInactivity:this.N.maxInactivity});break;case"closed":this.Y=!1,this.dispatchEvent("shutdown");break;case"error":this.dispatchEvent("error");break;case"ready":this.ha={id:b.applicationId,name:b.applicationName,sessionId:b.sessionId,namespaces:G(this.k),launchingSenderId:b.launchingSenderId},this.Y=!0,this.a.info("Dispatching CastReceiverManager system ready event ["+this.ha+"]"),c=new Gc("ready",this.ha),this.onReady&&this.onReady(c),this.dispatchEvent(c);break;case"senderconnected":d={id:b.senderId,userAgent:b.userAgent},this.a.info("Dispatching CastReceiverManager sender connected event ["+d.id+"]"),d.id in this.o&&ub(this.a,"Unexpected connected message for already connected sender: "+d.id),this.o[d.id]=d,a=new Gc("senderconnected",d.id);for(c in this.k){var b=this.k[c],e=d.id;e in b.e?ub(b.a,"Unexpected sender already registered ["+b.p+", "+e+"]"):(b.a.info("Registering sender ["+b.p+", "+e+"]"),b.e[e]=null)}this.onSenderConnected&&this.onSenderConnected(a),this.dispatchEvent(a);break;case"senderdisconnected":if(c=b.senderId,this.a.info("Dispatching sender disconnected event ["+c+"]"),c in this.o){delete this.o[c],a=new Gc("senderdisconnected",c);for(d in this.k)b=this.k[d],e=c,e in b.e&&(b.a.info("Unregistering sender ["+b.p+", "+e+"]"),b.e[e]&&b.e[e].close(),delete b.e[e]);this.onSenderDisconnected&&this.onSenderDisconnected(a),this.dispatchEvent(a)}else ub(this.a,"Unknown sender disconnected: "+c);break;case"volumechanged":c={level:b.level,muted:b.muted},this.a.info("Dispatching system volume changed event ["+c.level+", "+c.muted+"]"),c=new Gc("systemvolumechanged",c),this.onSystemVolumeChanged&&this.onSystemVolumeChanged(c),this.dispatchEvent(c);break;case"visibilitychanged":c=b.visible,this.a.info("Dispatching visibility changed event "+c),c=new Gc("visibilitychanged",c),this.onVisibilityChanged&&this.onVisibilityChanged(c),this.dispatchEvent(c);break;default:throw Error("Unexpected message type: "+b.type)}},Fc.prototype.d=function(){Fc.n.d.call(this),delete Fc.ma,vb(this.a,"Disposed "+this.s())},k("cast.receiver.media.MEDIA_NAMESPACE","urn:x-cast:com.google.cast.media"),k("cast.receiver.media.StreamType",{BUFFERED:"BUFFERED",LIVE:"LIVE",NONE:"NONE"});var Ic={INVALID_PLAYER_STATE:"INVALID_PLAYER_STATE",LOAD_FAILED:"LOAD_FAILED",LOAD_CANCELLED:"LOAD_CANCELLED",INVALID_REQUEST:"INVALID_REQUEST"};k("cast.receiver.media.ErrorType",Ic),k("cast.receiver.media.ErrorReason",{INVALID_COMMAND:"INVALID_COMMAND",INVALID_PARAMS:"INVALID_PARAMS",INVALID_MEDIA_SESSION_ID:"INVALID_MEDIA_SESSION_ID",DUPLICATE_REQUEST_ID:"DUPLICATE_REQUEST_ID"}),k("cast.receiver.media.IdleReason",{CANCELLED:"CANCELLED",INTERRUPTED:"INTERRUPTED",FINISHED:"FINISHED",ERROR:"ERROR"}),k("cast.receiver.media.SeekResumeState",{Rb:"PLAYBACK_START",Qb:"PLAYBACK_PAUSE"}),k("cast.receiver.media.PlayerState",{IDLE:"IDLE",PLAYING:"PLAYING",PAUSED:"PAUSED",BUFFERING:"BUFFERING"});var Jc=function(){this.contentId="",this.streamType="NONE",this.contentType="",this.customData=this.duration=this.metadata=void 0};k("cast.receiver.media.MediaInformation",Jc);var Kc=function(){this.muted=this.level=void 0};k("cast.receiver.media.Volume",Kc),k("cast.receiver.media.MediaStatus",function(){this.mediaSessionId=0,this.media=void 0,this.playbackRate=1,this.playerState="IDLE",this.idleReason=void 0,this.supportedMediaCommands=this.currentTime=0,this.volume={level:0,muted:!1},this.customData=void 0}),k("cast.receiver.media.Command",{PAUSE:1,SEEK:2,STREAM_VOLUME:4,STREAM_MUTE:8});var Lc=function(a,b){nc.call(this),this.X=Fc.Da().Ca("urn:x-cast:com.google.cast.media","JSON"),this.fa=0,this.Xa=1,this.Ya=b||15,this.Aa=this.za=this.C=this.W=this.h=this.b=this.c=null,this.l=!1,this.ea=0,this.L=this.f=null,this.customizedStatusCallback=this.Za,this.onLoad=this.eb,this.onPlay=this.hb,this.onSeek=this.ib,this.onPause=this.gb,this.onStop=this.kb,this.onSetVolume=this.jb,this.onMetadataLoaded=this.fb,this.onLoadMetadataError=this.cb,this.onEnded=this.$a,this.onError=this.ab,this.onGetStatus=this.bb,this.Ea(a),this.X.onMessage=this.K.bind(this),rc(h(this.Ba,this),1e3)};l(Lc,nc),k("cast.receiver.MediaManager",Lc),Lc.EventType={LOAD:"load",STOP:"stop",PAUSE:"pause",PLAY:"play",SEEK:"seek",SET_VOLUME:"setvolume",GET_STATUS:"getstatus"};var Mc=function(a,b,c){Eb.call(this,a),this.data=b,this.senderId=c};l(Mc,Eb),Lc.Event=Mc;var Nc=function(){this.requestId=0,this.mediaSessionId=void 0,this.customData=null};Lc.RequestData=Nc;var Oc=function(){this.media=new Jc,this.autoplay=!1,this.currentTime=0};l(Oc,Nc),Lc.LoadRequestData=Oc;var Pc=function(){this.volume=new Kc 2 | };l(Pc,Nc),Lc.VolumeRequestData=Pc,l(Pc,Nc),Lc.SeekRequestData=function(){this.resumeState=void 0,this.currentTime=0},l(Mc,Eb),Lc.LoadInfo=function(a,b){this.message=a,this.senderId=b},Lc.prototype.a=Ab("cast.receiver.MediaManager"),Lc.prototype.s=function(){return"MediaManager"},Lc.prototype.Gb=function(){return this.h},Lc.prototype.getMediaInformation=Lc.prototype.Gb,Lc.prototype.Nb=function(a,b,c){if(b=void 0==b||b,c&&!b)throw Error("No broadcast call but status customData has been provided");this.h=a,b&&this.m(!0,null,c)},Lc.prototype.setMediaInformation=Lc.prototype.Nb,Lc.prototype.K=function(a){var b=a.data;a=a.senderId;var c=b.type,d=b.requestId;if("number"==typeof d&&d==Math.floor(d))if(void 0!=b.mediaSessionId&&b.mediaSessionId!=this.fa||"LOAD"!=c&&"GET_STATUS"!=c&&("IDLE"==Qc(this)||void 0==b.mediaSessionId))ub(this.a,"Invalid media session ID: "+b.mediaSessionId),this.M(a,d,"INVALID_REQUEST","INVALID_MEDIA_SESSION_ID");else{wb(this.a,"MediaManager message received ["+a+"] "+JSON.stringify(b)),delete b.type;var e=null;switch(c){case"LOAD":this.a.info("Dispatching MediaManager load event"),b.media?(this.f?this.ka("LOAD_CANCELLED"):this.h&&this.H("INTERRUPTED"),this.f={senderId:a,message:b},this.ea=b.currentTime||0,this.h=b.media,this.fa++,b=new Mc("load",b,a),this.onLoad&&this.onLoad(b),this.dispatchEvent(b),e=null):(ub(this.a,"media is mandatory"),e={type:"INVALID_REQUEST",reason:"INVALID_PARAMS"});break;case"GET_STATUS":this.a.info("Dispatching MediaManager getStatus event"),b=new Mc("getstatus",b,a),this.onGetStatus&&this.onGetStatus(b),this.dispatchEvent(b),e=null;break;case"PLAY":this.a.info("Dispatching MediaManager play event"),b=new Mc("play",b,a),this.onPlay&&this.onPlay(b),this.dispatchEvent(b),e=null;break;case"SEEK":void 0==b.currentTime?(ub(this.a,"currentTime is mandatory"),e={type:"INVALID_REQUEST",reason:"INVALID_PARAMS"}):(this.a.info("Dispatching MediaManager seek event"),b=new Mc("seek",b,a),this.onSeek&&this.onSeek(b),this.dispatchEvent(b),e=null);break;case"STOP":this.a.info("Dispatching MediaManager stop event"),b=new Mc("stop",b,a),this.onStop&&this.onStop(b),this.dispatchEvent(b),e=null;break;case"PAUSE":this.a.info("Dispatching MediaManager pause event"),b=new Mc("pause",b,a),this.onPause&&this.onPause(b),this.dispatchEvent(b),e=null;break;case"SET_VOLUME":!b.volume||void 0==b.volume.level&&void 0==b.volume.muted?(ub(this.a,"volume is invalid"),e={type:"INVALID_REQUEST",reason:"INVALID_PARAMS"}):void 0!=b.volume.level&&0>b.volume.level||11e3*(this.C-a),b!=this.l?(wb(this.a,"Buffering state changed, isPlayerBuffering: "+this.l+" old time: "+a+" current time: "+this.C),this.m(!1)):!this.l&&(a=1e3*(this.C-this.za)-(Date.now()-this.Aa),a>1e3||-1e3>a)&&(wb(this.a,"Time drifted: "+a),this.m(!1))}},Lc.prototype.m=function(a,b,c){this.b||this.c?(wb(this.a,"Sending broadcast status message"),a=Rc(this,a,c),null!=a&&(a.requestId=b||0,this.X.Fa(a),Sc(this))):ub(this.a,"Not sending broadcast status message, state is invalid")},Lc.prototype.broadcastStatus=Lc.prototype.m,Lc.prototype.Mb=function(a){wb(this.a,"Setting IDLE reason: "+a),this.L=a},Lc.prototype.setIdleReason=Lc.prototype.Mb,Lc.prototype.M=function(a,b,c,d,e){this.a.info("Sending error message to "+a);var f={};f.requestId=b,f.type=c,d&&(f.reason=d),e&&(f.customData=e),this.X.send(a,f)},Lc.prototype.sendError=Lc.prototype.M,Lc.prototype.Ka=function(a,b,c,d){this.b||this.c?(wb(this.a,"Sending status message to "+a),c=Rc(this,c,d),null!=c&&(c.requestId=b,this.X.send(a,c),Sc(this))):(ub(this.a,"State is invalid"),this.M(a,b,"INVALID_PLAYER_STATE",null,d))},Lc.prototype.sendStatus=Lc.prototype.Ka,Lc.prototype.Za=function(a){return a},Lc.prototype.eb=function(a){var b=a.data;this.c?b.media&&b.media.contentId&&this.c.load(b.media.contentId,!!b.autoplay,b.currentTime):(this.b.autoplay=!1,b.media&&a.data.media.contentId&&(this.b.src=b.media.contentId),this.b.autoplay=void 0!=b.autoplay?b.autoplay:!0,this.b.load())},Lc.prototype.Ea=function(a){a.getState?(this.b&&(Uc(this),this.b=null),this.c!=a&&(Uc(this),this.c=a,Tc(this))):(this.c&&(Uc(this),this.c=null),this.b!=a&&(Uc(this),this.b=a,Tc(this)))},Lc.prototype.setMediaElement=Lc.prototype.Ea;var Tc=function(a){a.c?(a.c.registerErrorCallback(a.oa.bind(a)),a.c.registerEndedCallback(a.na.bind(a)),a.c.registerLoadCallback(a.pa.bind(a))):(dc(a.b,"loadedmetadata",a.pa,!1,a),dc(a.b,"error",a.oa,!1,a),dc(a.b,"ended",a.na,!1,a))},Uc=function(a){a.c?(a.c.unregisterErrorCallback(),a.c.unregisterEndedCallback(),a.c.unregisterLoadCallback()):(fc(a.b,"loadedmetadata",a.pa,!1,a),fc(a.b,"error",a.oa,!1,a),fc(a.b,"ended",a.na,!1,a))};Lc.prototype.pa=function(){this.f&&(this.a.info("Metadata loaded"),this.h&&(this.h.duration=this.c?this.c.getDurationSec():this.b.duration),this.l=!0,this.onMetadataLoaded?this.onMetadataLoaded(this.f):this.f=null)},Lc.prototype.fb=function(a){a.message.currentTime&&this.b&&(this.b.currentTime=a.message.currentTime),this.Ra()},Lc.prototype.oa=function(a){this.f?(ub(this.a,"Load metadata error"),this.onLoadMetadataError?this.onLoadMetadataError(this.f):this.f=null):this.onError&&this.onError(a)},Lc.prototype.ka=function(a,b){this.f?(this.M(this.f.senderId,this.f.message.requestId,a||"LOAD_FAILED",null,b),this.f=null):ub(this.a,"Not sending LOAD error as there is no on going LOAD request")},Lc.prototype.sendLoadError=Lc.prototype.ka,Lc.prototype.Ra=function(a){this.f?(this.m(!0,this.f.message.requestId,a),this.f=null):ub(this.a,"Not sending status as there is no on going LOAD request")},Lc.prototype.sendLoadComplete=Lc.prototype.Ra,a=Lc.prototype,a.ab=function(){this.H("ERROR")},a.cb=function(){this.H("ERROR",!1),this.ka("LOAD_FAILED")},a.na=function(){this.onEnded&&this.onEnded()},a.$a=function(){this.H("FINISHED")},a.bb=function(a){wb(this.a,"onGetStatus"),this.Ka(a.senderId,a.data.requestId,!0)},a.hb=function(a){wb(this.a,"onPlay"),this.c?this.c.play():this.b.play(),this.m(!1,a.data.requestId)},a.ib=function(a){a=a.data,wb(this.a,"onSeek: "+JSON.stringify(a)),this.c?(this.c.seek(a.currentTime,a.resumeState),"PAUSED"!=this.c.getState()&&(this.l=!0)):(this.b.currentTime=a.currentTime,"PLAYBACK_START"==a.resumeState&&this.b.paused?this.b.play():"PLAYBACK_PAUSE"!=a.resumeState||this.b.paused||this.b.pause(),this.b.paused||(this.l=!0)),this.m(!1,a.requestId)},a.kb=function(a){this.H("CANCELLED",!0,a.data.requestId)},a.H=function(a,b,c,d){if(b=void 0==b||b,(d||c)&&!b)throw Error("customData and requestId should only be provided in broadcast mode");this.h?(this.c?this.c.reset():(this.a.info("Resetting media element"),this.b.removeAttribute("src"),this.ea=0,this.b.load()),a&&(this.L=a),this.W=this.h,this.h=null,b&&this.m(!1,c,d)):this.a.info("Nothing to reset, Media is already null")},Lc.prototype.resetMediaElement=Lc.prototype.H,Lc.prototype.gb=function(a){this.c?this.c.pause():this.b.pause(),this.m(!1,a.data.requestId)},Lc.prototype.jb=function(a){a=a.data,this.c?this.c.setVolume(a.volume):(void 0!=a.volume.level&&(this.b.volume=a.volume.level),void 0!=a.volume.muted&&(this.b.muted=a.volume.muted)),this.m(!1,a.requestId)},Lc.prototype.d=function(){Lc.n.d.call(this),wb(this.a,"Disposed "+this.s())}}).call(window)},{}],2:[function(){!function(){var a=window.chrome||{};a.cast=a.cast||{},a.cast.media=a.cast.media||{},a.cast.ApiBootstrap_=function(){},a.cast.ApiBootstrap_.EXTENSION_IDS=["boadgeojelhgndaghljhdicfkmllpafd","dliochdbjfkdbacpmhlcpmleaejidimm","hfaagokkkhdbgiakmmlclaapfelnkoah","fmfcbgogabcbclcofgocippekhfcmgfj","enhhojjnijigcajfphajepfemndkmdlo"],a.cast.ApiBootstrap_.findInstalledExtension_=function(b){a.cast.ApiBootstrap_.findInstalledExtensionHelper_(0,b)},a.cast.ApiBootstrap_.findInstalledExtensionHelper_=function(b,c){b==a.cast.ApiBootstrap_.EXTENSION_IDS.length?c(null):a.cast.ApiBootstrap_.isExtensionInstalled_(a.cast.ApiBootstrap_.EXTENSION_IDS[b],function(d){d?c(a.cast.ApiBootstrap_.EXTENSION_IDS[b]):a.cast.ApiBootstrap_.findInstalledExtensionHelper_(b+1,c)})},a.cast.ApiBootstrap_.getCastSenderUrl_=function(a){return"chrome-extension://"+a+"/cast_sender.js"},a.cast.ApiBootstrap_.isExtensionInstalled_=function(b,c){var d=new XMLHttpRequest;d.onreadystatechange=function(){4==d.readyState&&200==d.status&&c(!0)},d.onerror=function(){c(!1)},d.open("GET",a.cast.ApiBootstrap_.getCastSenderUrl_(b),!0),d.send()},a.cast.ApiBootstrap_.findInstalledExtension_(function(b){if(b){console.log("Found cast extension: "+b),a.cast.extensionId=b;var c=document.createElement("script");c.src=a.cast.ApiBootstrap_.getCastSenderUrl_(b),(document.head||document.documentElement).appendChild(c)}else{var d="No cast extension found";console.log(d);var e=window.__onGCastApiAvailable;e&&"function"==typeof e&&e(!1,d)}})}()},{}],3:[function(a){!function(a,b){"use strict";"function"==typeof define&&define.amd?define([],b):a.chromecast=b()}(window,function(){"use strict";var b,c,d={},e={};return b={bind:function(a,b){return function(){a.apply(b,arguments)}},extend:function(a){var b,c,d={};for(b=1;b0&&b.extend(this._options,a),this._options},_trigger:function(a,b){var c,d,e;if(this._events&&this._events[a])for(d=this._events[a],c=0;c 2 | 3 | 4 | Cast Hello Text 5 | 23 | 24 | 25 |
Talk to me
26 | 27 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /examples/sender.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hello World 5 | 32 | 33 | 34 | 35 | 36 | 41 | 42 |
37 |
38 | 39 |
40 |
43 | 44 | 45 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chromecastjs", 3 | "version": "0.1.0", 4 | "description": "JavaScript project based on ChromeCast API to build ChromeCast apps very easy", 5 | "main": "chromecast.js", 6 | "directories": { 7 | "examples": "examples" 8 | }, 9 | "dependencies": {}, 10 | "devDependencies": { 11 | "connect-livereload": "~0.3.2", 12 | "grunt": "~0.4.4", 13 | "grunt-contrib-connect": "~0.7.1", 14 | "grunt-docco-multi": "~0.0.2", 15 | "grunt-open": "~0.2.3", 16 | "load-grunt-tasks": "~0.4.0", 17 | "lodash": "~2.4.1", 18 | "portscanner": "~0.2.2", 19 | "q": "~1.0.1", 20 | "grunt-contrib-watch": "~0.6.1", 21 | "grunt-contrib-jshint": "~0.9.2", 22 | "browserify": "~3.38.0", 23 | "grunt-browserify": "~2.0.1", 24 | "grunt-contrib-uglify": "~0.4.0" 25 | }, 26 | "scripts": { 27 | "test": "grunt test" 28 | }, 29 | "repository": { 30 | "type": "git", 31 | "url": "git://github.com/marcbuils/chromecastjs.git" 32 | }, 33 | "keywords": [ 34 | "chromecast", 35 | "google", 36 | "chrome", 37 | "cast", 38 | "js", 39 | "javascript", 40 | "api" 41 | ], 42 | "author": "Marc Buils", 43 | "license": "MIT", 44 | "bugs": { 45 | "url": "https://github.com/marcbuils/chromecastjs/issues" 46 | }, 47 | "homepage": "https://github.com/marcbuils/chromecastjs" 48 | } 49 | -------------------------------------------------------------------------------- /src/chromecast.js: -------------------------------------------------------------------------------- 1 | (function (root, factory) { 2 | 'use strict'; 3 | 4 | if (typeof define === 'function' && define.amd) { 5 | define([], factory); 6 | } else { 7 | root.chromecast = factory(); 8 | } 9 | }(window, function () { 10 | 'use strict'; 11 | 12 | var utils, Common, Sender = {}, Receiver = {}; 13 | 14 | utils = { 15 | bind: function (callback, context) { 16 | return function () { 17 | callback.apply(context, arguments); 18 | }; 19 | }, 20 | 21 | extend: function (target) { 22 | var attr = {}; 23 | var i, origin; 24 | 25 | for (i = 1; i < arguments.length; i++) { 26 | origin = arguments[i]; 27 | for (attr in origin) { 28 | if (origin.hasOwnProperty(attr)) { 29 | target[attr] = origin[attr]; 30 | } 31 | } 32 | } 33 | }, 34 | 35 | create: function (Module) { 36 | var Obj = function () {}; 37 | Obj.prototype = Module; 38 | 39 | return new Obj(); 40 | } 41 | }; 42 | 43 | Common = { 44 | _events: null, 45 | _options: null, 46 | 47 | on: function (event, callback) { 48 | if (!this._events) { 49 | this._events = {}; 50 | } 51 | if (!this._events[event]) { 52 | this._events[event] = []; 53 | } 54 | this._events[event].push(callback); 55 | 56 | return this; 57 | }, 58 | 59 | options: function (opt) { 60 | if (!this._options) { 61 | this._options = {}; 62 | } 63 | if (arguments.length > 0) { 64 | utils.extend(this._options, opt); 65 | } 66 | return this._options; 67 | }, 68 | 69 | _trigger: function (eventName, data) { 70 | var i, events, event; 71 | 72 | if (!this._events || !this._events[eventName]) { 73 | return; 74 | } 75 | 76 | events = this._events[eventName]; 77 | for (i = 0; i < events.length; i++) { 78 | event = events[i]; 79 | event.call(this, data); 80 | } 81 | } 82 | }; 83 | 84 | utils.extend(Sender, Common, { 85 | _session: null, 86 | 87 | initialize: function (options) { 88 | this.options(options); 89 | setTimeout(utils.bind(this._initializeCast, this), 1000); 90 | return this; 91 | }, 92 | 93 | sendMessage: function (message) { 94 | var options = this.options(); 95 | 96 | if (!this._isAvailable()) { 97 | return this; 98 | } 99 | this._session.sendMessage(options.namespace, message, utils.bind(this._success, this), utils.bind(this._error, this)); 100 | 101 | return this; 102 | }, 103 | 104 | start: function () { 105 | var options = this.options(); 106 | 107 | chrome.cast.requestSession(utils.bind(function (e) { 108 | this._session = e; 109 | this._session.addUpdateListener(utils.bind(this._sessionUpdateListener, this)); 110 | this._session.addMessageListener(options.namespace, utils.bind(this._receiverMessage, this)); 111 | }, this), utils.bind(this._error, this)); 112 | 113 | return this; 114 | }, 115 | 116 | _initializeCast: function () { 117 | var options = this.options(); 118 | var sessionRequest; 119 | var apiConfig; 120 | 121 | if (!this._isAvailable()) { 122 | return this; 123 | } 124 | 125 | sessionRequest = new chrome.cast.SessionRequest(options.applicationID); 126 | apiConfig = new chrome.cast.ApiConfig( 127 | sessionRequest, 128 | utils.bind(this._sessionListener, this), 129 | utils.bind(this._receiverListener, this)); 130 | chrome.cast.initialize(apiConfig, utils.bind(this._initSuccess, this), utils.bind(this._error, this)); 131 | 132 | return this; 133 | }, 134 | 135 | _isAvailable: function () { 136 | return chrome && chrome.cast && chrome.cast.isAvailable; 137 | }, 138 | 139 | _sessionListener: function (event) { 140 | var options = this.options(); 141 | 142 | this._trigger('session', event); 143 | this._session = event; 144 | this._session.addUpdateListener(utils.bind(this._sessionUpdateListener, this)); 145 | this._session.addMessageListener(options.namespace, utils.bind(this._receiverMessage, this)); 146 | }, 147 | 148 | 149 | _initSuccess: function () { 150 | this._trigger('initialized'); 151 | }, 152 | 153 | _error: function (message) { 154 | this._trigger('error', message); 155 | }, 156 | 157 | _success: function (message) { 158 | this._trigger('success', message); 159 | }, 160 | 161 | _stopAppSuccess: function () { 162 | this._trigger('stopappsuccess'); 163 | }, 164 | 165 | _sessionUpdateListener: function (isAlive) { 166 | this._trigger('sessionupdatelistener', isAlive); 167 | 168 | if (!isAlive) { 169 | this._session = null; 170 | } 171 | }, 172 | 173 | _receiverMessage: function (namespace, message) { 174 | this._trigger('message', { namespace: namespace, message: message }); 175 | }, 176 | 177 | _receiverListener: function (e) { 178 | this._trigger('listener', e); 179 | }, 180 | 181 | _stopApp: function () { 182 | this._session.stop( 183 | utils.bind(this._stopAppSuccess, this), 184 | utils.bind(this._error, this)); 185 | } 186 | }); 187 | 188 | utils.extend(Receiver, Common, { 189 | _castReceiverManager: null, 190 | _messageBus: null, 191 | 192 | initialize: function (options) { 193 | this.options(options); 194 | this._initializeCast(); 195 | return this; 196 | }, 197 | 198 | getSenders: function () { 199 | this._castReceiverManager.getSenders(); 200 | return this; 201 | }, 202 | 203 | disconnect: function () { 204 | window.close(); 205 | return this; 206 | }, 207 | 208 | setApplicationState: function (state) { 209 | this._castReceiverManager.setApplicationState(state); 210 | return this; 211 | }, 212 | 213 | _initializeCast: function () { 214 | var options = this.options(); 215 | var castReceiverManager, messageBus; 216 | 217 | cast.receiver.logger.setLevelValue(0); 218 | castReceiverManager = cast.receiver.CastReceiverManager.getInstance(); 219 | castReceiverManager.onReady = utils.bind(this._ready, this); 220 | castReceiverManager.onSenderConnected = utils.bind(this._senderConnected, this); 221 | castReceiverManager.onSenderDisconnected = utils.bind(this._senderDisconnected, this); 222 | castReceiverManager.onSystemVolumeChanged = utils.bind(this._systemVolumeChanged, this); 223 | 224 | messageBus = castReceiverManager.getCastMessageBus(options.namespace); 225 | messageBus.onMessage = utils.bind(this._message, this); 226 | 227 | this._messageBus = messageBus; 228 | this._castReceiverManager = castReceiverManager; 229 | 230 | castReceiverManager.start({ statusText: 'starting' }); 231 | }, 232 | 233 | _ready: function (event) { 234 | this._trigger('ready', event); 235 | this._castReceiverManager.setApplicationState('ready'); 236 | }, 237 | 238 | _senderConnected: function (event) { 239 | this._trigger('senderconnected', event); 240 | }, 241 | 242 | _senderDisconnected: function (event) { 243 | this._trigger('senderdisconnected', event); 244 | }, 245 | 246 | _systemVolumeChanged: function (event) { 247 | this._trigger('systemvolumechanged', event); 248 | }, 249 | 250 | _message: function (event) { 251 | this._trigger('message', event); 252 | this._messageBus.send(event.senderId, event.data); 253 | } 254 | }); 255 | 256 | return { 257 | createSender: function (options) { 258 | require('../bower_components/cast_sender/index'); 259 | return utils.create(Sender).initialize(options); 260 | }, 261 | createReceiver: function (options) { 262 | require('../bower_components/cast_receiver/index'); 263 | return utils.create(Receiver).initialize(options); 264 | } 265 | }; 266 | })); 267 | --------------------------------------------------------------------------------