import Config from "./config"; class WebRtc { private mediaStream: MediaStream | Blob | null = null; private pee: RTCPeerConnection | null = null; private ws: WebSocket | null = null; private video: HTMLVideoElement | null = null; private userToId: string = ""; open = () => { this.ws?.send(JSON.stringify({ type: "new", "data": { "name": "admin", "id": "31283192", "user_agent": "flutter-webrtc/js" } })) } async init() { this.ws = new WebSocket(Config.rtc) this.ws.addEventListener('open', this.open); let that = this; this.createOffer() this.ws.onmessage = function (evt) { let msg = JSON.parse(evt.data) if (!msg) { return console.log('failed to parse msg') } switch (msg.type) { case 'offer': let offer = msg.data.description that.pee?.setRemoteDescription(offer) that.pee?.createAnswer().then(answer => { that.pee?.setLocalDescription(answer) that.ws?.send(JSON.stringify({ type: 'answer', data: { 'to': msg.data.from, 'from': "31283192", 'description': { 'sdp': answer.sdp, 'type': answer.type }, 'session_id': msg.data.from + "-31283192", } })) }) return case 'candidate': let candidate = msg.data.candidate if (!candidate) { return console.log('failed to parse candidate') } that.pee?.addIceCandidate(candidate) break; case "answer": that.pee?.setRemoteDescription(msg.data.description) break; case "bye": that.pee?.close() that.close() break; } } } async createOffer() { var url = 'http://rw.quwanya.cn:12217/api/turn?service=turn&username=flutter-webrtc'; fetch(url) .then(response => response.json()) .then(data => { const configuration = { iceServers: [ { urls: data.uris[0], "username": data.username, "credential": data.password }, ] } this.gets(configuration) }) try { } catch (error) { console.log(error); } } async gets(configuration) { console.log(configuration); const peerConnection = new RTCPeerConnection(configuration); this.pee = peerConnection // 获取远方流添加到页面播放 peerConnection.ontrack = event => { const remoteVideo = document.querySelector('#remoteVideo') as HTMLVideoElement; remoteVideo.autoplay = true remoteVideo.controls = true remoteVideo.srcObject = event.streams[0]; console.log(event); event.track.onmute = function () { remoteVideo.play() } }; await this.getMedia(peerConnection) peerConnection.onicecandidate = e => { if (!e.candidate) { return } this.ws?.send(JSON.stringify({ type: 'candidate', data: e })) } } sendOffer(userId) { let that = this; that.userToId = userId; that.video = document.getElementById('rtcVideo') as HTMLVideoElement; if (that.pee?.connectionState === "closed") { that.createOffer() } that.pee?.createOffer().then(function (offer) { that.pee?.setLocalDescription(offer); that.ws?.send(JSON.stringify({ type: "offer", "data": { "to": userId, "from": "31283192", "description": offer, "media": "video", "session_id": userId + "-31283192", } })) }).catch(function (error) { // 错误处理 console.error(error); }); } addIceCandidate(candidate) { this.pee?.addIceCandidate(candidate) } async getMedia(pee: RTCPeerConnection) { try { const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true }); this.mediaStream = stream; stream.getTracks().forEach(track => pee.addTrack(track, stream)) } catch (error) { console.log(error); } } calls(userId) { this.sendOffer(userId) if (this.video) { this.video.srcObject = this.mediaStream; this.video.autoplay = true; } } close() { this.video?.pause(); this.pee?.close(); this.ws?.send(JSON.stringify({ "type": "bye", "data": { "session_id": this.userToId + "31283192", "to": this.userToId } } )); (this.mediaStream as MediaStream)?.getTracks().forEach(track => track.stop()); this.ws?.close() } } export const webRTC = new WebRtc()