mirror of
				https://github.com/pion/webrtc.git
				synced 2025-10-31 10:46:39 +08:00 
			
		
		
		
	Add examples/rtcp-processing
rtcp-processing demonstrates how to access RTCP Packets via ReadRTCP Resolves #2027
This commit is contained in:
		| @@ -18,6 +18,7 @@ For more full featured examples that use 3rd party libraries see our **[example- | |||||||
| * [RTP to WebRTC](rtp-to-webrtc): The rtp-to-webrtc example demonstrates how to take RTP packets sent to a Pion process into your browser. | * [RTP to WebRTC](rtp-to-webrtc): The rtp-to-webrtc example demonstrates how to take RTP packets sent to a Pion process into your browser. | ||||||
| * [Simulcast](simulcast): The simulcast example demonstrates how to accept and demux 1 Track that contains 3 Simulcast streams. It then returns the media as 3 independent Tracks back to the sender. | * [Simulcast](simulcast): The simulcast example demonstrates how to accept and demux 1 Track that contains 3 Simulcast streams. It then returns the media as 3 independent Tracks back to the sender. | ||||||
| * [Swap Tracks](swap-tracks): The swap-tracks example demonstrates deeper usage of the Pion Media API. The server accepts 3 media streams, and then dynamically routes them back as a single stream to the user. | * [Swap Tracks](swap-tracks): The swap-tracks example demonstrates deeper usage of the Pion Media API. The server accepts 3 media streams, and then dynamically routes them back as a single stream to the user. | ||||||
|  | * [RTCP Processing](rtcp-processing) The rtcp-processing example demonstrates Pion's RTCP APIs. This allow access to media statistics and control information. | ||||||
|  |  | ||||||
| #### Data Channel API | #### Data Channel API | ||||||
| * [Data Channels](data-channels): The data-channels example shows how you can send/recv DataChannel messages from a web browser. | * [Data Channels](data-channels): The data-channels example shows how you can send/recv DataChannel messages from a web browser. | ||||||
|   | |||||||
| @@ -115,7 +115,7 @@ | |||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
| 		"title": "Swap Tracks", | 		"title": "Swap Tracks", | ||||||
| 		"link": "#", | 		"link": "swap-tracks", | ||||||
| 		"description": "The swap-tracks example demonstrates deeper usage of the Pion Media API. The server accepts 3 media streams, and then dynamically routes them back as a single stream to the user.", | 		"description": "The swap-tracks example demonstrates deeper usage of the Pion Media API. The server accepts 3 media streams, and then dynamically routes them back as a single stream to the user.", | ||||||
| 		"type": "browser" | 		"type": "browser" | ||||||
| 	}, | 	}, | ||||||
| @@ -124,5 +124,11 @@ | |||||||
| 		"link": "#", | 		"link": "#", | ||||||
| 		"description": "The vnet example demonstrates Pion's network virtualisation library. This example connects two PeerConnections over a virtual network and prints statistics about the data traveling over it.", | 		"description": "The vnet example demonstrates Pion's network virtualisation library. This example connects two PeerConnections over a virtual network and prints statistics about the data traveling over it.", | ||||||
| 		"type": "browser" | 		"type": "browser" | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		"title": "rtcp-processing", | ||||||
|  | 		"link": "rtcp-processing", | ||||||
|  | 		"description": "The rtcp-processing example demonstrates Pion's RTCP APIs. This allow access to media statistics and control information.", | ||||||
|  | 		"type": "browser" | ||||||
| 	} | 	} | ||||||
| ] | ] | ||||||
|   | |||||||
							
								
								
									
										38
									
								
								examples/rtcp-processing/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								examples/rtcp-processing/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | |||||||
