Skip to content

Commit

Permalink
Delete rejected transceiver.
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinVison committed Jan 17, 2025
1 parent 49b555b commit 4e29ef2
Show file tree
Hide file tree
Showing 5 changed files with 330 additions and 9 deletions.
18 changes: 18 additions & 0 deletions examples/delete-transceiver/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# delete-transceiver
delete-transceiver demonstrates Pion WebRTC's ability to delete rejected transceivers.

## Instructions

### Download delete-transceiver
This example requires you to clone the repo since it is serving static HTML.

```
git clone https://github.com/pion/webrtc.git
cd webrtc/examples/delete-transceiver
```

### Run delete-transceiver
Execute `go run *.go`

### Open the Web UI
Open [http://localhost:8080](http://localhost:8080). This remote peerconnection will use single port 8443.
117 changes: 117 additions & 0 deletions examples/delete-transceiver/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<html>
<!--
SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
SPDX-License-Identifier: MIT
-->

<head>
<title>ice-single-port</title>
</head>

<body>
<h3> ICE Selected Pairs </h3>
<div id="iceSelectedPairs"></div> <br />
</body>

<script>
let removeTransceiverByMid = (sdp, mids) => {
const lines = sdp.split('\r\n');
const midSet = new Set(mids);
let currentMid = null;
let firstMid = null;
let updatedLines = [];
let lastMlineIndex = -1, lastDirectionIndex = -1;
let lamda = () => {
if (currentMid && midSet.has(currentMid)) {
if (currentMid != firstMid) {
const mLineParts = updatedLines[lastMlineIndex].split(' ');
mLineParts[1] = '0';
updatedLines[lastMlineIndex] = mLineParts.join(' ');
}
updatedLines[lastDirectionIndex] = 'a=inactive';
lastMlineIndex = lastDirectionIndex = -1;
}
};
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line.startsWith('m=')) {
lamda();
currentMid = null;
lastMlineIndex = updatedLines.length;
updatedLines.push(line);
continue;
}
if (line.startsWith('a=mid:')) {
currentMid = line.substring(6).trim();
if (!firstMid) {
firstMid = currentMid;
}
}
if (currentMid && midSet.has(currentMid)) {
if (line.startsWith('a=ssrc') || line.startsWith('a=ssrc-group')) {
continue;
}
if (line.match(/^a=(sendrecv|sendonly|recvonly|inactive)$/)) {
lastDirectionIndex = updatedLines.length;
updatedLines.push(line);
continue;
}
updatedLines.push(line);
}
else {
updatedLines.push(line);
}
}
lamda();
return updatedLines.join('\r\n');
}
let pc = new RTCPeerConnection()
pc.addTransceiver('video')
pc.addTransceiver('audio')

pc.createOffer()
.then(offer => {
pc.setLocalDescription(offer)

return fetch(`/doOffer`, {
method: 'post',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
},
body: JSON.stringify(offer)
})
})
.then(res => res.json())
.then(res => pc.setRemoteDescription(res))
.catch(alert)

setTimeout(() => {
const transceivers = pc.getTransceivers();
if (transceivers.length > 1) {
const secondTransceiver = transceivers[1];

// Get the MID of the second transceiver
const mid = secondTransceiver.mid;

sdp = removeTransceiverByMid(pc.localDescription.sdp, [mid]);
console.log("updated sdp:", sdp);
let offer = { type: "offer", sdp: sdp };
pc.setLocalDescription(offer);
fetch(`/doUpdate`, {
method: 'post',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
},
body: JSON.stringify(offer)
}).then(res => res.json())
.then(res => pc.setRemoteDescription(res))
.catch(alert)
} else {
console.log("The peer connection does not have a second transceiver.");
}
}, 3000);
</script>

</html>
133 changes: 133 additions & 0 deletions examples/delete-transceiver/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

//go:build !js
// +build !js

// delete-transceiver demonstrates Pion WebRTC's ability to delete rejected transceivers.
package main

import (
"encoding/json"
"fmt"
"net/http"
"time"

"github.com/pion/ice/v4"
"github.com/pion/webrtc/v4"
)

var api *webrtc.API //nolint
var peerConnection *webrtc.PeerConnection

// Everything below is the Pion WebRTC API! Thanks for using it ❤️.
func doOffer(w http.ResponseWriter, r *http.Request) {
var err error
peerConnection, err = api.NewPeerConnection(webrtc.Configuration{})
if err != nil {
panic(err)
}

// 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("ICE Connection State has changed: %s\n", connectionState.String())
})

// Send the current time via a DataChannel to the remote peer every 3 seconds
peerConnection.OnDataChannel(func(d *webrtc.DataChannel) {
d.OnOpen(func() {
for range time.Tick(time.Second * 3) {
if err = d.SendText(time.Now().String()); err != nil {
panic(err)
}
}
})
})

var offer webrtc.SessionDescription
if err = json.NewDecoder(r.Body).Decode(&offer); err != nil {
panic(err)
}

if err = peerConnection.SetRemoteDescription(offer); err != nil {
panic(err)
}

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

answer, err := peerConnection.CreateAnswer(nil)
if err != nil {
panic(err)
} else if err = peerConnection.SetLocalDescription(answer); 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

response, err := json.Marshal(*peerConnection.LocalDescription())
if err != nil {
panic(err)
}

w.Header().Set("Content-Type", "application/json")
if _, err := w.Write(response); err != nil {
panic(err)
}
}

func doUpdate(w http.ResponseWriter, r *http.Request) {
var err error
var offer webrtc.SessionDescription
if err = json.NewDecoder(r.Body).Decode(&offer); err != nil {
panic(err)
}

if err = peerConnection.SetRemoteDescription(offer); err != nil {
panic(err)
}

answer, err := peerConnection.CreateAnswer(nil)
if err != nil {
panic(err)
} else if err = peerConnection.SetLocalDescription(answer); err != nil {
panic(err)
}
response, err := json.Marshal(answer)
if err != nil {
panic(err)
}

w.Header().Set("Content-Type", "application/json")
if _, err := w.Write(response); err != nil {
panic(err)
}
}

func main() {
// Create a SettingEngine, this allows non-standard WebRTC behavior
settingEngine := webrtc.SettingEngine{}

// Listen on UDP Port 8443, will be used for all WebRTC traffic
mux, err := ice.NewMultiUDPMuxFromPort(8443)
if err != nil {
panic(err)
}
fmt.Printf("Listening for WebRTC traffic at %d\n", 8443)
settingEngine.SetICEUDPMux(mux)

// Create a new API using our SettingEngine
api = webrtc.NewAPI(webrtc.WithSettingEngine(settingEngine))

http.Handle("/", http.FileServer(http.Dir(".")))
http.HandleFunc("/doOffer", doOffer)
http.HandleFunc("/doUpdate", doUpdate)

fmt.Println("Open http://localhost:8080 to access this demo")
// nolint: gosec
panic(http.ListenAndServe(":8080", nil))
}
Loading

0 comments on commit 4e29ef2

Please sign in to comment.