1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
const Lang = imports.lang;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Signals = imports.signals;
const Soup = imports.gi.Soup;
const DialManager = imports.protocols.dialManager;
const WebSocket = imports.protocols.webSocket;
const CLIENT_ORIGIN = 'chrome-extension://boadgeojelhgndaghljhdicfkmllpafd';
const SERVICE_VERSION = 'release-3df2f7159e87f36d38115f377f5ca88335dd3649';
const REFRESH_INTERVAL = 1000; // milliseconds
const ChromeCast = new Lang.Class({
Name: 'ChromeCast',
_init: function() {
this._dialManager = new DialManager.DialManager({ appName: 'ChromeCast' });
this._senderId = this._generateSenderId();
this._dialManager.connect('device-found',
Lang.bind(this, function(manager, dialDevice) {
if (dialDevice.name == 'ChromeCast') {
print('device found');
this.emit('device-found', dialDevice);
}
}));
this._dialManager.discover();
},
_generateSenderId: function() {
let nonce = "";
for (let i = 0; i < 4; i++)
nonce += String.fromCharCode(GLib.random_int_range(0, 255));
return GLib.base64_encode(nonce, nonce.length);
},
_openCastSession: function(session, uri) {
print('opening cast session');
let message = new Soup.Message({ method: 'POST',
uri: uri });
let formData = JSON.stringify({ channel: 0,
senderId: { appName: 'ChromeCast',
senderId: this._senderId }});
print('formdata', formData);
message.set_request('application/json',
Soup.MemoryUse.COPY,
formData,
formData.length);
message.request_headers.replace('Origin', CLIENT_ORIGIN);
session.queue_message(message,
Lang.bind(this, function() {
print('response: ', message.status_code, message.reason_phrase);
let buffer = message.response_body.flatten();
let castSession = JSON.parse(buffer.get_as_bytes().get_data());
print(JSON.stringify(castSession));
if (castSession.URL) {
let webSocket = new WebSocket.WebSocket({ origin: CLIENT_ORIGIN,
pingInterval: castSession.pingInterval });
webSocket.open(castSession.URL, Lang.bind(this, function() {
print('websocket opened');
}));
}
}));
},
_castWhenReady: function(session, dialDevice, connectionUri) {
print('waiting to cast until app is ready');
dialDevice.refresh(Lang.bind(this, function(uri, app) {
if (!dialDevice.serviceURL)
GLib.timeout_add(GLib.PRIORITY_DEFAULT,
REFRESH_INTERVAL,
Lang.bind(this, function() {
this._castWhenReady(session, dialDevice, connectionUri);
}));
else
this._openCastSession(session, new Soup.URI(dialDevice.serviceURL));
}));
},
castToDevice: function(dialDevice) {
print('starting ChromeCast app');
let session = new Soup.Session();
let message = new Soup.Message({ method: 'POST',
uri: dialDevice.appResourceUri });
print('about to cast', dialDevice.appResourceUri.to_string(false));
let formData = Soup.form_encode_hash({ v: SERVICE_VERSION,
id: 'local:0',
idle: 'windowclose' });
message.set_request(Soup.FORM_MIME_TYPE_URLENCODED,
Soup.MemoryUse.COPY,
formData,
formData.length);
session.queue_message(message,
Lang.bind(this, function() {
let headers = message.response_headers;
let connectionUri = headers.get('Location');
print('response: ', message.status_code, message.reason_phrase);
if (connectionUri) {
print('Connection URI', connectionUri);
this._castWhenReady(session, dialDevice, connectionUri);
}
}));
},
});
Signals.addSignalMethods(ChromeCast.prototype);
|