| 11 | * 封装用于点对点数据传输的 WebRTC 数据通道 |
| 12 | */ |
| 13 | export class PeerDataChannel { |
| 14 | private static readonly DEFAULT_BLOCK_SIZE = 32768 |
| 15 | |
| 16 | private pc: RTCPeerConnection |
| 17 | private dc: RTCDataChannel | null = null |
| 18 | private receiveData: { |
| 19 | startTime: number |
| 20 | offset: number |
| 21 | count: number |
| 22 | type: string |
| 23 | chunks: (string | ArrayBuffer)[] |
| 24 | } = { startTime: 0, offset: 0, count: 0, type: '', chunks: [] } |
| 25 | private sendPromiseReject: ((reason?: any) => void) | null = null |
| 26 | private eventQueue: EventQueue<ArrayBuffer | string> |
| 27 | private blockSize: number |
| 28 | |
| 29 | public onReceive: ( |
| 30 | data: ArrayBuffer | string, |
| 31 | info: { size: number; duration: number } |
| 32 | ) => Promise<void> = async () => {} |
| 33 | public onSDP: (sdp: RTCSessionDescriptionInit) => void = () => {} |
| 34 | public onICECandidate: (candidate: RTCIceCandidate) => void = () => {} |
| 35 | public onError: (e: Error) => void = () => {} |
| 36 | public onConnected: () => void = () => {} |
| 37 | public onDispose: () => void = () => {} |
| 38 | public onOpen: () => void = () => {} |
| 39 | |
| 40 | /** |
| 41 | * 创建一个新的 PeerDataChannel 实例 |
| 42 | * @param config 配置 |
| 43 | */ |
| 44 | constructor(config: PeerDataChannelConfig = {}) { |
| 45 | this.blockSize = config.blockSize || PeerDataChannel.DEFAULT_BLOCK_SIZE |
| 46 | this.eventQueue = new EventQueue(this.onData.bind(this)) |
| 47 | this.pc = new RTCPeerConnection({ iceServers: config.iceServers }) |
| 48 | |
| 49 | this.setupPeerConnection() |
| 50 | |
| 51 | if (config.initializeDataChannel) { |
| 52 | this.initializeDataChannel() |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | private setupPeerConnection(): void { |
| 57 | this.pc.ondatachannel = this.handleDataChannel.bind(this) |
| 58 | this.pc.onnegotiationneeded = this.reNegotiation.bind(this) |
| 59 | this.pc.onicecandidate = (e) => e.candidate && this.onICECandidate(e.candidate) |
| 60 | this.pc.onicecandidateerror = (e) => { |
| 61 | // console.warn(e) |
| 62 | // ingore |
| 63 | } |
| 64 | this.pc.onconnectionstatechange = this.handleConnectionStateChange.bind(this) |
| 65 | } |
| 66 | |
| 67 | private handleDataChannel(e: RTCDataChannelEvent): void { |
| 68 | this.dc = e.channel |
| 69 | this.setupDataChannel() |
| 70 | } |
nothing calls this directly
no outgoing calls
no test coverage detected