diff options
Diffstat (limited to 'packages/meshbay-android/app/src/main/assets/bridge')
| -rw-r--r-- | packages/meshbay-android/app/src/main/assets/bridge/meshbay-bridge.js | 70 |
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'), |