Angular+Firefox环境下WebRTC ICE失败问题求助
WebRTC ICE交换错误排查求助
严格遵循WebRTC开发流程,整体流程顺畅,但在对等端交换ICE时出现错误。使用谷歌STUN服务器,本地测试时临时安装了CoTurn(sudo pacman -S coturn)。
配置信息
const configuration = { 'iceServers': [ { 'urls': 'stun:stun.l.google.com:19302' }, { urls: 'turn:192.168.1.71:3478', username: 'username', credential: 'password' } ] }
Angular客户端TypeScript代码
var peerConnection = new RTCPeerConnection(configuration); peerConnection.addEventListener('connectionstatechange', event => { if (peerConnection.connectionState === 'connected') { console.warn("SUCCESS! PEERS CONNECTED") } }); this.checkloginservice.socket$.subscribe( async (message) => { let action = (message as websocketDef).action switch (action) { case "offer": peerConnection.addEventListener('icecandidate', (event) => { if (event.candidate) { console.log(event.candidate) this.checkloginservice.socket$.next({ Action: 'icecandidate', Value: JSON.stringify({ for: this.callData.peerdata.userid, icecandidate: JSON.stringify(event.candidate), action: "icecandidate" }) }) } }); let data = message as incomingCallData this.incomingCall = { callerDisplayname: data.displayName, callerId: data.userid, callerPfp: data.pfp, chatid: data.chatid, } setTimeout(() => { this.document.querySelector(".ans")?.addEventListener("click", async () => { peerConnection.setRemoteDescription(new RTCSessionDescription(JSON.parse(data.offer))) const answer = await peerConnection.createAnswer(); await peerConnection.setLocalDescription(answer); this.checkloginservice.socket$.next({ Action: "answer", Value: JSON.stringify({ for: data.userid, answer: JSON.stringify(answer), action: "answer" }) }) }) }, 10); break; case "answer": peerConnection.addEventListener('icecandidate', (event) => { if (event.candidate) { console.log(event.candidate) this.checkloginservice.socket$.next({ Action: 'icecandidate', Value: JSON.stringify({ for: this.callData.peerdata.userid, icecandidate: JSON.stringify(event.candidate), action: "icecandidate" }) }) } }); let answerData = message as answerCallData const remoteDesc = new RTCSessionDescription(JSON.parse(answerData.answer)); await peerConnection.setRemoteDescription(remoteDesc); break; case "icecandidate": let icacand = message as iceCandData try { await peerConnection.addIceCandidate(JSON.parse(icacand.icecandidate)); } catch (e) { console.error('Error adding received ice candidate', e); } } } ) this.msgService.callFriend$.subscribe(async (calldata) => { if (calldata.friendid != '') { if (await this.chkMicPerms()) { let stream = await this.getUserMedia(false) if (stream == typeof String) { this.toastService.add({ severity: "error", summary: this.translateService.instant("callFailed"), detail: this.translateService.instant(stream) }) } else { localStream = stream as MediaStream this.callData.peerdata.userid = calldata.friendid this.callData.peerdata.displayName = calldata.friendname; this.callData.peerdata.pfp = calldata.friendpfp; this.callData.chatid = calldata.chatid; const offer = await peerConnection.createOffer({ offerToReceiveAudio: true }); await peerConnection.setLocalDescription(offer) this.checkloginservice.socket$.next({ Action: 'offer', Value: JSON.stringify({ for: calldata.friendid, offer: JSON.stringify(offer), username: userData.username, userid: userData.userid, displayName: userData.displayName, pfp: userData.pfp, chatid: calldata.chatid, action: "offer" }) }) } } else { this.toastService.add({ severity: "error", summary: this.translateService.instant("callFailed"), detail: this.translateService.instant("provideMic") }) } } })
Go语言服务器端代码
var ( upgrader = websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true }, } Rm = &roomManager{ rooms: make(map[string]*Client), mu: sync.Mutex{}, } ) func (rm *roomManager) Broadcast(message interface{}, userid string) { rm.mu.Lock() defer rm.mu.Unlock() for _, userConnection := range rm.rooms { if userConnection.Connection != nil && userConnection.Userid == userid { // if err := userConnection.Connection.WriteJSON(message); err != nil {} userConnection.Connection.WriteJSON(message) } } } func HandleWebSocket(c *gin.Context) { conn, err := upgrader.Upgrade(c.Writer, c.Request, nil) if err != nil { return } client := &Client{ Connection: conn, } for { _, p, err := conn.ReadMessage() if err != nil { Rm.removeUser(client.Userid) return } var message config.Websocket_DefaultMessage if err := json.Unmarshal(p, &message); err != nil { return } switch message.Action { case "joinRealtime": Rm.connectUser(conn, message.Value) client.Userid = message.Value Rm.Broadcast("Connected to WebSocket /user", message.Value) case "offer": type offerData struct { For string `json:"for"` Offer string `json:"offer"` Username string `json:"username"` Userid string `json:"userid"` DisplayName string `json:"displayName"` Pfp string `json:"pfp"` Chatid string `json:"chatid"` Action string `json:"action"` } var offer offerData if err := json.Unmarshal([]byte(message.Value), &offer); err != nil { return } Rm.Broadcast(offer, offer.For) case "answer": type answerData struct { For string `json:"for"` Answer string `json:"answer"` Action string `json:"action"` } var answer answerData if err := json.Unmarshal([]byte(message.Value), &answer); err != nil { return } Rm.Broadcast(answer, answer.For) case "icecandidate": type iceCandData struct { For string `json:"for"` Action string `json:"action"` Icecandidate string `json:"icecandidate"` } var iceCand iceCandData if err := json.Unmarshal([]byte(message.Value), &iceCand); err != nil { return } Rm.Broadcast(iceCand, iceCand.For) } } }
内容的提问来源于stack exchange,提问作者Alms
相关产品推荐
相关产品推荐