|  | # rtcp-processing | ||||||
|  | rtcp-processing demonstrates the Public API for processing RTCP packets in Pion WebRTC. | ||||||
|  |  | ||||||
|  | This example is only processing messages for a RTPReceiver. A RTPReceiver is used for accepting | ||||||
|  | media from a remote peer.  These APIs also exist on the RTPSender when sending media to a remote peer. | ||||||
|  |  | ||||||
|  | RTCP is used for statistics and control information for media in WebRTC. Using these messages | ||||||
|  | you can get information about the quality of the media, round trip time and packet loss. You can | ||||||
|  | also craft messages to influence the media quality. | ||||||
|  |  | ||||||
|  | ## Instructions | ||||||
|  | ### Download rtcp-processing | ||||||
|  | ``` | ||||||
|  | export GO111MODULE=on | ||||||
|  | go get github.com/pion/webrtc/v3/examples/rtcp-processing | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### Open rtcp-processing example page | ||||||
|  | [jsfiddle.net](https://jsfiddle.net/Le3zg7sd/) you should see two text-areas, 'Start Session' button and 'Copy browser SessionDescription to clipboard' | ||||||
|  |  | ||||||
|  | ### Run rtcp-processing with your browsers Session Description as stdin | ||||||
|  | In the jsfiddle press 'Copy browser Session Description to clipboard' or copy the base64 string manually. | ||||||
|  |  | ||||||
|  | Now use this value you just copied as the input to `rtcp-processing` | ||||||
|  |  | ||||||
|  | #### Linux/macOS | ||||||
|  | Run `echo $BROWSER_SDP | rtcp-processing` | ||||||
|  | #### Windows | ||||||
|  | 1. Paste the SessionDescription into a file. | ||||||
|  | 1. Run `rtcp-processing < my_file` | ||||||
|  |  | ||||||
|  | ### Input rtcp-processing's Session Description into your browser | ||||||
|  | Copy the text that `rtcp-processing` just emitted and copy into the second text area in the jsfiddle | ||||||
|  |  | ||||||
|  | ### Hit 'Start Session' in jsfiddle | ||||||
|  | You will see console messages for each inbound RTCP message from the remote peer. | ||||||
|  |  | ||||||
|  | Congrats, you have used Pion WebRTC! Now start building something cool | ||||||
							
								
								
									
										4
									
								
								examples/rtcp-processing/jsfiddle/demo.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								examples/rtcp-processing/jsfiddle/demo.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | textarea { | ||||||
|  |     width: 500px; | ||||||
|  |     min-height: 75px; | ||||||
|  | } | ||||||
							
								
								
									
										5
									
								
								examples/rtcp-processing/jsfiddle/demo.details
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								examples/rtcp-processing/jsfiddle/demo.details
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | --- | ||||||
|  |  name: rtcp-processing | ||||||
|  |  description: play-from-disk demonstrates how to process RTCP messages from Pion WebRTC | ||||||
|  |  authors: | ||||||
|  |    - Sean DuBois | ||||||
							
								
								
									
										25
									
								
								examples/rtcp-processing/jsfiddle/demo.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								examples/rtcp-processing/jsfiddle/demo.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | Browser Session Description | ||||||
|  | <br/> | ||||||
|  | <textarea id="localSessionDescription" readonly="true"></textarea> | ||||||
|  | <br/> | ||||||
|  |  | ||||||
|  | <button onclick="window.copySessionDescription()">Copy browser Session Description to clipboard</button> | ||||||
|  |  | ||||||
|  | <br/> | ||||||
|  | <br/> | ||||||
|  | <br/> | ||||||
|  |  | ||||||
|  | Remote Session Description | ||||||
|  | <br/> | ||||||
|  | <textarea id="remoteSessionDescription"></textarea> | ||||||
|  | <br/> | ||||||
|  | <button onclick="window.startSession()">Start Session</button> | ||||||
|  | <br/> | ||||||
|  | <br/> | ||||||
|  |  | ||||||
|  | Video<br /> | ||||||
|  | <video id="video1" width="160" height="120" autoplay muted></video> <br /> | ||||||
|  |  | ||||||
|  | Logs | ||||||
|  | <br/> | ||||||
|  | <div id="div"></div> | ||||||
							
								
								
									
										62
									
								
								examples/rtcp-processing/jsfiddle/demo.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								examples/rtcp-processing/jsfiddle/demo.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | |||||||
|  | /* eslint-env browser */ | ||||||
|  |  | ||||||
|  | const pc = new RTCPeerConnection({ | ||||||
|  |   iceServers: [{ | ||||||
|  |     urls: 'stun:stun.l.google.com:19302' | ||||||
|  |   }] | ||||||
|  | }) | ||||||
|  | const log = msg => { | ||||||
|  |   document.getElementById('div').innerHTML += msg + '<br>' | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pc.ontrack = function (event) { | ||||||
|  |   const el = document.createElement(event.track.kind) | ||||||
|  |   el.srcObject = event.streams[0] | ||||||
|  |   el.autoplay = true | ||||||
|  |   el.controls = true | ||||||
|  |  | ||||||
|  |   document.getElementById('remoteVideos').appendChild(el) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pc.oniceconnectionstatechange = e => log(pc.iceConnectionState) | ||||||
|  | pc.onicecandidate = event => { | ||||||
|  |   if (event.candidate === null) { | ||||||
|  |     document.getElementById('localSessionDescription').value = btoa(JSON.stringify(pc.localDescription)) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | navigator.mediaDevices.getUserMedia({ video: true, audio: true }) | ||||||
|  |   .then(stream => { | ||||||
|  |     document.getElementById('video1').srcObject = stream | ||||||
|  |     stream.getTracks().forEach(track => pc.addTrack(track, stream)) | ||||||
|  |  | ||||||
|  |     pc.createOffer().then(d => pc.setLocalDescription(d)).catch(log) | ||||||
|  |   }).catch(log) | ||||||
|  |  | ||||||
|  | window.startSession = () => { | ||||||
|  |   const sd = document.getElementById('remoteSessionDescription').value | ||||||
|  |   if (sd === '') { | ||||||
|  |     return alert('Session Description must not be empty') | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   try { | ||||||
|  |     pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(atob(sd)))) | ||||||
|  |   } catch (e) { | ||||||
|  |     alert(e) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | window.copySessionDescription = () => { | ||||||
|  |   const browserSessionDescription = document.getElementById('localSessionDescription') | ||||||
|  |  | ||||||
|  |   browserSessionDescription.focus() | ||||||
|  |   browserSessionDescription.select() | ||||||
|  |  | ||||||
|  |   try { | ||||||
|  |     const successful = document.execCommand('copy') | ||||||
|  |     const msg = successful ? 'successful' : 'unsuccessful' | ||||||
|  |     log('Copying SessionDescription was ' + msg) | ||||||
|  |   } catch (err) { | ||||||
|  |     log('Oops, unable to copy SessionDescription ' + err) | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										91
									
								
								examples/rtcp-processing/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								examples/rtcp-processing/main.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | |||||||
|  | // +build !js | ||||||
|  |  | ||||||
|  | package main | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  |  | ||||||
|  | 	"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) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Set a handler for when a new remote track starts | ||||||
|  | 	peerConnection.OnTrack(func(track *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) { | ||||||
|  | 		fmt.Printf("Track has started streamId(%s) id(%s) rid(%s) \n", track.StreamID(), track.ID(), track.RID()) | ||||||
|  |  | ||||||
|  | 		for { | ||||||
|  | 			// Read the RTCP packets as they become available for our new remote track | ||||||
|  | 			rtcpPackets, _, rtcpErr := receiver.ReadRTCP() | ||||||
|  | 			if rtcpErr != nil { | ||||||
|  | 				panic(rtcpErr) | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			for _, r := range rtcpPackets { | ||||||
|  | 				// Print a string description of the packets | ||||||
|  | 				if stringer, canString := r.(fmt.Stringer); canString { | ||||||
|  | 					fmt.Printf("Received RTCP Packet: %v", stringer.String()) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	// Set the handler for ICE connection state | ||||||
|  | 	// This will notify you when the peer has connected/disconnected | ||||||
|  | 	peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) { | ||||||
|  | 		fmt.Printf("Connection State has changed %s \n", connectionState.String()) | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	// 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 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 {} | ||||||
|  | } | ||||||
| @@ -13,9 +13,8 @@ var log = msg => { | |||||||
|  |  | ||||||
| navigator.mediaDevices.getUserMedia({ video: true, audio: true }) | navigator.mediaDevices.getUserMedia({ video: true, audio: true }) | ||||||
|   .then(stream => { |   .then(stream => { | ||||||
|  |  | ||||||
|     document.getElementById('video1').srcObject = stream |     document.getElementById('video1').srcObject = stream | ||||||
|     stream.getTracks().forEach(track => pc.addTrack(track, stream)); |     stream.getTracks().forEach(track => pc.addTrack(track, stream)) | ||||||
|  |  | ||||||
|     pc.createOffer().then(d => pc.setLocalDescription(d)).catch(log) |     pc.createOffer().then(d => pc.setLocalDescription(d)).catch(log) | ||||||
|   }).catch(log) |   }).catch(log) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Sean DuBois
					Sean DuBois