aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-android/app/src/main/assets/bridge
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-android/app/src/main/assets/bridge')
-rw-r--r--packages/meshbay-android/app/src/main/assets/bridge/meshbay-bridge.js70
1 files changed, 49 insertions, 21 deletions
diff --git a/packages/meshbay-android/app/src/main/assets/bridge/meshbay-bridge.js b/packages/meshbay-android/app/src/main/assets/bridge/meshbay-bridge.js
index 5fb5bb6..0a2582a 100644
--- a/packages/meshbay-android/app/src/main/assets/bridge/meshbay-bridge.js
+++ b/packages/meshbay-android/app/src/main/assets/bridge/meshbay-bridge.js
@@ -15,9 +15,10 @@
* that refuses: `platform.js` decides what to show from whether an object
* exists (`platform.node.available`, `platform.folder.available`, …).
*
- * `HUB_BASE` and `BINARY` are prepended by the shell when it injects this
- * file: the interface asks for the hub while its modules load, before anything
- * can await, and BINARY says whether the WebView carries ArrayBuffer messages.
+ * `HUB_BASE`, `BINARY` and `CAST` are prepended by the shell when it injects
+ * this file: the interface asks for the hub while its modules load, before
+ * anything can await; BINARY says whether the WebView carries ArrayBuffer
+ * messages; CAST whether this device can cast at all.
*/
(function () {
'use strict';
@@ -48,28 +49,34 @@
// big-endian — one copy, no JSON, no base64 (spike S-3: 136 MB/s awaited
// per 48 KB chunk). Without ArrayBuffer messages, base64 over JSON.
const SAVE_WRITE = 1;
+ const CAST_PUSH = 2;
const bytesOf = (chunk) => (chunk instanceof Uint8Array ? chunk
: ArrayBuffer.isView(chunk) ? new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength)
: new Uint8Array(chunk));
+ const base64Of = (bytes) => {
+ let s = '';
+ for (let i = 0; i < bytes.length; i += 0x8000) s += String.fromCharCode.apply(null, bytes.subarray(i, i + 0x8000));
+ return btoa(s);
+ };
+ const sendBinary = (channel, handle, bytes) => new Promise((resolve, reject) => {
+ const id = ++seq;
+ pending.set(id, { resolve, reject });
+ const frame = new ArrayBuffer(16 + bytes.length);
+ const head = new DataView(frame);
+ head.setUint32(0, 0x4d424231); // "MBB1"
+ head.setUint32(4, id);
+ head.setUint16(8, channel);
+ head.setUint32(12, handle);
+ new Uint8Array(frame, 16).set(bytes);
+ port.postMessage(frame);
+ });
const writeChunk = (handle, chunk) => {
const bytes = bytesOf(chunk);
- if (!BINARY) {
- let s = '';
- for (let i = 0; i < bytes.length; i += 0x8000) s += String.fromCharCode.apply(null, bytes.subarray(i, i + 0x8000));
- return call('save:write', handle, btoa(s));
- }
- return new Promise((resolve, reject) => {
- const id = ++seq;
- pending.set(id, { resolve, reject });
- const frame = new ArrayBuffer(16 + bytes.length);
- const head = new DataView(frame);
- head.setUint32(0, 0x4d424231); // "MBB1"
- head.setUint32(4, id);
- head.setUint16(8, SAVE_WRITE);
- head.setUint32(12, handle);
- new Uint8Array(frame, 16).set(bytes);
- port.postMessage(frame);
- });
+ return BINARY ? sendBinary(SAVE_WRITE, handle, bytes) : call('save:write', handle, base64Of(bytes));
+ };
+ const pushSegment = (chunk) => {
+ const bytes = bytesOf(chunk);
+ return BINARY ? sendBinary(CAST_PUSH, 0, bytes) : call('cast:push', base64Of(bytes));
};
const meshbay = {
@@ -80,7 +87,7 @@
nodeAdmin: false, // no node runs on a phone (§11.3)
localFolders: false,
nativeSave: true,
- lanCast: false, // phase 3
+ lanCast: CAST, // false where the vendor's play services are absent
tray: false,
},
@@ -132,6 +139,27 @@
backend: () => call('secrets:backend'),
},
+ // LAN cast relay: the page feeds it decrypted segments, a receiver on the
+ // same Wi-Fi plays from the URL. Present only where casting can work —
+ // `platform.cast.available` is whether this object exists.
+ ...(CAST ? { cast: {
+ start: (opts) => {
+ const o = Object.assign({}, opts || {});
+ if (o.initSegment) o.initSegment = base64Of(bytesOf(o.initSegment));
+ return call('cast:start', o);
+ },
+ push: (data) => pushSegment(data),
+ stop: () => call('cast:stop'),
+ subtitle: (sub) => call('cast:subtitle', sub),
+ finish: () => call('cast:finish'),
+ status: () => call('cast:status'),
+ scan: () => call('cast:scan'),
+ devices: () => call('cast:devices'),
+ chromecastConnect: (opts) => call('cast:chromecast:connect', opts),
+ chromecastReload: (opts) => call('cast:chromecast:reload', opts),
+ chromecastDisconnect: () => call('cast:chromecast:disconnect'),
+ } } : {}),
+
// Where downloads go, chosen once. A display name comes back, never a URI.
folder: {
choose: () => call('folder:choose'),