WebRTC.Net庫:讓你的應(yīng)用更親民友好,實現(xiàn)視頻通話無痛接入! 除了基本用法外,還有一些進階用法可以更好地利用該庫。
WebRTC.Net 默認使用 Google 的 STUN 服務(wù)器和 Coturn 的 TURN 服務(wù)器。如果你需要使用其他 STUN/TURN 服務(wù)器,則可以在初始化 PeerConnectionFactory 和 PeerConnection 時設(shè)置自定義配置。
例如,以下代碼設(shè)置了使用 coturn 服務(wù)器的 PeerConnectionFactory:
var config = new PeerConnectionConfiguration{ IceServers = new List<IceServer> { new IceServer{ Urls = new[] { "stun:stun.l.google.com:19302" }}, new IceServer{ Urls = new[] { "turn:my-turn-server.com" }, Username="myusername", Credential="mypassword" } }};var factory = new PeerConnectionFactory(config);
WebRTC.Net 庫本質(zhì)上是基于線程的,因此它的對象通常在單獨的線程中創(chuàng)建和使用。這樣可以避免在主線程中對 UI 線程造成大量負擔。
以下代碼在后臺線程中創(chuàng)建并使用 PeerConnection 對象:
Task.Run(() =>{ var config = new PeerConnectionConfiguration { IceServers = new List<IceServer> { new IceServer { Urls = new[] { "stun:stun.l.google.com:19302" } } } }; var factory = new PeerConnectionFactory(config); var pc = factory.CreatePeerConnection(config); // 在這里使用 PeerConnection 對象,不會阻塞主線程}).Wait();
在創(chuàng)建 PeerConnectionFactory 對象時,可以設(shè)置 defaultAudioDevice 和 defaultVideoDevice 參數(shù)以選擇默認的音頻和視頻設(shè)備。
例如,以下如何通過設(shè)備名稱選擇視頻和音頻設(shè)備:
var config = new PeerConnectionConfiguration{ IceServers = new List<IceServer> { new IceServer { Urls = new[] { "stun:stun.l.google.com:19302" } } }, DefaultVideoDevice = VideoCaptureDevice.GetDevices().FirstOrDefault(x => x.Name == "MyCameraName"), DefaultAudioDevice = AudioCaptureDevice.GetDevices().FirstOrDefault(x => x.Name == "MyMicrophoneName")};var factory = new PeerConnectionFactory(config);
WebRTC.Net 庫不僅支持音視頻傳輸,還支持實現(xiàn)數(shù)據(jù)通道(DataChannel)。使用數(shù)據(jù)通道,應(yīng)用程序可以在客戶端之間傳輸任意類型的數(shù)據(jù),例如聊天消息、游戲狀態(tài)等。
以下代碼如何創(chuàng)建數(shù)據(jù)通道:
// 創(chuàng)建 PeerConnection 對象var config = new PeerConnectionConfiguration { IceServers = new List<IceServer> { new IceServer { Urls = new[] { "stun:stun.l.google.com:19302" } } } };var factory = new PeerConnectionFactory(config);var pc = factory.CreatePeerConnection(config);// 創(chuàng)建數(shù)據(jù)通道var dcConfig = new DataChannelInit { Ordered = true };var dc = pc.CreateDataChannel("mydatachannel", dcConfig);// 監(jiān)聽數(shù)據(jù)通道事件dc.MessageReceived += (sender, e) =>{ // 處理接收到的數(shù)據(jù)};
除了音視頻傳輸和數(shù)據(jù)通道,WebRTC.Net 還支持屏幕共享。這意味著應(yīng)用程序可以捕獲屏幕上的內(nèi)容并將其共享給其他客戶端。
以下是使用 WinForm 技術(shù)棧和 WebRTC.Net 庫實現(xiàn)桌面共享的示例代碼。
using System;using System.Drawing;using System.Threading.Tasks;using System.Windows.Forms;using Windows.Graphics.Capture;using Windows.Graphics.DirectX.Direct3D11;using Microsoft.Toolkit.Win32.UI.Controls.Interop.WinRT;using Org.WebRtc;namespace DesktopStreaming{ public partial class MainForm : Form { private PeerConnection _peerConnection; private DataChannel _dataChannel; private Direct3D11CaptureFramePool _framePool; private GraphicsCaptureSession _session; private VideoTrack _videoTrack; public MainForm() { InitializeComponent(); // 初始化 WebRTC WebRTC.Initialize(new WebRTCInitializationOptions { EnableAudioBufferLog = false }); // 創(chuàng)建 PeerConnectionFactory 對象 var config = new PeerConnectionConfiguration { IceServers = new[] { new IceServer { Urls = new[] { "stun:stun.l.google.com:19302" } } } }; var factory = new PeerConnectionFactory(config); // 創(chuàng)建 PeerConnection 對象 _peerConnection = factory.CreatePeerConnection(); // 創(chuàng)建數(shù)據(jù)通道 _dataChannel = _peerConnection.CreateDataChannel("mychannel"); // 訂閱數(shù)據(jù)通道的消息事件 _dataChannel.MessageReceived += (sender, args) => { // 處理收到的消息 }; // 創(chuàng)建 Direct3D11CaptureFramePool 對象 var device = Direct3D11Helpers.CreateDevice(); var size = new Size(800, 600); _framePool = Direct3D11CaptureFramePool.CreateFreeThreaded( device, Direct3DPixelFormat.B8G8R8A8UIntNormalized, 1, size); // 訂閱 FrameArrived 事件 _framePool.FrameArrived += (sender, args) => { // 獲取最新的桌面幀 using var frame = sender.TryGetNextFrame(); if (frame == null) return; // 將桌面幀轉(zhuǎn)換為 RTCVideoFrame 對象 var videoFrame = new RTCVideoFrame(frame.ContentSize.Width, frame.ContentSize.Height, RTCVideoFrameType.RTCVideoFrameTypeI420); videoFrame.ConvertFromArgb32(frame.Surface.Direct3D11Device, frame.Surface); // 將 RTCVideoFrame 對象轉(zhuǎn)換為 VideoTrack 對象并發(fā)送 if (_videoTrack != null) _videoTrack.PushFrame(videoFrame); }; // 創(chuàng)建 GraphicsCaptureItem 對象 var item = ScreenCapture.GetDefault(); // 創(chuàng)建 GraphicsCaptureSession 對象 _session = _framePool.CreateCaptureSession(item); } private async void btnStart_Click(object sender, EventArgs e) { // 開始共享桌面 await _session.StartAsync(); // 創(chuàng)建視頻軌道 _videoTrack = await PeerConnectionFactory.GetVideoTrackSourceAsync(_framePool); // 添加視頻軌道到 PeerConnection 對象 await _peerConnection.AddTrack(_videoTrack); // 創(chuàng)建 Offer SDP 并設(shè)置本地描述符 var offerSdp = await _peerConnection.CreateOffer(); await _peerConnection.SetLocalDescription(offerSdp); // 發(fā)送 Offer SDP 到遠端 SendSdp(offerSdp); } private void SendSdp(RTCSessionDescription sdp) { // 將 SDP 轉(zhuǎn)換為 JSON 格式并發(fā)送到遠端 var json = Newtonsoft.Json.JsonConvert.SerializeObject(new { type = sdp.Type, sdp = sdp.Sdp }); _dataChannel.Send(json); } private async void MainForm_FormClosing(object sender, FormClosingEventArgs e) { // 關(guān)閉 PeerConnection 和 GraphicsCaptureSession 對象 await _peerConnection.CloseAsync(); _session.Dispose(); } }}
上述代碼中,我們使用了 ScreenCapture 類來獲取默認的桌面捕獲項目,然后創(chuàng)建了 GraphicsCaptureSession 對象來捕獲桌面幀。我們還使用了
Direct3D11CaptureFramePool 類來創(chuàng)建一個 Direct3D 11 幀池,并訂閱了 FrameArrived 事件以獲取最新的桌面幀。在每次收到桌面幀時,我們將其轉(zhuǎn)換為 RTCVideoFrame 對象,再將其發(fā)送到 WebRTC 連接中。通過這種方式,我們就實現(xiàn)了桌面共享的功能。
需要注意的是,由于 WebRTC 是基于 p2p 的實時通信協(xié)議,因此本示例代碼中僅演示了如何將桌面共享的數(shù)據(jù)發(fā)送給遠端客戶端,而沒有涉及如何在遠端客戶端上解析和顯示收到的數(shù)據(jù)。
WebRTC.Net 使用 ICE(Interactive Connectivity Establishment)協(xié)議來建立和維護客戶端之間的連接。ICE 協(xié)議涉及多個狀態(tài)和事件,例如 gathering、connected、disconnected 等等。應(yīng)用程序可以訂閱 PeerConnection 對象上的各種事件來處理這些狀態(tài)。
以下代碼如何訂閱 PeerConnection 對象上的連接狀態(tài):
// 創(chuàng)建 PeerConnection 對象var config = new PeerConnectionConfiguration { IceServers = new List<IceServer> { new IceServer { Urls = new[] { "stun:stun.l.google.com:19302" } } } };var factory = new PeerConnectionFactory(config);var pc = factory.CreatePeerConnection(config);// 訂閱 PeerConnection 對象上的連接狀態(tài)pc.IceStateChanged += (sender, iceState) =>{ if (iceState == IceConnectionState.Connected) { // 客戶端已成功連接 } else if (iceState == IceConnectionState.Disconnected) { // 客戶端已斷開連接 }};
WebRTC.Net 支持實現(xiàn)多路復用(Multiplexing),這意味著應(yīng)用程序可以在同一個數(shù)據(jù)通道上同時傳輸多種類型的數(shù)據(jù),例如音頻、視頻、文件等。
下面是使用 WinForm 技術(shù)棧和 WebRTC.Net 庫實現(xiàn)多路復用的示例代碼。
Copy Codeusing System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using System.Windows.Forms;using Microsoft.Toolkit.Win32.UI.Controls.Interop.WinRT;using Org.WebRtc;namespace WebRTC_Multiplexing{ public partial class Form1 : Form { private PeerConnection _peerConnection; private List<DataChannel> _dataChannels = new List<DataChannel>(); public Form1() { InitializeComponent(); // 初始化 WebRTC WebRTC.Initialize(new WebRTCInitializationOptions { EnableAudioBufferLog = false }); // 創(chuàng)建 PeerConnectionFactory 對象 var config = new PeerConnectionConfiguration { IceServers = new[] { new IceServer { Urls = new[] { "stun:stun.l.google.com:19302" } } } }; var factory = new PeerConnectionFactory(config); // 創(chuàng)建 PeerConnection 對象 _peerConnection = factory.CreatePeerConnection(); // 訂閱 PeerConnection 的連接狀態(tài)改變事件 _peerConnection.ConnectionStateChanged += (sender, args) => { // 處理連接狀態(tài)改變事件 BeginInvoke(new Action(() => txtOutput.AppendText($"連接狀態(tài):{args.NewState.ToString()}/r/n"))); }; // 訂閱 PeerConnection 的數(shù)據(jù)通道回調(diào)事件 _peerConnection.DataChannelAdded += (sender, args) => { // 處理數(shù)據(jù)通道回調(diào)事件 var dataChannel = args.Channel; dataChannel.MessageReceived += DataChannel_MessageReceived; _dataChannels.Add(dataChannel); BeginInvoke(new Action(() => txtOutput.AppendText($"收到數(shù)據(jù)通道:{dataChannel.Label}/r/n"))); }; } private async void btnCreateOffer_Click(object sender, EventArgs e) { // 創(chuàng)建 Offer SDP 并設(shè)置本地描述符 var offerSdp = await _peerConnection.CreateOffer(); await _peerConnection.SetLocalDescription(offerSdp); // 發(fā)送 Offer SDP 到對端 SendSdp(offerSdp); } private void SendSdp(RTCSessionDescription sdp) { // 將 SDP 轉(zhuǎn)換為 JSON 格式并發(fā)送到對端 var json = Newtonsoft.Json.JsonConvert.SerializeObject(new { type = sdp.Type, sdp = sdp.Sdp }); _dataChannels.ForEach(dc => dc.Send(json)); } private async void DataChannel_MessageReceived(object sender, DataChannelMessageEventArgs e) { // 收到數(shù)據(jù)通道消息后將其轉(zhuǎn)換為 RTCSessionDescription 對象 if (e.MessageType == DataMessageType.Text) { var text = e.Data; var sdp = Newtonsoft.Json.JsonConvert.DeserializeObject<RTCSessionDescription>(text); // 設(shè)置遠端描述符并完成連接 await _peerConnection.SetRemoteDescription(sdp); if (sdp.Type == RTCSessionDescriptionType.Offer) await _peerConnection.CreateAnswer(); } } }}
上述代碼中,我們創(chuàng)建了一個 PeerConnectionFactory 對象和一個 PeerConnection 對象,用于建立 WebRTC 連接。我們還創(chuàng)建了一個 _dataChannels 列表來保存所有的數(shù)據(jù)通道對象,每當 PeerConnection 對象添加一個新的數(shù)據(jù)通道時,我們就將其添加到 _dataChannels 列表中。
在 btnCreateOffer_Click 事件處理方法中,我們創(chuàng)建了一個 Offer SDP 并設(shè)置本地描述符,然后將其發(fā)送到所有的數(shù)據(jù)通道對象中。當收到對端發(fā)送過來的 SDP 消息時,我們將其轉(zhuǎn)換為 RTCSessionDescription 對象,并調(diào)用 SetRemoteDescription 方法設(shè)置遠端描述符。如果收到來自對端的 Offer SDP,則執(zhí)行 CreateAnswer 方法創(chuàng)建 Answer SDP 并將其發(fā)送回對端。
通過這種方式,我們就可以使用同一個 PeerConnection 對象來支持多路復用。每當需要發(fā)送數(shù)據(jù)時,只需要將數(shù)據(jù)發(fā)送到指定的數(shù)據(jù)通道對象即可。需要注意的是,在使用多路復用時,我們需要為不同的數(shù)據(jù)通道設(shè)置不同的標簽(Label),以便在接收端識別不同的通道。
本文鏈接:http://www.tebozhan.com/showinfo-26-147-0.htmlWebRTC.Net庫開發(fā)進階,教你實現(xiàn)屏幕共享和多路復用!
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com