Skip to content

Commit ee016ad

Browse files
committed
chore: move to set answer
1 parent 0ea417e commit ee016ad

File tree

4 files changed

+285
-28
lines changed

4 files changed

+285
-28
lines changed

examples/delete-transceiver/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# delete-transceiver
2+
delete-transceiver demonstrates Pion WebRTC's ability to delete rejected transceivers.
3+
4+
## Instructions
5+
6+
### Download delete-transceiver
7+
This example requires you to clone the repo since it is serving static HTML.
8+
9+
```
10+
git clone https://github.com/pion/webrtc.git
11+
cd webrtc/examples/delete-transceiver
12+
```
13+
14+
### Run delete-transceiver
15+
Execute `go run *.go`
16+
17+
### Open the Web UI
18+
Open [http://localhost:8080](http://localhost:8080). This remote peerconnection will use single port 8443.
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<html>
2+
<!--
3+
SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
4+
SPDX-License-Identifier: MIT
5+
-->
6+
7+
<head>
8+
<title>ice-single-port</title>
9+
</head>
10+
11+
<body>
12+
<h3> ICE Selected Pairs </h3>
13+
<div id="iceSelectedPairs"></div> <br />
14+
</body>
15+
16+
<script>
17+
let removeTransceiverByMid = (sdp, mids) => {
18+
const lines = sdp.split('\r\n');
19+
const midSet = new Set(mids);
20+
let currentMid = null;
21+
let firstMid = null;
22+
let updatedLines = [];
23+
let lastMlineIndex = -1, lastDirectionIndex = -1;
24+
let lamda = () => {
25+
if (currentMid && midSet.has(currentMid)) {
26+
if (currentMid != firstMid) {
27+
const mLineParts = updatedLines[lastMlineIndex].split(' ');
28+
mLineParts[1] = '0';
29+
updatedLines[lastMlineIndex] = mLineParts.join(' ');
30+
}
31+
updatedLines[lastDirectionIndex] = 'a=inactive';
32+
lastMlineIndex = lastDirectionIndex = -1;
33+
}
34+
};
35+
for (let i = 0; i < lines.length; i++) {
36+
const line = lines[i];
37+
if (line.startsWith('m=')) {
38+
lamda();
39+
currentMid = null;
40+
lastMlineIndex = updatedLines.length;
41+
updatedLines.push(line);
42+
continue;
43+
}
44+
if (line.startsWith('a=mid:')) {
45+
currentMid = line.substring(6).trim();
46+
if (!firstMid) {
47+
firstMid = currentMid;
48+
}
49+
}
50+
if (currentMid && midSet.has(currentMid)) {
51+
if (line.startsWith('a=ssrc') || line.startsWith('a=ssrc-group')) {
52+
continue;
53+
}
54+
if (line.match(/^a=(sendrecv|sendonly|recvonly|inactive)$/)) {
55+
lastDirectionIndex = updatedLines.length;
56+
updatedLines.push(line);
57+
continue;
58+
}
59+
updatedLines.push(line);
60+
}
61+
else {
62+
updatedLines.push(line);
63+
}
64+
}
65+
lamda();
66+
return updatedLines.join('\r\n');
67+
}
68+
let pc = new RTCPeerConnection()
69+
pc.addTransceiver('video')
70+
pc.addTransceiver('audio')
71+
72+
pc.createOffer()
73+
.then(offer => {
74+
pc.setLocalDescription(offer)
75+
76+
return fetch(`/doOffer`, {
77+
method: 'post',
78+
headers: {
79+
'Accept': 'application/json, text/plain, */*',
80+
'Content-Type': 'application/json'
81+
},
82+
body: JSON.stringify(offer)
83+
})
84+
})
85+
.then(res => res.json())
86+
.then(res => pc.setRemoteDescription(res))
87+
.catch(alert)
88+
89+
setTimeout(() => {
90+
const transceivers = pc.getTransceivers();
91+
if (transceivers.length > 1) {
92+
const secondTransceiver = transceivers[1];
93+
94+
// Get the MID of the second transceiver
95+
const mid = secondTransceiver.mid;
96+
97+
sdp = removeTransceiverByMid(pc.localDescription.sdp, [mid]);
98+
console.log("updated sdp:", sdp);
99+
let offer = { type: "offer", sdp: sdp };
100+
pc.setLocalDescription(offer);
101+
fetch(`/doUpdate`, {
102+
method: 'post',
103+
headers: {
104+
'Accept': 'application/json, text/plain, */*',
105+
'Content-Type': 'application/json'
106+
},
107+
body: JSON.stringify(offer)
108+
}).then(res => res.json())
109+
.then(res => pc.setRemoteDescription(res))
110+
.catch(alert)
111+
} else {
112+
console.log("The peer connection does not have a second transceiver.");
113+
}
114+
}, 3000);
115+
</script>
116+
117+
</html>

examples/delete-transceiver/main.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
2+
// SPDX-License-Identifier: MIT
3+
4+
//go:build !js
5+
// +build !js
6+
7+
// delete-transceiver demonstrates Pion WebRTC's ability to delete rejected transceivers.
8+
package main
9+
10+
import (
11+
"encoding/json"
12+
"fmt"
13+
"net/http"
14+
"time"
15+
16+
"github.com/pion/ice/v4"
17+
"github.com/pion/webrtc/v4"
18+
)
19+
20+
var api *webrtc.API //nolint
21+
var peerConnection *webrtc.PeerConnection
22+
23+
// Everything below is the Pion WebRTC API! Thanks for using it ❤️.
24+
func doOffer(w http.ResponseWriter, r *http.Request) {
25+
var err error
26+
peerConnection, err = api.NewPeerConnection(webrtc.Configuration{})
27+
if err != nil {
28+
panic(err)
29+
}
30+
31+
// Set the handler for ICE connection state
32+
// This will notify you when the peer has connected/disconnected
33+
peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) {
34+
fmt.Printf("ICE Connection State has changed: %s\n", connectionState.String())
35+
})
36+
37+
// Send the current time via a DataChannel to the remote peer every 3 seconds
38+
peerConnection.OnDataChannel(func(d *webrtc.DataChannel) {
39+
d.OnOpen(func() {
40+
for range time.Tick(time.Second * 3) {
41+
if err = d.SendText(time.Now().String()); err != nil {
42+
panic(err)
43+
}
44+
}
45+
})
46+
})
47+
48+
var offer webrtc.SessionDescription
49+
if err = json.NewDecoder(r.Body).Decode(&offer); err != nil {
50+
panic(err)
51+
}
52+
53+
if err = peerConnection.SetRemoteDescription(offer); err != nil {
54+
panic(err)
55+
}
56+
57+
// Create channel that is blocked until ICE Gathering is complete
58+
gatherComplete := webrtc.GatheringCompletePromise(peerConnection)
59+
60+
answer, err := peerConnection.CreateAnswer(nil)
61+
if err != nil {
62+
panic(err)
63+
} else if err = peerConnection.SetLocalDescription(answer); err != nil {
64+
panic(err)
65+
}
66+
67+
// Block until ICE Gathering is complete, disabling trickle ICE
68+
// we do this because we only can exchange one signaling message
69+
// in a production application you should exchange ICE Candidates via OnICECandidate
70+
<-gatherComplete
71+
72+
response, err := json.Marshal(*peerConnection.LocalDescription())
73+
if err != nil {
74+
panic(err)
75+
}
76+
77+
w.Header().Set("Content-Type", "application/json")
78+
if _, err := w.Write(response); err != nil {
79+
panic(err)
80+
}
81+
}
82+
83+
func doUpdate(w http.ResponseWriter, r *http.Request) {
84+
var err error
85+
var offer webrtc.SessionDescription
86+
if err = json.NewDecoder(r.Body).Decode(&offer); err != nil {
87+
panic(err)
88+
}
89+
90+
if err = peerConnection.SetRemoteDescription(offer); err != nil {
91+
panic(err)
92+
}
93+
94+
answer, err := peerConnection.CreateAnswer(nil)
95+
if err != nil {
96+
panic(err)
97+
} else if err = peerConnection.SetLocalDescription(answer); err != nil {
98+
panic(err)
99+
}
100+
response, err := json.Marshal(answer)
101+
if err != nil {
102+
panic(err)
103+
}
104+
105+
w.Header().Set("Content-Type", "application/json")
106+
if _, err := w.Write(response); err != nil {
107+
panic(err)
108+
}
109+
}
110+
111+
func main() {
112+
// Create a SettingEngine, this allows non-standard WebRTC behavior
113+
settingEngine := webrtc.SettingEngine{}
114+
115+
// Listen on UDP Port 8443, will be used for all WebRTC traffic
116+
mux, err := ice.NewMultiUDPMuxFromPort(8443)
117+
if err != nil {
118+
panic(err)
119+
}
120+
fmt.Printf("Listening for WebRTC traffic at %d\n", 8443)
121+
settingEngine.SetICEUDPMux(mux)
122+
123+
// Create a new API using our SettingEngine
124+
api = webrtc.NewAPI(webrtc.WithSettingEngine(settingEngine))
125+
126+
http.Handle("/", http.FileServer(http.Dir(".")))
127+
http.HandleFunc("/doOffer", doOffer)
128+
http.HandleFunc("/doUpdate", doUpdate)
129+
130+
fmt.Println("Open http://localhost:8080 to access this demo")
131+
// nolint: gosec
132+
panic(http.ListenAndServe(":8080", nil))
133+
}

