如何通过OnICECandidate交换ICE Candidates?解决<-gatherComplete耗时问题
解决pion/webrtc/v3中
<-gatherComplete导致连接响应过慢的问题 当前代码依赖<-gatherComplete阻塞等待所有ICE候选收集完成,相当于禁用Trickle ICE,只能通过单条信令交换全部候选,直接导致WebRTC连接建立延迟。需要改用OnICECandidate回调实时交换ICE候选,替代阻塞等待逻辑。
修改思路
- 删除
gatherComplete相关的阻塞代码 - 注册
OnICECandidate回调,收集到ICE候选后立即发送给对端 - 启用Trickle ICE后,无需等待所有候选收集完成即可发送Answer,大幅缩短连接准备时间
修改后的完整代码
package main import ( "fmt" "time" signal "github.com/Sup3r-Us3r/test-app/internal" "github.com/pion/mediadevices" "github.com/pion/mediadevices/pkg/codec/vpx" "github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3/pkg/media" "gocv.io/x/gocv" ) func main() { webcam, _ := gocv.OpenVideoCapture(0) defer webcam.Close() webRTCConfig := webrtc.Configuration{ ICEServers: []webrtc.ICEServer{ { URLs: []string{"stun:stun.l.google.com:19302"}, }, }, } // 等待输入远端Offer offer := webrtc.SessionDescription{} signal.Decode(signal.MustReadStdin(), &offer) // 初始化VP8编码参数 vp8Params, err := vpx.NewVP8Params() if err != nil { panic(err) } vp8Params.BitRate = 500_000 // 500kbps codecSelector := mediadevices.NewCodecSelector( mediadevices.WithVideoEncoders(&vp8Params), ) // 配置媒体引擎与PeerConnection mediaEngine := webrtc.MediaEngine{} mediaEngine.RegisterDefaultCodecs() codecSelector.Populate(&mediaEngine) api := webrtc.NewAPI(webrtc.WithMediaEngine(&mediaEngine)) peerConnection, _ := api.NewPeerConnection(webRTCConfig) // ICE连接状态变更监听 peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) { fmt.Printf("连接状态已变更: %s \n", connectionState.String()) }) // 实时处理ICE候选 peerConnection.OnICECandidate(func(candidate *webrtc.ICECandidate) { if candidate == nil { fmt.Println("ICE候选收集完成") return } // 将候选编码后发送给对端,需根据实际信令机制调整发送逻辑 fmt.Println("新ICE候选:", signal.Encode(candidate.ToJSON())) }) // 创建本地视频Track videoTrack, _ := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8}, "video", "pion") // 将Track添加到PeerConnection _, err = peerConnection.AddTrack(videoTrack) if err != nil { fmt.Println("\n添加Track错误: ", err) } // 设置远端SessionDescription err = peerConnection.SetRemoteDescription(offer) if err != nil { panic(err) } // 创建Answer answer, err := peerConnection.CreateAnswer(nil) if err != nil { panic(err) } // 设置本地SessionDescription,启动ICE收集 err = peerConnection.SetLocalDescription(answer) if err != nil { panic(err) } // 立即输出Answer,无需等待ICE收集完成 fmt.Println("Answer:", signal.Encode(*peerConnection.LocalDescription())) img := gocv.NewMat() defer img.Close() for { if ok := webcam.Read(&img); !ok { fmt.Printf("设备已关闭: %v\n", 0) return } if img.Empty() { continue } // 编码帧为JPEG并写入Track frame, _ := gocv.IMEncode(gocv.JPEGFileExt, img) err = videoTrack.WriteSample(media.Sample{Data: frame.GetBytes(), Duration: time.Second}) if err != nil { fmt.Println("\n错误: ", err) } } }
关键修改说明
- 移除了
webrtc.GatheringCompletePromise和<-gatherComplete的阻塞逻辑,无需等待所有ICE候选收集完成 - 添加
OnICECandidate回调,实时推送新收集到的ICE候选;当回调参数为nil时,表示ICE候选收集完成 - 设置本地描述后立即输出Answer,让对端提前启动连接流程,显著降低连接建立的等待时长
内容的提问来源于stack exchange,提问作者Mac
相关产品推荐
相关产品推荐

