UNPKG

react-native-webrtc

Version:
191 lines (148 loc) 5.79 kB
import * as base64 from 'base64-js'; import { EventTarget, defineEventAttribute } from 'event-target-shim/index'; import { NativeModules } from 'react-native'; import { addListener, removeListener } from './EventEmitter'; import MessageEvent from './MessageEvent'; import RTCDataChannelEvent from './RTCDataChannelEvent'; const { WebRTCModule } = NativeModules; type RTCDataChannelState = 'connecting' | 'open' | 'closing' | 'closed'; type DataChannelEventMap = { bufferedamountlow: RTCDataChannelEvent<'bufferedamountlow'>; close: RTCDataChannelEvent<'close'>; closing: RTCDataChannelEvent<'closing'>; error: RTCDataChannelEvent<'error'>; message: MessageEvent<'message'>; open: RTCDataChannelEvent<'open'>; }; export default class RTCDataChannel extends EventTarget<DataChannelEventMap> { _peerConnectionId: number; _reactTag: string; _bufferedAmount: number; _id: number; _label: string; _maxPacketLifeTime?: number; _maxRetransmits?: number; _negotiated: boolean; _ordered: boolean; _protocol: string; _readyState: RTCDataChannelState; binaryType = 'arraybuffer'; // we only support 'arraybuffer' bufferedAmountLowThreshold = 0; constructor(info) { super(); this._peerConnectionId = info.peerConnectionId; this._reactTag = info.reactTag; this._bufferedAmount = 0; this._label = info.label; this._id = info.id === -1 ? null : info.id; // null until negotiated. this._ordered = Boolean(info.ordered); this._maxPacketLifeTime = info.maxPacketLifeTime; this._maxRetransmits = info.maxRetransmits; this._protocol = info.protocol || ''; this._negotiated = Boolean(info.negotiated); this._readyState = info.readyState; this._registerEvents(); } get bufferedAmount(): number { return this._bufferedAmount; } get label(): string { return this._label; } get id(): number { return this._id; } get ordered(): boolean { return this._ordered; } get maxPacketLifeTime(): number | undefined { return this._maxPacketLifeTime; } get maxRetransmits(): number | undefined { return this._maxRetransmits; } get protocol(): string { return this._protocol; } get negotiated(): boolean { return this._negotiated; } get readyState(): string { return this._readyState; } send(data: string): void; send(data: ArrayBuffer): void; send(data: ArrayBufferView): void; send(data: string | ArrayBuffer | ArrayBufferView): void { if (typeof data === 'string') { WebRTCModule.dataChannelSend(this._peerConnectionId, this._reactTag, data, 'text'); return; } // Safely convert the buffer object to an Uint8Array for base64-encoding if (ArrayBuffer.isView(data)) { data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength); } else if (data instanceof ArrayBuffer) { data = new Uint8Array(data); } else { throw new TypeError('Data must be either string, ArrayBuffer, or ArrayBufferView'); } const base64data = base64.fromByteArray(data as Uint8Array); WebRTCModule.dataChannelSend(this._peerConnectionId, this._reactTag, base64data, 'binary'); } close(): void { if (this._readyState === 'closing' || this._readyState === 'closed') { return; } WebRTCModule.dataChannelClose(this._peerConnectionId, this._reactTag); } _registerEvents(): void { addListener(this, 'dataChannelStateChanged', (ev: any) => { if (ev.reactTag !== this._reactTag) { return; } this._readyState = ev.state; if (this._id === null && ev.id !== -1) { this._id = ev.id; } if (this._readyState === 'open') { this.dispatchEvent(new RTCDataChannelEvent('open', { channel: this })); } else if (this._readyState === 'closing') { this.dispatchEvent(new RTCDataChannelEvent('closing', { channel: this })); } else if (this._readyState === 'closed') { this.dispatchEvent(new RTCDataChannelEvent('close', { channel: this })); // This DataChannel is done, clean up event handlers. removeListener(this); WebRTCModule.dataChannelDispose(this._peerConnectionId, this._reactTag); } }); addListener(this, 'dataChannelReceiveMessage', (ev: any) => { if (ev.reactTag !== this._reactTag) { return; } let data = ev.data; if (ev.type === 'binary') { data = base64.toByteArray(ev.data).buffer; } this.dispatchEvent(new MessageEvent('message', { data })); }); addListener(this, 'dataChannelDidChangeBufferedAmount', (ev: any) => { if (ev.reactTag !== this._reactTag) { return; } this._bufferedAmount = ev.bufferedAmount; if (this._bufferedAmount < this.bufferedAmountLowThreshold) { this.dispatchEvent(new RTCDataChannelEvent('bufferedamountlow', { channel: this })); } }); } } /** * Define the `onxxx` event handlers. */ const proto = RTCDataChannel.prototype; defineEventAttribute(proto, 'bufferedamountlow'); defineEventAttribute(proto, 'close'); defineEventAttribute(proto, 'closing'); defineEventAttribute(proto, 'error'); defineEventAttribute(proto, 'message'); defineEventAttribute(proto, 'open');