peerconnection.go

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -847,29 +847,6 @@ func (pc *PeerConnection) CreateAnswer(*AnswerOptions) (SessionDescription, erro
847847
if err != nil {
848848
return SessionDescription{}, err
849849
}
850-
// remove inactive media sections
851-
var inactiveMidValue []string
852-
for _, media := range d.MediaDescriptions {
853-
if media.MediaName.Media == mediaSectionApplication {
854-
continue
855-
}
856-
if media.MediaName.Port.Value == 0 {
857-
var midValue string
858-
var inactive bool
859-
for _, attr := range media.Attributes {
860-
if attr.Key == sdp.AttrKeyInactive {
861-
inactive = true
862-
}
863-
if attr.Key == sdp.AttrKeyMID {
864-
midValue = attr.Value
865-
}
866-
}
867-
if inactive {
868-
inactiveMidValue = append(inactiveMidValue, midValue)
869-
}
870-
}
871-
}
872-
pc.removeRTPTransceiver(inactiveMidValue)
873850
desc := SessionDescription{
874851
Type: SDPTypeAnswer,
875852
SDP: string(sdpBytes),
@@ -1029,14 +1006,18 @@ func (pc *PeerConnection) SetLocalDescription(desc SessionDescription) error {
10291006
weAnswer := desc.Type == SDPTypeAnswer
10301007
remoteDesc := pc.RemoteDescription()
10311008
if weAnswer && remoteDesc != nil {
1032-
_ = setRTPTransceiverCurrentDirection(&desc, currentTransceivers, false)
1009+
rejected := []string{}
1010+
_ = setRTPTransceiverCurrentDirection(&desc, currentTransceivers, false, &rejected)
10331011
if err := pc.startRTPSenders(currentTransceivers); err != nil {
10341012
return err
10351013
}
10361014
pc.configureRTPReceivers(haveLocalDescription, remoteDesc, currentTransceivers)
10371015
pc.ops.Enqueue(func() {
10381016
pc.startRTP(haveLocalDescription, remoteDesc, currentTransceivers)
10391017
})
1018+
pc.mu.Lock()
1019+
pc.removeRTPTransceiver(rejected)
1020+
pc.mu.Unlock()
10401021
}
10411022

10421023
mediaSection, ok := selectCandidateMediaSection(desc.parsed)
@@ -1206,14 +1187,18 @@ func (pc *PeerConnection) SetRemoteDescription(desc SessionDescription) error {
12061187

12071188
if isRenegotiation {
12081189
if weOffer {
1209-
_ = setRTPTransceiverCurrentDirection(&desc, currentTransceivers, true)
1190+
rejected := []string{}
1191+
_ = setRTPTransceiverCurrentDirection(&desc, currentTransceivers, true, &rejected)
12101192
if err = pc.startRTPSenders(currentTransceivers); err != nil {
12111193
return err
12121194
}
12131195
pc.configureRTPReceivers(true, &desc, currentTransceivers)
12141196
pc.ops.Enqueue(func() {
12151197
pc.startRTP(true, &desc, currentTransceivers)
12161198
})
1199+
pc.mu.Lock()
1200+
pc.removeRTPTransceiver(rejected)
1201+
pc.mu.Unlock()
12171202
}
12181203
return nil
12191204
}
@@ -1236,7 +1221,7 @@ func (pc *PeerConnection) SetRemoteDescription(desc SessionDescription) error {
12361221
// Start the networking in a new routine since it will block until
12371222
// the connection is actually established.
12381223
if weOffer {
1239-
_ = setRTPTransceiverCurrentDirection(&desc, currentTransceivers, true)
1224+
_ = setRTPTransceiverCurrentDirection(&desc, currentTransceivers, true, nil)
12401225
if err := pc.startRTPSenders(currentTransceivers); err != nil {
12411226
return err
12421227
}
@@ -1299,7 +1284,8 @@ func (pc *PeerConnection) startReceiver(incoming trackDetails, receiver *RTPRece
12991284
}
13001285
}
13011286

1302-
func setRTPTransceiverCurrentDirection(answer *SessionDescription, currentTransceivers []*RTPTransceiver, weOffer bool) error {
1287+
// rejected is only meaningful when SessionDescription is answer
1288+
func setRTPTransceiverCurrentDirection(answer *SessionDescription, currentTransceivers []*RTPTransceiver, weOffer bool, rejected *[]string) error {
13031289
currentTransceivers = append([]*RTPTransceiver{}, currentTransceivers...)
13041290
for _, media := range answer.parsed.MediaDescriptions {
13051291
midValue := getMidValue(media)
@@ -1340,7 +1326,10 @@ func setRTPTransceiverCurrentDirection(answer *SessionDescription, currentTransc
13401326
if !weOffer && direction == RTPTransceiverDirectionSendonly && t.Sender() == nil {
13411327
direction = RTPTransceiverDirectionInactive
13421328
}
1343-
1329+
// reject transceiver if it is inactive
1330+
if rejected != nil && media.MediaName.Port.Value == 0 && direction == RTPTransceiverDirectionInactive {
1331+
*rejected = append(*rejected, midValue)
1332+
}
13441333
t.setCurrentDirection(direction)
13451334
}
13461335
return nil

0 commit comments

Comments
 (0)