-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathtrack_remote.go
232 lines (196 loc) · 5.53 KB
/
track_remote.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT
//go:build !js
// +build !js
package webrtc
import (
"sync"
"time"
"github.com/pion/interceptor"
"github.com/pion/rtp"
)
// TrackRemote represents a single inbound source of media
type TrackRemote struct {
mu sync.RWMutex
id string
streamID string
payloadType PayloadType
kind RTPCodecType
ssrc SSRC
rtxSsrc SSRC
codec RTPCodecParameters
params RTPParameters
rid string
receiver *RTPReceiver
peeked []byte
peekedAttributes interceptor.Attributes
}
func newTrackRemote(kind RTPCodecType, ssrc, rtxSsrc SSRC, rid string, receiver *RTPReceiver) *TrackRemote {
return &TrackRemote{
kind: kind,
ssrc: ssrc,
rtxSsrc: rtxSsrc,
rid: rid,
receiver: receiver,
}
}
// ID is the unique identifier for this Track. This should be unique for the
// stream, but doesn't have to globally unique. A common example would be 'audio' or 'video'
// and StreamID would be 'desktop' or 'webcam'
func (t *TrackRemote) ID() string {
t.mu.RLock()
defer t.mu.RUnlock()
return t.id
}
// RID gets the RTP Stream ID of this Track
// With Simulcast you will have multiple tracks with the same ID, but different RID values.
// In many cases a TrackRemote will not have an RID, so it is important to assert it is non-zero
func (t *TrackRemote) RID() string {
t.mu.RLock()
defer t.mu.RUnlock()
return t.rid
}
// PayloadType gets the PayloadType of the track
func (t *TrackRemote) PayloadType() PayloadType {
t.mu.RLock()
defer t.mu.RUnlock()
return t.payloadType
}
// Kind gets the Kind of the track
func (t *TrackRemote) Kind() RTPCodecType {
t.mu.RLock()
defer t.mu.RUnlock()
return t.kind
}
// StreamID is the group this track belongs too. This must be unique
func (t *TrackRemote) StreamID() string {
t.mu.RLock()
defer t.mu.RUnlock()
return t.streamID
}
// SSRC gets the SSRC of the track
func (t *TrackRemote) SSRC() SSRC {
t.mu.RLock()
defer t.mu.RUnlock()
return t.ssrc
}
// Msid gets the Msid of the track
func (t *TrackRemote) Msid() string {
return t.StreamID() + " " + t.ID()
}
// Codec gets the Codec of the track
func (t *TrackRemote) Codec() RTPCodecParameters {
t.mu.RLock()
defer t.mu.RUnlock()
return t.codec
}
// Read reads data from the track.
func (t *TrackRemote) Read(b []byte) (n int, attributes interceptor.Attributes, err error) {
t.mu.RLock()
r := t.receiver
peeked := t.peeked != nil
t.mu.RUnlock()
if peeked {
t.mu.Lock()
data := t.peeked
attributes = t.peekedAttributes
t.peeked = nil
t.peekedAttributes = nil
t.mu.Unlock()
// someone else may have stolen our packet when we
// released the lock. Deal with it.
if data != nil {
n = copy(b, data)
err = t.checkAndUpdateTrack(b)
return
}
}
// If there's a separate RTX track and an RTX packet is available, return that
if rtxPacketReceived := r.readRTX(t); rtxPacketReceived != nil {
n = copy(b, rtxPacketReceived.pkt)
attributes = rtxPacketReceived.attributes
rtxPacketReceived.release()
err = nil
} else {
// If there's no separate RTX track (or there's a separate RTX track but no RTX packet waiting), wait for and return
// a packet from the main track
n, attributes, err = r.readRTP(b, t)
if err != nil {
return
}
err = t.checkAndUpdateTrack(b)
}
return n, attributes, err
}
// checkAndUpdateTrack checks payloadType for every incoming packet
// once a different payloadType is detected the track will be updated
func (t *TrackRemote) checkAndUpdateTrack(b []byte) error {
if len(b) < 2 {
return errRTPTooShort
}
payloadType := PayloadType(b[1] & rtpPayloadTypeBitmask)
if payloadType != t.PayloadType() || len(t.params.Codecs) == 0 {
t.mu.Lock()
defer t.mu.Unlock()
params, err := t.receiver.api.mediaEngine.getRTPParametersByPayloadType(payloadType)
if err != nil {
return err
}
t.kind = t.receiver.kind
t.payloadType = payloadType
t.codec = params.Codecs[0]
t.params = params
}
return nil
}
// ReadRTP is a convenience method that wraps Read and unmarshals for you.
func (t *TrackRemote) ReadRTP() (*rtp.Packet, interceptor.Attributes, error) {
b := make([]byte, t.receiver.api.settingEngine.getReceiveMTU())
i, attributes, err := t.Read(b)
if err != nil {
return nil, nil, err
}
r := &rtp.Packet{}
if err := r.Unmarshal(b[:i]); err != nil {
return nil, nil, err
}
return r, attributes, nil
}
// peek is like Read, but it doesn't discard the packet read
func (t *TrackRemote) peek(b []byte) (n int, a interceptor.Attributes, err error) {
n, a, err = t.Read(b)
if err != nil {
return
}
t.mu.Lock()
// this might overwrite data if somebody peeked between the Read
// and us getting the lock. Oh well, we'll just drop a packet in
// that case.
data := make([]byte, n)
n = copy(data, b[:n])
t.peeked = data
t.peekedAttributes = a
t.mu.Unlock()
return
}
// SetReadDeadline sets the max amount of time the RTP stream will block before returning. 0 is forever.
func (t *TrackRemote) SetReadDeadline(deadline time.Time) error {
return t.receiver.setRTPReadDeadline(deadline, t)
}
// RtxSSRC returns the RTX SSRC for a track, or 0 if track does not have a separate RTX stream
func (t *TrackRemote) RtxSSRC() SSRC {
t.mu.RLock()
defer t.mu.RUnlock()
return t.rtxSsrc
}
// HasRTX returns true if the track has a separate RTX stream
func (t *TrackRemote) HasRTX() bool {
t.mu.RLock()
defer t.mu.RUnlock()
return t.rtxSsrc != 0
}
func (t *TrackRemote) setRtxSSRC(ssrc SSRC) {
t.mu.Lock()
defer t.mu.Unlock()
t.rtxSsrc = ssrc
}