├── .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 | [![Build Status](https://drone.io/github.com/danielvargas/gortp/status.png)](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 | --------------------------------------------------------------------------------