pion webrtc

pion 是go语言写的webrtc的开发库套装

DTLS 协议

    我们对DTLS 协议要适当的解释,TLS是用于TCP的,而DTLS是用于数据报的,很多应用运行在TCP之上,但是目前这种情况正在改变。现在不断增长的应用层协议,比如SIP (session initial protocol),RTP (real time protocol), MGCP (the Media Gateway Control Protocol),还有许多游戏协议都基于UDP传输而设计,而HTTP协议也正悄然改变,HTTP3可能也会转移到udp上。那么webrtc的datachannel也是基于这个协议的。

    DataChannel的数据通过boringssl加密后再通过udp发送给对端,实现了DTLS,发送datachannel数据和音视频数据的事实上是同一个sock。不过不一样的是:音视频数据传输使用了RTP协议,并且通过NACK和FEC算法来抗丢包,而DataChannel底层使用了SCTP(stream control transmission protocol)协议,SCTP和TCP类似,具备流量控制、拥塞控制,可以说是一个可靠性传输协议,因此可以不采取其它措施即,就已经实现DataChannel数据的可靠传输。webrtc采用了第三方开源库usrsctplib来实现SCTP协议。

pion示例代码

    这里,我们会对pion的示例一一解析,首先:启动 go run examples.go, ,example.go 是一个http协议的服务器,默认在80端口启动协议,这里我们打开网页后,打开datachannel示例:
pion示例


    点击run javascript后,得到Browser base64 Session Description框里的数据,复制里面的base64到一个文件中,保存名字为a.txt ![data channel 示例](https://img-blog.csdnimg.cn/6cd3bbdfc5dd44fba6fa57a9c288306c.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FpYW5ibzA0MjMxMQ==,size_16,color_FFFFFF,t_70) 然后进入datachannel 目录 go run main.go < a.txt 就会得到自己的sdp信息,将这个sdp信息复制到页面中, ![复制进去](https://img-blog.csdnimg.cn/3a8f9b70a01b4558bf5b3a8ad6049023.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FpYW5ibzA0MjMxMQ==,size_16,color_FFFFFF,t_70) 点击Start session, 网页和客户端可以开始互相发送信息。

示例datachannel

offer := webrtc.SessionDescription{}
signal.Decode(signal.MustReadStdin(), &offer)

singal 需要对输入进行读取,所以要从参数上输入offer,offer是一串码,sdp信息,我们来看看解码后的字符串:
{
offer v=0
o=- 203838700267639233 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0
a=extmap-allow-mixed
a=msid-semantic: WMS
m=application 3002 UDP/DTLS/SCTP webrtc-datachannel
c=IN IP4 1.86.247.81
a=candidate:2026329132 1 udp 2122260223 192.168.0.129 51720 typ host generation 0 network-id 1
a=candidate:910469340 1 tcp 1518280447 192.168.0.129 9 typ host tcptype active generation 0 network-id 1
a=candidate:4186919576 1 udp 1686052607 1.86.247.81 3002 typ srflx raddr 192.168.0.129 rport 51720 generation 0 network-id 1
a=ice-ufrag:y7zo
a=ice-pwd:vYIYqME4lmB5i0C3JwVZQicy
a=ice-options:trickle
a=fingerprint:sha-256 A2:28:50:C3:45:9D:19:12:6D:29:C5:32:06:97:C7:D2:37:9F:EA:A2:02:68:58:91:76:E6:44:17:8D:B9:C6:A8
a=setup:actpass
a=mid:0
a=sctp-port:5000
a=max-message-size:262144

}
这下看的很清晰了

package main

import (
	"fmt"
	"os"
	"time"

	"github.com/pion/webrtc/v3"
	"github.com/pion/webrtc/v3/examples/internal/signal"
)

func main() {
	// Everything below is the Pion WebRTC API! Thanks for using it ❤️.

	// Prepare the configuration
	config := webrtc.Configuration{
		ICEServers: []webrtc.ICEServer{
			{
				URLs: []string{"stun:stun.l.google.com:19302"},
			},
		},
	}

	// Create a new RTCPeerConnection
	peerConnection, err := webrtc.NewPeerConnection(config)
	if err != nil {
		panic(err)
	}
	defer func() {
		if cErr := peerConnection.Close(); cErr != nil {
			fmt.Printf("cannot close peerConnection: %v\n", cErr)
		}
	}()

	// Set the handler for Peer connection state
	// This will notify you when the peer has connected/disconnected
	peerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) {
		fmt.Printf("Peer Connection State has changed: %s\n", s.String())

		if s == webrtc.PeerConnectionStateFailed {
			// Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart.
			// Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout.
			// Note that the PeerConnection may come back from PeerConnectionStateDisconnected.
			fmt.Println("Peer Connection has gone to failed exiting")
			os.Exit(0)
		}
	})

	// Register data channel creation handling
	peerConnection.OnDataChannel(func(d *webrtc.DataChannel) {
		fmt.Printf("New DataChannel %s %d\n", d.Label(), d.ID())

		// Register channel opening handling
		d.OnOpen(func() {
			fmt.Printf("Data channel '%s'-'%d' open. Random messages will now be sent to any connected DataChannels every 5 seconds\n", d.Label(), d.ID())

			for range time.NewTicker(5 * time.Second).C {
				message := signal.RandSeq(15)
				fmt.Printf("Sending '%s'\n", message)

				// Send the message as text
				sendErr := d.SendText(message)
				if sendErr != nil {
					panic(sendErr)
				}
			}
		})

		// Register text message handling
		d.OnMessage(func(msg webrtc.DataChannelMessage) {
			fmt.Printf("Message from DataChannel '%s': '%s'\n", d.Label(), string(msg.Data))
		})
	})

	// Wait for the offer to be pasted
	offer := webrtc.SessionDescription{}
	signal.Decode(signal.MustReadStdin(), &offer)

	// Set the remote SessionDescription
	err = peerConnection.SetRemoteDescription(offer)
	if err != nil {
		panic(err)
	}

	// Create an answer
	answer, err := peerConnection.CreateAnswer(nil)
	if err != nil {
		panic(err)
	}

	// Create channel that is blocked until ICE Gathering is complete
	gatherComplete := webrtc.GatheringCompletePromise(peerConnection)

	// Sets the LocalDescription, and starts our UDP listeners
	err = peerConnection.SetLocalDescription(answer)
	if err != nil {
		panic(err)
	}

	// Block until ICE Gathering is complete, disabling trickle ICE
	// we do this because we only can exchange one signaling message
	// in a production application you should exchange ICE Candidates via OnICECandidate
	<-gatherComplete

	// Output the answer in base64 so we can paste it in browser
	fmt.Println(signal.Encode(*peerConnection.LocalDescription()))

	// Block forever
	select {}
}

网页和客户端

网页和客户端的api 非常接近,可以看出pion是非常友好的,可以根据这个 示例来制作点对点的聊天程序。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