diff options
| -rw-r--r-- | host/frontend/webrtc_operator/assets/js/cf_webrtc.js | 168 |
1 files changed, 95 insertions, 73 deletions
diff --git a/host/frontend/webrtc_operator/assets/js/cf_webrtc.js b/host/frontend/webrtc_operator/assets/js/cf_webrtc.js index 8c831a750..358aa497f 100644 --- a/host/frontend/webrtc_operator/assets/js/cf_webrtc.js +++ b/host/frontend/webrtc_operator/assets/js/cf_webrtc.js @@ -93,105 +93,127 @@ async function ajaxPostJson(url, data) { } class DeviceConnection { + #pc; + #control; + #description; + + #cameraDataChannel; + #cameraInputQueue; + #controlChannel; + #inputChannel; + #adbChannel; + #bluetoothChannel; + + #streams; + #streamPromiseResolvers; + #micSenders; + #cameraSenders; + #camera_res_x; + #camera_res_y; + + #onAdbMessage; + #onControlMessage; + #onBluetoothMessage; + constructor(pc, control) { - this._pc = pc; - this._control = control; - this._cameraDataChannel = pc.createDataChannel('camera-data-channel'); - this._cameraDataChannel.binaryType = 'arraybuffer'; - this._cameraInputQueue = new Array(); + this.#pc = pc; + this.#control = control; + this.#cameraDataChannel = pc.createDataChannel('camera-data-channel'); + this.#cameraDataChannel.binaryType = 'arraybuffer'; + this.#cameraInputQueue = new Array(); var self = this; - this._cameraDataChannel.onbufferedamountlow = () => { - if (self._cameraInputQueue.length > 0) { - self.sendCameraData(self._cameraInputQueue.shift()); + this.#cameraDataChannel.onbufferedamountlow = () => { + if (self.#cameraInputQueue.length > 0) { + self.sendCameraData(self.#cameraInputQueue.shift()); } }; - this._inputChannel = createDataChannel(pc, 'input-channel'); - this._adbChannel = createDataChannel(pc, 'adb-channel', (msg) => { - if (this._onAdbMessage) { - this._onAdbMessage(msg.data); + this.#inputChannel = createDataChannel(pc, 'input-channel'); + this.#adbChannel = createDataChannel(pc, 'adb-channel', (msg) => { + if (this.#onAdbMessage) { + this.#onAdbMessage(msg.data); } else { console.error('Received unexpected ADB message'); } }); - this._controlChannel = awaitDataChannel(pc, 'device-control', (msg) => { - if (this._onControlMessage) { - this._onControlMessage(msg); + this.#controlChannel = awaitDataChannel(pc, 'device-control', (msg) => { + if (this.#onControlMessage) { + this.#onControlMessage(msg); } else { console.error('Received unexpected Control message'); } }); - this._bluetoothChannel = + this.#bluetoothChannel = createDataChannel(pc, 'bluetooth-channel', (msg) => { - if (this._onBluetoothMessage) { - this._onBluetoothMessage(msg.data); + if (this.#onBluetoothMessage) { + this.#onBluetoothMessage(msg.data); } else { console.error('Received unexpected Bluetooth message'); } }); - this._streams = {}; - this._streamPromiseResolvers = {}; + this.#streams = {}; + this.#streamPromiseResolvers = {}; pc.addEventListener('track', e => { console.debug('Got remote stream: ', e); for (const stream of e.streams) { - this._streams[stream.id] = stream; - if (this._streamPromiseResolvers[stream.id]) { - for (let resolver of this._streamPromiseResolvers[stream.id]) { + this.#streams[stream.id] = stream; + if (this.#streamPromiseResolvers[stream.id]) { + for (let resolver of this.#streamPromiseResolvers[stream.id]) { resolver(); } - delete this._streamPromiseResolvers[stream.id]; + delete this.#streamPromiseResolvers[stream.id]; } } }); } set description(desc) { - this._description = desc; + this.#description = desc; } get description() { - return this._description; + return this.#description; } get imageCapture() { - if (this._cameraSenders && this._cameraSenders.length > 0) { - let track = this._cameraSenders[0].track; + if (this.#cameraSenders && this.#cameraSenders.length > 0) { + let track = this.#cameraSenders[0].track; return new ImageCapture(track); } return undefined; } get cameraWidth() { - return this._x_res; + return this.#camera_res_x; } get cameraHeight() { - return this._y_res; + return this.#camera_res_y; } get cameraEnabled() { - return this._cameraSenders && this._cameraSenders.length > 0; + return this.#cameraSenders && this.#cameraSenders.length > 0; } getStream(stream_id) { return new Promise((resolve, reject) => { - if (this._streams[stream_id]) { - resolve(this._streams[stream_id]); + if (this.#streams[stream_id]) { + resolve(this.#streams[stream_id]); } else { - if (!this._streamPromiseResolvers[stream_id]) { - this._streamPromiseResolvers[stream_id] = []; + if (!this.#streamPromiseResolvers[stream_id]) { + this.#streamPromiseResolvers[stream_id] = []; } - this._streamPromiseResolvers[stream_id].push(resolve); + this.#streamPromiseResolvers[stream_id].push(resolve); } }); } - _sendJsonInput(evt) { - this._inputChannel.send(JSON.stringify(evt)); + #sendJsonInput(evt) { + this.#inputChannel.send(JSON.stringify(evt)); } sendMousePosition({x, y, down, display_label}) { - this._sendJsonInput({ + this.#sendJsonInput({ type: 'mouse', down: down ? 1 : 0, x, @@ -203,7 +225,7 @@ class DeviceConnection { // TODO (b/124121375): This should probably be an array of pointer events and // have different properties. sendMultiTouch({idArr, xArr, yArr, down, slotArr, display_label}) { - this._sendJsonInput({ + this.#sendJsonInput({ type: 'multi-touch', id: idArr, x: xArr, @@ -215,101 +237,101 @@ class DeviceConnection { } sendKeyEvent(code, type) { - this._sendJsonInput({type: 'keyboard', keycode: code, event_type: type}); + this.#sendJsonInput({type: 'keyboard', keycode: code, event_type: type}); } disconnect() { - this._pc.close(); + this.#pc.close(); } // Sends binary data directly to the in-device adb daemon (skipping the host) sendAdbMessage(msg) { - this._adbChannel.send(msg); + this.#adbChannel.send(msg); } // Provide a callback to receive data from the in-device adb daemon onAdbMessage(cb) { - this._onAdbMessage = cb; + this.#onAdbMessage = cb; } // Send control commands to the device sendControlMessage(msg) { - this._controlChannel.send(msg); + this.#controlChannel.send(msg); } async useMic(in_use) { if (in_use) { - if (this._micSenders) { + if (this.#micSenders) { console.warn('Microphone is already in use'); return; } - this._micSenders = []; + this.#micSenders = []; try { let audioStream = await navigator.mediaDevices.getUserMedia( {video: false, audio: true}); audioStream.getTracks().forEach(track => { console.info(`Using ${track.kind} device: ${track.label}`); - this._micSenders.push(this._pc.addTrack(track)); + this.#micSenders.push(this.#pc.addTrack(track)); }); } catch (e) { console.error('Failed to add audio stream to peer connection: ', e); } } else { - if (!this._micSenders) { + if (!this.#micSenders) { return; } - for (const sender of this._micSenders) { + for (const sender of this.#micSenders) { console.info( `Removing ${sender.track.kind} device: ${sender.track.label}`); let track = sender.track; track.stop(); - this._pc.removeTrack(sender); + this.#pc.removeTrack(sender); } - delete this._micSenders; + this.#micSenders = undefined; } - this._control.renegotiateConnection(); + this.#control.renegotiateConnection(); } async useVideo(in_use) { if (in_use) { - if (this._cameraSenders) { + if (this.#cameraSenders) { console.warn('Video is already in use'); return; } - this._cameraSenders = []; + this.#cameraSenders = []; try { let videoStream = await navigator.mediaDevices.getUserMedia( {video: true, audio: false}); this.sendCameraResolution(videoStream); videoStream.getTracks().forEach(track => { console.info(`Using ${track.kind} device: ${track.label}`); - this._cameraSenders.push(this._pc.addTrack(track)); + this.#cameraSenders.push(this.#pc.addTrack(track)); }); } catch (e) { console.error('Failed to add video stream to peer connection: ', e); } } else { - if (!this._cameraSenders) { + if (!this.#cameraSenders) { return; } - for (const sender of this._cameraSenders) { + for (const sender of this.#cameraSenders) { console.info( `Removing ${sender.track.kind} device: ${sender.track.label}`); let track = sender.track; track.stop(); - this._pc.removeTrack(sender); + this.#pc.removeTrack(sender); } - delete this._cameraSenders; + this.#cameraSenders = undefined; } - this._control.renegotiateConnection(); + this.#control.renegotiateConnection(); } sendCameraResolution(stream) { const cameraTracks = stream.getVideoTracks(); if (cameraTracks.length > 0) { const settings = cameraTracks[0].getSettings(); - this._x_res = settings.width; - this._y_res = settings.height; + this.#camera_res_x = settings.width; + this.#camera_res_y = settings.height; this.sendControlMessage(JSON.stringify({ command: 'camera_settings', width: settings.width, @@ -321,9 +343,9 @@ class DeviceConnection { } sendOrQueueCameraData(data) { - if (this._cameraDataChannel.bufferedAmount > 0 || - this._cameraInputQueue.length > 0) { - this._cameraInputQueue.push(data); + if (this.#cameraDataChannel.bufferedAmount > 0 || + this.#cameraInputQueue.length > 0) { + this.#cameraInputQueue.push(data); } else { this.sendCameraData(data); } @@ -334,28 +356,28 @@ class DeviceConnection { const END_MARKER = 'EOF'; for (let i = 0; i < data.byteLength; i += MAX_SIZE) { // range is clamped to the valid index range - this._cameraDataChannel.send(data.slice(i, i + MAX_SIZE)); + this.#cameraDataChannel.send(data.slice(i, i + MAX_SIZE)); } - this._cameraDataChannel.send(END_MARKER); + this.#cameraDataChannel.send(END_MARKER); } // Provide a callback to receive control-related comms from the device onControlMessage(cb) { - this._onControlMessage = cb; + this.#onControlMessage = cb; } sendBluetoothMessage(msg) { - this._bluetoothChannel.send(msg); + this.#bluetoothChannel.send(msg); } onBluetoothMessage(cb) { - this._onBluetoothMessage = cb; + this.#onBluetoothMessage = cb; } // Provide a callback to receive connectionstatechange states. onConnectionStateChange(cb) { - this._pc.addEventListener( - 'connectionstatechange', evt => cb(this._pc.connectionState)); + this.#pc.addEventListener( + 'connectionstatechange', evt => cb(this.#pc.connectionState)); } } |
