├── .gitignore
├── README.md
├── ctrlpacket_test.go
├── datapacket_test.go
├── iana
└── iana_const.go
├── packets.go
├── payload.go
├── receive_test.go
├── rtpmain
└── rtpmain.go
├── session.go
├── sessionlocal.go
├── stream.go
├── transport.go
└── transportUDP.go
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | *.kdev4
3 | .kdev*
4 | _go_.*
5 | bin/
6 | /pkg/
7 | build/
8 | UseDoxygen/
9 | _obj/
10 | _test/
11 | [68].out
12 | _*.*
13 | rtpmain/rtpmain
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | GoRTP
2 | =====
3 | [](https://drone.io/github.com/danielvargas/gortp/latest)
4 |
5 | ## RTP/RTCP stack for Go
6 |
7 | This Go implementation of the RTP/RTCP protocol uses a set of structures to
8 | provide a high degree of flexibility and to adhere to the RFC 3550 notation of
9 | RTP sessions (refer to RFC 3550 chapter 3, RTP session) and its associated
10 | streams.
11 |
12 | Figure 1 depicts the high-level layout of the data structure. This
13 | documentation describes the parts in some more detail.
14 |
15 | ```
16 | +---------------------+ transport modules
17 | | Session | +-------+ +-------+ +-------+
18 | | | use | | | | | |
19 | | - top-level module +-<---+ +--+ +--+ | receiver
20 | | for transports | +-------+ +-------+ +-------+
21 | | - start/stop of | +-------+ +-------+
22 | | transports | use | | | |
23 | | - RTCP management +------------->--+ +--+ | sender
24 | | - interface to | +-------+ +-------+
25 | | applications |
26 | | - maintains streams |
27 | | |
28 | | |
29 | | | creates and manages
30 | | +------------------------+
31 | | | |
32 | | +--------+ |
33 | | | | |
34 | | | +---+---+ +---+---+ stream data:
35 | +---------------------+ | | | | - SSRC
36 | +-------+ | +-------+ | - sequence no
37 | | |-+ | |-+ - timestamp
38 | | | | | - statistics
39 | +-------+ +-------+
40 | Streams
41 | RTP input RTP output
42 | ```
43 | Figure 1: Data structure in Go RTP implementation
44 |
45 |
46 | Figure 1 does not show the RTP / RTCP packet module that implements support
47 | and management functions to handle RTP and RTCP packet data structures.
48 |
49 | ### How to build
50 |
51 | The _rtp_ sources use the GOPATH directory structure. To build, test, and run
52 | the software just add the main goRTP directory to GOPATH. For further
53 | information about this structure run `go help gopath` and follow the
54 | instructions.
55 |
56 | To build and install the package just run `go get github.com/danielvargas/gortp`.
57 | To excecute the tests just run `go test github.com/danielvargas/gortp`. The tests
58 | check if the code works with the current Go installation on your system. It should
59 | PASS.
60 |
61 | A demo program is available and is called _rtpmain_. Use `go install github.com/danielvargas/gortp/rtpmain` to build it.
62 | The command `go install net/rtpmain` installs it in
63 | the `bin` directory of the main directory.
64 |
65 | ### How to use
66 |
67 | This is a pure RTP / RTCP stack and it does not contain any media processing,
68 | for example generating or packing the payload for audio or video codecs.
69 |
70 | The directory `src/net/rtpmain` contains an example Go program that performs a
71 | RTP some tests on _localhost_ that shows how to setup a RTP session, an
72 | output stream and how to send and receive RTP data and control events. Parts
73 | of this program are used in the package documentation.
74 |
75 | The software should be ready to use for many RTP applications. Standard
76 | point-to-point RTP applications should not pose any problems. RTP multi-cast
77 | using IP multi-cast addresses is not supported. If somebody really requires IP
78 | multi-cast it could be added at the transport level.
79 |
80 | RTCP reporting works without support from application. The stack reports RTCP
81 | packets and if the stack created new input streams and an application may
82 | connect to the control channel to receive the RTCP events. Just have a look
83 | into the example program. The RTCP fields in the stream structures are
84 | accessible - however, to use them you may need to have some know-how of the
85 | RTCP definitions and reporting.
86 |
87 | ### RTP data packets
88 |
89 | The Go RTP stack implementation supports the necessary methods to access and
90 | modify the contents and header fields of a RTP data packet. Most often
91 | application only deal with the payload and timestamp of RTP data
92 | packets. The RTP stack maintains the other fields and keeps track of them.
93 |
94 | The packet module implements a leaky buffer mechanism to reduce the number of
95 | dynamically allocated packets. While not an absolute requirement it is advised
96 | to use FreePacket() to return the packet to the packet queue because it
97 | reduces the number of dynamic memory allocation and garbage collection
98 | overhead. This might be an davantage to long running audio/video applications
99 | which send a lot of data on long lasting RTP sessions.
100 |
101 |
102 | ### Transport Modules
103 |
104 | The Go RTP implementation uses stackable transport modules. The lowest layer
105 | (nearest to the real network) implements the UDP, TCP or other network
106 | transports. Each transport module must implement the interfaces TransportRecv
107 | and/or TransportWrite if it acts a is a receiver oder sender module. This
108 | separtion of interfaces enables an asymmetric transport stack as shown in
109 | figure 1.
110 |
111 | Usually upper layer transport modules filter incoming data or create some
112 | specific output data, for example a ICE transport module would handle all ICE
113 | relevant data and would not pass ICE data packets to the Session module
114 | because the Session module expects RTP (SRTP in a later step) data only. The
115 | Session module would discard all non-RTP or non-RTCP packets.
116 |
117 | It is the client application's responsibility to build a transport stack
118 | according to its requirements. The application uses the top level transport
119 | module to initialize the RTP session. Usually an application uses only one
120 | transport module. The following code snippet shows how this works:
121 | ```go
122 | var localPort = 5220
123 | var local, _ = net.ResolveIPAddr("ip", "127.0.0.1")
124 |
125 | var remotePort = 5222
126 | var remote, _ = net.ResolveIPAddr("ip", "127.0.0.1")
127 |
128 | ...
129 |
130 | // Create a UDP transport with "local" address and use this for a "local" RTP session
131 | // The RTP session uses the transport to receive and send RTP packets to the remote peer.
132 | tpLocal, _ := rtp.NewTransportUDP(local, localPort)
133 |
134 | // TransportUDP implements TransportWrite and TransportRecv interfaces thus
135 | // use it as write and read modules for the Session.
136 | rsLocal = rtp.NewSession(tpLocal, tpLocal)
137 |
138 | ...
139 | ```
140 | You may have noticed that the code does not use a standard Go UDP address but
141 | separates the IP address and the port number. This separation makes it easier
142 | to implement several network transport, such as UDP or TCP. The network
143 | transport module creates its own address format. RTP requires two port
144 | numbers, one for the data and the other one for the control connection. The
145 | RFC 3550 specifies that ports with even numbers provide the data connection
146 | (RTP), and the next following port number provides the control connection
147 | (RTCP). Therefore the transport module requires only the port number of the
148 | data connection.
149 |
150 | An application may stack several transport modules. To do so an application
151 | first creates the required transport modules. Then it connects them in the
152 | following way:
153 | ```go
154 | transportNet, _ := rtp.NewTransportUDP(local, localPort)
155 | transportAboveNet, _ := rtp.NewTransportWhatEver(....)
156 |
157 | // Register AboveNet as upper layer transport
158 | transportNet.SetCallUpper(transportAboveNet)
159 |
160 | // Register transportNet as lower layer
161 | transportAboveNet.SetToLower(transportNet)
162 | ```
163 | The application then uses transportAboveNet to initialize the Session. If
164 | transportAboveNet only filters or processes data in one direction then only
165 | the relevant registration is required. For example if transportAboveNet
166 | processes incoming data (receiving) then the application would perform the
167 | first registration only and initializes the Session as follows:
168 | ```go
169 | session := rtp.NewSession(transportNet, transportAboveNet)
170 | ```
171 |
172 | ### Session and Streams
173 |
174 | After an RTP application created the transports it can create a RTP
175 | session. The RTP session requires a write and a read transport module to
176 | manage the data traffic. The NewSession method just allocates and initializes
177 | all necessary data structure but it does not start any data transfers. The
178 | next steps are:
179 |
180 | - allocate and initialize output stream(s)
181 |
182 | - add the address(es) of the remote application(s) (peers) to the Session
183 |
184 | - set up and connect the application's data processing to the Session's data
185 | channel
186 |
187 | - optionally set up and connect the application's control processing to the
188 | Session's control event channel
189 |
190 | After the application completed these steps it can start the Session. The next
191 | paragraphs show each step in some more detail.
192 |
193 |
194 | ### Allocate and initialize streams
195 |
196 | The Session provides methods to creates an access output and input streams. An
197 | application must create and initialize output streams, the RTP stack creates
198 | input streams on-the-fly if it detects RTP or RTCP traffic for yet unknown
199 | streams. Creation of a new ouput stream is simple. The application just calls
200 | ```go
201 | strLocalIdx := rsLocal.NewSsrcStreamOut(&rtp.Address{local.IP, localPort, localPort + 1}, 0, 0)
202 | ```
203 | to create a new ouput stream. The RTP stack requires the address to detect
204 | collisions and loops during RTP data transfers. The other two parameters are
205 | usually zero, only if the application want's to control the RTP SSRC and
206 | starting sequence numbers it would set these parameters. To use the output
207 | stream the application must set the payload type for this stream. Applications
208 | use signaling protocol such as SIP or XMPP to negotiate the payload types. The
209 | Go RTP implementation provides the standard set of predefined RTP payloads -
210 | refer to the payload.go documentation. The example uses payload type 0,
211 | standard PCM uLaw (PCMU):
212 | ```go
213 | rsLocal.SsrcStreamOutForIndex(strLocalIdx).SetPayloadType(0)
214 | ```
215 | An application shall always use the stream's index as returned during stream
216 | creation to get the current stream and to call stream methods. The stream's
217 | index does not change duringe the lifetime of a Session while the stream's
218 | internal data structure and thus it's pointer may change. Such a change may
219 | happen if the RTP stack detects a SSRC collision or loop and must reallocate
220 | streams to solve collisions or loops.
221 |
222 | Now the output stream is ready.
223 |
224 |
225 | ### Add addresses of remote application(s)
226 |
227 | A Session can hold several remote addresses and it sends RTP and RTCP packets
228 | to all known remote applications. To add a remote address the application may
229 | perform:
230 | ```go
231 | rsLocal.AddRemote(&rtp.Address{remote.IP, remotePort, remotePort + 1})
232 | ```
233 |
234 | Connect to the RTP receiver
235 |
236 | Before starting the RTP Session the application shall connect its main input
237 | processing function the the Session's data receive channel. The next code
238 | snippet show a very simple method that perfoms just this.
239 | ```go
240 | func receivePacketLocal() {
241 | // Create and store the data receive channel.
242 | dataReceiver := rsLocal.CreateDataReceiveChan()
243 | var cnt int
244 |
245 | for {
246 | select {
247 | case rp := <-dataReceiver:
248 | if (cnt % 50) == 0 {
249 | println("Remote receiver got:", cnt, "packets")
250 | }
251 | cnt++
252 | rp.FreePacket()
253 | case <-stopLocalRecv:
254 | return
255 | }
256 | }
257 | }
258 | ```
259 | This simple function just counts packets and outputs a message. The second
260 | select case is a local channel to stop the loop. The main RTP application
261 | would do something like
262 | ```go
263 | go receivePacketLocal()
264 | ```
265 | to fire up the receiver function.
266 |
267 |
268 | ### Start the Session and perform RTP processing
269 |
270 | After all the preparations it's now time to start the RTP Session. The
271 | application just calls
272 | ```go
273 | rsLocal.StartSession()
274 | ```
275 | and the Session is up and running. This method starts the transports receiver
276 | methods and also starts the interal RTCP service. The RTCP service sends some
277 | RTCP information to all known remote peers to announce the application and its
278 | output streams.
279 |
280 | Once the applications started the Session it now may gather some data, for
281 | example voice or video data, get a RTP data packet, fill in the gathered data
282 | and send it to the remote peers. Thus an application would perform the
283 | following steps
284 | ```go
285 | payloadByteSlice := gatherPayload(....)
286 | rp := rsLocal.NewDataPacket(rtpTimestamp)
287 | rp.SetPayload(payloadByteSlice)
288 | rsLocal.WriteData(rp)
289 |
290 | rp.FreePacket()
291 | ```
292 | The NewDataPacket method returns an initialized RTP data packet. The packet
293 | contains the output stream's SSRC, the correct sequence number, and the
294 | updated timestamp. The application must compute and provide the timestamp as
295 | defined in RFC 3550, chapter 5.1. The RTP timestamp depends on the payload
296 | attributes, such as sampling frequency, and on the number of data packets per
297 | second. After the application wrote the RTP data packet it shall free the
298 | packet as it helps to reduce the overhead of dynamic memory allocation.
299 |
300 | The example uses PCMU and this payload has a sampling frequency of 8000Hz thus
301 | its produces 8000 sampling values per second or 8 values per millisecond. Very
302 | often an audio application sends a data packet every 20ms (50 packets per
303 | second). Such a data packet contains 160 sampling values and the application
304 | must increase the RTP timestamp by 160 for each packet. If an applications
305 | uses other payload types it has to compute and maintain the correct RTP
306 | timestamps and use them when it creates a new RTP data packet.
307 |
308 | ### Some noteable features
309 |
310 | * The current release V1.0.0 computes the RTCP intervals based on the length of
311 | RTCP compound packets and the bandwidth allocated to RTCP. The application may
312 | set the bandwidth, if no set GoRTP makes somes educated guesses.
313 |
314 | * The application may set the maximum number of output and input streams even
315 | while the RTP session is active. If the application des not set GoRTP sets
316 | the values to 5 and 30 respectively.
317 |
318 | * GoRTP produces SR and RR reports and the associated SDES for active streams
319 | only, thus it implements the activity check as defined in chapter 6.4
320 |
321 | * An appplication may use GoRTP in _simple RTP_ mode. In this mode only RTP
322 | data packets are exchanged between the peers. No RTCP service is active, no
323 | statistic counters, and GoRTP discards RTCP packets it receives.
324 |
325 | * GoRTP limits the number of RR to 31 per RTCP report interval. GoRTP does not
326 | add an additional RR packet in case it detects more than 31 active input
327 | streams. This restriction is mainly due to MTU contraints of modern Ethernet
328 | or DSL based networks. The MTU is usually less than 1500 bytes, GoRTP limits
329 | the RTP/RTCP packet size to 1200 bytes. The length of an RR is 24 bytes,
330 | thus 31 RR already require 774 bytes. Adding some data for SR and SDES fills
331 | the rest.
332 |
333 | * An application may register to a control event channel and GoRTP delivers a
334 | nice set of control and error events. The events cover:
335 | - Creation of a new input stream when receiving an RTP or RTCP packet and
336 | the SSRC was not known
337 | - RTCP events to inform about RTCP packets and received reports
338 | - Error events
339 |
340 | * Currently GoRTP supports only SR, RR, SDES, and BYE RTCP packets. Inside
341 | SDES GoRTP does not support SDES Private and SDES H.323 items.
342 |
343 |
344 | ### Further documentation
345 |
346 | Beside the documentation of the global methods, functions, variables and constants I
347 | also documented all internally used stuff. Thus if you need more information how it
348 | works or if you would like to enhance GoRTP please have a look in the sources.
349 |
350 | ## License
351 | ```
352 | Copyright (C) 2011 Werner Dittmann
353 |
354 | This program is free software: you can redistribute it and/or modify
355 | it under the terms of the GNU General Public License as published by
356 | the Free Software Foundation, either version 3 of the License, or
357 | (at your option) any later version.
358 |
359 | This program is distributed in the hope that it will be useful,
360 | but WITHOUT ANY WARRANTY; without even the implied warranty of
361 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
362 | GNU General Public License for more details.
363 |
364 | You should have received a copy of the GNU General Public License
365 | along with this program. If not, see .
366 |
367 | Authors: Werner Dittmann
368 | ```
369 |
--------------------------------------------------------------------------------
/ctrlpacket_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2011 Werner Dittmann
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU General Public License as published by
5 | // the Free Software Foundation, either version 3 of the License, or
6 | // (at your option) any later version.
7 | //
8 | // This program is distributed in the hope that it will be useful,
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with this program. If not, see .
15 | //
16 | // Authors: Werner Dittmann
17 | //
18 |
19 | package rtp
20 |
21 | import (
22 | "fmt"
23 | // "net"
24 | "testing"
25 | )
26 |
27 | // V=2, P=0, chunks=2; PT=SDES; length=5 32bit words (24 bytes)
28 | var sdes_1 = []byte{0x81, 202, 0x00, 0x05,
29 | 0x01, 0x02, 0x03, 0x04, // SSRC 0x01020304
30 | 0x01, 0x01, 0x02, // CNAME, len=1, content=2
31 | 0x00, // END (chunk length: 8)
32 | 0x05, 0x06, 0x07, 0x08, // SSRC 0x05060707
33 | 0x01, 0x03, 0x05, 0x06, 0x07, // CNAME, len=3, content=5,6,7
34 | 0x00, 0x00, 0x00} // END plus 2 padding (chunk length: 12)
35 | // V=2, P=0, chunks=2; PT=SDES; length=8 32bit words (36 bytes)
36 | var sdes_2 = []byte{0x81, 202, 0x00, 0x08,
37 | // first chunk, two items: CNAME, NAME, END)
38 | 0x01, 0x02, 0x03, 0x04, // SSRC 0x01020304
39 | 0x01, 0x01, 0x02, // CNAME, len=1, content=2 (item length: 3)
40 | 0x02, 0x07, // NAME, len=7
41 | 0x05, 0x06, 0x07, 0x07, 0x06, 0x05, 0x04, // content 5,6,7,7,6,5,4 (item length 9)
42 | 0x00, 0x00, 0x00, 0x00, // END plus 3 padding (chunk length: 20)
43 | // second chunk, one item (CNAME, END)
44 | 0x05, 0x06, 0x07, 0x08, // SSRC 0x05060707
45 | 0x01, 0x03, 0x05, 0x06, 0x07, // CNAME, len=3, content=5,6,7
46 | 0x00, 0x00, 0x00} // END plus 2 padding (chunk length: 12)
47 |
48 | // V=2, P=0, chunks=2; PT=SDES; length=5 32bit words (24 bytes)
49 | var sdes_1_wrong = []byte{0x81, 202, 0x00, 0x05,
50 | 0x01, 0x02, 0x03, 0x04, // SSRC 0x01020304
51 | 0x01, 0x03, 0x02, // CNAME, len=3 (wrong, should be 1), content=2
52 | 0x00, // END (chunk length: 8)
53 | 0x05, 0x06, 0x07, 0x08, // SSRC 0x05060707
54 | 0x01, 0x03, 0x05, 0x06, 0x07, // CNAME, len=3, content=5,6,7
55 | 0x00, 0x00, 0x00} // END plus 2 padding (chunk length: 12)
56 |
57 | func sdesCheck(t *testing.T) (result bool) {
58 | result = false
59 |
60 | rp := new(CtrlPacket) // allocate a new CTRL packet.
61 | rp.buffer = sdes_1
62 |
63 | cnt := int((rp.Length(0) + 1) * 4) // SDES Length incl. header word
64 | if cnt != 24 {
65 | t.Error(fmt.Sprintf("Basic first SDES length check failed. Expected: 24, got: %d\n", cnt))
66 | return
67 | }
68 | offset := 4
69 | // first SDES chunk starts ofter first header word
70 | sdesChunk := rp.toSdesChunk(offset, cnt-4)
71 |
72 | // Get length of first chunk - must be 8
73 | chunkLen, _ := sdesChunk.chunkLen()
74 | if chunkLen != 8 {
75 | t.Error(fmt.Sprintf("Basic first SDES chunk length check failed. Expected: 8, got: %d\n", chunkLen))
76 | return
77 | }
78 | offset += chunkLen
79 | cnt -= chunkLen
80 | // second SDES chunk starts ofter first chunk :-)
81 | sdesChunk = rp.toSdesChunk(offset, cnt-4)
82 |
83 | // Get length of second chunk - must be 12
84 | chunkLen, _ = sdesChunk.chunkLen()
85 | if chunkLen != 12 {
86 | t.Error(fmt.Sprintf("Basic first SDES chunk length check failed. Expected: 12, got: %d\n", chunkLen))
87 | return
88 | }
89 |
90 | rp.buffer = sdes_2
91 | cnt = int((rp.Length(0) + 1) * 4) // SDES Length incl. header word
92 | if cnt != 36 {
93 | t.Error(fmt.Sprintf("Basic second SDES length check failed. Expected: 36, got: %d\n", cnt))
94 | return
95 | }
96 | offset = 4
97 | // first SDES chunk starts ofter first header word
98 | sdesChunk = rp.toSdesChunk(offset, cnt-4)
99 |
100 | // Get length of first chunk - must be 20
101 | chunkLen, _ = sdesChunk.chunkLen()
102 | if chunkLen != 20 {
103 | t.Error(fmt.Sprintf("Basic second SDES chunk length check failed. Expected: 20, got: %d\n", chunkLen))
104 | return
105 | }
106 | offset += chunkLen
107 | cnt -= chunkLen
108 | // second SDES chunk starts ofter first chunk :-)
109 | sdesChunk = rp.toSdesChunk(offset, cnt-4)
110 |
111 | // Get length of second chunk - must be 12
112 | chunkLen, _ = sdesChunk.chunkLen()
113 | if chunkLen != 12 {
114 | t.Error(fmt.Sprintf("Basic second SDES chunk length check failed. Expected: 12, got: %d\n", chunkLen))
115 | return
116 | }
117 |
118 | rp.buffer = sdes_1_wrong
119 | offset = 4
120 | // SDES chunk starts ofter first header word
121 | sdesChunk = rp.toSdesChunk(offset, cnt-4)
122 |
123 | // Get length of chunk - must fail
124 | chunkLen, ok := sdesChunk.chunkLen()
125 | if ok {
126 | t.Errorf("Chunk length error handling failed, expected: 0, false; got: %d, %v\n", chunkLen, ok)
127 | return
128 | }
129 |
130 | result = true
131 | return
132 | }
133 |
134 | func rtcpPacketBasic(t *testing.T) {
135 | sdesCheck(t)
136 | }
137 |
138 | func TestRtcpPacket(t *testing.T) {
139 | parseFlags()
140 | rtcpPacketBasic(t)
141 | }
142 |
--------------------------------------------------------------------------------
/datapacket_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2011 Werner Dittmann
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU General Public License as published by
5 | // the Free Software Foundation, either version 3 of the License, or
6 | // (at your option) any later version.
7 | //
8 | // This program is distributed in the hope that it will be useful,
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with this program. If not, see .
15 | //
16 | // Authors: Werner Dittmann
17 | //
18 |
19 | package rtp
20 |
21 | import (
22 | "flag"
23 | "fmt"
24 | "net"
25 | "testing"
26 | "time"
27 | )
28 |
29 | var verbose *bool = flag.Bool("verbose", false, "Verbose output during tests")
30 | var parsed bool
31 |
32 | var payload = []byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20}
33 | var payloadNull = []byte{}
34 |
35 | var initialPacket = []byte{0x80, 0x03, 0x47, 0x11, 0xf0, 0xe0, 0xd0, 0xc0, 0x01, 0x02, 0x03, 0x04,
36 | 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20}
37 |
38 | var csrc_1 = []uint32{0x21435465, 0x65544322}
39 | var csrc_2 = []uint32{0x23445566, 0x66554423, 0x87766554}
40 | var csrc_3 = []uint32{}
41 |
42 | // profile ID length
43 | var ext_1 = []byte{0x77, 0x88, 0x00, 0x02, 0x01, 0x02, 0x03, 0x04, 0x04, 0x03, 0x02, 0x01} // len: 12
44 | var ext_2 = []byte{0x77, 0x89, 0x00, 0x03, 0x01, 0x02, 0x03, 0x04, 0x04, 0x03, 0x02, 0x01, 0x11, 0x22, 0x33, 0x44} // len: 16
45 | var ext_3 = []byte{0x77, 0x8a, 0x00, 0x00} // len: 4
46 | var ext_4 = []byte{}
47 |
48 | func headerCheck(rp *DataPacket, t *testing.T) (result bool) {
49 | result = false
50 |
51 | ssrc := rp.Ssrc()
52 | if ssrc != 0x01020304 {
53 | t.Error(fmt.Sprintf("SSRC check failed. Expected: 0x1020304, got: %x\n", ssrc))
54 | return
55 | }
56 | seq := rp.Sequence()
57 | if seq != 0x4711 {
58 | t.Error(fmt.Sprintf("Sequence check failed. Expected: 0x4711, got: %x\n", seq))
59 | return
60 | }
61 | ts := rp.Timestamp()
62 | if ts != 0xF0E0D0C0 {
63 | t.Error(fmt.Sprintf("Timestamp check failed. Expected: 0xF0E0D0C0, got: %x\n", ts))
64 | return
65 | }
66 |
67 | result = true
68 | return
69 | }
70 |
71 | func csrcTest(rp *DataPacket, t *testing.T, csrc []uint32, run int) (result bool) {
72 | result = false
73 | rp.SetCsrcList(csrc)
74 |
75 | if !headerCheck(rp, t) {
76 | return
77 | }
78 | ssrcLen := rp.CsrcCount()
79 | if int(ssrcLen) != len(csrc) {
80 | t.Error(fmt.Sprintf("CSRC-%d length check failed. Expected: %d, got: %d\n", run, len(csrc), ssrcLen))
81 | return
82 | }
83 | csrcTmp := rp.CsrcList()
84 | for i, v := range csrcTmp {
85 | if v != csrc[i] {
86 | t.Error(fmt.Sprintf("CSRC-%d check failed at %i. Expected: %x, got: %x\n", run, i, csrc[i], csrcTmp[i]))
87 | return
88 | }
89 | }
90 | use := rp.InUse()
91 | expected := rtpHeaderLength + len(payload) + len(csrc)*4 + rp.ExtensionLength()
92 | if use != expected {
93 | t.Error(fmt.Sprintf("Payload-CSRC-%d length check failed. Expected: %d, got: %d\n", run, expected, use))
94 | return
95 | }
96 | pay := rp.Payload()
97 | for i, v := range payload {
98 | if v != pay[i] {
99 | t.Error(fmt.Sprintf("Payload-CSRC-%d check failed at %i. Expected: %x, got: %x\n", run, i, payload[i], pay[i]))
100 | return
101 | }
102 | }
103 | if *verbose {
104 | rp.Print(fmt.Sprintf("CSRC-%d check", run))
105 | }
106 | result = true
107 | return
108 | }
109 |
110 | func extTest(rp *DataPacket, t *testing.T, ext []byte, run int) (result bool) {
111 | result = false
112 | rp.SetExtension(ext)
113 |
114 | if !headerCheck(rp, t) {
115 | return
116 | }
117 | extLen := rp.ExtensionLength()
118 | if extLen != len(ext) {
119 | t.Error(fmt.Sprintf("EXT-%d length check failed. Expected: %d, got: %d\n", run, len(ext), extLen))
120 | return
121 | }
122 | extTmp := rp.Extension()
123 | for i, v := range extTmp {
124 | if v != ext[i] {
125 | t.Error(fmt.Sprintf("EXT-%d check failed at %i. Expected: %x, got: %x\n", run, i, ext[i], extTmp[i]))
126 | return
127 | }
128 | }
129 | use := rp.InUse()
130 | expected := rtpHeaderLength + len(payload) + int(rp.CsrcCount()*4) + len(ext)
131 | if use != expected {
132 | t.Error(fmt.Sprintf("Payload-EXT-%d length check failed. Expected: %d, got: %d\n", run, expected, use))
133 | return
134 | }
135 | pay := rp.Payload()
136 | for i, v := range payload {
137 | if v != pay[i] {
138 | t.Error(fmt.Sprintf("Payload-EXT-%d check failed at %i. Expected: %x, got: %x\n", run, i, payload[i], pay[i]))
139 | return
140 | }
141 | }
142 | if *verbose {
143 | rp.Print(fmt.Sprintf("EXT-%d check", run))
144 | }
145 | result = true
146 | return
147 | }
148 |
149 | func rtpPacket(t *testing.T) {
150 |
151 | // Prepare some data to create a RP session, RTP stream and then RTP packets
152 | port := 5220
153 | local, _ := net.ResolveIPAddr("ip", "127.0.0.1")
154 |
155 | // Create a UDP transport with "local" address and use this for a "local" RTP session
156 | // The RTP session uses the transport to receive and send RTP packets to the remote peers.
157 | tpLocal, _ := NewTransportUDP(local, port)
158 |
159 | // TransportUDP implements RtpTransportWrite and RtpTransportRecv interfaces thus
160 | // set it in the RtpSession for both interfaces
161 | rsLocal := NewSession(tpLocal, tpLocal)
162 |
163 | // Create a media stream.
164 | // The SSRC identifies the stream. Each stream has its own sequence number and other
165 | // context. A RTP session can have several RTP stream for example to send several
166 | // streams of the same media.
167 | //
168 | strIdx, _ := rsLocal.NewSsrcStreamOut(&Address{local.IP, port, port + 1}, 0x01020304, 0x4711)
169 | rsLocal.SsrcStreamOutForIndex(strIdx).SetPayloadType(3)
170 |
171 | // Create a RTP packet suitable for standard stream (index 0) with a payload length of 160 bytes
172 | // The method initializes the RTP packet with SSRC, sequence number, and RTP version number.
173 | // If the payload type was set with the RTP stream then the payload type is also set in
174 | // the RTP packet
175 | rp := rsLocal.NewDataPacket(160)
176 | rp.SetTimestamp(0xF0E0D0C0)
177 |
178 | if !headerCheck(rp, t) {
179 | return
180 | }
181 | use := rp.InUse()
182 | if use != rtpHeaderLength {
183 | t.Error(fmt.Sprintf("RTP header length check failed. Expected: 12, got: %d\n", use))
184 | return
185 | }
186 |
187 | // Check basic payload handling
188 | rp.SetPayload(payload)
189 |
190 | if *verbose {
191 | rp.Print("Basic payload")
192 | }
193 | use = rp.InUse()
194 | if use != rtpHeaderLength+len(payload) {
195 | t.Error(fmt.Sprintf("Packet length check failed. Expected: %d, got: %d\n", rtpHeaderLength+len(payload), use))
196 | return
197 | }
198 | pay := rp.Payload()
199 | if len(pay) != len(payload) {
200 | t.Error(fmt.Sprintf("Payload length check failed. Expected: %d, got: %d\n", len(payload), len(pay)))
201 | return
202 | }
203 | for i, v := range payload {
204 | if v != pay[i] {
205 | t.Error(fmt.Sprintf("Payload check failed at %i. Expected: %x, got: %x\n", i, payload[i], pay[i]))
206 | return
207 | }
208 | }
209 | buf := rp.Buffer()
210 | for i, v := range buf[0:use] {
211 | if v != initialPacket[i] {
212 | t.Error(fmt.Sprintf("Basic header buffer check failed at %d. Expected: %x, got: %x\n", i, initialPacket[i], buf[i]))
213 | return
214 | }
215 | }
216 | rp.SetMarker(true)
217 | if buf[markerPtOffset] != 0x83 {
218 | t.Error(fmt.Sprintf("Marker/PT check 1 failed. Expected: 0x83, got: %x\n", buf[markerPtOffset]))
219 | return
220 | }
221 | pt := rp.PayloadType()
222 | if pt != 3 {
223 | t.Error(fmt.Sprintf("PT-after-Marker check 1 failed. Expected: 3, got: %x\n", pt))
224 | return
225 | }
226 | rp.SetMarker(false)
227 | if buf[markerPtOffset] != 3 {
228 | t.Error(fmt.Sprintf("Marker/PT check 2 failed. Expected: 3, got: %x\n", buf[markerPtOffset]))
229 | return
230 | }
231 | pt = rp.PayloadType()
232 | if pt != 3 {
233 | t.Error(fmt.Sprintf("PT-after-Marker check 2 failed. Expected: 3, got: %x\n", pt))
234 | return
235 | }
236 |
237 | // Delete payload, prepare for padding tests
238 | rp.SetPayload(payloadNull)
239 |
240 | // Check padding
241 | rp.SetPadding(true, 0) // zero defaults to multiple of int32 (4)
242 |
243 | // Check payload handling with padding; len(payload) + rtpHeaderLength is 22, thus 2 bytes padding
244 | rp.SetPayload(payload)
245 | use = rp.InUse()
246 | if use != (rtpHeaderLength + len(payload) + 2) {
247 | t.Error(fmt.Sprintf("Padding packet length check failed. Expected: %d, got: %d\n", rtpHeaderLength+len(payload)+2, use))
248 | return
249 | }
250 | pay = rp.Payload()
251 | if len(pay) != len(payload) {
252 | t.Error(fmt.Sprintf("Padding payload length check failed. Expected: %d, got: %d\n", len(payload), len(pay)))
253 | return
254 | }
255 | for i, v := range payload {
256 | if v != pay[i] {
257 | t.Error(fmt.Sprintf("Payload check failed at %i. Expected: %x, got: %x\n", i, payload[i], pay[i]))
258 | return
259 | }
260 | }
261 | if *verbose {
262 | rp.Print("Payload with padding")
263 | }
264 |
265 | // delete padded payload and switch off padding
266 | rp.SetPayload(payloadNull)
267 | rp.SetPadding(false, 0)
268 |
269 | // set normal payload without padding to perform other tests
270 | rp.SetPayload(payload)
271 |
272 | // Now check CSRC list handling. These modify InUse and shift the payload inside the packet buffer.
273 | if !csrcTest(rp, t, csrc_1, 1) || !csrcTest(rp, t, csrc_2, 2) || !csrcTest(rp, t, csrc_3, 3) {
274 | return
275 | }
276 | // After last CSCR test the packet shall be in initial state, check it.
277 | use = rp.InUse()
278 | if use != rtpHeaderLength+len(payload) {
279 | t.Error(fmt.Sprintf("Packet length check afer CSRC failed. Expected: %d, got: %d\n", rtpHeaderLength+len(payload), use))
280 | return
281 | }
282 | buf = rp.Buffer()
283 | for i, v := range buf[0:use] {
284 | if v != initialPacket[i] {
285 | t.Error(fmt.Sprintf("Basic header buffer check after CSRC failed at %d. Expected: %x, got: %x\n", i, initialPacket[i], buf[i]))
286 | return
287 | }
288 | }
289 | if !extTest(rp, t, ext_1, 1) || !extTest(rp, t, ext_2, 2) || !extTest(rp, t, ext_3, 3) || !extTest(rp, t, ext_4, 4) {
290 | return
291 | }
292 | // After last EXT test the packet shall be in initial state, check it.
293 | use = rp.InUse()
294 | if use != rtpHeaderLength+len(payload) {
295 | t.Error(fmt.Sprintf("Packet length check afer EXT failed. Expected: %d, got: %d\n", rtpHeaderLength+len(payload), use))
296 | return
297 | }
298 | buf = rp.Buffer()
299 | for i, v := range buf[0:use] {
300 | if v != initialPacket[i] {
301 | t.Error(fmt.Sprintf("Basic header buffer check after CSRC failed at %d. Expected: %x, got: %x\n", i, initialPacket[i], buf[i]))
302 | return
303 | }
304 | }
305 | if !csrcTest(rp, t, csrc_1, 1) || !extTest(rp, t, ext_1, 1) {
306 | return
307 | }
308 | if *verbose {
309 | rp.Print("CSCR/EXT combined")
310 | }
311 | use = rp.InUse()
312 | expected := rtpHeaderLength + len(payload) + len(csrc_1)*4 + len(ext_1)
313 | if use != expected {
314 | t.Error(fmt.Sprintf("Packet length check afer CSRC/EXT failed. Expected: %d, got: %d\n", expected, use))
315 | return
316 | }
317 | }
318 |
319 | func intervalCheck(t *testing.T) {
320 | // members, senders, RTCP bandwidth, packet length, weSent, initial
321 | tm, _ := rtcpInterval(1, 0, 3500.0, 80.0, false, true)
322 | fmt.Printf("Interval: %d\n", tm)
323 | tm, _ = rtcpInterval(100, 0, 3500.0, 160.0, false, true)
324 | fmt.Printf("Interval: %d\n", tm)
325 | }
326 |
327 | func ntpCheck(t *testing.T) {
328 | tm := time.Now().UnixNano()
329 | high, low := toNtpStamp(tm)
330 | tm1 := fromNtp(high, low)
331 | diff := tm - tm1
332 | if diff < -1 || diff > 1 {
333 | t.Error(fmt.Sprintf("NTP time conversion check failed. Expected range: +/-1 got: %d\n", diff))
334 | return
335 | }
336 | }
337 |
338 | func parseFlags() {
339 | if !parsed {
340 | flag.Parse()
341 | parsed = true
342 | }
343 | }
344 |
345 | func TestRtpPacket(t *testing.T) {
346 | parseFlags()
347 | rtpPacket(t)
348 | ntpCheck(t)
349 | // intervalCheck(t)
350 | }
351 |
--------------------------------------------------------------------------------
/iana/iana_const.go:
--------------------------------------------------------------------------------
1 | // file copied from internal: golang.org/x/net/internal/iana
2 |
3 | // go generate gen.go
4 | // GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
5 |
6 | // Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).
7 | package iana
8 |
9 | // Differentiated Services Field Codepoints (DSCP), Updated: 2013-06-25
10 | const (
11 | DiffServCS0 = 0x0 // CS0
12 | DiffServCS1 = 0x20 // CS1
13 | DiffServCS2 = 0x40 // CS2
14 | DiffServCS3 = 0x60 // CS3
15 | DiffServCS4 = 0x80 // CS4
16 | DiffServCS5 = 0xa0 // CS5
17 | DiffServCS6 = 0xc0 // CS6
18 | DiffServCS7 = 0xe0 // CS7
19 | DiffServAF11 = 0x28 // AF11
20 | DiffServAF12 = 0x30 // AF12
21 | DiffServAF13 = 0x38 // AF13
22 | DiffServAF21 = 0x48 // AF21
23 | DiffServAF22 = 0x50 // AF22
24 | DiffServAF23 = 0x58 // AF23
25 | DiffServAF31 = 0x68 // AF31
26 | DiffServAF32 = 0x70 // AF32
27 | DiffServAF33 = 0x78 // AF33
28 | DiffServAF41 = 0x88 // AF41
29 | DiffServAF42 = 0x90 // AF42
30 | DiffServAF43 = 0x98 // AF43
31 | DiffServEFPHB = 0xb8 // EF PHB
32 | DiffServVOICEADMIT = 0xb0 // VOICE-ADMIT
33 | )
34 |
35 | // IPv4 TOS Byte and IPv6 Traffic Class Octet, Updated: 2001-09-06
36 | const (
37 | NotECNTransport = 0x0 // Not-ECT (Not ECN-Capable Transport)
38 | ECNTransport1 = 0x1 // ECT(1) (ECN-Capable Transport(1))
39 | ECNTransport0 = 0x2 // ECT(0) (ECN-Capable Transport(0))
40 | CongestionExperienced = 0x3 // CE (Congestion Experienced)
41 | )
42 |
43 | // Protocol Numbers, Updated: 2015-06-23
44 | const (
45 | ProtocolIP = 0 // IPv4 encapsulation, pseudo protocol number
46 | ProtocolHOPOPT = 0 // IPv6 Hop-by-Hop Option
47 | ProtocolICMP = 1 // Internet Control Message
48 | ProtocolIGMP = 2 // Internet Group Management
49 | ProtocolGGP = 3 // Gateway-to-Gateway
50 | ProtocolIPv4 = 4 // IPv4 encapsulation
51 | ProtocolST = 5 // Stream
52 | ProtocolTCP = 6 // Transmission Control
53 | ProtocolCBT = 7 // CBT
54 | ProtocolEGP = 8 // Exterior Gateway Protocol
55 | ProtocolIGP = 9 // any private interior gateway (used by Cisco for their IGRP)
56 | ProtocolBBNRCCMON = 10 // BBN RCC Monitoring
57 | ProtocolNVPII = 11 // Network Voice Protocol
58 | ProtocolPUP = 12 // PUP
59 | ProtocolARGUS = 13 // ARGUS
60 | ProtocolEMCON = 14 // EMCON
61 | ProtocolXNET = 15 // Cross Net Debugger
62 | ProtocolCHAOS = 16 // Chaos
63 | ProtocolUDP = 17 // User Datagram
64 | ProtocolMUX = 18 // Multiplexing
65 | ProtocolDCNMEAS = 19 // DCN Measurement Subsystems
66 | ProtocolHMP = 20 // Host Monitoring
67 | ProtocolPRM = 21 // Packet Radio Measurement
68 | ProtocolXNSIDP = 22 // XEROX NS IDP
69 | ProtocolTRUNK1 = 23 // Trunk-1
70 | ProtocolTRUNK2 = 24 // Trunk-2
71 | ProtocolLEAF1 = 25 // Leaf-1
72 | ProtocolLEAF2 = 26 // Leaf-2
73 | ProtocolRDP = 27 // Reliable Data Protocol
74 | ProtocolIRTP = 28 // Internet Reliable Transaction
75 | ProtocolISOTP4 = 29 // ISO Transport Protocol Class 4
76 | ProtocolNETBLT = 30 // Bulk Data Transfer Protocol
77 | ProtocolMFENSP = 31 // MFE Network Services Protocol
78 | ProtocolMERITINP = 32 // MERIT Internodal Protocol
79 | ProtocolDCCP = 33 // Datagram Congestion Control Protocol
80 | Protocol3PC = 34 // Third Party Connect Protocol
81 | ProtocolIDPR = 35 // Inter-Domain Policy Routing Protocol
82 | ProtocolXTP = 36 // XTP
83 | ProtocolDDP = 37 // Datagram Delivery Protocol
84 | ProtocolIDPRCMTP = 38 // IDPR Control Message Transport Proto
85 | ProtocolTPPP = 39 // TP++ Transport Protocol
86 | ProtocolIL = 40 // IL Transport Protocol
87 | ProtocolIPv6 = 41 // IPv6 encapsulation
88 | ProtocolSDRP = 42 // Source Demand Routing Protocol
89 | ProtocolIPv6Route = 43 // Routing Header for IPv6
90 | ProtocolIPv6Frag = 44 // Fragment Header for IPv6
91 | ProtocolIDRP = 45 // Inter-Domain Routing Protocol
92 | ProtocolRSVP = 46 // Reservation Protocol
93 | ProtocolGRE = 47 // Generic Routing Encapsulation
94 | ProtocolDSR = 48 // Dynamic Source Routing Protocol
95 | ProtocolBNA = 49 // BNA
96 | ProtocolESP = 50 // Encap Security Payload
97 | ProtocolAH = 51 // Authentication Header
98 | ProtocolINLSP = 52 // Integrated Net Layer Security TUBA
99 | ProtocolNARP = 54 // NBMA Address Resolution Protocol
100 | ProtocolMOBILE = 55 // IP Mobility
101 | ProtocolTLSP = 56 // Transport Layer Security Protocol using Kryptonet key management
102 | ProtocolSKIP = 57 // SKIP
103 | ProtocolIPv6ICMP = 58 // ICMP for IPv6
104 | ProtocolIPv6NoNxt = 59 // No Next Header for IPv6
105 | ProtocolIPv6Opts = 60 // Destination Options for IPv6
106 | ProtocolCFTP = 62 // CFTP
107 | ProtocolSATEXPAK = 64 // SATNET and Backroom EXPAK
108 | ProtocolKRYPTOLAN = 65 // Kryptolan
109 | ProtocolRVD = 66 // MIT Remote Virtual Disk Protocol
110 | ProtocolIPPC = 67 // Internet Pluribus Packet Core
111 | ProtocolSATMON = 69 // SATNET Monitoring
112 | ProtocolVISA = 70 // VISA Protocol
113 | ProtocolIPCV = 71 // Internet Packet Core Utility
114 | ProtocolCPNX = 72 // Computer Protocol Network Executive
115 | ProtocolCPHB = 73 // Computer Protocol Heart Beat
116 | ProtocolWSN = 74 // Wang Span Network
117 | ProtocolPVP = 75 // Packet Video Protocol
118 | ProtocolBRSATMON = 76 // Backroom SATNET Monitoring
119 | ProtocolSUNND = 77 // SUN ND PROTOCOL-Temporary
120 | ProtocolWBMON = 78 // WIDEBAND Monitoring
121 | ProtocolWBEXPAK = 79 // WIDEBAND EXPAK
122 | ProtocolISOIP = 80 // ISO Internet Protocol
123 | ProtocolVMTP = 81 // VMTP
124 | ProtocolSECUREVMTP = 82 // SECURE-VMTP
125 | ProtocolVINES = 83 // VINES
126 | ProtocolTTP = 84 // Transaction Transport Protocol
127 | ProtocolIPTM = 84 // Internet Protocol Traffic Manager
128 | ProtocolNSFNETIGP = 85 // NSFNET-IGP
129 | ProtocolDGP = 86 // Dissimilar Gateway Protocol
130 | ProtocolTCF = 87 // TCF
131 | ProtocolEIGRP = 88 // EIGRP
132 | ProtocolOSPFIGP = 89 // OSPFIGP
133 | ProtocolSpriteRPC = 90 // Sprite RPC Protocol
134 | ProtocolLARP = 91 // Locus Address Resolution Protocol
135 | ProtocolMTP = 92 // Multicast Transport Protocol
136 | ProtocolAX25 = 93 // AX.25 Frames
137 | ProtocolIPIP = 94 // IP-within-IP Encapsulation Protocol
138 | ProtocolSCCSP = 96 // Semaphore Communications Sec. Pro.
139 | ProtocolETHERIP = 97 // Ethernet-within-IP Encapsulation
140 | ProtocolENCAP = 98 // Encapsulation Header
141 | ProtocolGMTP = 100 // GMTP
142 | ProtocolIFMP = 101 // Ipsilon Flow Management Protocol
143 | ProtocolPNNI = 102 // PNNI over IP
144 | ProtocolPIM = 103 // Protocol Independent Multicast
145 | ProtocolARIS = 104 // ARIS
146 | ProtocolSCPS = 105 // SCPS
147 | ProtocolQNX = 106 // QNX
148 | ProtocolAN = 107 // Active Networks
149 | ProtocolIPComp = 108 // IP Payload Compression Protocol
150 | ProtocolSNP = 109 // Sitara Networks Protocol
151 | ProtocolCompaqPeer = 110 // Compaq Peer Protocol
152 | ProtocolIPXinIP = 111 // IPX in IP
153 | ProtocolVRRP = 112 // Virtual Router Redundancy Protocol
154 | ProtocolPGM = 113 // PGM Reliable Transport Protocol
155 | ProtocolL2TP = 115 // Layer Two Tunneling Protocol
156 | ProtocolDDX = 116 // D-II Data Exchange (DDX)
157 | ProtocolIATP = 117 // Interactive Agent Transfer Protocol
158 | ProtocolSTP = 118 // Schedule Transfer Protocol
159 | ProtocolSRP = 119 // SpectraLink Radio Protocol
160 | ProtocolUTI = 120 // UTI
161 | ProtocolSMP = 121 // Simple Message Protocol
162 | ProtocolPTP = 123 // Performance Transparency Protocol
163 | ProtocolISIS = 124 // ISIS over IPv4
164 | ProtocolFIRE = 125 // FIRE
165 | ProtocolCRTP = 126 // Combat Radio Transport Protocol
166 | ProtocolCRUDP = 127 // Combat Radio User Datagram
167 | ProtocolSSCOPMCE = 128 // SSCOPMCE
168 | ProtocolIPLT = 129 // IPLT
169 | ProtocolSPS = 130 // Secure Packet Shield
170 | ProtocolPIPE = 131 // Private IP Encapsulation within IP
171 | ProtocolSCTP = 132 // Stream Control Transmission Protocol
172 | ProtocolFC = 133 // Fibre Channel
173 | ProtocolRSVPE2EIGNORE = 134 // RSVP-E2E-IGNORE
174 | ProtocolMobilityHeader = 135 // Mobility Header
175 | ProtocolUDPLite = 136 // UDPLite
176 | ProtocolMPLSinIP = 137 // MPLS-in-IP
177 | ProtocolMANET = 138 // MANET Protocols
178 | ProtocolHIP = 139 // Host Identity Protocol
179 | ProtocolShim6 = 140 // Shim6 Protocol
180 | ProtocolWESP = 141 // Wrapped Encapsulating Security Payload
181 | ProtocolROHC = 142 // Robust Header Compression
182 | ProtocolReserved = 255 // Reserved
183 | )
184 |
--------------------------------------------------------------------------------
/packets.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2011 Werner Dittmann
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU General Public License as published by
5 | // the Free Software Foundation, either version 3 of the License, or
6 | // (at your option) any later version.
7 | //
8 | // This program is distributed in the hope that it will be useful,
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with this program. If not, see .
15 | //
16 | // Authors: Werner Dittmann
17 | //
18 |
19 | package rtp
20 |
21 | import (
22 | "encoding/binary"
23 | "encoding/hex"
24 | "fmt"
25 | )
26 |
27 | const (
28 | defaultBufferSize = 1200
29 | freeListLengthRtp = 10
30 | freeListLengthRtcp = 5
31 | rtpHeaderLength = 12
32 | rtcpHeaderLength = 4
33 | rtcpSsrcLength = 4
34 | padToMultipleOf = 4
35 | )
36 |
37 | const (
38 | markerPtOffset = 1
39 | packetTypeOffset = 1
40 | lengthOffset = 2
41 | sequenceOffset = 2
42 | timestampOffset = sequenceOffset + 2
43 | ssrcOffsetRtp = timestampOffset + 4
44 | ssrcOffsetRtcp = sequenceOffset + 2
45 | )
46 |
47 | const (
48 | version2Bit = 0x80
49 | versionMask = 0xc0
50 | extensionBit = 0x10
51 | paddingBit = 0x20
52 | markerBit = 0x80
53 | ccMask = 0x0f
54 | ptMask = 0x7f
55 | countMask = 0x1f
56 | )
57 |
58 | // For full reference of registered RTP parameters refer to:
59 | // http://www.iana.org/assignments/rtp-parameters
60 |
61 | // RTCP packet types
62 | const (
63 | RtcpSR = 200 // SR sender report [RFC3550]
64 | RtcpRR = 201 // RR receiver report [RFC3550]
65 | RtcpSdes = 202 // SDES source description [RFC3550]
66 | RtcpBye = 203 // BYE goodbye [RFC3550]
67 | RtcpApp = 204 // APP application-defined [RFC3550]
68 | RtcpRtpfb = 205 // RTPFB Generic RTP Feedback [RFC4585]
69 | RtcpPsfb = 206 // PSFB Payload-specific [RFC4585]
70 | RtcpXr = 207 // XR extended report [RFC3611]
71 | )
72 |
73 | // RTCP SDES item types
74 | const (
75 | SdesEnd = iota // END end of SDES list [RFC3550]
76 | SdesCname // CNAME canonical name [RFC3550]
77 | SdesName // NAME user name [RFC3550]
78 | SdesEmail // EMAIL user's electronic mail address [RFC3550]
79 | SdesPhone // PHONE user's phone number [RFC3550]
80 | SdesLoc // LOC geographic user location [RFC3550]
81 | SdesTool // TOOL name of application or tool [RFC3550]
82 | SdesNote // NOTE notice about the source [RFC3550]
83 | SdesPriv // PRIV private extensions [RFC3550]
84 | SdesH323Caddr // H323-CADDR H.323 callable address [Kumar]
85 | sdesMax
86 | )
87 |
88 | // Length of fixed report blocks in bytes
89 | const (
90 | senderInfoLen = 20
91 | reportBlockLen = 24
92 | )
93 |
94 | // nullArray is what it's names says: a long array filled with zeros.
95 | // used to clear (fill with zeros) arrays/slices inside a buffer by copying.
96 | var nullArray [1200]byte
97 |
98 | type RawPacket struct {
99 | inUse int
100 | padTo int
101 | isFree bool
102 | fromAddr Address
103 | buffer []byte
104 | }
105 |
106 | // Buffer returns the internal buffer in raw format.
107 | // Usually only other Transports use the buffer in raw format, for example to encrypt
108 | // or decrypt the buffer.
109 | // Always call Buffer() just before the the buffer is actually used because several packet
110 | // handling functions may re-allocate buffers.
111 | func (raw *RawPacket) Buffer() []byte {
112 | return raw.buffer
113 | }
114 |
115 | // InUse returns the number of valid bytes in the packet buffer.
116 | // Several function modify the inUse variable, for example when copying payload or setting extensions
117 | // in the RTP packet. Thus "buffer[0:inUse]" is the slice inside the buffer that will be sent or
118 | // was received.
119 | func (rp *RawPacket) InUse() int {
120 | return rp.inUse
121 | }
122 |
123 | // *** RTP specific functions start here ***
124 |
125 | // RTP packet type to define RTP specific functions
126 | type DataPacket struct {
127 | RawPacket
128 | payloadLength int16
129 | }
130 |
131 | var freeListRtp = make(chan *DataPacket, freeListLengthRtp)
132 |
133 | func newDataPacket() (rp *DataPacket) {
134 | // Grab a packet if available; allocate if not.
135 | select {
136 | case rp = <-freeListRtp: // Got one; nothing more to do.
137 | default:
138 | rp = new(DataPacket) // None free, so allocate a new one.
139 | rp.buffer = make([]byte, defaultBufferSize)
140 | }
141 | rp.buffer[0] = version2Bit // RTP: V = 2, P, X, CC = 0
142 | rp.inUse = rtpHeaderLength
143 | rp.isFree = false
144 | return
145 | }
146 |
147 | // FreePacket returns the packet to the free RTP list.
148 | // A packet marked as free is ignored, thus calling FreePacket multiple times for the same
149 | // packet is possible.
150 | func (rp *DataPacket) FreePacket() {
151 | if rp.isFree {
152 | return
153 | }
154 | rp.buffer[0] = 0 // invalidate RTP packet
155 | rp.inUse = 0
156 | rp.padTo = 0
157 | rp.fromAddr.DataPort = 0
158 | rp.fromAddr.IpAddr = nil
159 | rp.isFree = true
160 |
161 | select {
162 | case freeListRtp <- rp: // Packet on free list; nothing more to do.
163 | default: // Free list full, just carry on.
164 | }
165 | }
166 |
167 | // CsrcCount return the number of CSRC values in this packet
168 | func (rp *DataPacket) CsrcCount() uint8 {
169 | return rp.buffer[0] & ccMask
170 | }
171 |
172 | // SetCsrcList takes the CSRC in this list, converts from host to network order and sets into the RTP packet.
173 | // The new CSRC list replaces an existing CSCR list. The list can have a maximum length of 16 CSCR values,
174 | // if the list contains more values the method leaves the RTP packet untouched.
175 | func (rp *DataPacket) SetCsrcList(csrc []uint32) {
176 |
177 | if len(csrc) > 16 {
178 | return
179 | }
180 | // For this method: content is any data after an existing (or new) CSRC list. This
181 | // includes RTP extension data and payload.
182 | offsetOld := int(rp.CsrcCount()*4 + rtpHeaderLength) // offset to old content
183 | offsetNew := len(csrc)*4 + rtpHeaderLength // offset to new content
184 |
185 | newInUse := offsetNew + rp.inUse - offsetOld
186 | if newInUse > cap(rp.buffer) {
187 | return
188 | }
189 | tmpRp := newDataPacket() // get a new packet first
190 | newBuf := tmpRp.buffer // and get its buffer
191 |
192 | copy(newBuf, rp.buffer[0:rtpHeaderLength]) // copy fixed header
193 | copy(newBuf[offsetNew:], rp.buffer[offsetOld:rp.inUse]) // copy over old content
194 |
195 | for i := 0; i < len(csrc); i++ {
196 | binary.BigEndian.PutUint32(newBuf[rtpHeaderLength+i*4:], csrc[i]) // CSCR in network order
197 | }
198 | tmpRp.buffer = rp.buffer // switch buffers
199 | rp.buffer = newBuf
200 | tmpRp.FreePacket() // free temporary RTP packet
201 |
202 | rp.buffer[0] &^= ccMask // clear old length
203 | rp.buffer[0] |= byte(len(csrc) & ccMask)
204 | rp.inUse = newInUse
205 | }
206 |
207 | // CsrcList returns the list of CSRC values as uint32 slice in host horder
208 | func (rp *DataPacket) CsrcList() (list []uint32) {
209 | list = make([]uint32, rp.CsrcCount())
210 | for i := 0; i < len(list); i++ {
211 | list[i] = binary.BigEndian.Uint32(rp.buffer[rtpHeaderLength+i*4:])
212 | }
213 | return
214 | }
215 |
216 | // SetExtension takes a byte slice and set it as extension into the RTP packet.
217 | // The byte slice must conform to one of the formats specified in RFC 3550 or RFC 5258, thus
218 | // the length must be a multiple of uint32 (4) and the length field must be in the 3rd and 4th
219 | // byte (uint16) and its value must adhere to RFC 3550 / RFC 5258.
220 | func (rp *DataPacket) SetExtension(ext []byte) {
221 | if (len(ext) % 4) != 0 {
222 | return
223 | }
224 | l := 0
225 | if len(ext) > 0 {
226 | l = int((binary.BigEndian.Uint16(ext[2:]) + 1) * 4)
227 | }
228 | if l != len(ext) {
229 | return
230 | }
231 | // For this method: content is any data after an existing (or new) Extension area. This
232 | // is the payload.
233 | offsetExt := int(rp.CsrcCount()*4 + rtpHeaderLength) // offset to Extension
234 | offsetOld := int(rp.CsrcCount()*4 + rtpHeaderLength) // offset to old content
235 | if rp.ExtensionBit() {
236 | offsetOld += rp.ExtensionLength()
237 | }
238 | offsetNew := offsetExt + l // offset to new content
239 |
240 | newInUse := rp.inUse + l - (offsetOld - offsetExt)
241 | if newInUse > cap(rp.buffer) {
242 | return
243 | }
244 | tmpRp := newDataPacket() // get a new packet first
245 | newBuf := tmpRp.buffer // and get its buffer
246 |
247 | copy(newBuf, rp.buffer[0:rtpHeaderLength]) // copy fixed header
248 | copy(newBuf[offsetExt:], ext) // copy new extension
249 | copy(newBuf[offsetNew:], rp.buffer[offsetOld:rp.inUse]) // copy over old content
250 |
251 | tmpRp.buffer = rp.buffer // switch buffers
252 | rp.buffer = newBuf
253 | tmpRp.FreePacket() // free temporary RTP packet
254 | if l == 0 {
255 | rp.buffer[0] &^= extensionBit
256 | } else {
257 | rp.buffer[0] |= extensionBit
258 | }
259 | rp.inUse = newInUse
260 | }
261 |
262 | // Extension returns the byte slice of the RTP packet extension part, if not extension available it returns nil.
263 | // This is not a copy of the extension part but the slice points into the real RTP packet buffer.
264 | func (rp *DataPacket) Extension() []byte {
265 | if !rp.ExtensionBit() {
266 | return nil
267 | }
268 | offset := int(rp.CsrcCount()*4 + rtpHeaderLength)
269 | return rp.buffer[offset : offset+rp.ExtensionLength()]
270 | }
271 |
272 | // Ssrc returns the SSRC as uint32 in host order.
273 | func (rp *DataPacket) Ssrc() uint32 {
274 | return binary.BigEndian.Uint32(rp.buffer[ssrcOffsetRtp:])
275 | }
276 |
277 | // SetSsrc converts SSRC from host order into network order and stores it in the RTP packet.
278 | func (rp *DataPacket) SetSsrc(ssrc uint32) {
279 | binary.BigEndian.PutUint32(rp.buffer[ssrcOffsetRtp:], ssrc)
280 | }
281 |
282 | // Timestamp returns the Timestamp as uint32 in host order.
283 | func (rp *DataPacket) Timestamp() uint32 {
284 | return binary.BigEndian.Uint32(rp.buffer[timestampOffset:])
285 | }
286 |
287 | // SetTimestamp converts timestamp from host order into network order and stores it in the RTP packet.
288 | func (rp *DataPacket) SetTimestamp(timestamp uint32) {
289 | binary.BigEndian.PutUint32(rp.buffer[timestampOffset:], timestamp)
290 | }
291 |
292 | // SetMarker set or resets the Marker bit.
293 | // If the parameter m is true the methods sets the Marker bit, resets it otherweise.
294 | func (rp *DataPacket) SetMarker(m bool) {
295 | if m {
296 | rp.buffer[markerPtOffset] |= markerBit
297 | } else {
298 | rp.buffer[markerPtOffset] &^= markerBit
299 | }
300 | }
301 |
302 | // Marker returns the state of the Marker bit.
303 | // If the Marker bit is set the method return true, otherwise it returns false
304 | func (rp *DataPacket) Marker() bool {
305 | return (rp.buffer[markerPtOffset] & markerBit) == markerBit
306 | }
307 |
308 | // SetPadding set or resets the padding bit.
309 | // If the parameter p is true the methods sets the Padding bit, resets it otherweise.
310 | // If parameter p is true and padTo is zero, then this method sets pads the whole
311 | // RTP packet to a multiple of 4, otherwise the given value is used which must be
312 | // greater than 1.
313 | //
314 | // NOTE: padding is only done when adding payload to the packet, thus if an application
315 | // required padding then seeting the payload should be the last step in RTP packet creation
316 | func (rp *DataPacket) SetPadding(p bool, padTo int) {
317 | if padTo == 0 {
318 | padTo = padToMultipleOf
319 | }
320 | if p {
321 | rp.buffer[0] |= paddingBit
322 | rp.padTo = padTo
323 | } else {
324 | rp.buffer[0] &^= paddingBit
325 | rp.padTo = 0
326 | }
327 | }
328 |
329 | // Padding returns the state of the Padding bit.
330 | // If the Padding bit is set the method return true, otherwise it returns false
331 | func (rp *DataPacket) Padding() bool {
332 | return (rp.buffer[0] & paddingBit) == paddingBit
333 | }
334 |
335 | // SetPayloadType sets a new payload type value in the RTP packet header.
336 | func (rp *DataPacket) SetPayloadType(pt byte) {
337 | rp.buffer[markerPtOffset] &^= ptMask // first: clear old type
338 | rp.buffer[markerPtOffset] |= (pt & ptMask)
339 | }
340 |
341 | // PayloadType return the payload type value from RTP packet header.
342 | func (rp *DataPacket) PayloadType() byte {
343 | return rp.buffer[markerPtOffset] & ptMask
344 | }
345 |
346 | // SetSequence converts the sequence from host order into network order and stores it in the RTP packet header.
347 | func (rp *DataPacket) SetSequence(seq uint16) {
348 | binary.BigEndian.PutUint16(rp.buffer[sequenceOffset:], seq)
349 | }
350 |
351 | // Sequence returns the sequence number as uint16 in host order.
352 | func (rp *DataPacket) Sequence() uint16 {
353 | return binary.BigEndian.Uint16(rp.buffer[sequenceOffset:])
354 | }
355 |
356 | // ExtensionBit returns true if the Extension bit is set in the header, false otherwise.
357 | func (rp *DataPacket) ExtensionBit() bool {
358 | return (rp.buffer[0] & extensionBit) == extensionBit
359 | }
360 |
361 | // ExtensionLength returns the full length in bytes of RTP packet extension (including the main extension header).
362 | func (rp *DataPacket) ExtensionLength() (length int) {
363 | if !rp.ExtensionBit() {
364 | return 0
365 | }
366 | offset := int16(rp.CsrcCount()*4 + rtpHeaderLength) // offset to extension header 32bit word
367 | offset += 2
368 | length = int(binary.BigEndian.Uint16(rp.buffer[offset:])) + 1 // +1 for the main extension header word
369 | length *= 4
370 | return
371 | }
372 |
373 | // Payload returns the byte slice of the payload after removing length of possible padding.
374 | //
375 | // The slice is not a copy of the payload but the slice points into the real RTP packet buffer.
376 | func (rp *DataPacket) Payload() []byte {
377 | payOffset := int(rp.CsrcCount()*4+rtpHeaderLength) + rp.ExtensionLength()
378 | pad := 0
379 | if rp.Padding() {
380 | pad = int(rp.buffer[rp.inUse-1])
381 | }
382 | return rp.buffer[payOffset : rp.inUse-pad]
383 | }
384 |
385 | // SetPayload copies the contents of payload byte slice into the RTP packet, and replaces an existing payload.
386 | //
387 | // Only SetPayload honors the Padding bit and pads the RTP packet to a multiple of the value specified
388 | // in SetPadding. SetPayload performs padding only if the payload length is greate zero. A payload of
389 | // zero length removes an existing payload including a possible padding
390 | func (rp *DataPacket) SetPayload(payload []byte) {
391 |
392 | payOffset := int(rp.CsrcCount()*4+rtpHeaderLength) + rp.ExtensionLength()
393 | payloadLenOld := rp.inUse - payOffset
394 |
395 | pad := 0
396 | padOffset := 0
397 | if rp.Padding() {
398 | // adjust payloadLenOld to honor padding length
399 | if payloadLenOld > rp.padTo {
400 | payloadLenOld += int(rp.buffer[rp.inUse])
401 | }
402 | // Reduce length of inUse by length of old content, thus remove old content
403 | rp.inUse -= payloadLenOld
404 | // Compute new padding length
405 | pad = (len(payload) + rp.inUse) % rp.padTo
406 | if pad == 0 {
407 | pad = rp.padTo
408 | }
409 | } else {
410 | // Reduce length of inUse by length of old content, thus remove old content
411 | rp.inUse -= payloadLenOld
412 | }
413 | if (payOffset + len(payload) + pad) > cap(rp.buffer) {
414 | return
415 | }
416 | rp.inUse += copy(rp.buffer[payOffset:], payload)
417 |
418 | if rp.Padding() && len(payload) > 0 {
419 | padOffset = payOffset + len(payload)
420 | for i := 0; i < pad-1; i++ {
421 | rp.buffer[padOffset] = 0
422 | padOffset++
423 | }
424 | rp.buffer[padOffset] = byte(pad)
425 | rp.inUse += pad
426 | }
427 | return
428 | }
429 |
430 | func (rp *DataPacket) IsValid() bool {
431 | if (rp.buffer[0] & versionMask) != version2Bit {
432 | return false
433 | }
434 | if PayloadFormatMap[int(rp.PayloadType())] == nil {
435 | return false
436 | }
437 | return true
438 | }
439 |
440 | // Print outputs a formatted dump of the RTP packet.
441 | func (rp *DataPacket) Print(label string) {
442 | fmt.Printf("RTP Packet at: %s\n", label)
443 | fmt.Printf(" fixed header dump: %s\n", hex.EncodeToString(rp.buffer[0:rtpHeaderLength]))
444 | fmt.Printf(" Version: %d\n", (rp.buffer[0]&0xc0)>>6)
445 | fmt.Printf(" Padding: %t\n", rp.Padding())
446 | fmt.Printf(" Extension: %t\n", rp.ExtensionBit())
447 | fmt.Printf(" Contributing SRCs: %d\n", rp.CsrcCount())
448 | fmt.Printf(" Marker: %t\n", rp.Marker())
449 | fmt.Printf(" Payload type: %d (0x%x)\n", rp.PayloadType(), rp.PayloadType())
450 | fmt.Printf(" Sequence number: %d (0x%x)\n", rp.Sequence(), rp.Sequence())
451 | fmt.Printf(" Timestamp: %d (0x%x)\n", rp.Timestamp(), rp.Timestamp())
452 | fmt.Printf(" SSRC: %d (0x%x)\n", rp.Ssrc(), rp.Ssrc())
453 |
454 | if rp.CsrcCount() > 0 {
455 | cscr := rp.CsrcList()
456 | fmt.Printf(" CSRC list:\n")
457 | for i, v := range cscr {
458 | fmt.Printf(" %d: %d (0x%x)\n", i, v, v)
459 | }
460 | }
461 | if rp.ExtensionBit() {
462 | extLen := rp.ExtensionLength()
463 | fmt.Printf(" Extentsion length: %d\n", extLen)
464 | offsetExt := rtpHeaderLength + int(rp.CsrcCount()*4)
465 | fmt.Printf(" extension: %s\n", hex.EncodeToString(rp.buffer[offsetExt:offsetExt+extLen]))
466 | }
467 | payOffset := rtpHeaderLength + int(rp.CsrcCount()*4) + rp.ExtensionLength()
468 | fmt.Printf(" payload: %s\n", hex.EncodeToString(rp.buffer[payOffset:rp.inUse]))
469 | }
470 |
471 | // *** RTCP specific funtions start here ***
472 |
473 | // RTCP packet type to define RTCP specific functions.
474 | type CtrlPacket struct {
475 | RawPacket
476 | }
477 |
478 | var freeListRtcp = make(chan *CtrlPacket, freeListLengthRtcp)
479 |
480 | // newCtrlPacket gets a raw packet, initializes the first fixed RTCP header, advances inUse to point after new fixed header.
481 | func newCtrlPacket() (rp *CtrlPacket, offset int) {
482 |
483 | // Grab a packet if available; allocate if not.
484 | select {
485 | case rp = <-freeListRtcp: // Got one; nothing more to do.
486 | default:
487 | rp = new(CtrlPacket) // None free, so allocate a new one.
488 | rp.buffer = make([]byte, defaultBufferSize)
489 | }
490 | rp.buffer[0] = version2Bit // RTCP: V = 2, P, RC = 0
491 | rp.inUse = rtcpHeaderLength
492 | offset = rtcpHeaderLength
493 | return
494 | }
495 |
496 | // addHeaderCtrl adds a new fixed RTCP header field into the compound, initializes, advances inUse to point after new fixed header.
497 | func (rp *CtrlPacket) addHeaderCtrl(offset int) int {
498 | rp.buffer[offset] = version2Bit // RTCP: V = 2, P, RC = 0
499 | rp.inUse += 4
500 | return rp.inUse
501 | }
502 |
503 | // addHeaderSsrc adds a SSRC header into the compound (usually after fixed header field), advances inUse to point after SSRC.
504 | func (rp *CtrlPacket) addHeaderSsrc(offset int, ssrc uint32) int {
505 | binary.BigEndian.PutUint32(rp.buffer[offset:], ssrc)
506 | rp.inUse += 4
507 | return rp.inUse
508 | }
509 |
510 | func (rp *CtrlPacket) FreePacket() {
511 | if rp.isFree {
512 | return
513 | }
514 | rp.buffer[0] = 0 // invalidate RTCP packet
515 | rp.inUse = 0
516 | rp.padTo = 0
517 | rp.fromAddr.CtrlPort = 0
518 | rp.fromAddr.IpAddr = nil
519 | rp.isFree = true
520 |
521 | select {
522 | case freeListRtcp <- rp: // Packet on free list; nothing more to do.
523 | default: // Free list full, just carry on.
524 | }
525 | }
526 |
527 | // SetSsrc converts SSRC from host order into network order and stores it in the RTCP as packet sender.
528 | func (rp *CtrlPacket) SetSsrc(offset int, ssrc uint32) {
529 | binary.BigEndian.PutUint32(rp.buffer[offset+ssrcOffsetRtcp:], ssrc)
530 | }
531 |
532 | // Ssrc returns the SSRC of the packet sender as uint32 in host order.
533 | func (rp *CtrlPacket) Ssrc(offset int) (ssrc uint32) {
534 | ssrc = binary.BigEndian.Uint32(rp.buffer[offset+ssrcOffsetRtcp:])
535 | return
536 | }
537 |
538 | // Count returns the counter bits in the word defined by offset.
539 | // Offset points to the first byte of the header word of a RTCP packet.
540 | func (rp *CtrlPacket) Count(offset int) int {
541 | return int(rp.buffer[offset] & countMask)
542 | }
543 |
544 | // SetCount returns the counter bits in the word defined by offset.
545 | // Offset points to the first byte of the header word of a RTCP packet.
546 | func (rp *CtrlPacket) SetCount(offset, count int) {
547 | rp.buffer[offset] |= byte(count & countMask)
548 | }
549 |
550 | // SetLength converts the length from host order into network order and stores it in the RTCP packet header.
551 | // Offset points to the first byte of the header word of a RTCP packet.
552 | func (rp *CtrlPacket) SetLength(offset int, length uint16) {
553 | binary.BigEndian.PutUint16(rp.buffer[offset+lengthOffset:], length)
554 | }
555 |
556 | // Length returns the length as uint16 in host order.
557 | // Offset points to the first byte of the header word of a RTCP packet.
558 | func (rp *CtrlPacket) Length(offset int) uint16 {
559 | return binary.BigEndian.Uint16(rp.buffer[offset+lengthOffset:])
560 | }
561 |
562 | // Type returns the report type stored in the header word.
563 | // Offset points to the first byte of the header word of a RTCP packet.
564 | func (rp *CtrlPacket) Type(offset int) int {
565 | return int(rp.buffer[offset+packetTypeOffset])
566 | }
567 |
568 | // SetType sets the report type in the header word.
569 | // Offset points to the first byte of the header word of a RTCP packet.
570 | func (rp *CtrlPacket) SetType(offset, packetType int) {
571 | rp.buffer[offset+packetTypeOffset] = byte(packetType)
572 | }
573 |
574 | type senderInfo []byte
575 | type recvReport []byte
576 | type sdesChunk []byte
577 | type byeData []byte
578 |
579 | /*
580 | * Functions to fill/access a sender info structure
581 | */
582 |
583 | // newSenderInfo returns a senderInfo which is positioned at the current inUse offet and advances inUse to point after senderInfo.
584 | func (rp *CtrlPacket) newSenderInfo() (info senderInfo, offset int) {
585 | info = rp.toSenderInfo(rp.inUse)
586 | rp.inUse += len(info)
587 | offset = rp.inUse
588 | return
589 | }
590 |
591 | // toSenderInfo returns the senderInfo byte slice inside the RTCP packet buffer as senderInfo type, used for received RTCP packets.
592 | // Use functions for this type to parse and access the senderInfo data.
593 | func (rp *CtrlPacket) toSenderInfo(offset int) senderInfo {
594 | return rp.buffer[offset : offset+senderInfoLen]
595 | }
596 |
597 | // ntpTimeStamp returns the NTP time stamp as second, fraction as unsigned 32bit in host order.
598 | func (in senderInfo) ntpTimeStamp() (seconds, fraction uint32) {
599 | seconds = binary.BigEndian.Uint32(in[0:])
600 | fraction = binary.BigEndian.Uint32(in[4:])
601 | return
602 | }
603 |
604 | // setNtpTimeStamp takes NTP timestamp values in host order and sets it in network order in SR.
605 | func (in senderInfo) setNtpTimeStamp(seconds, fraction uint32) {
606 | binary.BigEndian.PutUint32(in[0:], seconds)
607 | binary.BigEndian.PutUint32(in[4:], fraction)
608 | }
609 |
610 | // rtpTimeStamp returns the RTP time stamp as 32bit unsigned in host order.
611 | func (in senderInfo) rtpTimeStamp() uint32 {
612 | return binary.BigEndian.Uint32(in[8:])
613 | }
614 |
615 | // setRtpTimeStamp takes a 32 unsigned timestamp in host order and sets it in network order in SR.
616 | func (in senderInfo) setRtpTimeStamp(stamp uint32) {
617 | binary.BigEndian.PutUint32(in[8:], stamp)
618 | }
619 |
620 | // packetCount returns the sender's packet count as 32bit unsigned in host order.
621 | func (in senderInfo) packetCount() uint32 {
622 | return binary.BigEndian.Uint32(in[12:])
623 | }
624 |
625 | // setPacketCount takes a 32 unsigned counter in host order and sets it in network order in SR.
626 | func (in senderInfo) setPacketCount(cnt uint32) {
627 | binary.BigEndian.PutUint32(in[12:], cnt)
628 | }
629 |
630 | // octetCount returns the sender's octet count as 32bit unsigned in host order.
631 | func (in senderInfo) octetCount() uint32 {
632 | return binary.BigEndian.Uint32(in[16:])
633 | }
634 |
635 | // setOctetCount takes a 32 unsigned counter in host order and sets it in network order in SR.
636 | func (in senderInfo) setOctetCount(cnt uint32) {
637 | binary.BigEndian.PutUint32(in[16:], cnt)
638 | }
639 |
640 | /*
641 | * Functions to fill/access a receiver report structure
642 | */
643 |
644 | // newSenderInfo returns a senderInfo which is positioned at the current inUse offet and advances inUse to point after senderInfo.
645 | func (rp *CtrlPacket) newRecvReport() (report recvReport, offset int) {
646 | report = rp.toRecvReport(rp.inUse)
647 | rp.inUse += len(report)
648 | offset = rp.inUse
649 | return
650 | }
651 |
652 | // toRecvReport returns the report blocks byte slices inside the RTCP packet buffer as recvReport type.
653 | // Use functions for this type to parse and access the report blocks data.
654 | func (rp *CtrlPacket) toRecvReport(offset int) recvReport {
655 | return rp.buffer[offset : offset+reportBlockLen]
656 | }
657 |
658 | // ssrc returns the receiver report SSRC as 32bit unsigned in host order.
659 | func (rr recvReport) ssrc() uint32 {
660 | return binary.BigEndian.Uint32(rr[0:])
661 | }
662 |
663 | // setSSrc takes a 32 unsigned SSRC in host order and sets it in network order in RR.
664 | func (rr recvReport) setSsrc(ssrc uint32) {
665 | binary.BigEndian.PutUint32(rr[0:], ssrc)
666 | }
667 |
668 | // packetsLost returns the receiver report packets lost data as 32bit unsigned in host order.
669 | func (rr recvReport) packetsLost() uint32 {
670 | lost := binary.BigEndian.Uint32(rr[4:])
671 | return lost >> 8
672 | }
673 |
674 | // setPacketsLost takes a 32 unsigned packet lost number in host order and sets lower 24 bits in network order in RR.
675 | func (rr recvReport) setPacketsLost(pktLost uint32) {
676 | fracSave := rr[4]
677 | pktLost &= 0xffffff
678 | binary.BigEndian.PutUint32(rr[4:], pktLost)
679 | rr[4] = fracSave
680 | }
681 |
682 | // packetsLostFrac returns the receiver report packets lost fractional data as byte.
683 | func (rr recvReport) packetsLostFrac() byte {
684 | return rr[4]
685 | }
686 |
687 | // setPacketsLostFrac takes the byte packet lost fractional and sets it in RR.
688 | func (rr recvReport) setPacketsLostFrac(frac byte) {
689 | rr[4] = frac
690 | }
691 |
692 | // highestSeq returns the receiver report highest sequence number as 32bit unsigned in host order.
693 | func (rr recvReport) highestSeq() uint32 {
694 | return binary.BigEndian.Uint32(rr[8:])
695 | }
696 |
697 | // setHighestSeq takes a 32 unsigned sequence number in host order and sets it in network order in RR.
698 | func (rr recvReport) setHighestSeq(seq uint32) {
699 | binary.BigEndian.PutUint32(rr[8:], seq)
700 | }
701 |
702 | // jitter returns the receiver report jitter as 32bit unsigned in host order.
703 | func (rr recvReport) jitter() uint32 {
704 | return binary.BigEndian.Uint32(rr[12:])
705 | }
706 |
707 | // setJitter takes a 32 unsigned jitter value in host order and sets it in network order in RR.
708 | func (rr recvReport) setJitter(jitter uint32) {
709 | binary.BigEndian.PutUint32(rr[12:], jitter)
710 | }
711 |
712 | // lsr returns the receiver report LSR as 32bit unsigned in host order.
713 | func (rr recvReport) lsr() uint32 {
714 | return binary.BigEndian.Uint32(rr[16:])
715 | }
716 |
717 | // setLsr takes a 32 unsigned LSR value in host order and sets it in network order in RR.
718 | func (rr recvReport) setLsr(lsr uint32) {
719 | binary.BigEndian.PutUint32(rr[16:], lsr)
720 | }
721 |
722 | // dlsr returns the receiver report DLSR as 32bit unsigned in host order.
723 | func (rr recvReport) dlsr() uint32 {
724 | return binary.BigEndian.Uint32(rr[20:])
725 | }
726 |
727 | // setDlsr takes a 32 unsigned DLSR value in host order and sets it in network order in RR.
728 | func (rr recvReport) setDlsr(dlsr uint32) {
729 | binary.BigEndian.PutUint32(rr[20:], dlsr)
730 | }
731 |
732 | /*
733 | * Functions to fill/access a SDES structure
734 | */
735 |
736 | // newSdesChunk returns a SDES chunk which is positioned at the current inUse offet and advances inUse to point after sdesChunk.
737 | func (rp *CtrlPacket) newSdesChunk(length int) (chunk sdesChunk, offset int) {
738 | chunk = rp.toSdesChunk(rp.inUse, length)
739 | rp.inUse += len(chunk)
740 | offset = rp.inUse
741 | return
742 | }
743 |
744 | // toSdesChunk returns the SDES byte slices inside the RTCP packet buffer as sdesChunktype.
745 | // Use functions for this type to parse and access the report blocks data.
746 | func (rp *CtrlPacket) toSdesChunk(offset, length int) sdesChunk {
747 | if offset > len(rp.buffer) || offset+length > len(rp.buffer) {
748 | return nil
749 | }
750 | return rp.buffer[offset : offset+length]
751 | }
752 |
753 | // ssrc returns the receiver report SSRC as 32bit unsigned in host order.
754 | func (sdes sdesChunk) ssrc() uint32 {
755 | return binary.BigEndian.Uint32(sdes[0:])
756 | }
757 |
758 | // setSSrc takes a 32 unsigned SSRC in host order and sets it in network order in SDES chunk.
759 | func (sdes sdesChunk) setSsrc(ssrc uint32) {
760 | binary.BigEndian.PutUint32(sdes[0:], ssrc)
761 | }
762 |
763 | // setItemData takes the item type and the item text and fills it into the chunk.
764 | // The functions returns the offset where to store the next item.
765 | func (sdes sdesChunk) setItemData(itemOffset int, itemType byte, text string) int {
766 | sdes[itemOffset] = itemType
767 | sdes[itemOffset+1] = byte(len(text))
768 | return copy(sdes[itemOffset+2:], text) + 2
769 | }
770 |
771 | func (sdes sdesChunk) getItemType(itemOffset int) int {
772 | return int(sdes[itemOffset])
773 | }
774 |
775 | func (sdes sdesChunk) getItemLen(itemOffset int) int {
776 | return int(sdes[itemOffset+1])
777 | }
778 |
779 | func (sdes sdesChunk) getItemText(itemOffset, length int) string {
780 | if itemOffset+2+length > len(sdes) {
781 | return ""
782 | }
783 | return string(sdes[itemOffset+2 : itemOffset+2+length])
784 | }
785 |
786 | func (sc sdesChunk) chunkLen() (int, bool) {
787 |
788 | // length is at least: SSRC plus SdesEnd byte
789 | if 4+1 > len(sc) {
790 | return 0, false
791 | }
792 | length := 4 // include SSRC field of this chunk
793 | itemType := sc[length]
794 | if itemType == SdesEnd { // Cover case if chunk has zero items
795 | if 4+4 > len(sc) { // SSRC (4 byte), SdesEnd (1 byte) plus 3 bytes padding
796 | return 0, false
797 | }
798 | return 8, true
799 | }
800 | // Loop over valid items and add their overall length to offset.
801 | for ; itemType != SdesEnd; itemType = sc[length] {
802 | length += int(sc[length+1]) + 2 // lenght points to next item type field
803 | if length > len(sc) {
804 | return 0, false
805 | }
806 | }
807 | return (length + 4) &^ 0x3, true
808 | }
809 |
810 | // newByePacket returns a BYE data structure which is positioned at the current inUse offet and advances inUse to point after BYE.
811 | func (rp *CtrlPacket) newByeData(length int) (bye byeData, offset int) {
812 | bye = rp.toByeData(rp.inUse, length)
813 | rp.inUse += len(bye)
814 | offset = rp.inUse
815 | return
816 | }
817 |
818 | // toByePacket returns the BYE byte slices inside the RTCP packet buffer as byePacket type.
819 | // Use functions for this type to parse and access the BYE data.
820 | func (rp *CtrlPacket) toByeData(offset, length int) byeData {
821 | if offset > len(rp.buffer) || offset+length > len(rp.buffer) {
822 | return nil
823 | }
824 | return rp.buffer[offset : offset+length]
825 | }
826 |
827 | // ssrc returns the bye data SSRC at ssrcIdx as 32bit unsigned in host order.
828 | func (bye byeData) ssrc(ssrcIdx int) uint32 {
829 | if (ssrcIdx+1)*4 > len(bye) {
830 | return 0
831 | }
832 | return binary.BigEndian.Uint32(bye[ssrcIdx*4:])
833 | }
834 |
835 | // setSSrc takes a 32 unsigned SSRC in host order and sets it at ssrcIdx in bye data (network order).
836 | func (bye byeData) setSsrc(ssrcIdx int, ssrc uint32) {
837 | binary.BigEndian.PutUint32(bye[ssrcIdx*4:], ssrc)
838 | }
839 |
840 | // setReason takes reason text and fills it into the bye data after ssrcCnt SSRC/CSRC entries.
841 | // The functions returns the offset where to store the next item.
842 | func (bye byeData) setReason(reason string, ssrcCnt int) {
843 | bye[ssrcCnt*4] = byte(len(reason))
844 | copy(bye[ssrcCnt*4+1:], reason)
845 | }
846 |
847 | // getReason returns the reason string if it is available
848 | func (bye byeData) getReason(ssrcCnt int) string {
849 | offset := ssrcCnt * 4
850 | if offset >= len(bye) {
851 | return ""
852 | }
853 | length := int(bye[offset])
854 | offset++
855 | if offset+length > len(bye) {
856 | return ""
857 | }
858 | return string(bye[offset : offset+length])
859 | }
860 |
--------------------------------------------------------------------------------
/payload.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2011 Werner Dittmann
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU General Public License as published by
5 | // the Free Software Foundation, either version 3 of the License, or
6 | // (at your option) any later version.
7 | //
8 | // This program is distributed in the hope that it will be useful,
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with this program. If not, see .
15 | //
16 | // Authors: Werner Dittmann
17 | //
18 |
19 | package rtp
20 |
21 | // For full reference of registered RTP parameters and payload types refer to:
22 | // http://www.iana.org/assignments/rtp-parameters
23 |
24 | // Registry:
25 | // PT encoding name audio/video (A/V) clock rate (Hz) channels (audio) Reference
26 | // -------- -------------- ----------------- --------------- ---------------- ---------
27 | // 0 PCMU A 8000 1 [RFC3551]
28 | // 1 Reserved
29 | // 2 Reserved
30 | // 3 GSM A 8000 1 [RFC3551]
31 | // 4 G723 A 8000 1 [Kumar][RFC3551]
32 | // 5 DVI4 A 8000 1 [RFC3551]
33 | // 6 DVI4 A 16000 1 [RFC3551]
34 | // 7 LPC A 8000 1 [RFC3551]
35 | // 8 PCMA A 8000 1 [RFC3551]
36 | // 9 G722 A 8000 1 [RFC3551]
37 | // 10 L16 A 44100 2 [RFC3551]
38 | // 11 L16 A 44100 1 [RFC3551]
39 | // 12 QCELP A 8000 1 [RFC3551]
40 | // 13 CN A 8000 1 [RFC3389]
41 | // 14 MPA A 90000 [RFC3551][RFC2250]
42 | // 15 G728 A 8000 1 [RFC3551]
43 | // 16 DVI4 A 11025 1 [DiPol]
44 | // 17 DVI4 A 22050 1 [DiPol]
45 | // 18 G729 A 8000 1 [RFC3551]
46 | // 19 Reserved A
47 | // 20 Unassigned A
48 | // 21 Unassigned A
49 | // 22 Unassigned A
50 | // 23 Unassigned A
51 | // 24 Unassigned V
52 | // 25 CelB V 90000 [RFC2029]
53 | // 26 JPEG V 90000 [RFC2435]
54 | // 27 Unassigned V
55 | // 28 nv V 90000 [RFC3551]
56 | // 29 Unassigned V
57 | // 30 Unassigned V
58 | // 31 H261 V 90000 [RFC4587]
59 | // 32 MPV V 90000 [RFC2250]
60 | // 33 MP2T AV 90000 [RFC2250]
61 | // 34 H263 V 90000 [Zhu]
62 | // 35-71 Unassigned ?
63 | // 72-76 Reserved for RTCP conflict avoidance [RFC3551]
64 | // 77-95 Unassigned ?
65 | // 96-127 dynamic ? [RFC3551]
66 |
67 | const (
68 | Audio = 1
69 | Video = 2
70 | )
71 |
72 | // PayloadFormat holds RTP payload formats.
73 | //
74 | // The global variable PayloadFormatMap holds the well known payload formats
75 | // (see http://www.iana.org/assignments/rtp-parameters).
76 | // Applications shall not alter these predefined formats.
77 | //
78 | // If an application needs additional payload formats it must create and populate
79 | // PayloadFormat structures and insert them into PayloadFormatMap before setting
80 | // up the RTP communication. The index (key) into the map must be the payload
81 | // format number. For dynamic payload formats applications shall use payload
82 | // format numbers between 96 and 127 only.
83 | //
84 | // For example if a dynamic format uses the payload number 98 then the application
85 | // may perform:
86 | //
87 | // PayloadFormatMap[98] = &net.rtp.PayloadFormat{98, net.rtp.Audio, 41000, 2, "CD"}
88 | //
89 | type PayloadFormat struct {
90 | TypeNumber,
91 | MediaType,
92 | ClockRate,
93 | Channels int
94 | Name string
95 | }
96 | type payloadMap map[int]*PayloadFormat
97 |
98 | var PayloadFormatMap = make(payloadMap, 128)
99 |
100 | func init() {
101 | PayloadFormatMap[0] = &PayloadFormat{0, Audio, 8000, 1, "PCMU"}
102 | // 1 Reserved
103 | // 2 Reserved
104 | PayloadFormatMap[3] = &PayloadFormat{3, Audio, 8000, 1, "GSM"}
105 | PayloadFormatMap[4] = &PayloadFormat{4, Audio, 8000, 1, "G723"}
106 | PayloadFormatMap[5] = &PayloadFormat{5, Audio, 8000, 1, "DVI4"}
107 | PayloadFormatMap[6] = &PayloadFormat{6, Audio, 16000, 1, "DVI4"}
108 | PayloadFormatMap[7] = &PayloadFormat{7, Audio, 8000, 1, "LPC"}
109 | PayloadFormatMap[8] = &PayloadFormat{8, Audio, 8000, 1, "PCMA"}
110 | PayloadFormatMap[9] = &PayloadFormat{9, Audio, 8000, 1, "G722"}
111 | PayloadFormatMap[10] = &PayloadFormat{10, Audio, 44100, 2, "L16"}
112 | PayloadFormatMap[11] = &PayloadFormat{11, Audio, 44100, 1, "L16"}
113 | PayloadFormatMap[12] = &PayloadFormat{12, Audio, 8000, 1, "QCELP"}
114 | PayloadFormatMap[13] = &PayloadFormat{13, Audio, 8000, 1, "CN"}
115 | PayloadFormatMap[14] = &PayloadFormat{14, Audio, 90000, 0, "MPA"}
116 | PayloadFormatMap[15] = &PayloadFormat{15, Audio, 8000, 1, "G728"}
117 | PayloadFormatMap[16] = &PayloadFormat{16, Audio, 11025, 1, "DVI4"}
118 | PayloadFormatMap[17] = &PayloadFormat{17, Audio, 22050, 1, "DVI4"}
119 | PayloadFormatMap[18] = &PayloadFormat{18, Audio, 8000, 1, "G729"}
120 | // 19 Reserved A
121 | // 20 Unassigned A
122 | // 21 Unassigned A
123 | // 22 Unassigned A
124 | // 23 Unassigned A
125 | // 24 Unassigned V
126 | PayloadFormatMap[25] = &PayloadFormat{25, Video, 90000, 0, "CelB"}
127 | PayloadFormatMap[26] = &PayloadFormat{26, Video, 90000, 0, "JPEG"}
128 | // 27 Unassigned V
129 | PayloadFormatMap[28] = &PayloadFormat{28, Video, 90000, 0, "nv"}
130 | // 29 Unassigned V
131 | // 30 Unassigned V
132 | PayloadFormatMap[31] = &PayloadFormat{31, Video, 90000, 0, "H261"}
133 | PayloadFormatMap[32] = &PayloadFormat{32, Video, 90000, 0, "MPV"}
134 | PayloadFormatMap[33] = &PayloadFormat{33, Audio | Video, 90000, 0, "MP2T"}
135 | PayloadFormatMap[34] = &PayloadFormat{34, Video, 90000, 0, "H263"}
136 | // 35-71 Unassigned ?
137 | // 72-76 Reserved for RTCP conflict avoidance
138 | // 77-95 Unassigned ?
139 | // 96-127 dynamic ?
140 | PayloadFormatMap[96] = &PayloadFormat{96, Video, 90000, 0, "H264"}
141 | PayloadFormatMap[97] = &PayloadFormat{97, Audio, 90000, 0, "DYN1"}
142 | PayloadFormatMap[98] = &PayloadFormat{98, Audio, 90000, 0, "DYN2"}
143 | PayloadFormatMap[99] = &PayloadFormat{99, Audio, 90000, 0, "DYN3"}
144 | PayloadFormatMap[100] = &PayloadFormat{100, Audio, 90000, 0, "DYN4"}
145 | }
146 |
--------------------------------------------------------------------------------
/receive_test.go:
--------------------------------------------------------------------------------
1 | package rtp
2 |
3 | import (
4 | "net"
5 | "testing"
6 | "time"
7 | // "encoding/hex"
8 | // "fmt"
9 | )
10 |
11 | var rsRecv, rsSender *Session
12 |
13 | var recvPort = 5220
14 | var senderPort = 5222
15 | var senderAddr *net.IPAddr
16 | var dataReceiver DataReceiveChan
17 |
18 | func initSessions() {
19 | recvAddr, _ := net.ResolveIPAddr("ip", "127.0.0.1")
20 | senderAddr, _ = net.ResolveIPAddr("ip", "127.0.0.2")
21 |
22 | // Create a UDP transport with "local" address and use this for a "local" RTP session
23 | // Not used in these tests, used to initialize and get a Session
24 | tpRecv, _ := NewTransportUDP(recvAddr, recvPort)
25 |
26 | // TransportUDP implements RtpTransportWrite and RtpTransportRecv interfaces thus
27 | // set it in the RtpSession for both interfaces
28 | rsRecv = NewSession(tpRecv, tpRecv)
29 |
30 | // Create and store the data receive channel.
31 | dataReceiver = rsRecv.CreateDataReceiveChan()
32 |
33 | // Create a media stream.
34 | // The SSRC identifies the stream. Each stream has its own sequence number and other
35 | // context. A RTP session can have several RTP stream for example to send several
36 | // streams of the same media. Need an output stream to test for collisions/loops
37 | //
38 | strIdx, _ := rsRecv.NewSsrcStreamOut(&Address{recvAddr.IP, recvPort, recvPort + 1}, 0x01020304, 0x4711)
39 | rsRecv.SsrcStreamOutForIndex(strIdx).SetSdesItem(SdesCname, "AAAAAA")
40 | rsRecv.SsrcStreamOutForIndex(strIdx).SetPayloadType(0)
41 | rsRecv.rtcpServiceActive = true // to simulate an active RTCP service
42 |
43 | tpSender, _ := NewTransportUDP(senderAddr, senderPort)
44 | rsSender = NewSession(tpSender, tpSender)
45 | }
46 |
47 | func receivePacket(t *testing.T, num int) {
48 |
49 | select {
50 | case rp := <-dataReceiver: // just get a packet - maybe we add some tests later
51 | rp.FreePacket()
52 | default: // no packet - should not happen, report this
53 | t.Errorf("Unexpected case: data receiver channel is empty at %d.\n", num)
54 | }
55 | }
56 |
57 | // Create a RTP "sender" packet, no payload, just SSRC and address pair
58 | func newSenderPacket(stamp uint32) (rp *DataPacket) {
59 | rp = rsSender.NewDataPacket(stamp)
60 |
61 | // initialize with "sender" address to enable all necessary checks
62 | rp.fromAddr.IpAddr = senderAddr.IP
63 | rp.fromAddr.DataPort = senderPort
64 | rp.fromAddr.CtrlPort = 0
65 | return
66 | }
67 |
68 | // The following tests are really white box tests - they check internal variables, manipulate
69 | // internal variables to get the expected results.
70 |
71 | func rtpReceive(t *testing.T) {
72 | // ******************** New session setup to have fresh data ***************************
73 | initSessions()
74 |
75 | pay := make([]byte, 160)
76 | // Create a RTP "sender" stream, with defined SSRC, sequence and payload type (PCMU in this case)
77 | // The defined sequence number (maxDropout-1) tests one path of sequence number initialization for
78 | // the input stream.
79 | seqNum := uint16(maxDropout - 1)
80 | strIdx, _ := rsSender.NewSsrcStreamOut(&Address{senderAddr.IP, senderPort, senderPort + 1}, 0x04030201, seqNum)
81 | strOut := rsSender.SsrcStreamOutForIndex(strIdx)
82 | strOut.SetPayloadType(0)
83 |
84 | // Test the SDES management stuff
85 | strOut.SetSdesItem(SdesCname, "AAAAAA")
86 | strOut.SetSdesItem(SdesEmail, "BBBBBBB")
87 | if strOut.sdesChunkLen != 24 { // Chunk length does not include SDES header (4 bytes)
88 | t.Errorf("SDES chunk length check 1 failed. Expected: 24, got: %d\n", strOut.sdesChunkLen)
89 | return
90 | }
91 | strOut.SetSdesItem(SdesEmail, "BBBBBB") // reset e-mail name, on char less, total length must stay (padding)
92 | if strOut.sdesChunkLen != 24 {
93 | t.Errorf("SDES chunk length check 2 failed. Expected: 24, got: %d\n", strOut.sdesChunkLen)
94 | return
95 | }
96 | rpSender := newSenderPacket(160)
97 | rpSender.SetPayload(pay)
98 |
99 | // Feed into receiver session, then check if packet was processed correctly
100 | rsRecv.OnRecvData(rpSender)
101 |
102 | // Expect one new input stream with SSRC and address of sender packet
103 | idx := rsRecv.streamInIndex
104 | if idx != 1 {
105 | t.Errorf("StreamIn index check failed. Expected: 1, got: %d\n", idx)
106 | return
107 | }
108 | // get the new (default) input stream
109 | strIn := rsRecv.SsrcStreamIn()
110 | ssrc := strIn.Ssrc()
111 | if ssrc != 0x04030201 {
112 | t.Errorf("StreamIn SSRC check failed. Expected: 0x04030201, got: %x\n", ssrc)
113 | return
114 | }
115 | maxSeq := strIn.statistics.maxSeqNum
116 | if maxSeq != seqNum {
117 | t.Errorf("First maxSeqNum check failed. Expected: %d, got: %d\n", seqNum, maxSeq)
118 | return
119 | }
120 | badSeq := strIn.statistics.badSeqNum
121 | if badSeq != seqNumMod+1 {
122 | t.Errorf("First badSeqNum check failed. Expected: 0x%x, got: 0x%x\n", seqNumMod+1, badSeq)
123 | return
124 | }
125 | receivePacket(t, 0)
126 |
127 | // The 20/15ms sleeps simulate a jitter at the receiver's end. The expected jitter range takes some
128 | // additional delays into account. "go thread" switching introduces additional delays
129 | time.Sleep(20e6)
130 |
131 | rpSender = newSenderPacket(320)
132 | seqNum++
133 | rsRecv.OnRecvData(rpSender)
134 | receivePacket(t, 1)
135 | time.Sleep(15e6)
136 |
137 | rpSender = newSenderPacket(480)
138 | seqNum++
139 | rsRecv.OnRecvData(rpSender)
140 | receivePacket(t, 2)
141 | time.Sleep(20e6)
142 |
143 | rpSender = newSenderPacket(640)
144 | seqNum++
145 | rsRecv.OnRecvData(rpSender)
146 | receivePacket(t, 3)
147 | time.Sleep(15e6)
148 |
149 | rpSender = newSenderPacket(800)
150 | seqNum++
151 | rsRecv.OnRecvData(rpSender)
152 | receivePacket(t, 4)
153 | time.Sleep(20e6)
154 |
155 | rpSender = newSenderPacket(960)
156 | seqNum++
157 | rsRecv.OnRecvData(rpSender)
158 |
159 | maxSeq = strIn.statistics.maxSeqNum
160 | if maxSeq != seqNum {
161 | t.Errorf("Second maxSeqNum check failed. Expected: %d, got: %d\n", seqNum, maxSeq)
162 | return
163 | }
164 | badSeq = strIn.statistics.badSeqNum
165 | if badSeq != seqNumMod+1 {
166 | t.Errorf("Second badSeqNum check failed. Expected: 0x%x, got: 0x%x\n", seqNumMod+1, badSeq)
167 | return
168 | }
169 | jitter := strIn.statistics.jitter >> 4
170 | if jitter <= 0 && jitter > 10 {
171 | t.Errorf("Jitter test failed. Expected jitter range: 0 < jitter < 10, got: %d\n", jitter)
172 | return
173 | }
174 | receivePacket(t, 5)
175 |
176 | // Create a RTCP packet and fill in senderInfo of the output stream
177 | rcTime, offset := strOut.newCtrlPacket(RtcpSR)
178 | rcTime.addHeaderSsrc(offset, strOut.Ssrc())
179 |
180 | newInfo, _ := rcTime.newSenderInfo()
181 | strOut.fillSenderInfo(newInfo) // create a sender info block after fixed header and SSRC.
182 |
183 | // the above jitter test took 90ms. Thus the difference between session start and now is about 90ms and
184 | // the RTP timestamp should be 720 units for the selected payload (PCMU, 8000Hz). To get this we have
185 | // to subtract the random initial timestamp.
186 | tm := time.Now().UnixNano()
187 | info := rcTime.toSenderInfo(rtcpHeaderLength + rtcpSsrcLength)
188 | stamp := info.rtpTimeStamp() - strOut.initialStamp
189 |
190 | if stamp != 720 {
191 | t.Logf("rtpTimeStamp test out of range - logged only. Expected rtpTimeStamp: 720, got: %d\n", stamp)
192 | }
193 | high, low := info.ntpTimeStamp()
194 | tm1 := fromNtp(high, low)
195 | diff := tm - tm1
196 | // check if it is in a reasonable range. Take some thread switching into account. tm1 must be smaller than
197 | // tm because tm was taken after makeSenderInfo that computes the timestamp in the senderInfo.
198 | if diff > 30000 {
199 | t.Errorf("NTP time check in senderInfo failed. Expected range: +30000, got: %d\n", diff)
200 | return
201 | }
202 |
203 | // Create a RTCP compound packet that will contain: one RTCP header, one recvReport, one SDES with
204 | // chunk length 28 which gives a compound total of 8 + 24 + 28 = 60 bytes
205 |
206 | // First get a new ctrl packet and initialize it so that we can "send" it to some internal "receiver" methods.
207 |
208 | // Set the receiver as "sender" as well, thus we will have a senderInfo part in the packet as well
209 | rsRecv.streamsOut[0].sender = true
210 |
211 | // build a RTCP packet for the standard output stream
212 | rcSender := rsRecv.buildRtcpPkt(rsRecv.SsrcStreamOut(), 31)
213 |
214 | rcSender.fromAddr.IpAddr = senderAddr.IP
215 | rcSender.fromAddr.DataPort = 0
216 | rcSender.fromAddr.CtrlPort = senderPort + 1
217 |
218 | // *** fmt.Printf("1st Ctrl buffer: %s\n", hex.EncodeToString(rcSender.buffer[:rcSender.InUse()]))
219 | rcTotalLength := rcSender.InUse()
220 | if rcTotalLength != rtcpHeaderLength+rtcpSsrcLength+senderInfoLen+reportBlockLen+20 { // 20: SDES header plus SDES chunk
221 | t.Errorf("rcSender packet length check failed. Expected: %d, got: %d\n",
222 | rtcpHeaderLength+rtcpSsrcLength+senderInfoLen+reportBlockLen+20, rcTotalLength)
223 | return
224 | }
225 | if !rsRecv.OnRecvCtrl(rcSender) {
226 | t.Errorf("OnRecvCtrl failed for RTCP packet.\n")
227 | return
228 | }
229 | // Need to perform a lookup here: with the last OnRecvCtrl we have produced a collision. Now the receiver has two
230 | // input streams: one with 0x04030201 and one with 0x01020304. This happened because, for this test,
231 | // we have produced the control packet from the receiver session and fed that packet into the receiver.
232 | // The receiver now has a newly initialized output stream (one only) with new random SSRC and sequence numbers.
233 |
234 | if rsRecv.streamInIndex != 2 {
235 | t.Errorf("Input stream index check failed. Expected: 2, got: %d\n", rsRecv.streamInIndex)
236 | return
237 | }
238 | if rsRecv.streamOutIndex != 1 {
239 | t.Errorf("Output stream index check failed. Expected: 1, got: %d\n", rsRecv.streamOutIndex)
240 | return
241 | }
242 | // lookup and get the new input stream and check if SDES was parsed correctly
243 | inx, _, _ := rsRecv.lookupSsrcMapIn(rcSender.Ssrc(0))
244 | if inx.SdesItems[SdesCname] != "AAAAAA" {
245 | t.Errorf("SDES chunk parsing failed. Expected: 'AAAAAA', got: %s\n", strIn.SdesItems[SdesCname])
246 | return
247 | }
248 |
249 | // Now set sender to false, only RR packet plus SDES
250 | rsRecv.streamsOut[0].sender = false
251 | rsRecv.streamsOut[0].streamStatus = active // just to pass the active check during onRecvCtrl()
252 |
253 | rsRecv.streamsIn[0].dataAfterLastReport = true // just to simulate received RTP data to generate correct RR
254 |
255 | rcSender = rsRecv.buildRtcpPkt(rsRecv.SsrcStreamOut(), 31)
256 |
257 | rcSender.fromAddr.IpAddr = senderAddr.IP
258 | rcSender.fromAddr.DataPort = 0
259 | rcSender.fromAddr.CtrlPort = senderPort + 3 // just to avoid an addtional conflict - but collosion will happen
260 |
261 | // *** fmt.Printf("2nd Ctrl buffer: %s\n", hex.EncodeToString(rcSender.buffer[:rcSender.InUse()]))
262 | rcTotalLength = rcSender.InUse()
263 |
264 | // we have still have 1 receiver report here because the second receiver generated (see test above) never
265 | // sent an RTP packet, thus is not included in RR
266 | if rcTotalLength != rtcpHeaderLength+rtcpSsrcLength+reportBlockLen+20 { // 20: SDES header plus SDES chunk
267 | t.Errorf("rcSender packet length check failed. Expected: %d, got: %d\n",
268 | rtcpHeaderLength+rtcpSsrcLength+reportBlockLen+20, rcTotalLength)
269 | return
270 | }
271 | if !rsRecv.OnRecvCtrl(rcSender) {
272 | t.Errorf("OnRecvCtrl failed for RTCP packet.\n")
273 | return
274 | }
275 | // Need to perform a lookup here: with this test we have produced another collision. Now the receiver has three
276 | // input streams: one with 0x04030201, one with 0x01020304, one with random SSRC (see test above). This
277 | // happened because, for this test, we have produced the control packet from the receiver session and fed that
278 | // packet into the receiver.
279 | // The receiver now again has a newly initialized output stream (one only) with new random SSRC and sequence numbers.
280 |
281 | if rsRecv.streamInIndex != 3 {
282 | t.Errorf("Input stream index check failed. Expected: 3, got: %d\n", rsRecv.streamInIndex)
283 | return
284 | }
285 | if rsRecv.streamOutIndex != 1 {
286 | t.Errorf("Output stream index check failed. Expected: 1, got: %d\n", rsRecv.streamOutIndex)
287 | return
288 | }
289 | // lookup and get the new input stream and check if SDES was parsed correctly
290 | inx, _, _ = rsRecv.lookupSsrcMapIn(rcSender.Ssrc(0))
291 | if inx.SdesItems[SdesCname] != "AAAAAA" {
292 | t.Errorf("SDES chunk parsing failed. Expected: 'AAAAAA', got: %s\n", strIn.SdesItems[SdesCname])
293 | return
294 | }
295 | // The receiver has three input streams: one with 0x04030201, one with 0x01020304, one with random
296 | // SSRC (see test above) - the latest one with random SSRC is ommited from receiver reports because
297 | // it was no "active", neither sent or received a packet
298 |
299 | rcSender = rsRecv.buildRtcpByePkt(rsRecv.SsrcStreamOut(), "CCCCCC")
300 | rcTotalLength = rcSender.InUse()
301 | // *** fmt.Printf("3rd Ctrl buffer: %s\n", hex.EncodeToString(rcSender.buffer[:rcSender.InUse()]))
302 |
303 | // BYE packet has empty RR; 20: SDES header plus SDES chunk; 16: BYE RTCP packet
304 | if rcTotalLength != rtcpHeaderLength+rtcpSsrcLength+20+16 {
305 | t.Errorf("rcSender packet length check failed. Expected: %d, got: %d\n",
306 | rtcpHeaderLength+rtcpSsrcLength+20+16, rcTotalLength)
307 | return
308 | }
309 |
310 | // ******************** New session setup to have fresh data ***************************
311 | initSessions()
312 | // Create a RTP "sender" stream, with defined SSRC, sequence and payload type. Define the sequence number to
313 | // check second if-path when initalizing the sequence number for input stream
314 | seqNum = uint16(maxDropout)
315 | strIdx, _ = rsSender.NewSsrcStreamOut(&Address{senderAddr.IP, senderPort, senderPort + 1}, 0x04030201, seqNum)
316 | strOut = rsSender.SsrcStreamOutForIndex(strIdx)
317 | strOut.SetPayloadType(0)
318 |
319 | rpSender = newSenderPacket(160)
320 | rsRecv.OnRecvData(rpSender)
321 | receivePacket(t, 6)
322 |
323 | strIn = rsRecv.SsrcStreamIn()
324 | maxSeq = strIn.statistics.maxSeqNum
325 | if maxSeq != seqNum {
326 | t.Errorf("Third maxSeqNum check failed. Expected: %d, got: %d\n", seqNum, maxSeq)
327 | return
328 | }
329 | badSeq = strIn.statistics.badSeqNum
330 | if badSeq != uint32(seqNum+1) {
331 | t.Errorf("Third badSeqNum check failed. Expected: %d, got: %d\n", seqNum+1, badSeq)
332 | return
333 | }
334 |
335 | // After receiving a packet with a sequence number "maxDropout" now simulate a large step in the sequence
336 | // number. Expected result: the old sequence nummber (maxSeq) stays, badSeq is the new (higher) sequence plus one
337 | rpSender = newSenderPacket(160)
338 |
339 | // Force a large jump in sequence number which causes the receiver to drop this packet, so don't try to receive it.
340 | seqNum = uint16(maxDropout * 2)
341 | rpSender.SetSequence(seqNum)
342 | rsRecv.OnRecvData(rpSender)
343 | // receivePacket(t, 7)
344 |
345 | maxSeq = strIn.statistics.maxSeqNum
346 | if maxSeq != maxDropout {
347 | t.Errorf("Forth maxSeqNum check failed. Expected: %d, got: %d\n", maxDropout, maxSeq)
348 | return
349 | }
350 | badSeq = strIn.statistics.badSeqNum
351 | if badSeq != uint32(seqNum+1) {
352 | t.Errorf("Forth badSeqNum check failed. Expected: %d, got: %d\n", seqNum+1, badSeq)
353 | return
354 | }
355 |
356 | // Now send a packet which is in sequence to the first (lower, maxDropout+1) sequence. This simluates
357 | // a lingering RTP packet after the sender switched to new higher sequence numbers.
358 | // Expected result: sequence nummber maxSeq is maxDropout+1, badSeq is the new (higer) sequence plus one
359 | rpSender = newSenderPacket(160)
360 | seqNum = uint16(maxDropout + 1)
361 | rpSender.SetSequence(seqNum)
362 | rsRecv.OnRecvData(rpSender)
363 | receivePacket(t, 8)
364 |
365 | maxSeq = strIn.statistics.maxSeqNum
366 | if maxSeq != maxDropout+1 {
367 | t.Errorf("Fifth maxSeqNum check failed. Expected: %d, got: %d\n", maxDropout+1, maxSeq)
368 | return
369 | }
370 | badSeq = strIn.statistics.badSeqNum
371 | if badSeq != 2*maxDropout+1 {
372 | t.Errorf("Fifth badSeqNum check failed. Expected: %d, got: %d\n", 2*maxDropout+1, badSeq)
373 | return
374 | }
375 | // Now send a packet which is in sequence with the new higher (maxDropout*2+1) sequence. This simluates
376 | // a RTP packet in sequence after the sender switched to new higher sequence numbers
377 | // Expected result: sequence nummber maxSeq is maxDropout*2+1, badSeq is seqNumMod + 1, a resync happened
378 | rpSender = newSenderPacket(160)
379 | seqNum = uint16(maxDropout*2 + 1)
380 | rpSender.SetSequence(seqNum)
381 | rsRecv.OnRecvData(rpSender)
382 | receivePacket(t, 9)
383 |
384 | maxSeq = strIn.statistics.maxSeqNum
385 | if maxSeq != seqNum {
386 | t.Errorf("Sixth maxSeqNum check failed. Expected: %d, got: %d\n", seqNum, maxSeq)
387 | return
388 | }
389 | badSeq = strIn.statistics.badSeqNum
390 | if badSeq != seqNumMod+1 {
391 | t.Errorf("Sixth badSeqNum check failed. Expected: %d, got: %d\n", seqNumMod+1, badSeq)
392 | return
393 | }
394 |
395 | // ******************** New session setup to have fresh data ***************************
396 | initSessions()
397 | // Create a RTP "sender" stream, with defined SSRC, sequence and payload type. Define the sequence number to
398 | // enable checks if sequence number wraps. First use a sequence number near wrap but small enough to go through
399 | // the initial tests
400 | seqNum = uint16(seqNumMod - maxMisorder - 2)
401 | strIdx, _ = rsSender.NewSsrcStreamOut(&Address{senderAddr.IP, senderPort, senderPort + 1}, 0x04030201, seqNum)
402 | strOut = rsSender.SsrcStreamOutForIndex(strIdx)
403 | strOut.SetPayloadType(0)
404 |
405 | rpSender = newSenderPacket(160)
406 | rsRecv.OnRecvData(rpSender)
407 | receivePacket(t, 10)
408 |
409 | strIn = rsRecv.SsrcStreamIn()
410 | maxSeq = strIn.statistics.maxSeqNum
411 | if maxSeq != seqNum {
412 | t.Errorf("Seventh maxSeqNum check failed. Expected: %d, got: %d\n", seqNum, maxSeq)
413 | return
414 | }
415 | badSeq = strIn.statistics.badSeqNum
416 | if badSeq != uint32(seqNum+1) {
417 | t.Errorf("Seventh badSeqNum check failed. Expected: %d, got: %d\n", seqNum+1, badSeq)
418 | return
419 | }
420 | rpSender = newSenderPacket(160)
421 |
422 | // Now step up sequence number near wrapping value (2^16-1), this step is small, thus it is considered "in sequence"
423 | // and badSeqNum will not change from its value above
424 | seqNum = uint16(seqNumMod - 1)
425 | rpSender.SetSequence(seqNum)
426 | rsRecv.OnRecvData(rpSender)
427 | receivePacket(t, 11)
428 |
429 | strIn = rsRecv.SsrcStreamIn()
430 | maxSeq = strIn.statistics.maxSeqNum
431 | if maxSeq != seqNum {
432 | t.Errorf("Eighth maxSeqNum check failed. Expected: %d, got: %d\n", seqNum, maxSeq)
433 | return
434 | }
435 | rpSender = newSenderPacket(160)
436 |
437 | // Now step up sequence number so it wraps from 2^16-1 to 2^16 (i.e. 0), it is considered "in sequence" and
438 | // the sequence numbers will wrap to 0, the warp-counter (accum) is enhanced by seqNumMod (was zero in this case)
439 | seqNum++
440 | rpSender.SetSequence(seqNum)
441 | rsRecv.OnRecvData(rpSender)
442 | receivePacket(t, 12)
443 |
444 | strIn = rsRecv.SsrcStreamIn()
445 | maxSeq = strIn.statistics.maxSeqNum
446 | if maxSeq != seqNum {
447 | t.Errorf("Nineth maxSeqNum check failed. Expected: %d, got: %d\n", seqNum, maxSeq)
448 | return
449 | }
450 | accu := strIn.statistics.seqNumAccum
451 | if accu != seqNumMod {
452 | t.Errorf("Sequence number wrapping check failed. Expected: %d, got: %d\n", seqNumMod, accu)
453 | return
454 | }
455 | select {
456 | case <-dataReceiver: // Here we have a lingering packet.
457 | t.Errorf("Unexpected packet received after all tests done.\n")
458 | default: // no packet - should not happen, report this
459 | }
460 | }
461 |
462 | func TestReceive(t *testing.T) {
463 | parseFlags()
464 | rtpReceive(t)
465 | }
466 |
--------------------------------------------------------------------------------
/rtpmain/rtpmain.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2011 Werner Dittmann
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU General Public License as published by
5 | // the Free Software Foundation, either version 3 of the License, or
6 | // (at your option) any later version.
7 | //
8 | // This program is distributed in the hope that it will be useful,
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with this program. If not, see .
15 | //
16 | // Authors: Werner Dittmann
17 | //
18 |
19 | package main
20 |
21 | import (
22 | // "encoding/hex"
23 | "fmt"
24 | "net"
25 | "time"
26 |
27 | "github.com/antongulenko/gortp"
28 | )
29 |
30 | var localPort = 5220
31 | var local, _ = net.ResolveIPAddr("ip", "127.0.0.1")
32 |
33 | var remotePort = 5222
34 | var remote, _ = net.ResolveIPAddr("ip", "127.0.0.1")
35 |
36 | var rsLocal *rtp.Session
37 | var rsRemote *rtp.Session
38 |
39 | var localPay [160]byte
40 | var remotePay [160]byte
41 |
42 | var stop bool
43 | var stopLocalRecv chan bool
44 | var stopRemoteRecv chan bool
45 | var stopLocalCtrl chan bool
46 | var stopRemoteCtrl chan bool
47 |
48 | var eventNamesNew = []string{"NewStreamData", "NewStreamCtrl"}
49 | var eventNamesRtcp = []string{"SR", "RR", "SDES", "BYE"}
50 |
51 | // Create a RTP packet suitable for standard stream (index 0) with a payload length of 160 bytes
52 | // The method initializes the RTP packet with SSRC, sequence number, and RTP version number.
53 | // If the payload type was set with the RTP stream then the payload type is also set in
54 | // the RTP packet
55 | func sendLocalToRemote() {
56 |
57 | var cnt int
58 | stamp := uint32(0)
59 | for !stop {
60 | rp := rsLocal.NewDataPacket(stamp)
61 | rp.SetPayload(localPay[:])
62 | rsLocal.WriteData(rp)
63 | rp.FreePacket()
64 | if (cnt % 50) == 0 {
65 | fmt.Printf("Local sent %d packets\n", cnt)
66 | }
67 | cnt++
68 | stamp += 160
69 | time.Sleep(20e6)
70 | }
71 | }
72 |
73 | func sendLocalToRemoteIdx(index uint32) {
74 |
75 | var cnt int
76 | stamp := uint32(0)
77 | for !stop {
78 | rp := rsLocal.NewDataPacketForStream(index, stamp)
79 | rp.SetPayload(localPay[:])
80 | rsLocal.WriteData(rp)
81 | rp.FreePacket()
82 | if (cnt % 50) == 0 {
83 | fmt.Printf("Local with index sent %d packets\n", cnt)
84 | }
85 | cnt++
86 | stamp += 160
87 | time.Sleep(20e6)
88 | }
89 | }
90 |
91 | func sendRemoteToLocal() {
92 |
93 | var cnt int
94 | stamp := uint32(0)
95 | for !stop {
96 | rp := rsRemote.NewDataPacket(stamp)
97 | rp.SetPayload(remotePay[:])
98 | rsRemote.WriteData(rp)
99 | rp.FreePacket()
100 | if (cnt % 50) == 0 {
101 | fmt.Printf("Remote sent %d packets\n", cnt)
102 | }
103 | cnt++
104 | stamp += 160
105 | time.Sleep(20e6)
106 | }
107 | }
108 |
109 | func receivePacketLocal() {
110 | // Create and store the data receive channel.
111 | dataReceiver := rsLocal.CreateDataReceiveChan(128)
112 | var cnt int
113 |
114 | for {
115 | select {
116 | case rp := <-dataReceiver: // just get a packet - maybe we add some tests later
117 | if (cnt % 50) == 0 {
118 | fmt.Printf("Remote receiver got %d packets\n", cnt)
119 | }
120 | cnt++
121 | rp.FreePacket()
122 | case <-stopLocalRecv:
123 | return
124 | }
125 | }
126 | }
127 |
128 | func receivePacketRemote() {
129 | // Create and store the data receive channel.
130 | dataReceiver := rsRemote.CreateDataReceiveChan(128)
131 | var cnt int
132 |
133 | for {
134 | select {
135 | case rp := <-dataReceiver: // just get a packet - maybe we add some tests later
136 | if (cnt % 50) == 0 {
137 | fmt.Printf("Remote receiver got: %d packets\n", cnt)
138 | }
139 | cnt++
140 | rp.FreePacket()
141 | case <-stopRemoteRecv:
142 | return
143 | }
144 | }
145 | }
146 |
147 | func receiveCtrlLocal() {
148 | // Create and store the control event channel.
149 | ctrlReceiver := rsLocal.CreateCtrlEventChan(3)
150 | for {
151 | select {
152 | case evSlice := <-ctrlReceiver: // get an event
153 | fmt.Println("Local: Length of event slice:", len(evSlice))
154 | for _, event := range evSlice {
155 | if event != nil {
156 | var eventName string
157 | if event.EventType < 200 {
158 | eventName = eventNamesNew[event.EventType]
159 | } else {
160 | eventName = eventNamesRtcp[event.EventType-200]
161 | }
162 | fmt.Printf("Local: received ctrl event, type: %s, ssrc: %d, %s\n", eventName, event.Ssrc, event.Reason)
163 | } else {
164 | fmt.Println("Local: unexpected nil event")
165 | }
166 | }
167 | case <-stopLocalCtrl:
168 | return
169 | }
170 | }
171 | }
172 |
173 | func receiveCtrlRemote() {
174 | // Create and store the control event channel.
175 | ctrlReceiver := rsRemote.CreateCtrlEventChan(3)
176 | for {
177 | select {
178 | case evSlice := <-ctrlReceiver: // get an event
179 | fmt.Println("Remote: Length of event slice:", len(evSlice))
180 | for _, event := range evSlice {
181 | if event != nil {
182 | var eventName string
183 | if event.EventType < 200 {
184 | eventName = eventNamesNew[event.EventType]
185 | } else {
186 | eventName = eventNamesRtcp[event.EventType-200]
187 | }
188 | fmt.Printf("Remote: received ctrl event, type: %s, ssrc: %d, %s\n", eventName, event.Ssrc, event.Reason)
189 | } else {
190 | fmt.Println("Remote: unexpected nil event")
191 | }
192 | }
193 | case <-stopRemoteCtrl:
194 | return
195 | }
196 | }
197 | }
198 |
199 | func initialize() {
200 | // Some initialization for payload byte arrays
201 | for i := range localPay {
202 | localPay[i] = byte(i)
203 | }
204 | for i := range remotePay {
205 | remotePay[i] = byte(len(remotePay) - i)
206 | }
207 | stopLocalRecv = make(chan bool, 1)
208 | stopRemoteRecv = make(chan bool, 1)
209 | stopLocalCtrl = make(chan bool, 1)
210 | stopRemoteCtrl = make(chan bool, 1)
211 | }
212 |
213 | func fullDuplex() {
214 | fmt.Println("Starting full duplex test.")
215 |
216 | // Create a UDP transport with "local" address and use this for a "local" RTP session
217 | // The RTP session uses the transport to receive and send RTP packets to the remote peer.
218 | tpLocal, _ := rtp.NewTransportUDP(local, localPort)
219 |
220 | // TransportUDP implements TransportWrite and TransportRecv interfaces thus
221 | // use it to initialize the Session for both interfaces.
222 | rsLocal = rtp.NewSession(tpLocal, tpLocal)
223 |
224 | // Add address of a remote peer (participant)
225 | rsLocal.AddRemote(&rtp.Address{remote.IP, remotePort, remotePort + 1})
226 |
227 | // Create a media stream.
228 | // The SSRC identifies the stream. Each stream has its own sequence number and other
229 | // context. A RTP session can have several RTP stream for example to send several
230 | // streams of the same media.
231 | //
232 | strLocalIdx, _ := rsLocal.NewSsrcStreamOut(&rtp.Address{local.IP, localPort, localPort + 1}, 1020304, 4711)
233 | rsLocal.SsrcStreamOutForIndex(strLocalIdx).SetPayloadType(0)
234 |
235 | // Create the same set for a "remote" peer and use the "local" as its remote peer
236 | tpRemote, _ := rtp.NewTransportUDP(remote, remotePort)
237 | rsRemote = rtp.NewSession(tpRemote, tpRemote)
238 | rsRemote.AddRemote(&rtp.Address{local.IP, localPort, localPort + 1})
239 |
240 | strRemoteIdx, _ := rsRemote.NewSsrcStreamOut(&rtp.Address{remote.IP, remotePort, remotePort + 1}, 4030201, 815)
241 | rsRemote.SsrcStreamOutForIndex(strRemoteIdx).SetPayloadType(0)
242 |
243 | go receivePacketLocal()
244 | go receivePacketRemote()
245 |
246 | go receiveCtrlLocal()
247 | go receiveCtrlRemote()
248 |
249 | rsLocal.StartSession()
250 | rsRemote.StartSession()
251 |
252 | go sendLocalToRemote()
253 | go sendRemoteToLocal()
254 |
255 | time.Sleep(8e9)
256 |
257 | stop = true
258 | time.Sleep(30e6) // allow the sender to drain
259 |
260 | stopRemoteRecv <- true
261 | stopLocalRecv <- true
262 | stopRemoteCtrl <- true
263 | stopLocalCtrl <- true
264 |
265 | rsLocal.CloseSession()
266 | rsRemote.CloseSession()
267 |
268 | time.Sleep(10e6)
269 |
270 | fmt.Println("Full duplex test done.")
271 | }
272 |
273 | func fullDuplexTwoStreams() {
274 | fmt.Println("Starting full duplex test with two output streams from local to remote.")
275 |
276 | // Create a UDP transport with "local" address and use this for a "local" RTP session
277 | // The RTP session uses the transport to receive and send RTP packets to the remote peer.
278 | tpLocal, _ := rtp.NewTransportUDP(local, localPort)
279 |
280 | // TransportUDP implements TransportWrite and TransportRecv interfaces thus
281 | // use it to initialize the Session for both interfaces.
282 | rsLocal = rtp.NewSession(tpLocal, tpLocal)
283 |
284 | // Add address of a remote peer (participant)
285 | rsLocal.AddRemote(&rtp.Address{remote.IP, remotePort, remotePort + 1})
286 |
287 | // Create a media stream.
288 | // The SSRC identifies the stream. Each stream has its own sequence number and other
289 | // context. A RTP session can have several RTP stream for example to send several
290 | // streams of the same media.
291 | //
292 | strLocalIdx, _ := rsLocal.NewSsrcStreamOut(&rtp.Address{local.IP, localPort, localPort + 1}, 1020304, 4711)
293 | rsLocal.SsrcStreamOutForIndex(strLocalIdx).SetPayloadType(0)
294 |
295 | // create a second output stream
296 | strLocalIdx, _ = rsLocal.NewSsrcStreamOut(&rtp.Address{local.IP, localPort, localPort + 1}, 11223344, 1234)
297 | rsLocal.SsrcStreamOutForIndex(strLocalIdx).SetPayloadType(0)
298 |
299 | // Create the same set for a "remote" peer and use the "local" as its remote peer. Remote peer has one output stream only.
300 | tpRemote, _ := rtp.NewTransportUDP(remote, remotePort)
301 | rsRemote = rtp.NewSession(tpRemote, tpRemote)
302 | rsRemote.AddRemote(&rtp.Address{local.IP, localPort, localPort + 1})
303 |
304 | strRemoteIdx, _ := rsRemote.NewSsrcStreamOut(&rtp.Address{remote.IP, remotePort, remotePort + 1}, 4030201, 815)
305 | rsRemote.SsrcStreamOutForIndex(strRemoteIdx).SetPayloadType(0)
306 |
307 | go receivePacketLocal()
308 | go receivePacketRemote()
309 |
310 | go receiveCtrlLocal()
311 | go receiveCtrlRemote()
312 |
313 | rsLocal.StartSession()
314 | rsRemote.StartSession()
315 |
316 | go sendLocalToRemote()
317 | go sendLocalToRemoteIdx(strLocalIdx)
318 | go sendRemoteToLocal()
319 |
320 | time.Sleep(8e9)
321 |
322 | stop = true
323 | time.Sleep(30e6) // allow the sender to drain
324 |
325 | stopRemoteRecv <- true
326 | stopLocalRecv <- true
327 | stopRemoteCtrl <- true
328 | stopLocalCtrl <- true
329 |
330 | rsLocal.CloseSession()
331 | rsRemote.CloseSession()
332 |
333 | time.Sleep(10e6)
334 |
335 | fmt.Printf("Full duplex test with 2 output streams done.")
336 | }
337 |
338 | func simpleRtp() {
339 | fmt.Println("Starting simple RTP test.")
340 |
341 | // Create a UDP transport with "local" address and use this for a "local" RTP session
342 | // The RTP session uses the transport to receive and send RTP packets to the remote peer.
343 | tpLocal, _ := rtp.NewTransportUDP(local, localPort)
344 |
345 | // TransportUDP implements TransportWrite and TransportRecv interfaces thus
346 | // use it to initialize the Session for both interfaces.
347 | rsLocal = rtp.NewSession(tpLocal, tpLocal)
348 |
349 | // Add address of a remote peer (participant)
350 | rsLocal.AddRemote(&rtp.Address{remote.IP, remotePort, remotePort + 1})
351 |
352 | // Create a media stream.
353 | // The SSRC identifies the stream. Each stream has its own sequence number and other
354 | // context. A RTP session can have several RTP stream for example to send several
355 | // streams of the same media.
356 | //
357 | strLocalIdx, _ := rsLocal.NewSsrcStreamOut(&rtp.Address{local.IP, localPort, localPort + 1}, 1020304, 4711)
358 | rsLocal.SsrcStreamOutForIndex(strLocalIdx).SetPayloadType(0)
359 |
360 | // Create the same set for a "remote" peer and use the "local" as its remote peer.
361 | tpRemote, _ := rtp.NewTransportUDP(remote, remotePort)
362 | rsRemote = rtp.NewSession(tpRemote, tpRemote)
363 | rsRemote.AddRemote(&rtp.Address{local.IP, localPort, localPort + 1})
364 |
365 | strRemoteIdx, _ := rsRemote.NewSsrcStreamOut(&rtp.Address{remote.IP, remotePort, remotePort + 1}, 4030201, 815)
366 | rsRemote.SsrcStreamOutForIndex(strRemoteIdx).SetPayloadType(0)
367 |
368 | go receivePacketLocal()
369 | go receivePacketRemote()
370 |
371 | // simple RTP: just listen on the RTP and RTCP receive transports. Do not start Session.
372 | rsLocal.ListenOnTransports()
373 | rsRemote.ListenOnTransports()
374 |
375 | // Just connect to control event channel, however in simple RTP mode GoRTP does not report any events.
376 | go sendLocalToRemote()
377 | go sendRemoteToLocal()
378 |
379 | time.Sleep(8e9)
380 |
381 | stop = true
382 | time.Sleep(30e6) // allow the sender to drain
383 |
384 | stopRemoteRecv <- true
385 | stopLocalRecv <- true
386 | stopRemoteCtrl <- true
387 | stopLocalCtrl <- true
388 |
389 | // Just close the receivers, no need to close a session.
390 | rsLocal.CloseRecv()
391 | rsRemote.CloseRecv()
392 |
393 | time.Sleep(10e6)
394 |
395 | fmt.Printf("Simple RTP test done.")
396 |
397 | }
398 |
399 | func main() {
400 | initialize()
401 | // fullDuplex()
402 | // fullDuplexTwoStreams()
403 | simpleRtp()
404 | }
405 |
--------------------------------------------------------------------------------
/session.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2011 Werner Dittmann
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU General Public License as published by
5 | // the Free Software Foundation, either version 3 of the License, or
6 | // (at your option) any later version.
7 | //
8 | // This program is distributed in the hope that it will be useful,
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with this program. If not, see .
15 | //
16 | // Authors: Werner Dittmann
17 | //
18 |
19 | package rtp
20 |
21 | /*
22 | * This source file contains the global types, constants, methods and functions for the Session type
23 | */
24 |
25 | import (
26 | "github.com/antongulenko/RTP/stats"
27 | "log"
28 | "net"
29 | "sync"
30 | "time"
31 | )
32 |
33 | var _ = log.Fatal
34 |
35 | // Session contols and manages the resources and actions of a RTP session.
36 | //
37 | type Session struct {
38 | RtcpTransmission // Data structure to control and manage RTCP reports.
39 | MaxNumberOutStreams int // Applications may set this to increase the number of supported output streams
40 | MaxNumberInStreams int // Applications may set this to increase the number of supported input streams
41 |
42 | dataReceiveChan DataReceiveChan
43 | ctrlEventChan CtrlEventChan
44 |
45 | streamsMapMutex sync.Mutex // synchronize activities on stream maps
46 | streamsOut streamOutMap
47 | streamsIn streamInMap
48 | remotes remoteMap
49 | conflicts conflictMap
50 |
51 | activeSenders,
52 | streamOutIndex,
53 | streamInIndex,
54 | remoteIndex,
55 | conflictIndex uint32
56 |
57 | weSent bool // is true if an output stream sent some RTP data
58 | rtcpServiceActive bool // true if an input stream received RTP packets after last RR
59 | rtcpCtrlChan rtcpCtrlChan
60 | transportEnd TransportEnd
61 | transportEndUpper TransportEnd
62 | transportWrite TransportWrite
63 | transportRecv TransportRecv
64 |
65 | DroppedDataPackets *stats.Stats
66 | DroppedCtrlPackets *stats.Stats
67 | }
68 |
69 | // Remote stores a remote addess in a transport independent way.
70 | //
71 | // The transport implementations construct UDP or TCP addresses and use them to send the data.
72 | type Address struct {
73 | IpAddr net.IP
74 | DataPort, CtrlPort int
75 | }
76 |
77 | // The RTP stack sends CtrlEvent to the application if it creates a new input stream or receives RTCP packets.
78 | //
79 | // A RTCP compound may contain several RTCP packets. The RTP stack creates a CtrlEvent structure for each RTCP
80 | // packet (SDES, BYE, etc) or report and stores them in a slice of CtrlEvent pointers and sends
81 | // this slice to the application after all RTCP packets and reports are processed. The application may now loop
82 | // over the slice and select the events that it may process.
83 | //
84 | type CtrlEvent struct {
85 | EventType int // Either a Stream event or a Rtcp* packet type event, e.g. RtcpSR, RtcpRR, RtcpSdes, RtcpBye
86 | Ssrc uint32 // the input stream's SSRC
87 | Index uint32 // and its index
88 | Reason string // Resaon string if it was available, empty otherwise
89 | }
90 |
91 | // Use a channel to signal if the transports are really closed.
92 | type TransportEnd chan int
93 |
94 | // Use a channel to send RTP data packets to the upper layer application.
95 | type DataReceiveChan chan *DataPacket
96 |
97 | // Use a channel to send RTCP control events to the upper layer application.
98 | type CtrlEventChan chan []*CtrlEvent
99 |
100 | // RTCP values to manage RTCP transmission intervals
101 | type RtcpTransmission struct {
102 | tprev, // the last time an RTCP packet was transmitted
103 | tnext int64 // next scheduled transmission time
104 | RtcpSessionBandwidth float64 // Applications may (should) set this to bits/sec for RTCP traffic.
105 | // If not set RTP stack makes an educated guess.
106 | avrgPacketLength float64
107 | }
108 |
109 | // Returned in case of an error.
110 | type Error string
111 |
112 | func (s Error) Error() string {
113 | return string(s)
114 | }
115 |
116 | // Specific control event type that signal that a new input stream was created.
117 | //
118 | // If the RTP stack receives a data or control packet for a yet unknown input stream
119 | // (SSRC not known) the stack creates a new input stream and signals this action to the application.
120 | const (
121 | NewStreamData = iota // Input stream creation triggered by a RTP data packet
122 | NewStreamCtrl // Input stream creation triggered by a RTCP control packet
123 | MaxNumInStreamReachedData // Maximum number of input streams reached while receiving an RTP packet
124 | MaxNumInStreamReachedCtrl // Maximum number of input streams reached while receiving an RTCP packet
125 | WrongStreamStatusData // Received RTP packet for an inactive stream
126 | WrongStreamStatusCtrl // Received RTCP packet for an inactive stream
127 | StreamCollisionLoopData // Detected a collision or loop processing an RTP packet
128 | StreamCollisionLoopCtrl // Detected a collision or loop processing an RTCP packet
129 | )
130 |
131 | // The receiver transports return these vaules via the TransportEnd channel when they are
132 | // done stopping the data or control receivers.
133 | const (
134 | DataTransportRecvStopped = 0x1
135 | CtrlTransportRecvStopped = 0x2
136 | )
137 |
138 | // Global Session functions.
139 |
140 | // NewSession creates a new RTP session.
141 | //
142 | // A RTP session requires two transports:
143 | // tpw - a transport that implements the RtpTransportWrite interface
144 | // tpr - a transport that implements the RtpTransportRecv interface
145 | //
146 | func NewSession(tpw TransportWrite, tpr TransportRecv) *Session {
147 | rs := new(Session)
148 |
149 | // Maps grow dynamically, set size to avoid resizing in normal cases.
150 | rs.streamsOut = make(streamOutMap, maxNumberOutStreams)
151 | rs.streamsIn = make(streamInMap, maxNumberInStreams)
152 | rs.remotes = make(remoteMap, 2)
153 | rs.conflicts = make(conflictMap, 2)
154 |
155 | rs.MaxNumberOutStreams = maxNumberOutStreams
156 | rs.MaxNumberInStreams = maxNumberInStreams
157 |
158 | rs.transportWrite = tpw
159 | rs.transportRecv = tpr
160 |
161 | rs.transportEnd = make(TransportEnd, 2)
162 | rs.rtcpCtrlChan = make(rtcpCtrlChan, 1)
163 |
164 | tpr.SetCallUpper(rs)
165 | tpr.SetEndChannel(rs.transportEnd)
166 |
167 | rs.DroppedDataPackets = stats.NewStats("Dropped RTP data packets")
168 | rs.DroppedCtrlPackets = stats.NewStats("Dropped RTP ctrl packets")
169 |
170 | return rs
171 | }
172 |
173 | // AddRemote adds the address and RTP port number of an additional remote peer.
174 | //
175 | // The port number must be even. The socket with the even port number sends and receives
176 | // RTP packets. The socket with next odd port number sends and receives RTCP packets.
177 | //
178 | // remote - the RTP address of the remote peer. The RTP data port number must be even.
179 | //
180 | func (rs *Session) AddRemote(remote *Address) (index uint32, err error) {
181 | // if (remote.DataPort & 0x1) == 0x1 {
182 | // return 0, Error("RTP data port number is not an even number.")
183 | // }
184 | rs.remotes[rs.remoteIndex] = remote
185 | index = rs.remoteIndex
186 | rs.remoteIndex++
187 | return
188 | }
189 |
190 | // RemoveRemote removes the address at the specified index.
191 | //
192 | func (rs *Session) RemoveRemote(index uint32) {
193 | delete(rs.remotes, index)
194 | }
195 |
196 | // NewOutputStream creates a new RTP output stream and returns its index.
197 | //
198 | // A RTP session may have several output streams. The first output stream (stream with index 0)
199 | // is the standard output stream. To use other output streams the application must use the
200 | // the "*ForStream(...)" methods and specifiy the correct index of the stream.
201 | //
202 | // The index does not change for the lifetime of the stream and will not be reused during the lifetime of this session.
203 | // (up to 2^64 streams per session :-) )
204 | //
205 | // own - Output stream's own address. Required to detect collisions and loops.
206 | // ssrc - If not zero then this is the SSRC of the output stream. If zero then
207 | // the method generates a random SSRC according to RFC 3550.
208 | // sequenceNo - If not zero then this is the starting sequence number of the output stream.
209 | // If zero then the method generates a random starting sequence number according
210 | // to RFC 3550
211 | //
212 | func (rs *Session) NewSsrcStreamOut(own *Address, ssrc uint32, sequenceNo uint16) (index uint32, err Error) {
213 |
214 | if len(rs.streamsOut) > rs.MaxNumberOutStreams {
215 | return 0, Error("Maximum number of output streams reached.")
216 | }
217 | str := newSsrcStreamOut(own, ssrc, sequenceNo)
218 | str.streamStatus = active
219 |
220 | // Synchronize - may be called from several Go application functions in parallel
221 | rs.streamsMapMutex.Lock()
222 | defer rs.streamsMapMutex.Unlock()
223 |
224 | // Don't reuse an existing SSRC
225 | for _, _, exists := rs.lookupSsrcMap(str.Ssrc()); exists; _, _, exists = rs.lookupSsrcMap(str.Ssrc()) {
226 | str.newSsrc()
227 | }
228 | rs.streamsOut[rs.streamOutIndex] = str
229 | index = rs.streamOutIndex
230 | rs.streamOutIndex++
231 | return
232 | }
233 |
234 | // StartSession activates the transports and starts the RTCP service.
235 | //
236 | // An application must have created an output stream that the session can use to send RTCP data. This
237 | // is true even if the application is in "listening" mode only. An application must send receiver
238 | // reports to it's remote peers.
239 | //
240 | func (rs *Session) StartSession() (err error) {
241 | err = rs.ListenOnTransports() // activate the transports
242 | if err != nil {
243 | return
244 | }
245 | // compute first transmission interval
246 | if rs.RtcpSessionBandwidth == 0.0 { // If not set by application try to guess a value
247 | for _, str := range rs.streamsOut {
248 | format := PayloadFormatMap[int(str.PayloadType())]
249 | if format == nil {
250 | rs.RtcpSessionBandwidth += 64000. / 20.0 // some standard: 5% of a 64000 bit connection
251 | } else {
252 | // Assumption: fixed codec used, 8 byte per sample, one channel
253 | rs.RtcpSessionBandwidth += float64(format.ClockRate) * 8.0 / 20.
254 | }
255 | }
256 | }
257 | if rs.RtcpSessionBandwidth == 0.0 {
258 | rs.RtcpSessionBandwidth += 64000. / 20.0
259 | }
260 | rs.avrgPacketLength = float64(len(rs.streamsOut)*senderInfoLen + reportBlockLen + 20) // 28 for SDES
261 |
262 | // initial call: members, senders, RTCP bandwidth, packet length, weSent, initial
263 | ti, td := rtcpInterval(1, 0, rs.RtcpSessionBandwidth, rs.avrgPacketLength, false, true)
264 | rs.tnext = ti + time.Now().UnixNano()
265 |
266 | go rs.rtcpService(ti, td)
267 | return
268 | }
269 |
270 | // CloseSession closes the complete RTP session immediately.
271 | //
272 | // The methods stops the RTCP service, sends a BYE to all remaining active output streams, and
273 | // closes the receiver transports,
274 | //
275 | func (rs *Session) CloseSession() {
276 | if rs.rtcpServiceActive {
277 | rs.rtcpCtrlChan <- rtcpStopService
278 | for idx := range rs.streamsOut {
279 | rs.SsrcStreamCloseForIndex(idx)
280 | }
281 | rs.CloseRecv() // de-activate the transports
282 | }
283 | return
284 | }
285 |
286 | // NewDataPacket creates a new RTP packet suitable for use with the standard output stream.
287 | //
288 | // This method returns an initialized RTP packet that contains the correct SSRC, sequence
289 | // number, the updated timestamp, and payload type if payload type was set in the stream.
290 | //
291 | // The application computes the next stamp based on the payload's frequency. The stamp usually
292 | // advances by the number of samples contained in the RTP packet.
293 | //
294 | // For example PCMU with a 8000Hz frequency sends 160 samples every 20m - thus the timestamp
295 | // must adavance by 160 for each following packet. For fixed codecs, for example PCMU, the
296 | // number of samples correspond to the payload length. For variable codecs the number of samples
297 | // has no direct relationship with the payload length.
298 | //
299 | // stamp - the RTP timestamp for this packet.
300 | //
301 | func (rs *Session) NewDataPacket(stamp uint32) *DataPacket {
302 | str := rs.streamsOut[0]
303 | return str.newDataPacket(stamp)
304 | }
305 |
306 | func (rs *Session) dataPacketDropped() {
307 | rs.DroppedDataPackets.AddPacketNow()
308 | }
309 |
310 | func (rs *Session) ctrlPacketDropped() {
311 | rs.DroppedCtrlPackets.AddPacketNow()
312 | }
313 |
314 | // NewDataPacketForStream creates a new RTP packet suitable for use with the specified output stream.
315 | //
316 | // This method returns an initialized RTP packet that contains the correct SSRC, sequence
317 | // number, and payload type if payload type was set in the stream. See also documentation of
318 | // NewDataPacket.
319 | //
320 | // streamindex - the index of the output stream as returned by NewSsrcStreamOut
321 | // stamp - the RTP timestamp for this packet.
322 | //
323 | func (rs *Session) NewDataPacketForStream(streamIndex uint32, stamp uint32) *DataPacket {
324 | str := rs.streamsOut[streamIndex]
325 | return str.newDataPacket(stamp)
326 | }
327 |
328 | // CreateDataReceivedChan creates the data received channel and returns it to the caller.
329 | //
330 | // An application shall listen on this channel to get received RTP data packets.
331 | // If the channel is full then the RTP receiver discards the data packets.
332 | //
333 | func (rs *Session) CreateDataReceiveChan(bufferLength int) DataReceiveChan {
334 | rs.dataReceiveChan = make(DataReceiveChan, bufferLength)
335 | return rs.dataReceiveChan
336 | }
337 |
338 | // RemoveDataReceivedChan deletes the data received channel.
339 | //
340 | // The receiver discards all received packets.
341 | //
342 | func (rs *Session) RemoveDataReceiveChan() {
343 | rs.dataReceiveChan = nil
344 | }
345 |
346 | // CreateCtrlEventChan creates the control event channel and returns it to the caller.
347 | //
348 | // An application shall listen on this channel to get control events.
349 | // If the channel is full then the RTCP receiver does not send control events.
350 | //
351 | func (rs *Session) CreateCtrlEventChan(bufferLength int) CtrlEventChan {
352 | rs.ctrlEventChan = make(CtrlEventChan, bufferLength)
353 | return rs.ctrlEventChan
354 | }
355 |
356 | // RemoveCtrlEventChan deletes the control event channel.
357 | //
358 | func (rs *Session) RemoveCtrlEventChan() {
359 | rs.ctrlEventChan = nil
360 | }
361 |
362 | // SsrcStreamOut gets the standard output stream.
363 | //
364 | func (rs *Session) SsrcStreamOut() *SsrcStream {
365 | return rs.streamsOut[0]
366 | }
367 |
368 | // SsrcStreamOut gets the output stream at streamIndex.
369 | //
370 | // streamindex - the index of the output stream as returned by NewSsrcStreamOut
371 | //
372 | func (rs *Session) SsrcStreamOutForIndex(streamIndex uint32) *SsrcStream {
373 | return rs.streamsOut[streamIndex]
374 | }
375 |
376 | // SsrcStreamIn gets the standard input stream.
377 | //
378 | func (rs *Session) SsrcStreamIn() *SsrcStream {
379 | return rs.streamsIn[0]
380 | }
381 |
382 | // SsrcStreamInForIndex Get the input stream with index.
383 | //
384 | // streamindex - the index of the output stream as returned by NewSsrcStreamOut
385 | //
386 | func (rs *Session) SsrcStreamInForIndex(streamIndex uint32) *SsrcStream {
387 | return rs.streamsIn[streamIndex]
388 | }
389 |
390 | // SsrcStreamClose sends a RTCP BYE to the standard output stream (index 0).
391 | //
392 | // The method does not close the stream immediately but marks it as 'is closing'.
393 | // In this state the stream stops its activities, does not send any new data or
394 | // control packets. Eventually it will be in the state "is closed" and its resources
395 | // are returned to the system. An application must not re-use a session.
396 | //
397 | func (rs *Session) SsrcStreamClose() {
398 | rs.SsrcStreamOutForIndex(0)
399 | }
400 |
401 | // SsrcStreamCloseForIndex sends a RTCP BYE to the stream at index index.
402 | //
403 | // See description for SsrcStreamClose above.
404 | //
405 | // streamindex - the index of the output stream as returned by NewSsrcStreamOut
406 | //
407 | func (rs *Session) SsrcStreamCloseForIndex(streamIndex uint32) {
408 | if rs.rtcpServiceActive {
409 | str := rs.streamsOut[streamIndex]
410 | rc := rs.buildRtcpByePkt(str, "Go RTP says good-bye")
411 | rs.WriteCtrl(rc)
412 |
413 | str.streamStatus = isClosing
414 | }
415 | }
416 |
417 | /*
418 | *** The following methods implement the rtp.TransportRecv interface.
419 | */
420 |
421 | // SetCallUpper implements the rtp.RtpTransportRecv SetCallUpper method.
422 | //
423 | // Normal application don't use this method. Only if an application implements its own idea
424 | // of the rtp.TransportRecv interface it may enable the call to upper layer.
425 | //
426 | // Currently this is a No-Op - delegating is not yet implemented.
427 | //
428 | func (rs *Session) SetCallUpper(upper TransportRecv) {
429 | }
430 |
431 | // ListenOnTransports implements the rtp.TransportRecv ListenOnTransports method.
432 | //
433 | // The session just forwards this to the appropriate transport receiver.
434 | //
435 | // Only relevant if an application uses "simple RTP".
436 | //
437 | func (rs *Session) ListenOnTransports() (err error) {
438 | return rs.transportRecv.ListenOnTransports()
439 | }
440 |
441 | // OnRecvData implements the rtp.TransportRecv OnRecvData method.
442 | //
443 | // Normal application don't use this method. Only if an application implements its own idea
444 | // of the rtp.TransportRecv interface it must implement this function.
445 | //
446 | // Delegating is not yet implemented. Applications receive data via the DataReceiveChan.
447 | //
448 | func (rs *Session) OnRecvData(rp *DataPacket) bool {
449 |
450 | if !rp.IsValid() {
451 | rs.dataPacketDropped()
452 | rp.FreePacket()
453 | return false
454 | }
455 | // Check here if SRTP is enabled for the SSRC of the packet - a stream attribute
456 |
457 | if rs.rtcpServiceActive {
458 | ssrc := rp.Ssrc()
459 |
460 | now := time.Now().UnixNano()
461 |
462 | rs.streamsMapMutex.Lock()
463 | str, _, existing := rs.lookupSsrcMap(ssrc)
464 |
465 | // if not found in the input stream then create a new SSRC input stream
466 | if !existing {
467 | str = newSsrcStreamIn(&rp.fromAddr, ssrc)
468 | if len(rs.streamsIn) > rs.MaxNumberInStreams {
469 | rs.sendDataCtrlEvent(MaxNumInStreamReachedData, ssrc, 0)
470 | rp.FreePacket()
471 | rs.streamsMapMutex.Unlock()
472 | rs.dataPacketDropped()
473 | return false
474 | }
475 | rs.streamsIn[rs.streamInIndex] = str
476 | rs.streamInIndex++
477 | str.streamStatus = active
478 | str.statistics.initialDataTime = now // First packet arrival time.
479 | rs.sendDataCtrlEvent(NewStreamData, ssrc, rs.streamInIndex-1)
480 | } else {
481 | // Check if an existing stream is active
482 | if str.streamStatus != active {
483 | rs.sendDataCtrlEvent(WrongStreamStatusData, ssrc, rs.streamInIndex-1)
484 | rp.FreePacket()
485 | rs.streamsMapMutex.Unlock()
486 | rs.dataPacketDropped()
487 | return false
488 |
489 | }
490 | // Test if RTCP packets had been received but this is the first data packet from this source.
491 | if str.DataPort == 0 {
492 | str.DataPort = rp.fromAddr.DataPort
493 | }
494 | }
495 | rs.streamsMapMutex.Unlock()
496 |
497 | // Before forwarding packet to next upper layer (application) for further processing:
498 | // 1) check for collisions and loops. If the packet cannot be assigned to a source, it will be rejected.
499 | // 2) check the source is a sufficiently well known source
500 | // TODO: also check CSRC identifiers.
501 | if !str.checkSsrcIncomingData(existing, rs, rp) || !str.recordReceptionData(rp, rs, now) {
502 | // must be discarded due to collision or loop or invalid source
503 | rs.sendDataCtrlEvent(StreamCollisionLoopData, ssrc, rs.streamInIndex-1)
504 | rp.FreePacket()
505 | rs.dataPacketDropped()
506 | return false
507 | }
508 | }
509 | select {
510 | case rs.dataReceiveChan <- rp: // forwarded packet, that's all folks
511 | default:
512 | rp.FreePacket() // either channel full or not created - free packet
513 | rs.dataPacketDropped()
514 | }
515 | return true
516 | }
517 |
518 | // OnRecvCtrl implements the rtp.TransportRecv OnRecvCtrl method.
519 | //
520 | // Normal application don't use this method. Only if an application implements its own idea
521 | // of the rtp.TransportRecv interface it must implement this function.
522 | //
523 | // Delegating is not yet implemented. Applications may receive control events via
524 | // the CtrlEventChan.
525 | //
526 | func (rs *Session) OnRecvCtrl(rp *CtrlPacket) bool {
527 |
528 | if !rs.rtcpServiceActive {
529 | rs.ctrlPacketDropped()
530 | return true
531 | }
532 |
533 | if pktType := rp.Type(0); pktType != RtcpSR && pktType != RtcpRR && pktType != RtcpPsfb && pktType != RtcpRtpfb {
534 | rp.FreePacket()
535 | rs.ctrlPacketDropped()
536 | return false
537 | }
538 | // Check here if SRTCP is enabled for the SSRC of the packet - a stream attribute
539 |
540 | ctrlEvArr := make([]*CtrlEvent, 0, 10)
541 |
542 | offset := 0
543 | for offset < rp.inUse {
544 | pktLen := int((rp.Length(offset) + 1) * 4)
545 |
546 | switch rp.Type(offset) {
547 | case RtcpSR:
548 | rrCnt := rp.Count(offset)
549 | if offset+pktLen > len(rp.Buffer()) {
550 | rs.ctrlPacketDropped()
551 | return false
552 | }
553 | // Always check sender's SSRC first in case of RR or SR
554 | str, strIdx, existing := rs.rtcpSenderCheck(rp, offset)
555 | if str == nil {
556 | ctrlEvArr = append(ctrlEvArr, newCrtlEvent(int(strIdx), str.Ssrc(), 0))
557 | } else {
558 | if !existing {
559 | ctrlEvArr = append(ctrlEvArr, newCrtlEvent(NewStreamCtrl, str.Ssrc(), rs.streamInIndex-1))
560 | }
561 | str.statistics.lastRtcpSrTime = str.statistics.lastRtcpPacketTime
562 | str.readSenderInfo(rp.toSenderInfo(rtcpHeaderLength + rtcpSsrcLength + offset))
563 |
564 | ctrlEvArr = append(ctrlEvArr, newCrtlEvent(RtcpSR, str.Ssrc(), strIdx))
565 |
566 | // Offset to first RR block: offset to SR + fixed Header length for SR + length of sender info
567 | rrOffset := offset + rtcpHeaderLength + rtcpSsrcLength + senderInfoLen
568 |
569 | for i := 0; i < rrCnt; i++ {
570 | rr := rp.toRecvReport(rrOffset)
571 | strOut, idx, exists := rs.lookupSsrcMapOut(rr.ssrc())
572 | // Process Receive Reports that match own output streams (SSRC).
573 | if exists {
574 | strOut.readRecvReport(rr)
575 | ctrlEvArr = append(ctrlEvArr, newCrtlEvent(RtcpRR, rr.ssrc(), idx))
576 | }
577 | rrOffset += reportBlockLen
578 | }
579 | }
580 | // Advance to the next packet in the compound.
581 | offset += pktLen
582 |
583 | case RtcpRR:
584 | if offset+pktLen > len(rp.Buffer()) {
585 | rs.ctrlPacketDropped()
586 | return false
587 | }
588 | // Always check sender's SSRC first in case of RR or SR
589 | str, strIdx, existing := rs.rtcpSenderCheck(rp, offset)
590 | if str == nil {
591 | ctrlEvArr = append(ctrlEvArr, newCrtlEvent(int(strIdx), str.Ssrc(), 0))
592 | } else {
593 | if !existing {
594 | ctrlEvArr = append(ctrlEvArr, newCrtlEvent(NewStreamCtrl, str.Ssrc(), rs.streamInIndex-1))
595 | }
596 |
597 | rrCnt := rp.Count(offset)
598 | // Offset to first RR block: offset to RR + fixed Header length for RR
599 | rrOffset := offset + rtcpHeaderLength + rtcpSsrcLength
600 | for i := 0; i < rrCnt; i++ {
601 | rr := rp.toRecvReport(rrOffset)
602 | strOut, idx, exists := rs.lookupSsrcMapOut(rr.ssrc())
603 | // Process Receive Reports that match own output streams (SSRC)
604 | if exists {
605 | strOut.readRecvReport(rr)
606 | ctrlEvArr = append(ctrlEvArr, newCrtlEvent(RtcpRR, rr.ssrc(), idx))
607 | }
608 | rrOffset += reportBlockLen
609 | }
610 | }
611 | // Advance to the next packet in the compound.
612 | offset += pktLen
613 |
614 | case RtcpSdes:
615 | if offset+pktLen > len(rp.Buffer()) {
616 | rs.ctrlPacketDropped()
617 | return false
618 | }
619 | sdesChunkCnt := rp.Count(offset)
620 | sdesPktLen := int(rp.Length(offset) * 4) // length excl. header word
621 | // Offset to first SDES chunk: offset to SDES + Header word for SDES
622 | sdesChunkOffset := offset + 4
623 | for i := 0; i < sdesChunkCnt; i++ {
624 | chunk := rp.toSdesChunk(sdesChunkOffset, sdesPktLen)
625 | if chunk == nil {
626 | break
627 | }
628 | chunkLen, idx, ok := rs.processSdesChunk(chunk, rp)
629 | if !ok {
630 | break
631 | }
632 | ctrlEvArr = append(ctrlEvArr, newCrtlEvent(RtcpSdes, chunk.ssrc(), idx))
633 | sdesChunkOffset += chunkLen
634 | sdesPktLen -= chunkLen
635 | }
636 | // Advance to the next packet in the compound, is also index after SDES packet
637 | offset += pktLen
638 |
639 | case RtcpBye:
640 | if offset+pktLen > len(rp.Buffer()) {
641 | rs.ctrlPacketDropped()
642 | return false
643 | }
644 | // Currently the method suports only one SSRC per BYE packet. To enhance this we need
645 | // to return an array of SSRC/CSRC values.
646 | //
647 | byeCnt := rp.Count(offset)
648 | byePkt := rp.toByeData(offset+4, pktLen-4)
649 | if byePkt != nil {
650 | // Send BYE control event only for known input streams.
651 | if st, idx, ok := rs.lookupSsrcMapIn(byePkt.ssrc(0)); ok {
652 | ctrlEv := newCrtlEvent(RtcpBye, byePkt.ssrc(0), idx)
653 | ctrlEv.Reason = byePkt.getReason(byeCnt)
654 | ctrlEvArr = append(ctrlEvArr, ctrlEv)
655 | st.streamStatus = isClosing
656 | }
657 | // Recompute time intervals, see chapter 6.3.4
658 | // TODO: not len(rs.streamsIn) but get number of members with streamStatus == active
659 | pmembers := float64(len(rs.streamsOut) + len(rs.streamsIn))
660 | members := pmembers - 1.0 // received a BYE for one input channel
661 | tc := float64(time.Now().UnixNano())
662 | tn := tc + members/pmembers*(float64(rs.tnext)-tc)
663 | rs.tnext = int64(tn)
664 | }
665 | // Advance to the next packet in the compound.
666 | offset += pktLen
667 |
668 | case RtcpApp:
669 | // Advance to the next packet in the compound.
670 | offset += pktLen
671 | case RtcpRtpfb:
672 | if offset+pktLen > len(rp.Buffer()) {
673 | rs.ctrlPacketDropped()
674 | return false
675 | }
676 | str, _, _ := rs.rtcpSenderCheck(rp, offset)
677 | ctrlEv := newCrtlEvent(RtcpRtpfb, str.Ssrc(), 0)
678 | fbOffset := offset + rtcpHeaderLength + rtcpSsrcLength + rtcpSsrcLength
679 | ctrlEv.Reason = string(rp.buffer[fbOffset:(offset + pktLen)])
680 | ctrlEvArr = append(ctrlEvArr, ctrlEv)
681 | offset += pktLen
682 | case RtcpPsfb:
683 | if offset+pktLen > len(rp.Buffer()) {
684 | rs.ctrlPacketDropped()
685 | return false
686 | }
687 | str, _, _ := rs.rtcpSenderCheck(rp, offset)
688 | ctrlEv := newCrtlEvent(RtcpPsfb, str.Ssrc(), 0)
689 | fbOffset := offset + rtcpHeaderLength + rtcpSsrcLength + rtcpSsrcLength
690 | ctrlEv.Reason = string(rp.buffer[fbOffset : fbOffset+8])
691 | ctrlEvArr = append(ctrlEvArr, ctrlEv)
692 | offset += pktLen
693 | case RtcpXr:
694 | // Advance to the next packet in the compound.
695 | offset += pktLen
696 |
697 | }
698 | }
699 | if rs.ctrlEventChan != nil {
700 | select {
701 | case rs.ctrlEventChan <- ctrlEvArr: // send control event
702 | default:
703 | rs.ctrlPacketDropped()
704 | }
705 | }
706 | // re-compute average packet size. Don't re-compute RTCP interval time, will be done on next RTCP report
707 | // interval. The timing is not affected that much by delaying the interval re-computation.
708 | size := float64(rp.InUse() + 20 + 8) // TODO: get real values for IP and transport from transport module
709 | rs.avrgPacketLength = (1.0/16.0)*size + (15.0/16.0)*rs.avrgPacketLength
710 |
711 | rp.FreePacket()
712 | ctrlEvArr = nil
713 | return true
714 | }
715 |
716 | // CloseRecv implements the rtp.TransportRecv CloseRecv method.
717 | //
718 | // The method calls the registered transport's CloseRecv() method and waits for the Stopped
719 | // signal data for RTP and RTCP.
720 | //
721 | // If a upper layer application has registered a transportEnd channel forward the signal to it.
722 | //
723 | // Only relevant if an application uses "simple RTP".
724 | //
725 | func (rs *Session) CloseRecv() {
726 | if rs.transportRecv != nil {
727 | rs.transportRecv.CloseRecv()
728 | for allClosed := 0; allClosed != (DataTransportRecvStopped | CtrlTransportRecvStopped); {
729 | allClosed |= <-rs.transportEnd
730 | }
731 | }
732 | if rs.transportEndUpper != nil {
733 | rs.transportEndUpper <- (DataTransportRecvStopped | CtrlTransportRecvStopped)
734 | }
735 | }
736 |
737 | // SetEndChannel implements the rtp.TransportRecv SetEndChannel method.
738 | //
739 | // An application may register a specific control channel to get information after
740 | // all receiver transports were closed.
741 | //
742 | // Only relevant if an application uses "simple RTP".
743 | //
744 | func (rs *Session) SetEndChannel(ch TransportEnd) {
745 | rs.transportEndUpper = ch
746 | }
747 |
748 | /*
749 | *** The following methods implement the rtp.TransportWrite interface.
750 | */
751 |
752 | // WriteData implements the rtp.TransportWrite WriteData method and sends an RTP packet.
753 | //
754 | // The method writes the packet of an active output stream to all known remote destinations.
755 | // This functions updates some statistical values to enable RTCP processing.
756 | //
757 | func (rs *Session) WriteData(rp *DataPacket) (n int, err error) {
758 |
759 | strOut, _, _ := rs.lookupSsrcMapOut(rp.Ssrc())
760 | if strOut.streamStatus != active {
761 | return 0, nil
762 | }
763 | strOut.SenderPacketCnt++
764 | strOut.SenderOctectCnt += uint32(len(rp.Payload()))
765 |
766 | strOut.streamMutex.Lock()
767 | if !strOut.sender && rs.rtcpCtrlChan != nil {
768 | rs.rtcpCtrlChan <- rtcpIncrementSender
769 | strOut.sender = true
770 | }
771 | strOut.statistics.lastPacketTime = time.Now().UnixNano()
772 | strOut.streamMutex.Unlock()
773 | rs.weSent = true
774 |
775 | // Check here if SRTP is enabled for the SSRC of the packet - a stream attribute
776 | for _, remote := range rs.remotes {
777 | _, err := rs.transportWrite.WriteDataTo(rp, remote)
778 | if err != nil {
779 | return 0, err
780 | }
781 | }
782 | return n, nil
783 | }
784 |
785 | // WriteCtrl implements the rtp.TransportWrite WriteCtrl method and sends an RTCP packet.
786 | //
787 | // The method sends an RTCP packet of an active output stream to all known remote destinations.
788 | // Usually normal applications don't use this function, RTCP is handled internally.
789 | //
790 | func (rs *Session) WriteCtrl(rp *CtrlPacket) (n int, err error) {
791 |
792 | // Check here if SRTCP is enabled for the SSRC of the packet - a stream attribute
793 | strOut, _, _ := rs.lookupSsrcMapOut(rp.Ssrc(0))
794 | if strOut.streamStatus != active {
795 | return 0, nil
796 | }
797 | for _, remote := range rs.remotes {
798 | _, err := rs.transportWrite.WriteCtrlTo(rp, remote)
799 | if err != nil {
800 | return 0, err
801 | }
802 | }
803 | return n, nil
804 | }
805 |
--------------------------------------------------------------------------------
/sessionlocal.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2011 Werner Dittmann
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU General Public License as published by
5 | // the Free Software Foundation, either version 3 of the License, or
6 | // (at your option) any later version.
7 | //
8 | // This program is distributed in the hope that it will be useful,
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with this program. If not, see .
15 | //
16 | // Authors: Werner Dittmann
17 | //
18 |
19 | package rtp
20 |
21 | /*
22 | * This source file contains the local types, constants, methods and functions for the Session type
23 | */
24 |
25 | import (
26 | "crypto/rand"
27 | "time"
28 | )
29 |
30 | const (
31 | maxNumberOutStreams = 5
32 | maxNumberInStreams = 30
33 | )
34 |
35 | // conflictAddr stores conflicting address detected during loop and collision check
36 | // It also stores the time of the latest conflict-
37 | type conflictAddr struct {
38 | Address
39 | seenAt int64
40 | }
41 |
42 | // The RTCP control commands a a simple uint32: the MSB defines the command, the lower
43 | // 3 bytes the value for the command, if a value is necssary for the command.
44 | //
45 | const (
46 | rtcpCtrlCmdMask = 0xff000000
47 | rtcpStopService = 0x01000000
48 | rtcpModifyInterval = 0x02000000 // Modify RTCP timer interval, low 3 bytes contain new tick time in ms
49 | rtcpIncrementSender = 0x03000000 // a stream became an active sender, count this globally
50 | )
51 |
52 | // rtcpCtrlChan sends control data to the RTCP service.
53 | // USe this channel to send a stop service command or a modify time command to the
54 | // rtcpService. With this technique the rtcpService can modify its time between
55 | // service runs without being stopped.
56 | //
57 | type rtcpCtrlChan chan uint32
58 |
59 | // Manages the output SSRC streams.
60 | //
61 | // Refer to RFC 3550: do not use SSRC to multiplex different media types on one session. One RTP session
62 | // shall handle one media type only. However, a RTP session can have several SSRC output streams for the
63 | // same media types, for example sending video data from two or more cameras.
64 | // The output streams are identified with our "own" SSRCs, thus a RTP session may have several "own" SSRCs.
65 | type streamOutMap map[uint32]*SsrcStream
66 |
67 | // Manages the input SSRC streams.
68 | type streamInMap map[uint32]*SsrcStream
69 |
70 | // The remote peers.
71 | type remoteMap map[uint32]*Address
72 |
73 | type conflictMap map[uint32]*conflictAddr
74 |
75 | // rtcpService provides the RTCP service and sends RTCP reports at computed intervals.
76 | //
77 | func (rs *Session) rtcpService(ti, td int64) {
78 |
79 | granularity := time.Duration(250e6) // 250 ms
80 | ssrcTimeout := 5 * td
81 | dataTimeout := 2 * ti
82 |
83 | rs.rtcpServiceActive = true
84 | ticker := time.NewTicker(granularity)
85 | var cmd uint32
86 | for cmd != rtcpStopService {
87 | select {
88 | case <-ticker.C:
89 | now := time.Now().UnixNano()
90 | if now < rs.tnext {
91 | continue
92 | }
93 |
94 | var outActive, inActive int // Counts all members in active state
95 | var inActiveSinceLastRR int
96 |
97 | for idx, str := range rs.streamsIn {
98 | switch str.streamStatus {
99 | case active:
100 | str.streamMutex.Lock()
101 | // Manage number of active senders on input streams.
102 | // Every time this stream receives a packet it updates the last packet time. If the input stream
103 | // did not receive a RTP packet for 2 RTCP intervals its sender status is set to false and the
104 | // number of active senders in this session is decremented if not already zero. See chapter 6.3.5
105 | rtpDiff := now - str.statistics.lastPacketTime
106 | if str.sender {
107 | if str.dataAfterLastReport {
108 | inActiveSinceLastRR++
109 | }
110 | if rtpDiff > dataTimeout {
111 | str.sender = false
112 | if rs.activeSenders > 0 {
113 | rs.activeSenders--
114 | }
115 | }
116 | }
117 | // SSRC timeout processing: check for inactivity longer than 5*non-random interval time
118 | // (both RTP/RTCP inactivity) chapter 6.3.5
119 | rtcpDiff := now - str.statistics.lastRtcpPacketTime
120 | if rtpDiff > rtcpDiff {
121 | rtpDiff = rtcpDiff
122 | }
123 | if rtpDiff > ssrcTimeout {
124 | delete(rs.streamsIn, idx)
125 | }
126 | str.streamMutex.Unlock()
127 |
128 | case isClosing:
129 | str.streamStatus = isClosed
130 |
131 | case isClosed:
132 | delete(rs.streamsOut, idx)
133 | }
134 | }
135 |
136 | var rc *CtrlPacket
137 | var streamForRR *SsrcStream
138 | var outputSenders int
139 |
140 | for idx, str := range rs.streamsOut {
141 | switch str.streamStatus {
142 | case active:
143 | outActive++
144 | streamForRR = str // remember one active stream in case there is no sending output stream
145 |
146 | // Manage number of active senders. Every time this stream sends a packet the output stream
147 | // sender updates the last packet time. If the output stream did not send RTP for 2 RTCP
148 | // intervals its sender status is set to false and the number of active senders in this session
149 | // is decremented if not already zero. See chapter 6.3.8
150 | //
151 | str.streamMutex.Lock()
152 | rtpDiff := now - str.statistics.lastPacketTime
153 | if str.sender {
154 | outputSenders++
155 | if rtpDiff > dataTimeout {
156 | str.sender = false
157 | outputSenders--
158 | if rs.activeSenders > 0 {
159 | rs.activeSenders--
160 | }
161 | }
162 | }
163 | str.streamMutex.Unlock()
164 | if str.sender {
165 | if rc == nil {
166 | rc = rs.buildRtcpPkt(str, inActiveSinceLastRR)
167 | } else {
168 | rs.addSenderReport(str, rc)
169 | }
170 | }
171 |
172 | case isClosing:
173 | str.streamStatus = isClosed
174 |
175 | case isClosed:
176 | delete(rs.streamsOut, idx)
177 | }
178 | }
179 | // If no active output stream is left then weSent becomes false
180 | rs.weSent = outputSenders > 0
181 |
182 | // if rc is nil then we found no sending stream and havent't build a control packet. Just use
183 | // one active output stream as proxy to create at least an RR and the proxy's SDES (RR may be
184 | // empty as well). If also no active output stream - don't create and send RTCP report. In this
185 | // case the RTP stack in completey inactive.
186 | if rc == nil && streamForRR != nil {
187 | rc = rs.buildRtcpPkt(streamForRR, inActiveSinceLastRR)
188 | }
189 | if rc != nil {
190 | rs.WriteCtrl(rc)
191 | rs.tprev = now
192 | size := float64(rc.InUse() + 20 + 8) // TODO: get real values for IP and transport from transport module
193 | rs.avrgPacketLength = (1.0/16.0)*size + (15.0/16.0)*rs.avrgPacketLength
194 |
195 | ti, td := rtcpInterval(outActive+inActive, int(rs.activeSenders), rs.RtcpSessionBandwidth,
196 | rs.avrgPacketLength, rs.weSent, false)
197 | rs.tnext = ti + now
198 | dataTimeout = 2 * ti
199 | ssrcTimeout = 5 * td
200 | rc.FreePacket()
201 | }
202 | outActive = 0
203 | inActive = 0
204 |
205 | case cmd = <-rs.rtcpCtrlChan:
206 | switch cmd & rtcpCtrlCmdMask {
207 | case rtcpStopService:
208 | ticker.Stop()
209 |
210 | case rtcpModifyInterval:
211 | ticker.Stop()
212 | granularity = time.Duration(cmd &^ rtcpCtrlCmdMask)
213 | ticker = time.NewTicker(granularity)
214 |
215 | case rtcpIncrementSender:
216 | rs.activeSenders++
217 | }
218 | }
219 | }
220 | rs.rtcpServiceActive = false
221 | }
222 |
223 | // buildRtcpPkt creates an RTCP compound and fills it with a SR or RR packet.
224 | //
225 | // This method loops over the known input streams and fills in receiver reports.
226 | // the method adds a maximum of 31 receiver reports. The SR and/or RRs and the SDES
227 | // of the output stream always fit in the RTCP compund, thus no further checks required.
228 | //
229 | // Other output streams just add their sender reports and SDES info.
230 | //
231 | func (rs *Session) buildRtcpPkt(strOut *SsrcStream, inStreamCnt int) (rc *CtrlPacket) {
232 |
233 | var pktLen, offset int
234 | if strOut.sender {
235 | rc, offset = strOut.newCtrlPacket(RtcpSR)
236 | offset = rc.addHeaderSsrc(offset, strOut.Ssrc())
237 |
238 | var info senderInfo
239 | info, offset = rc.newSenderInfo()
240 | strOut.fillSenderInfo(info) // create a sender info block after fixed header and SSRC.
241 | } else {
242 | rc, offset = strOut.newCtrlPacket(RtcpRR)
243 | offset = rc.addHeaderSsrc(offset, strOut.Ssrc())
244 | }
245 | pktLen = offset/4 - 1
246 | // TODO Handle round-robin if we have more then 31 really active input streams (chap 6.4)
247 | if inStreamCnt >= 31 {
248 | inStreamCnt = 31
249 | }
250 | var rrCnt int
251 | if inStreamCnt > 0 {
252 | for _, strIn := range rs.streamsIn {
253 | if strIn.dataAfterLastReport {
254 | strIn.dataAfterLastReport = false
255 | strIn.makeRecvReport(rc)
256 | pktLen += reportBlockLen / 4 // increment SR/RR to include length of this recv report block
257 | rrCnt++
258 | if inStreamCnt--; inStreamCnt <= 0 {
259 | break
260 | }
261 | }
262 | }
263 | }
264 | rc.SetLength(0, uint16(pktLen)) // length of first RTCP packet in compound: fixed header, 0 or 1 SR, n*RR
265 | rc.SetCount(0, rrCnt)
266 |
267 | rs.addSdes(strOut, rc)
268 |
269 | return
270 | }
271 |
272 | // buildRtcpByePkt builds an RTCP BYE compound.
273 | //
274 | func (rs *Session) buildRtcpByePkt(strOut *SsrcStream, reason string) (rc *CtrlPacket) {
275 | rc = rs.buildRtcpPkt(strOut, 0)
276 |
277 | headerOffset := rc.InUse()
278 | strOut.addCtrlHeader(rc, headerOffset, RtcpBye)
279 | // Here we may add a loop over CSRC (addtional data in ouput steam) and hand over to makeByeData
280 | offset := strOut.makeByeData(rc, reason)
281 | rc.SetCount(headerOffset, 1) // currently one BYE SSRC/CSRC per packet
282 | rc.SetLength(headerOffset, uint16((offset-headerOffset)/4-1)) // length of BYE packet in compound: fixed header plus BYE data
283 | return
284 | }
285 |
286 | // addSenderReport appends a SDES packet into to control packet.
287 | //
288 | func (rs *Session) addSdes(strOut *SsrcStream, rc *CtrlPacket) {
289 | offsetSdes := rc.InUse()
290 | if strOut.sdesChunkLen > 0 {
291 | strOut.addCtrlHeader(rc, offsetSdes, RtcpSdes) // Add a RTCP SDES packet header after the SR/RR packet
292 | // makeSdesChunk returns position where to append next chunk - for CSRCs that contribute to this, chap 6.5, RFC 3550
293 | // CSRCs currently not supported, need additional data structures in output stream.
294 | nextChunk := strOut.makeSdesChunk(rc)
295 | rc.SetCount(offsetSdes, 1) // currently one SDES chunk per SDES packet
296 | rc.SetLength(offsetSdes, uint16((nextChunk-offsetSdes)/4-1)) // length of SDES packet in compound: fixed header plus SDES chunk len
297 | }
298 | }
299 |
300 | // addSenderReport appends a sender report into to control packet if the output stream is a sender.
301 | //
302 | // The method just adds the sender report for the output stream. It does not loop over the
303 | // input streams to fill in the sreceiver reports. Only one output stream's sender report
304 | // contains receiver reports of our input streams.
305 | //
306 | func (rs *Session) addSenderReport(strOut *SsrcStream, rc *CtrlPacket) {
307 |
308 | if !strOut.sender {
309 | return
310 | }
311 |
312 | headerOffset := rc.InUse()
313 | if headerOffset+strOut.sdesChunkLen+8 > len(rc.Buffer()) {
314 | return
315 | }
316 | offset := strOut.addCtrlHeader(rc, headerOffset, RtcpSR)
317 | rc.addHeaderSsrc(offset, strOut.Ssrc())
318 |
319 | var info senderInfo
320 | info, offset = rc.newSenderInfo()
321 | strOut.fillSenderInfo(info) // create a sender info block after fixed header and SSRC.
322 |
323 | pktLen := (offset-headerOffset)/4 - 1
324 | rc.SetLength(headerOffset, uint16(pktLen)) // length of RTCP packet in compound: fixed header, SR, 0*RR
325 | rc.SetCount(headerOffset, 0) // zero receiver reports in this SR
326 |
327 | rs.addSdes(strOut, rc)
328 | }
329 |
330 | // rtcpSenderCheck is a helper function for OnRecvCtrl and checks if a sender's SSRC.
331 | //
332 | func (rs *Session) rtcpSenderCheck(rp *CtrlPacket, offset int) (*SsrcStream, uint32, bool) {
333 | ssrc := rp.Ssrc(offset) // get SSRC from control packet
334 |
335 | rs.streamsMapMutex.Lock()
336 | str, strIdx, existing := rs.lookupSsrcMap(ssrc)
337 |
338 | // if not found in the input stream then create a new SSRC input stream
339 | if !existing {
340 | if len(rs.streamsIn) > rs.MaxNumberInStreams {
341 | rs.streamsMapMutex.Unlock()
342 | return nil, MaxNumInStreamReachedCtrl, false
343 | }
344 | str = newSsrcStreamIn(&rp.fromAddr, ssrc)
345 | str.streamStatus = active
346 | rs.streamsIn[rs.streamInIndex] = str
347 | rs.streamInIndex++
348 | } else {
349 | // Check if an existing stream is active
350 | if str.streamStatus != active {
351 | rs.streamsMapMutex.Unlock()
352 | return nil, WrongStreamStatusCtrl, false
353 | }
354 | // Test if RTP packets had been received but this is the first control packet from this source.
355 | if str.CtrlPort == 0 {
356 | str.CtrlPort = rp.fromAddr.CtrlPort
357 | }
358 | }
359 | rs.streamsMapMutex.Unlock()
360 |
361 | // Check if sender's SSRC collides or loops
362 | if !str.checkSsrcIncomingCtrl(existing, rs, &rp.fromAddr) {
363 | return nil, StreamCollisionLoopCtrl, false
364 | }
365 | // record reception time
366 | str.statistics.lastRtcpPacketTime = time.Now().UnixNano()
367 | return str, strIdx, existing
368 | }
369 |
370 | // sendDataCtrlEvent is a helper function to OnRecvData and sends one control event to the application
371 | // if the control event chanel is active.
372 | //
373 | func (rs *Session) sendDataCtrlEvent(code int, ssrc, index uint32) {
374 | var ctrlEvArr [1]*CtrlEvent
375 | ctrlEvArr[0] = newCrtlEvent(code, ssrc, index)
376 |
377 | if ctrlEvArr[0] != nil {
378 | select {
379 | case rs.ctrlEventChan <- ctrlEvArr[:]: // send control event
380 | default:
381 | }
382 | }
383 | }
384 |
385 | // lookupSsrcMap returns a SsrcStream, either a SsrcStreamIn or SsrcStreamOut for a given SSRC, nil and false if none found.
386 | //
387 | func (rs *Session) lookupSsrcMap(ssrc uint32) (str *SsrcStream, idx uint32, exists bool) {
388 | if str, idx, exists = rs.lookupSsrcMapOut(ssrc); exists {
389 | return
390 | }
391 | if str, idx, exists = rs.lookupSsrcMapIn(ssrc); exists {
392 | return
393 | }
394 | return nil, 0, false
395 | }
396 |
397 | // lookupSsrcMapIn returns a SsrcStreamIn for a given SSRC, nil and false if none found.
398 | //
399 | func (rs *Session) lookupSsrcMapIn(ssrc uint32) (*SsrcStream, uint32, bool) {
400 | for idx, str := range rs.streamsIn {
401 | if ssrc == str.ssrc {
402 | return str, idx, true
403 | }
404 | }
405 | return nil, 0, false
406 | }
407 |
408 | // lookupSsrcMapOut returns a SsrcStreamOut for a given SSRC, nil and false if none found.
409 | //
410 | func (rs *Session) lookupSsrcMapOut(ssrc uint32) (*SsrcStream, uint32, bool) {
411 | for idx, str := range rs.streamsOut {
412 | if ssrc == str.ssrc {
413 | return str, idx, true
414 | }
415 | }
416 | return nil, 0, false
417 | }
418 |
419 | // isOutputSsrc checks if a given SSRC is already used in our output streams.
420 | // Use this functions to detect collisions.
421 | //
422 | func (rs *Session) isOutputSsrc(ssrc uint32) (found bool) {
423 | var str *SsrcStream
424 | for _, str = range rs.streamsOut {
425 | if ssrc == str.ssrc {
426 | found = true
427 | break
428 | }
429 | }
430 | return
431 | }
432 |
433 | // checkConflictData checks and manages entries of conflicting data addresses.
434 | // If an address/port pair is already recorded just update the time and return
435 | // the entry and true.
436 | //
437 | // If an entry was not found then create an entry, populate it and return entry
438 | // and false.
439 | //
440 | func (rs *Session) checkConflictData(addr *Address) (found bool) {
441 | var entry *conflictAddr
442 | tm := time.Now().UnixNano()
443 |
444 | for _, entry = range rs.conflicts {
445 | if addr.IpAddr.Equal(entry.IpAddr) && addr.DataPort == entry.DataPort {
446 | found = true
447 | entry.seenAt = tm
448 | return
449 | }
450 | }
451 | entry = new(conflictAddr)
452 | entry.IpAddr = addr.IpAddr
453 | entry.DataPort = addr.DataPort
454 | entry.seenAt = tm
455 | rs.conflicts[rs.conflictIndex] = entry
456 | rs.conflictIndex++
457 | found = false
458 | return
459 | }
460 |
461 | // checkConflictData checks and manages entries of conflicting data addresses.
462 | // If an address/port pair is already recorded just update the time and return
463 | // the entry and true.
464 | //
465 | // If an entry was not found then create an entry, populate it and return entry
466 | // and false.
467 | //
468 | func (rs *Session) checkConflictCtrl(addr *Address) (found bool) {
469 | var entry *conflictAddr
470 | tm := time.Now().UnixNano()
471 |
472 | for _, entry = range rs.conflicts {
473 | if addr.IpAddr.Equal(entry.IpAddr) && addr.CtrlPort == entry.CtrlPort {
474 | found = true
475 | entry.seenAt = tm
476 | return
477 | }
478 | }
479 | entry = new(conflictAddr)
480 | entry.IpAddr = addr.IpAddr
481 | entry.CtrlPort = addr.CtrlPort
482 | entry.seenAt = tm
483 | rs.conflicts[rs.conflictIndex] = entry
484 | rs.conflictIndex++
485 | found = false
486 | return
487 | }
488 |
489 | // processSdesChunk checks if the chunk's SSRC is already known and if yes, parse it.
490 | // The method returns the length of the chunk .
491 | //
492 | func (rs *Session) processSdesChunk(chunk sdesChunk, rp *CtrlPacket) (int, uint32, bool) {
493 | chunkLen, ok := chunk.chunkLen()
494 | if !ok {
495 | return 0, 0, false
496 | }
497 | strIn, idx, existing := rs.lookupSsrcMapIn(chunk.ssrc())
498 | if !existing {
499 | return chunkLen, idx, true
500 | }
501 | strIn.parseSdesChunk(chunk)
502 | return chunkLen, idx, true
503 | }
504 |
505 | // replaceStream creates a new output stream, initializes it from the old output stream and replaces the old output stream.
506 | //
507 | // The old output stream will then become an input streamm - this handling is called if we have a conflict during
508 | // collision, loop detection (see algorithm in chap 8.2, RFC 3550).
509 | //
510 | func (rs *Session) replaceStream(oldOut *SsrcStream) (newOut *SsrcStream) {
511 | var str *SsrcStream
512 | var idx uint32
513 | for idx, str = range rs.streamsOut {
514 | if oldOut.ssrc == str.ssrc {
515 | break
516 | }
517 | }
518 | // get new stream and copy over attributes from old stream
519 | newOut = newSsrcStreamOut(&Address{oldOut.IpAddr, oldOut.DataPort, oldOut.CtrlPort}, 0, 0)
520 |
521 | for itemType, itemTxt := range oldOut.SdesItems {
522 | newOut.SetSdesItem(itemType, itemTxt)
523 | }
524 | newOut.SetPayloadType(oldOut.PayloadType())
525 | newOut.sender = oldOut.sender
526 |
527 | // Now lock and re-shuffle the streams
528 | rs.streamsMapMutex.Lock()
529 | defer rs.streamsMapMutex.Unlock()
530 |
531 | // Don't reuse an existing SSRC
532 | for _, _, exists := rs.lookupSsrcMap(newOut.Ssrc()); exists; _, _, exists = rs.lookupSsrcMap(newOut.Ssrc()) {
533 | newOut.newSsrc()
534 | }
535 | newOut.streamType = OutputStream
536 | rs.streamsOut[idx] = newOut // replace the oldOut with a new initialized out, new SSRC, sequence but old address
537 |
538 | // sanity check - this is a panic, something stange happened
539 | for idx, str = range rs.streamsIn {
540 | if oldOut.ssrc == str.ssrc {
541 | panic("Panic: found input stream during collision handling - expected none")
542 | return
543 | }
544 | }
545 | oldOut.streamType = InputStream
546 | rs.streamsIn[rs.streamInIndex] = oldOut
547 | rs.streamInIndex++
548 | return
549 | }
550 |
551 | // The following constants were taken from RFC 3550, chapters 6.3.1 and A.7
552 | const (
553 | rtcpMinimumTime = 5.0
554 | rtcpSenderFraction = 0.25
555 | rtcpRecvFraction = 1.0 - rtcpSenderFraction
556 | compensation = 2.71828 - 1.5
557 | )
558 |
559 | // rtcpInterval helper function computes the next time when to send an RTCP packet.
560 | //
561 | // The algorithm is copied from RFC 2550, A.7 and a little bit adapted to Go. This includes some important comments :-) .
562 | //
563 | func rtcpInterval(members, senders int, rtcpBw, avrgSize float64, weSent, initial bool) (int64, int64) {
564 |
565 | rtcpMinTime := rtcpMinimumTime
566 | if initial {
567 | rtcpMinTime /= 2
568 | }
569 |
570 | /*
571 | * Dedicate a fraction of the RTCP bandwidth to senders unless
572 | * the number of senders is large enough that their share is
573 | * more than that fraction.
574 | */
575 | n := members
576 | if senders <= int((float64(members) * rtcpSenderFraction)) {
577 | if weSent {
578 | rtcpBw *= rtcpSenderFraction
579 | n = senders
580 | } else {
581 | rtcpBw *= rtcpRecvFraction
582 | n -= senders
583 | }
584 | }
585 | /*
586 | * The effective number of sites times the average packet size is
587 | * the total number of octets sent when each site sends a report.
588 | * Dividing this by the effective bandwidth gives the time
589 | * interval over which those packets must be sent in order to
590 | * meet the bandwidth target, with a minimum enforced. In that
591 | * time interval we send one report so this time is also our
592 | * average time between reports.
593 | */
594 | t := avrgSize * float64(n) / rtcpBw
595 | if t < rtcpMinTime {
596 | t = rtcpMinTime
597 | }
598 | td := int64(t * 1e9) // determinisitic interval, see chap 6.3.1, 6.3.5
599 | var randBuf [2]byte
600 | rand.Read(randBuf[:])
601 | randNo := uint16(randBuf[0])
602 | randNo |= uint16(randBuf[1]) << 8
603 | randFloat := float64(randNo)/65536.0 + 0.5
604 |
605 | t *= randFloat
606 | t /= compensation
607 | // return as nanoseconds
608 | return int64(t * 1e9), td
609 | }
610 |
611 | // newCrtlEvent is a little helper function to create and initialize a new control event.
612 | func newCrtlEvent(eventType int, ssrc, idx uint32) (ctrlEv *CtrlEvent) {
613 | ctrlEv = new(CtrlEvent)
614 | ctrlEv.EventType = eventType
615 | ctrlEv.Ssrc = ssrc
616 | ctrlEv.Index = idx
617 | return
618 | }
619 |
620 | // Number of seconds ellapsed from 1900 to 1970, see RFC 5905
621 | const ntpEpochOffset = 2208988800
622 |
623 | // toNtpStamp converts a GO time into the NTP format according to RFC 5905
624 | func toNtpStamp(tm int64) (seconds, fraction uint32) {
625 | seconds = uint32(tm/1e9 + ntpEpochOffset) // Go uses ns, thus divide by 1e9 to get seconds
626 | fraction = uint32(((tm % 1e9) << 32) / 1e9)
627 | return
628 | }
629 |
630 | // fromNtp converts a NTP timestamp into GO time
631 | func fromNtp(seconds, fraction uint32) (tm int64) {
632 | n := (int64(fraction) * 1e9) >> 32
633 | tm = (int64(seconds)-ntpEpochOffset)*1e9 + n
634 | return
635 | }
636 |
--------------------------------------------------------------------------------
/stream.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2011 Werner Dittmann
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU General Public License as published by
5 | // the Free Software Foundation, either version 3 of the License, or
6 | // (at your option) any later version.
7 | //
8 | // This program is distributed in the hope that it will be useful,
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with this program. If not, see .
15 | //
16 | // Authors: Werner Dittmann
17 | //
18 |
19 | package rtp
20 |
21 | import (
22 | "crypto/rand"
23 | "sync"
24 | "time"
25 | )
26 |
27 | const (
28 | maxDropout = 3000
29 | minSequential = 0
30 | maxMisorder = 100
31 | )
32 |
33 | // The type of the stream.
34 | const (
35 | InputStream = iota
36 | OutputStream
37 | )
38 |
39 | const (
40 | idle = iota
41 | active
42 | isClosing
43 | isClosed
44 | )
45 |
46 | type SdesItemMap map[int]string
47 |
48 | // ctrlStatistics holds data relevant to compute RTCP Receive Reports (RR) and this is part of SsrcStreamIn
49 | type ctrlStatistics struct {
50 | //
51 | // all times are in nanoseconds
52 | lastPacketTime, // time the last RTP packet from this source was received
53 | lastRtcpPacketTime, // time the last RTCP packet was received.
54 | initialDataTime,
55 | lastRtcpSrTime int64 // time the last RTCP SR was received. Required for DLSR computation.
56 |
57 | // Data used to compute outgoing RR reports.
58 | packetCount, // number of packets received from this source.
59 | octetCount, // number of octets received from this source.
60 | extendedMaxSeqNum,
61 | lastPacketTransitTime,
62 | initialDataTimestamp,
63 | cumulativePacketLost uint32
64 | maxSeqNum uint16 // the highest sequence number seen from this source
65 | fractionLost uint8
66 | // for interarrivel jitter computation
67 | // interarrival jitter of packets from this source.
68 | jitter uint32
69 |
70 | // this flag assures we only call one gotHello and one gotGoodbye for this src.
71 | flag bool
72 | // for source validation:
73 | probation int // packets in sequence before valid.
74 | baseSeqNum uint16
75 | expectedPrior,
76 | receivedPrior,
77 | badSeqNum,
78 | seqNumAccum uint32
79 | }
80 |
81 | // SenderInfoData stores the counters if used for an output stream, stores the received sender info data for an input stream.
82 | type SenderInfoData struct {
83 | NtpTime int64
84 | RtpTimestamp,
85 | SenderPacketCnt,
86 | SenderOctectCnt uint32
87 | }
88 |
89 | type RecvReportData struct {
90 | FracLost uint8
91 | PacketsLost,
92 | HighestSeqNo,
93 | Jitter,
94 | LastSr,
95 | Dlsr uint32
96 | }
97 |
98 | type SsrcStream struct {
99 | streamType int
100 | streamStatus int
101 | streamMutex sync.Mutex
102 | Address // Own if it is an output stream, remote address in case of input stream
103 | SenderInfoData // Sender reports if this is an input stream, read only.
104 | RecvReportData // Receiver reports if this is an output stream, read anly.
105 | SdesItems SdesItemMap // SDES item map, indexed by the RTCP SDES item types constants.
106 | // Read only, to set item use SetSdesItem()
107 | sdesChunkLen int // pre-computed SDES chunk length - updated when setting a new name, relevant for output streams
108 |
109 | // the following two field are active for input streams ony
110 | prevConflictAddr *Address
111 | statistics ctrlStatistics
112 |
113 | // The following two field are active for ouput streams only
114 | initialTime int64
115 | initialStamp uint32
116 |
117 | sequenceNumber uint16
118 | ssrc uint32
119 | payloadType byte
120 | sender bool // true if this source (ouput or input) was identified as active sender
121 |
122 | // For input streams: true if RTP packet seen after last RR
123 | dataAfterLastReport bool
124 | }
125 |
126 | const defaultCname = "GoRTP1.0.0@somewhere"
127 |
128 | const seqNumMod = (1 << 16)
129 |
130 | /*
131 | * *****************************************************************
132 | * SsrcStream functions, valid for output and input streams
133 | * *****************************************************************
134 | */
135 |
136 | // Ssrc returns the SSRC of this stream in host order.
137 | func (str *SsrcStream) Ssrc() uint32 {
138 | return str.ssrc
139 | }
140 |
141 | // SequenceNo returns the current RTP packet sequence number of this stream in host order.
142 | func (str *SsrcStream) SequenceNo() uint16 {
143 | return str.sequenceNumber
144 | }
145 |
146 | // SetPayloadType sets the payload type of this stream.
147 | //
148 | // According to RFC 3550 an application may change the payload type during a
149 | // the lifetime of a RTP stream. Refer to rtp.PayloadFormat type.
150 | //
151 | // The method returns false and does not set the payload type if the payload format
152 | // is not available in rtp.PayloadFormatMap. An application must either use a known
153 | // format or set the new payload format at the correct index before it sets the
154 | // payload type of the stream.
155 | //
156 | // pt - the payload type number.
157 | //
158 | func (str *SsrcStream) SetPayloadType(pt byte) (ok bool) {
159 | if _, ok = PayloadFormatMap[int(pt)]; !ok {
160 | return
161 | }
162 | str.payloadType = pt
163 | return
164 | }
165 |
166 | // PayloadType returns the payload type of this stream.
167 | func (str *SsrcStream) PayloadType() byte {
168 | return str.payloadType
169 | }
170 |
171 | // StreamType returns stream's type, either input stream or otput stream.
172 | //
173 | func (str *SsrcStream) StreamType() int {
174 | return str.streamType
175 | }
176 |
177 | /*
178 | * *****************************************************************
179 | * Processing for output streams
180 | * *****************************************************************
181 | */
182 |
183 | func newSsrcStreamOut(own *Address, ssrc uint32, sequenceNo uint16) (so *SsrcStream) {
184 | so = new(SsrcStream)
185 | so.streamType = OutputStream
186 | so.ssrc = ssrc
187 | if ssrc == 0 {
188 | so.newSsrc()
189 | }
190 | so.sequenceNumber = sequenceNo
191 | if sequenceNo == 0 {
192 | so.newSequence()
193 | }
194 | so.IpAddr = own.IpAddr
195 | so.DataPort = own.DataPort
196 | so.CtrlPort = own.CtrlPort
197 | so.payloadType = 0xff // initialize to illegal payload type
198 | so.initialTime = time.Now().UnixNano()
199 | so.newInitialTimestamp()
200 | so.SdesItems = make(SdesItemMap, 2)
201 | so.SetSdesItem(SdesCname, defaultCname)
202 | return
203 | }
204 |
205 | // newDataPacket creates a new RTP packet suitable for use with the output stream.
206 | //
207 | // This method returns an initialized RTP packet that contains the correct SSRC, sequence
208 | // number, the updated timestamp, and payload type if payload type was set in the stream.
209 | //
210 | // The application computes the next stamp based on the payload's frequency. The stamp usually
211 | // advances by the number of samples contained in the RTP packet.
212 | //
213 | // For example PCMU with a 8000Hz frequency sends 160 samples every 20m - thus the timestamp
214 | // must adavance by 160 for each following packet. For fixed codecs, for example PCMU, the
215 | // number of samples correspond to the payload length. For variable codecs the number of samples
216 | // has no direct relationship with the payload length.
217 | //
218 | // stamp - the RTP timestamp for this packet.
219 | //
220 | func (str *SsrcStream) newDataPacket(stamp uint32) (rp *DataPacket) {
221 | rp = newDataPacket()
222 | rp.SetSsrc(str.ssrc)
223 | rp.SetPayloadType(str.payloadType)
224 | rp.SetTimestamp(stamp + str.initialStamp)
225 | rp.SetSequence(str.sequenceNumber)
226 | str.sequenceNumber++
227 | return
228 | }
229 |
230 | // newCtrlPacket creates a new RTCP packet suitable for use with the specified output stream.
231 | //
232 | // This method returns an initialized RTCP packet that contains the correct SSRC, and the RTCP packet
233 | // type. In addition the method returns the offset to the next position inside the buffer.
234 | //
235 | //
236 | // streamindex - the index of the output stream as returned by NewSsrcStreamOut
237 | // stamp - the RTP timestamp for this packet.
238 | //
239 | func (str *SsrcStream) newCtrlPacket(pktType int) (rp *CtrlPacket, offset int) {
240 | rp, offset = newCtrlPacket()
241 | rp.SetType(0, pktType)
242 | rp.SetSsrc(0, str.ssrc)
243 | return
244 | }
245 |
246 | // AddHeaderCtrl adds a new fixed RTCP header word into the compound, does not set SSRC after fixed header field
247 | func (str *SsrcStream) addCtrlHeader(rp *CtrlPacket, offset, pktType int) (newOffset int) {
248 | newOffset = rp.addHeaderCtrl(offset)
249 | rp.SetType(offset, pktType)
250 | return
251 | }
252 |
253 | // newSsrc generates a random SSRC and sets it in stream
254 | func (str *SsrcStream) newSsrc() {
255 | var randBuf [4]byte
256 | rand.Read(randBuf[:])
257 | ssrc := uint32(randBuf[0])
258 | ssrc |= uint32(randBuf[1]) << 8
259 | ssrc |= uint32(randBuf[2]) << 16
260 | ssrc |= uint32(randBuf[3]) << 24
261 | str.ssrc = ssrc
262 |
263 | }
264 |
265 | // newInitialTimestamp creates a random initiali timestamp for outgoing packets
266 | func (str *SsrcStream) newInitialTimestamp() {
267 | var randBuf [4]byte
268 | rand.Read(randBuf[:])
269 | tmp := uint32(randBuf[0])
270 | tmp |= uint32(randBuf[1]) << 8
271 | tmp |= uint32(randBuf[2]) << 16
272 | tmp |= uint32(randBuf[3]) << 24
273 | str.initialStamp = (tmp & 0xFFFFFFF)
274 | }
275 |
276 | // newSequence generates a random sequence and sets it in stream
277 | func (str *SsrcStream) newSequence() {
278 | var randBuf [2]byte
279 | rand.Read(randBuf[:])
280 | sequenceNo := uint16(randBuf[0])
281 | sequenceNo |= uint16(randBuf[1]) << 8
282 | sequenceNo &= 0xEFFF
283 | str.sequenceNumber = sequenceNo
284 | }
285 |
286 | // readRecvReport reads data from receive report and fills it into output stream RecvReportData structure
287 | func (so *SsrcStream) readRecvReport(report recvReport) {
288 | so.FracLost = report.packetsLostFrac()
289 | so.PacketsLost = report.packetsLost()
290 | so.HighestSeqNo = report.highestSeq()
291 | so.Jitter = report.jitter()
292 | so.LastSr = report.lsr()
293 | so.Dlsr = report.dlsr()
294 | }
295 |
296 | // fillSenderInfo fills in the senderInfo.
297 | func (so *SsrcStream) fillSenderInfo(info senderInfo) {
298 | info.setOctetCount(so.SenderOctectCnt)
299 | info.setPacketCount(so.SenderPacketCnt)
300 | tm := time.Now().UnixNano()
301 | sec, frac := toNtpStamp(tm)
302 | info.setNtpTimeStamp(sec, frac)
303 |
304 | tm1 := uint32((tm - so.initialTime) / 1e6) // time since session creation in ms
305 | tm1 *= uint32(PayloadFormatMap[int(so.payloadType)].ClockRate / 1e3) // compute number of samples
306 | tm1 += so.initialStamp
307 | info.setRtpTimeStamp(tm1)
308 | }
309 |
310 | // makeSdesChunk creates an SDES chunk at the current inUse position and returns offset that points after the chunk.
311 | func (so *SsrcStream) makeSdesChunk(rc *CtrlPacket) (newOffset int) {
312 | chunk, newOffset := rc.newSdesChunk(so.sdesChunkLen)
313 | copy(chunk, nullArray[:]) // fill with zeros before using
314 | chunk.setSsrc(so.ssrc)
315 | itemOffset := 4
316 | for itemType, name := range so.SdesItems {
317 | itemOffset += chunk.setItemData(itemOffset, byte(itemType), name)
318 | }
319 | return
320 | }
321 |
322 | // SetSdesItem set a new SDES item or overwrites an existing one with new text (string).
323 | // An application shall set at least a CNAME SDES item text otherwise w use a default string.
324 | func (so *SsrcStream) SetSdesItem(itemType int, itemText string) bool {
325 | if itemType <= SdesEnd || itemType >= sdesMax {
326 | return false
327 | }
328 | so.SdesItems[itemType] = itemText
329 | length := 4 // Initialize with SSRC length
330 | for _, name := range so.SdesItems {
331 | length += 2 + len(name) // add length of each item
332 | }
333 | if rem := length & 0x3; rem == 0 { // if already multiple of 4 add another 4 that holds "end" marker byte plus 3 bytes padding
334 | length += 4
335 | } else {
336 | length += 4 - rem
337 | }
338 | so.sdesChunkLen = length
339 | return true
340 | }
341 |
342 | // makeByeData creates a by data block after the BYE RTCP header field.
343 | // Currently only one SSRC for bye data supported. Additional CSRCs requiere addiitonal data structure in output stream.
344 | func (so *SsrcStream) makeByeData(rc *CtrlPacket, reason string) (newOffset int) {
345 | length := 4
346 | if len(reason) > 0 {
347 | length += (len(reason) + 3 + 1) & ^3 // plus one is the length field
348 | }
349 | bye, newOffset := rc.newByeData(length)
350 | bye.setSsrc(0, so.ssrc)
351 | if len(reason) > 0 {
352 | bye.setReason(reason, 1)
353 | }
354 | return
355 | }
356 |
357 | /*
358 | * *****************************************************************
359 | * Processing for input streams
360 | * *****************************************************************
361 | */
362 |
363 | // newSsrcStreamIn creates a new input stream and sets the variables required for
364 | // RTP and RTCP processing to well defined initial values.
365 | func newSsrcStreamIn(from *Address, ssrc uint32) (si *SsrcStream) {
366 | si = new(SsrcStream)
367 | si.streamType = InputStream
368 | si.ssrc = ssrc
369 | si.IpAddr = from.IpAddr
370 | si.DataPort = from.DataPort
371 | si.CtrlPort = from.CtrlPort
372 | si.SdesItems = make(SdesItemMap, 2)
373 | si.initStats()
374 | return
375 | }
376 |
377 | // checkSsrcIncomingData checks for collision or loops on incoming data packets.
378 | // Implements th algorithm found in chap 8.2 in RFC 3550
379 | func (si *SsrcStream) checkSsrcIncomingData(existingStream bool, rs *Session, rp *DataPacket) (result bool) {
380 | result = true
381 |
382 | // Test if the source is new and its SSRC is not already used in an output stream.
383 | // Thus a new input stream without collision.
384 | if !existingStream && !rs.isOutputSsrc(si.ssrc) {
385 | return result
386 | }
387 |
388 | // Found an existing input stream. Check if it is still same address/port.
389 | // if yes, no conflicts, no further checks required.
390 | if si.DataPort != rp.fromAddr.DataPort || !si.IpAddr.Equal(rp.fromAddr.IpAddr) {
391 | // SSRC collision or a loop has happened
392 | strOut, _, localSsrc := rs.lookupSsrcMapOut(si.ssrc)
393 | if !localSsrc { // Not a SSRC in use for own output (local SSRC)
394 | // TODO: Optional error counter: Known SSRC stream changed address or port
395 | // Note this differs from the default in the RFC. Discard packet only when the collision is
396 | // repeating (to avoid flip-flopping)
397 | if si.prevConflictAddr != nil &&
398 | si.prevConflictAddr.IpAddr.Equal(rp.fromAddr.IpAddr) &&
399 | si.prevConflictAddr.DataPort == rp.fromAddr.DataPort {
400 | result = false // discard packet and do not flip-flop
401 | } else {
402 | // Record who has collided so that in the future we can know if the collision repeats.
403 | si.prevConflictAddr = &Address{rp.fromAddr.IpAddr, rp.fromAddr.DataPort, 0}
404 | // Change sync source transport address
405 | si.IpAddr = rp.fromAddr.IpAddr
406 | si.DataPort = rp.fromAddr.DataPort
407 | }
408 | } else {
409 | // Collision or loop of own packets. In this case si was found in ouput stream map,
410 | // thus cannot be in input stream map
411 | if rs.checkConflictData(&rp.fromAddr) {
412 | // Optional error counter.
413 | result = false
414 | } else {
415 | // New collision
416 | // dispatch a BYE for a new confilicting output stream, using old SSRC
417 | // renew the output stream's SSRC
418 | rs.WriteCtrl(rs.buildRtcpByePkt(strOut, "SSRC collision detected when receiving RTCP packet."))
419 | rs.replaceStream(strOut)
420 | si.IpAddr = rp.fromAddr.IpAddr
421 | si.DataPort = rp.fromAddr.DataPort
422 | si.CtrlPort = 0
423 | si.initStats()
424 | }
425 | }
426 | }
427 | return
428 | }
429 |
430 | // recordReceptionData checks validity (probation), sequence numbers, computes jitter, and records the statistics for incoming data packets.
431 | // See algorithms in chapter A.1 (sequence number handling) and A.8 (jitter computation)
432 | func (si *SsrcStream) recordReceptionData(rp *DataPacket, rs *Session, recvTime int64) (result bool) {
433 | result = true
434 |
435 | seq := rp.Sequence()
436 |
437 | if si.statistics.probation != 0 {
438 | // source is not yet valid.
439 | if seq == si.statistics.maxSeqNum+1 {
440 | // packet in sequence.
441 | si.statistics.probation--
442 | if si.statistics.probation == 0 {
443 | si.statistics.seqNumAccum = 0
444 | } else {
445 | result = false
446 | }
447 | } else {
448 | // packet not in sequence.
449 | si.statistics.probation = minSequential - 1
450 | result = false
451 | }
452 | si.statistics.maxSeqNum = seq
453 | } else {
454 | // source was already valid.
455 | step := seq - si.statistics.maxSeqNum
456 | if step < maxDropout {
457 | // Ordered, with not too high step.
458 | if seq < si.statistics.maxSeqNum {
459 | // sequene number wrapped.
460 | si.statistics.seqNumAccum += seqNumMod
461 | }
462 | si.statistics.maxSeqNum = seq
463 | } else if step <= (seqNumMod - maxMisorder) {
464 | // too high step of the sequence number.
465 | // TODO: check usage of baseSeqNum
466 | if uint32(seq) == si.statistics.badSeqNum {
467 | // Here we saw two sequential packets - assume other side restarted, so just re-sync
468 | // and treat this packet as first packet
469 | si.statistics.maxSeqNum = seq
470 | si.statistics.baseSeqNum = seq
471 | si.statistics.seqNumAccum = 0
472 | si.statistics.badSeqNum = seqNumMod + 1
473 | } else {
474 | si.statistics.badSeqNum = uint32((seq + 1) & (seqNumMod - 1))
475 | // This additional check avoids that the very first packet from a source be discarded.
476 | if si.statistics.packetCount > 0 {
477 | result = false
478 | } else {
479 | si.statistics.maxSeqNum = seq
480 | }
481 | }
482 | } else {
483 | // duplicate or reordered packet
484 | }
485 | }
486 |
487 | if result {
488 | si.sequenceNumber = si.statistics.maxSeqNum
489 | // the packet is considered valid.
490 | si.statistics.packetCount++
491 | si.statistics.octetCount += uint32(len(rp.Payload()))
492 | if si.statistics.packetCount == 1 {
493 | si.statistics.initialDataTimestamp = rp.Timestamp()
494 | si.statistics.baseSeqNum = seq
495 | }
496 | si.streamMutex.Lock()
497 | si.statistics.lastPacketTime = recvTime
498 | if !si.sender && rs.rtcpCtrlChan != nil {
499 | rs.rtcpCtrlChan <- rtcpIncrementSender
500 | }
501 | si.sender = true // Stream is sender. If it was false new stream or no RTP packets for some time
502 | si.dataAfterLastReport = true
503 | si.streamMutex.Unlock()
504 |
505 | // compute the interarrival jitter estimation.
506 | pt := int(rp.PayloadType())
507 | // compute lastPacketTime to ms and clockrate as kHz
508 | arrival := uint32(si.statistics.lastPacketTime / 1e6 * int64(PayloadFormatMap[pt].ClockRate/1e3))
509 | transitTime := arrival - rp.Timestamp()
510 | if si.statistics.lastPacketTransitTime != 0 {
511 | delta := int32(transitTime - si.statistics.lastPacketTransitTime)
512 | if delta < 0 {
513 | delta = -delta
514 | }
515 | si.statistics.jitter += uint32(delta) - ((si.statistics.jitter + 8) >> 4)
516 | }
517 | si.statistics.lastPacketTransitTime = transitTime
518 | }
519 | return
520 | }
521 |
522 | // checkSsrcIncomingData checks for collision or loops on incoming data packets.
523 | // Implements th algorithm found in chap 8.2 in RFC 3550
524 | func (si *SsrcStream) checkSsrcIncomingCtrl(existingStream bool, rs *Session, from *Address) (result bool) {
525 | result = true
526 |
527 | // Test if the source is new and its SSRC is not already used in an output stream.
528 | // Thus a new input stream without collision.
529 | if !existingStream && !rs.isOutputSsrc(si.ssrc) {
530 | return result
531 | }
532 | // Found an existing input stream. Check if it is still same address/port.
533 | // if yes, no conflicts, no further checks required.
534 | if si.CtrlPort != from.CtrlPort || !si.IpAddr.Equal(from.IpAddr) {
535 | // SSRC collision or a loop has happened
536 | strOut, _, localSsrc := rs.lookupSsrcMapOut(si.ssrc)
537 | if !localSsrc { // Not a SSRC in use for own output (local SSRC)
538 | // TODO: Optional error counter: Know SSRC stream changed address or port
539 | // Note this differs from the default in the RFC. Discard packet only when the collision is
540 | // repeating (to avoid flip-flopping)
541 | if si.prevConflictAddr != nil &&
542 | si.prevConflictAddr.IpAddr.Equal(from.IpAddr) &&
543 | si.prevConflictAddr.CtrlPort == from.CtrlPort {
544 | result = false // discard packet and do not flip-flop
545 | } else {
546 | // Record who has collided so that in the future we can know if the collision repeats.
547 | si.prevConflictAddr = &Address{from.IpAddr, 0, from.CtrlPort}
548 | // Change sync source transport address
549 | si.IpAddr = from.IpAddr
550 | si.CtrlPort = from.CtrlPort
551 | }
552 | } else {
553 | // Collision or loop of own packets. In this case strOut == si.
554 | if rs.checkConflictCtrl(from) {
555 | // Optional error counter.
556 | result = false
557 | } else {
558 | // New collision, dispatch a BYE using old SSRC, renew the output stream's SSRC
559 | rs.WriteCtrl(rs.buildRtcpByePkt(strOut, "SSRC collision detected when receiving RTCP packet."))
560 | rs.replaceStream(strOut)
561 | si.IpAddr = from.IpAddr
562 | si.DataPort = 0
563 | si.CtrlPort = from.CtrlPort
564 | si.initStats()
565 | }
566 | }
567 | }
568 | return
569 | }
570 |
571 | // makeRecvReport fills a receiver report at the current inUse position and returns offset that points after the report.
572 | // See chapter A.3 in RFC 3550 regarding the packet lost algorithm, end of chapter 6.4.1 regarding LSR, DLSR stuff.
573 | //
574 | func (si *SsrcStream) makeRecvReport(rp *CtrlPacket) (newOffset int) {
575 |
576 | report, newOffset := rp.newRecvReport()
577 |
578 | extMaxSeq := si.statistics.seqNumAccum + uint32(si.statistics.maxSeqNum)
579 | expected := extMaxSeq - uint32(si.statistics.baseSeqNum) + 1
580 | lost := expected - si.statistics.packetCount
581 | if si.statistics.packetCount == 0 {
582 | lost = 0
583 | }
584 | expectedDelta := expected - si.statistics.expectedPrior
585 | si.statistics.expectedPrior = expected
586 |
587 | receivedDelta := si.statistics.packetCount - si.statistics.receivedPrior
588 | si.statistics.receivedPrior = si.statistics.packetCount
589 |
590 | lostDelta := expectedDelta - receivedDelta
591 |
592 | var fracLost byte
593 | if expectedDelta != 0 && lostDelta > 0 {
594 | fracLost = byte((lostDelta << 8) / expectedDelta)
595 | }
596 |
597 | var lsr, dlsr uint32
598 | if si.statistics.lastRtcpSrTime != 0 {
599 | sec, frac := toNtpStamp(si.statistics.lastRtcpSrTime)
600 | ntp := (sec << 32) | frac
601 | lsr = ntp >> 16
602 | sec, frac = toNtpStamp(time.Now().UnixNano() - si.statistics.lastRtcpSrTime)
603 | ntp = (sec << 32) | frac
604 | dlsr = ntp >> 16
605 | }
606 |
607 | report.setSsrc(si.ssrc)
608 | report.setPacketsLost(lost)
609 | report.setPacketsLostFrac(fracLost)
610 | report.setHighestSeq(extMaxSeq)
611 | report.setJitter(si.statistics.jitter >> 4)
612 | report.setLsr(lsr)
613 | report.setDlsr(dlsr)
614 |
615 | return
616 | }
617 |
618 | func (si *SsrcStream) readSenderInfo(info senderInfo) {
619 | seconds, fraction := info.ntpTimeStamp()
620 | si.NtpTime = fromNtp(seconds, fraction)
621 | si.RtpTimestamp = info.rtpTimeStamp()
622 | si.SenderPacketCnt = info.packetCount()
623 | si.SenderOctectCnt = info.octetCount()
624 | }
625 |
626 | // goodBye marks this source as having sent a BYE control packet.
627 | func (si *SsrcStream) goodbye() bool {
628 | if !si.statistics.flag {
629 | return false
630 | }
631 | si.statistics.flag = false
632 | return true
633 | }
634 |
635 | // hello marks this source as having sent some packet.
636 | func (si *SsrcStream) hello() bool {
637 | if si.statistics.flag {
638 | return false
639 | }
640 | si.statistics.flag = true
641 | return true
642 | }
643 |
644 | // initStats initializes all RTCP statistic counters and other relevant data.
645 | func (si *SsrcStream) initStats() {
646 | si.statistics.lastPacketTime = 0
647 | si.statistics.lastRtcpPacketTime = 0
648 | si.statistics.lastRtcpSrTime = 0
649 |
650 | si.statistics.packetCount = 0
651 | si.statistics.octetCount = 0
652 | si.statistics.maxSeqNum = 0
653 | si.statistics.extendedMaxSeqNum = 0
654 | si.statistics.cumulativePacketLost = 0
655 | si.statistics.fractionLost = 0
656 | si.statistics.jitter = 0
657 | si.statistics.initialDataTimestamp = 0
658 | si.statistics.initialDataTime = 0
659 | si.statistics.flag = false
660 |
661 | si.statistics.badSeqNum = seqNumMod + 1
662 | si.statistics.probation = minSequential
663 | si.statistics.baseSeqNum = 0
664 | si.statistics.expectedPrior = 0
665 | si.statistics.receivedPrior = 0
666 | si.statistics.seqNumAccum = 0
667 | }
668 |
669 | func (si *SsrcStream) parseSdesChunk(sc sdesChunk) {
670 | offset := 4 // points after SSRC field of this chunk
671 |
672 | for {
673 | itemType := sc.getItemType(offset)
674 | if itemType <= SdesEnd || itemType >= sdesMax {
675 | return
676 | }
677 |
678 | txtLen := sc.getItemLen(offset)
679 | itemTxt := sc.getItemText(offset, txtLen)
680 | offset += 2 + txtLen
681 | if name, ok := si.SdesItems[itemType]; ok && name == itemTxt {
682 | continue
683 | }
684 | txt := make([]byte, len(itemTxt))
685 | copy(txt, itemTxt)
686 | si.SdesItems[itemType] = string(txt)
687 | }
688 | }
689 |
--------------------------------------------------------------------------------
/transport.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2011 Werner Dittmann
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU General Public License as published by
5 | // the Free Software Foundation, either version 3 of the License, or
6 | // (at your option) any later version.
7 | //
8 | // This program is distributed in the hope that it will be useful,
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with this program. If not, see .
15 | //
16 | // Authors: Werner Dittmann
17 | //
18 |
19 | package rtp
20 |
21 | type TransportRecv interface {
22 | ListenOnTransports() error
23 | OnRecvData(rp *DataPacket) bool
24 | OnRecvCtrl(rp *CtrlPacket) bool
25 | SetCallUpper(upper TransportRecv)
26 | CloseRecv()
27 | SetEndChannel(ch TransportEnd)
28 | }
29 |
30 | type TransportWrite interface {
31 | WriteDataTo(rp *DataPacket, addr *Address) (n int, err error)
32 | WriteCtrlTo(rp *CtrlPacket, addr *Address) (n int, err error)
33 | SetToLower(lower TransportWrite)
34 | CloseWrite()
35 | }
36 |
37 | type TransportCommon struct {
38 | transportEnd TransportEnd
39 | dataRecvStop,
40 | ctrlRecvStop,
41 | dataWriteStop,
42 | ctrlWriteStop bool
43 | }
44 |
--------------------------------------------------------------------------------
/transportUDP.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2011 Werner Dittmann
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU General Public License as published by
5 | // the Free Software Foundation, either version 3 of the License, or
6 | // (at your option) any later version.
7 | //
8 | // This program is distributed in the hope that it will be useful,
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | // GNU General Public License for more details.
12 | //
13 | // You should have received a copy of the GNU General Public License
14 | // along with this program. If not, see .
15 | //
16 | // Authors: Werner Dittmann
17 | //
18 |
19 | package rtp
20 |
21 | import (
22 | "fmt"
23 | "net"
24 | "time"
25 |
26 | "github.com/cloudvm/gortp/iana"
27 | "golang.org/x/net/ipv4"
28 | )
29 |
30 | // RtpTransportUDP implements the interfaces RtpTransportRecv and RtpTransportWrite for RTP transports.
31 | type TransportUDP struct {
32 | TransportCommon
33 | callUpper TransportRecv
34 | toLower TransportWrite
35 | dataConn, ctrlConn *net.UDPConn
36 | localAddrRtp, localAddrRtcp *net.UDPAddr
37 | }
38 |
39 | // NewRtpTransportUDP creates a new RTP transport for UPD.
40 | //
41 | // addr - The UPD socket's local IP address
42 | //
43 | // port - The port number of the RTP data port. This must be an even port number.
44 | // The following odd port number is the control (RTCP) port.
45 | //
46 | func NewTransportUDP(addr *net.IPAddr, port int) (*TransportUDP, error) {
47 | tp := new(TransportUDP)
48 | tp.callUpper = tp
49 | tp.localAddrRtp = &net.UDPAddr{addr.IP, port, ""}
50 | tp.localAddrRtcp = &net.UDPAddr{addr.IP, port + 1, ""}
51 | return tp, nil
52 | }
53 |
54 | // ListenOnTransports listens for incoming RTP and RTCP packets addressed
55 | // to this transport.
56 | //
57 | func (tp *TransportUDP) ListenOnTransports() (err error) {
58 | tp.dataConn, err = net.ListenUDP(tp.localAddrRtp.Network(), tp.localAddrRtp)
59 | if err != nil {
60 | return
61 | }
62 |
63 | p := ipv4.NewConn(tp.dataConn)
64 | if err = p.SetTOS(iana.DiffServAF41); err != nil {
65 | fmt.Printf("TransportUDP: failed to set TOS marking on dataConn\n")
66 | }
67 |
68 | tp.ctrlConn, err = net.ListenUDP(tp.localAddrRtcp.Network(), tp.localAddrRtcp)
69 | if err != nil {
70 | tp.dataConn.Close()
71 | tp.dataConn = nil
72 | return
73 | }
74 | go tp.readDataPacket()
75 | go tp.readCtrlPacket()
76 | return nil
77 | }
78 |
79 | // *** The following methods implement the rtp.TransportRecv interface.
80 |
81 | // SetCallUpper implements the rtp.TransportRecv SetCallUpper method.
82 | func (tp *TransportUDP) SetCallUpper(upper TransportRecv) {
83 | tp.callUpper = upper
84 | }
85 |
86 | // OnRecvRtp implements the rtp.TransportRecv OnRecvRtp method.
87 | //
88 | // TransportUDP does not implement any processing because it is the lowest
89 | // layer and expects an upper layer to receive data.
90 | func (tp *TransportUDP) OnRecvData(rp *DataPacket) bool {
91 | fmt.Printf("TransportUDP: no registered upper layer RTP packet handler\n")
92 | return false
93 | }
94 |
95 | // OnRecvRtcp implements the rtp.TransportRecv OnRecvRtcp method.
96 | //
97 | // TransportUDP does not implement any processing because it is the lowest
98 | // layer and expects an upper layer to receive data.
99 | func (tp *TransportUDP) OnRecvCtrl(rp *CtrlPacket) bool {
100 | fmt.Printf("TransportUDP: no registered upper layer RTCP packet handler\n")
101 | return false
102 | }
103 |
104 | // CloseRecv implements the rtp.TransportRecv CloseRecv method.
105 | func (tp *TransportUDP) CloseRecv() {
106 | //
107 | // The correct way to do it is to close the UDP connection after setting the
108 | // stop flags to true. However, until issue 2116 is solved just set the flags
109 | // and rely on the read timeout in the read packet functions
110 | //
111 | tp.dataRecvStop = true
112 | tp.ctrlRecvStop = true
113 |
114 | // err := tp.rtpConn.Close()
115 | // if err != nil {
116 | // fmt.Printf("Close failed: %s\n", err.String())
117 | // }
118 | // tp.rtcpConn.Close()
119 | }
120 |
121 | // setEndChannel receives and set the channel to signal back after network socket was closed and receive loop terminated.
122 | func (tp *TransportUDP) SetEndChannel(ch TransportEnd) {
123 | tp.transportEnd = ch
124 | }
125 |
126 | // *** The following methods implement the rtp.TransportWrite interface.
127 |
128 | // SetToLower implements the rtp.TransportWrite SetToLower method.
129 | //
130 | // Usually TransportUDP is already the lowest layer.
131 | func (tp *TransportUDP) SetToLower(lower TransportWrite) {
132 | tp.toLower = lower
133 | }
134 |
135 | // WriteRtpTo implements the rtp.TransportWrite WriteRtpTo method.
136 | func (tp *TransportUDP) WriteDataTo(rp *DataPacket, addr *Address) (n int, err error) {
137 | return tp.dataConn.WriteToUDP(rp.buffer[0:rp.inUse], &net.UDPAddr{addr.IpAddr, addr.DataPort, ""})
138 | }
139 |
140 | // WriteRtcpTo implements the rtp.TransportWrite WriteRtcpTo method.
141 | func (tp *TransportUDP) WriteCtrlTo(rp *CtrlPacket, addr *Address) (n int, err error) {
142 | //return tp.ctrlConn.WriteToUDP(rp.buffer[0:rp.inUse], &net.UDPAddr{addr.IpAddr, addr.CtrlPort, ""})
143 | // TODO: big hack - send back RTCP packets (SR) in RTP data port, since hole punching is only
144 | // done on the RTP data port...
145 | return tp.dataConn.WriteToUDP(rp.buffer[0:rp.inUse], &net.UDPAddr{addr.IpAddr, addr.DataPort, ""})
146 | }
147 |
148 | // CloseWrite implements the rtp.TransportWrite CloseWrite method.
149 | //
150 | // Nothing to do for TransportUDP. The application shall close the receiver (CloseRecv()), this will
151 | // close the local UDP socket.
152 | func (tp *TransportUDP) CloseWrite() {
153 | }
154 |
155 | // *** Local functions and methods.
156 |
157 | // Here the local RTP and RTCP UDP network receivers. The ListenOnTransports() starts them
158 | // as go functions. The functions just receive data from the network, copy it into
159 | // the packet buffers and forward the packets to the next upper layer via callback
160 | // if callback is not nil
161 |
162 | func (tp *TransportUDP) readDataPacket() {
163 | var buf [defaultBufferSize]byte
164 |
165 | tp.dataRecvStop = false
166 | for {
167 | tp.dataConn.SetReadDeadline(time.Now().Add(20 * time.Millisecond)) // 20 ms, re-test and remove after Go issue 2116 is solved
168 | n, addr, err := tp.dataConn.ReadFromUDP(buf[0:])
169 | if tp.dataRecvStop {
170 | break
171 | }
172 | if e, ok := err.(net.Error); ok && e.Timeout() {
173 | continue
174 | }
175 | if err != nil {
176 | break
177 | }
178 | rp := newDataPacket()
179 | rp.fromAddr.IpAddr = addr.IP
180 | rp.fromAddr.DataPort = addr.Port
181 | rp.fromAddr.CtrlPort = 0
182 | rp.inUse = n
183 | copy(rp.buffer, buf[0:n])
184 |
185 | if tp.callUpper != nil {
186 | tp.callUpper.OnRecvData(rp)
187 | }
188 | }
189 | tp.dataConn.Close()
190 | tp.transportEnd <- DataTransportRecvStopped
191 | }
192 |
193 | func (tp *TransportUDP) readCtrlPacket() {
194 | var buf [defaultBufferSize]byte
195 |
196 | tp.ctrlRecvStop = false
197 | for {
198 | tp.ctrlConn.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) // 100 ms, re-test and remove after Go issue 2116 is solved
199 | n, addr, err := tp.ctrlConn.ReadFromUDP(buf[0:])
200 | if tp.ctrlRecvStop {
201 | break
202 | }
203 | if e, ok := err.(net.Error); ok && e.Timeout() {
204 | continue
205 | }
206 | if err != nil {
207 | break
208 | }
209 | rp, _ := newCtrlPacket()
210 | rp.fromAddr.IpAddr = addr.IP
211 | rp.fromAddr.CtrlPort = addr.Port
212 | rp.fromAddr.DataPort = 0
213 | rp.inUse = n
214 | copy(rp.buffer, buf[0:n])
215 |
216 | if tp.callUpper != nil {
217 | tp.callUpper.OnRecvCtrl(rp)
218 | }
219 | }
220 | tp.ctrlConn.Close()
221 | tp.transportEnd <- CtrlTransportRecvStopped
222 | }
223 |
--------------------------------------------------------------------------------