8. SSRC Identifier Allocation and Use The SSRC identifier carried in the RTP header and in various fields of RTCP packets is a random 32-bit number that is required to be globally unique within an RTP session. It is crucial that the number be chosen with care in order that participants on the same network or starting at the same time are not likely to choose the same number. It is not sufficient to use the local network address (such as an IPv4 address) for the identifier because the address may not be unique. Since RTP translators and mixers enable interoperation among multiple networks with different address spaces, the allocation patterns for addresses within two spaces might result in a much higher rate of collision than would occur with random allocation. Multiple sources running on one host would also conflict. It is also not sufficient to obtain an SSRC identifier simply by calling random() without carefully initializing the state. An example of how to generate a random identifier is presented in Appendix A.6. 8.1 Probability of Collision Since the identifiers are chosen randomly, it is possible that two or more sources will choose the same number. Collision occurs with the highest probability when all sources are started simultaneously, for example when triggered automatically by some session management event. If N is the number of sources and L the length of the identifier (here, 32 bits), the probability that two sources
independently pick the same value can be approximated for large N [20] as 1 - exp(-N**2 / 2**(L+1)). For N=1000, the probability is roughly 10**-4. The typical collision probability is much lower than the worst-case above. When one new source joins an RTP session in which all the other sources already have unique identifiers, the probability of collision is just the fraction of numbers used out of the space. Again, if N is the number of sources and L the length of the identifier, the probability of collision is N / 2**L. For N=1000, the probability is roughly 2*10**-7. The probability of collision is further reduced by the opportunity for a new source to receive packets from other participants before sending its first packet (either data or control). If the new source keeps track of the other participants (by SSRC identifier), then before transmitting its first packet the new source can verify that its identifier does not conflict with any that have been received, or else choose again. 8.2 Collision Resolution and Loop Detection Although the probability of SSRC identifier collision is low, all RTP implementations must be prepared to detect collisions and take the appropriate actions to resolve them. If a source discovers at any time that another source is using the same SSRC identifier as its own, it must send an RTCP BYE packet for the old identifier and choose another random one. If a receiver discovers that two other sources are colliding, it may keep the packets from one and discard the packets from the other when this can be detected by different source transport addresses or CNAMEs. The two sources are expected to resolve the collision so that the situation doesn't last. Because the random identifiers are kept globally unique for each RTP session, they can also be used to detect loops that may be introduced by mixers or translators. A loop causes duplication of data and control information, either unmodified or possibly mixed, as in the following examples: o A translator may incorrectly forward a packet to the same multicast group from which it has received the packet, either directly or through a chain of translators. In that case, the same packet appears several times, originating from different network sources. o Two translators incorrectly set up in parallel, i.e., with the same multicast groups on both sides, would both forward packets from one multicast group to the other. Unidirectional
translators would produce two copies; bidirectional translators would form a loop. o A mixer can close a loop by sending to the same transport destination upon which it receives packets, either directly or through another mixer or translator. In this case a source might show up both as an SSRC on a data packet and a CSRC in a mixed data packet. A source may discover that its own packets are being looped, or that packets from another source are being looped (a third-party loop). Both loops and collisions in the random selection of a source identifier result in packets arriving with the same SSRC identifier but a different source transport address, which may be that of the end system originating the packet or an intermediate system. Consequently, if a source changes its source transport address, it must also choose a new SSRC identifier to avoid being interpreted as a looped source. Loops or collisions occurring on the far side of a translator or mixer cannot be detected using the source transport address if all copies of the packets go through the translator or mixer, however collisions may still be detected when chunks from two RTCP SDES packets contain the same SSRC identifier but different CNAMEs. To detect and resolve these conflicts, an RTP implementation must include an algorithm similar to the one described below. It ignores packets from a new source or loop that collide with an established source. It resolves collisions with the participant's own SSRC identifier by sending an RTCP BYE for the old identifier and choosing a new one. However, when the collision was induced by a loop of the participant's own packets, the algorithm will choose a new identifier only once and thereafter ignore packets from the looping source transport address. This is required to avoid a flood of BYE packets. This algorithm depends upon the source transport address being the same for both RTP and RTCP packets from a source. The algorithm would require modifications to support applications that don't meet this constraint. This algorithm requires keeping a table indexed by source identifiers and containing the source transport address from which the identifier was (first) received, along with other state for that source. Each SSRC or CSRC identifier received in a data or control packet is looked up in this table in order to process that data or control information. For control packets, each element with its own SSRC, for example an SDES chunk, requires a separate lookup. (The SSRC in a reception report block is an exception.) If the SSRC or CSRC is not
found, a new entry is created. These table entries are removed when an RTCP BYE packet is received with the corresponding SSRC, or after no packets have arrived for a relatively long time (see Section 6.2.1). In order to track loops of the participant's own data packets, it is also necessary to keep a separate list of source transport addresses (not identifiers) that have been found to be conflicting. Note that this should be a short list, usually empty. Each element in this list stores the source address plus the time when the most recent conflicting packet was received. An element may be removed from the list when no conflicting packet has arrived from that source for a time on the order of 10 RTCP report intervals (see Section 6.2). For the algorithm as shown, it is assumed that the participant's own source identifier and state are included in the source identifier table. The algorithm could be restructured to first make a separate comparison against the participant's own source identifier. IF the SSRC or CSRC identifier is not found in the source identifier table: THEN create a new entry storing the source transport address and the SSRC or CSRC along with other state. CONTINUE with normal processing. (identifier is found in the table) IF the source transport address from the packet matches the one saved in the table entry for this identifier: THEN CONTINUE with normal processing. (an identifier collision or a loop is indicated) IF the source identifier is not the participant's own: THEN IF the source identifier is from an RTCP SDES chunk containing a CNAME item that differs from the CNAME in the table entry: THEN (optionally) count a third-party collision. ELSE (optionally) count a third-party loop. ABORT processing of data packet or control element. (a collision or loop of the participant's own data) IF the source transport address is found in the list of conflicting addresses: THEN IF the source identifier is not from an RTCP SDES chunk containing a CNAME item OR if that CNAME is the participant's own:
THEN (optionally) count occurrence of own traffic looped. mark current time in conflicting address list entry. ABORT processing of data packet or control element. log occurrence of a collision. create a new entry in the conflicting address list and mark current time. send an RTCP BYE packet with the old SSRC identifier. choose a new identifier. create a new entry in the source identifier table with the old SSRC plus the source transport address from the packet being processed. CONTINUE with normal processing. In this algorithm, packets from a newly conflicting source address will be ignored and packets from the original source will be kept. (If the original source was through a mixer and later the same source is received directly, the receiver may be well advised to switch unless other sources in the mix would be lost.) If no packets arrive from the original source for an extended period, the table entry will be timed out and the new source will be able to take over. This might occur if the original source detects the collision and moves to a new source identifier, but in the usual case an RTCP BYE packet will be received from the original source to delete the state without having to wait for a timeout. When a new SSRC identifier is chosen due to a collision, the candidate identifier should first be looked up in the source identifier table to see if it was already in use by some other source. If so, another candidate should be generated and the process repeated. A loop of data packets to a multicast destination can cause severe network flooding. All mixers and translators are required to implement a loop detection algorithm like the one here so that they can break loops. This should limit the excess traffic to no more than one duplicate copy of the original traffic, which may allow the session to continue so that the cause of the loop can be found and fixed. However, in extreme cases where a mixer or translator does not properly break the loop and high traffic levels result, it may be necessary for end systems to cease transmitting data or control packets entirely. This decision may depend upon the application. An error condition should be indicated as appropriate. Transmission might be attempted again periodically after a long, random time (on the order of minutes).
9. Security Lower layer protocols may eventually provide all the security services that may be desired for applications of RTP, including authentication, integrity, and confidentiality. These services have recently been specified for IP. Since the need for a confidentiality service is well established in the initial audio and video applications that are expected to use RTP, a confidentiality service is defined in the next section for use with RTP and RTCP until lower layer services are available. The overhead on the protocol for this service is low, so the penalty will be minimal if this service is obsoleted by lower layer services in the future. Alternatively, other services, other implementations of services and other algorithms may be defined for RTP in the future if warranted. The selection presented here is meant to simplify implementation of interoperable, secure applications and provide guidance to implementors. No claim is made that the methods presented here are appropriate for a particular security need. A profile may specify which services and algorithms should be offered by applications, and may provide guidance as to their appropriate use. Key distribution and certificates are outside the scope of this document. 9.1 Confidentiality Confidentiality means that only the intended receiver(s) can decode the received packets; for others, the packet contains no useful information. Confidentiality of the content is achieved by encryption. When encryption of RTP or RTCP is desired, all the octets that will be encapsulated for transmission in a single lower-layer packet are encrypted as a unit. For RTCP, a 32-bit random number is prepended to the unit before encryption to deter known plaintext attacks. For RTP, no prefix is required because the sequence number and timestamp fields are initialized with random offsets. For RTCP, it is allowed to split a compound RTCP packet into two lower-layer packets, one to be encrypted and one to be sent in the clear. For example, SDES information might be encrypted while reception reports were sent in the clear to accommodate third-party monitors that are not privy to the encryption key. In this example, depicted in Fig. 4, the SDES information must be appended to an RR packet with no reports (and the encrypted) to satisfy the requirement that all compound RTCP packets begin with an SR or RR packet.
UDP packet UDP packet ------------------------------------- ------------------------- [32-bit ][ ][ # ] [ # sender # receiver] [random ][ RR ][SDES # CNAME, ...] [ SR # report # report ] [integer][(empty)][ # ] [ # # ] ------------------------------------- ------------------------- encrypted not encrypted #: SSRC Figure 4: Encrypted and non-encrypted RTCP packets The presence of encryption and the use of the correct key are confirmed by the receiver through header or payload validity checks. Examples of such validity checks for RTP and RTCP headers are given in Appendices A.1 and A.2. The default encryption algorithm is the Data Encryption Standard (DES) algorithm in cipher block chaining (CBC) mode, as described in Section 1.1 of RFC 1423 [21], except that padding to a multiple of 8 octets is indicated as described for the P bit in Section 5.1. The initialization vector is zero because random values are supplied in the RTP header or by the random prefix for compound RTCP packets. For details on the use of CBC initialization vectors, see [22]. Implementations that support encryption should always support the DES algorithm in CBC mode as the default to maximize interoperability. This method is chosen because it has been demonstrated to be easy and practical to use in experimental audio and video tools in operation on the Internet. Other encryption algorithms may be specified dynamically for a session by non-RTP means. As an alternative to encryption at the RTP level as described above, profiles may define additional payload types for encrypted encodings. Those encodings must specify how padding and other aspects of the encryption should be handled. This method allows encrypting only the data while leaving the headers in the clear for applications where that is desired. It may be particularly useful for hardware devices that will handle both decryption and decoding. 9.2 Authentication and Message Integrity Authentication and message integrity are not defined in the current specification of RTP since these services would not be directly feasible without a key management infrastructure. It is expected that authentication and integrity services will be provided by lower layer protocols in the future.
10. RTP over Network and Transport Protocols This section describes issues specific to carrying RTP packets within particular network and transport protocols. The following rules apply unless superseded by protocol-specific definitions outside this specification. RTP relies on the underlying protocol(s) to provide demultiplexing of RTP data and RTCP control streams. For UDP and similar protocols, RTP uses an even port number and the corresponding RTCP stream uses the next higher (odd) port number. If an application is supplied with an odd number for use as the RTP port, it should replace this number with the next lower (even) number. RTP data packets contain no length field or other delineation, therefore RTP relies on the underlying protocol(s) to provide a length indication. The maximum length of RTP packets is limited only by the underlying protocols. If RTP packets are to be carried in an underlying protocol that provides the abstraction of a continuous octet stream rather than messages (packets), an encapsulation of the RTP packets must be defined to provide a framing mechanism. Framing is also needed if the underlying protocol may contain padding so that the extent of the RTP payload cannot be determined. The framing mechanism is not defined here. A profile may specify a framing method to be used even when RTP is carried in protocols that do provide framing in order to allow carrying several RTP packets in one lower-layer protocol data unit, such as a UDP packet. Carrying several RTP packets in one network or transport packet reduces header overhead and may simplify synchronization between different streams. 11. Summary of Protocol Constants This section contains a summary listing of the constants defined in this specification. The RTP payload type (PT) constants are defined in profiles rather than this document. However, the octet of the RTP header which contains the marker bit(s) and payload type must avoid the reserved values 200 and 201 (decimal) to distinguish RTP packets from the RTCP SR and RR packet types for the header validation procedure described in Appendix A.1. For the standard definition of one marker bit and a 7-bit payload type field as shown in this specification, this restriction means that payload types 72 and 73 are reserved.
11.1 RTCP packet types abbrev. name value SR sender report 200 RR receiver report 201 SDES source description 202 BYE goodbye 203 APP application-defined 204 These type values were chosen in the range 200-204 for improved header validity checking of RTCP packets compared to RTP packets or other unrelated packets. When the RTCP packet type field is compared to the corresponding octet of the RTP header, this range corresponds to the marker bit being 1 (which it usually is not in data packets) and to the high bit of the standard payload type field being 1 (since the static payload types are typically defined in the low half). This range was also chosen to be some distance numerically from 0 and 255 since all-zeros and all-ones are common data patterns. Since all compound RTCP packets must begin with SR or RR, these codes were chosen as an even/odd pair to allow the RTCP validity check to test the maximum number of bits with mask and value. Other constants are assigned by IANA. Experimenters are encouraged to register the numbers they need for experiments, and then unregister those which prove to be unneeded. 11.2 SDES types abbrev. name value END end of SDES list 0 CNAME canonical name 1 NAME user name 2 EMAIL user's electronic mail address 3 PHONE user's phone number 4 LOC geographic user location 5 TOOL name of application or tool 6 NOTE notice about the source 7 PRIV private extensions 8 Other constants are assigned by IANA. Experimenters are encouraged to register the numbers they need for experiments, and then unregister those which prove to be unneeded.
12. RTP Profiles and Payload Format Specifications A complete specification of RTP for a particular application will require one or more companion documents of two types described here: profiles, and payload format specifications. RTP may be used for a variety of applications with somewhat differing requirements. The flexibility to adapt to those requirements is provided by allowing multiple choices in the main protocol specification, then selecting the appropriate choices or defining extensions for a particular environment and class of applications in a separate profile document. Typically an application will operate under only one profile so there is no explicit indication of which profile is in use. A profile for audio and video applications may be found in the companion Internet-Draft draft-ietf-avt-profile for The second type of companion document is a payload format specification, which defines how a particular kind of payload data, such as H.261 encoded video, should be carried in RTP. These documents are typically titled "RTP Payload Format for XYZ Audio/Video Encoding". Payload formats may be useful under multiple profiles and may therefore be defined independently of any particular profile. The profile documents are then responsible for assigning a default mapping of that format to a payload type value if needed. Within this specification, the following items have been identified for possible definition within a profile, but this list is not meant to be exhaustive: RTP data header: The octet in the RTP data header that contains the marker bit and payload type field may be redefined by a profile to suit different requirements, for example with more or fewer marker bits (Section 5.3). Payload types: Assuming that a payload type field is included, the profile will usually define a set of payload formats (e.g., media encodings) and a default static mapping of those formats to payload type values. Some of the payload formats may be defined by reference to separate payload format specifications. For each payload type defined, the profile must specify the RTP timestamp clock rate to be used (Section 5.1). RTP data header additions: Additional fields may be appended to the fixed RTP data header if some additional functionality is required across the profile's class of applications independent of payload type (Section 5.3).
RTP data header extensions: The contents of the first 16 bits of the RTP data header extension structure must be defined if use of that mechanism is to be allowed under the profile for implementation-specific extensions (Section 5.3.1). RTCP packet types: New application-class-specific RTCP packet types may be defined and registered with IANA. RTCP report interval: A profile should specify that the values suggested in Section 6.2 for the constants employed in the calculation of the RTCP report interval will be used. Those are the RTCP fraction of session bandwidth, the minimum report interval, and the bandwidth split between senders and receivers. A profile may specify alternate values if they have been demonstrated to work in a scalable manner. SR/RR extension: An extension section may be defined for the RTCP SR and RR packets if there is additional information that should be reported regularly about the sender or receivers (Section 6.3.3). SDES use: The profile may specify the relative priorities for RTCP SDES items to be transmitted or excluded entirely (Section 6.2.2); an alternate syntax or semantics for the CNAME item (Section 6.4.1); the format of the LOC item (Section 6.4.5); the semantics and use of the NOTE item (Section 6.4.7); or new SDES item types to be registered with IANA. Security: A profile may specify which security services and algorithms should be offered by applications, and may provide guidance as to their appropriate use (Section 9). String-to-key mapping: A profile may specify how a user-provided password or pass phrase is mapped into an encryption key. Underlying protocol: Use of a particular underlying network or transport layer protocol to carry RTP packets may be required. Transport mapping: A mapping of RTP and RTCP to transport-level addresses, e.g., UDP ports, other than the standard mapping defined in Section 10 may be specified. Encapsulation: An encapsulation of RTP packets may be defined to allow multiple RTP data packets to be carried in one lower-layer packet or to provide framing over underlying protocols that do not already do so (Section 10).
It is not expected that a new profile will be required for every application. Within one application class, it would be better to extend an existing profile rather than make a new one in order to facilitate interoperation among the applications since each will typically run under only one profile. Simple extensions such as the definition of additional payload type values or RTCP packet types may be accomplished by registering them through the Internet Assigned Numbers Authority and publishing their descriptions in an addendum to the profile or in a payload format specification.
A. Algorithms We provide examples of C code for aspects of RTP sender and receiver algorithms. There may be other implementation methods that are faster in particular operating environments or have other advantages. These implementation notes are for informational purposes only and are meant to clarify the RTP specification. The following definitions are used for all examples; for clarity and brevity, the structure definitions are only valid for 32-bit big- endian (most significant octet first) architectures. Bit fields are assumed to be packed tightly in big-endian bit order, with no additional padding. Modifications would be required to construct a portable implementation. /* * rtp.h -- RTP header file (RFC XXXX) */ #include <sys/types.h> /* * The type definitions below are valid for 32-bit architectures and * may have to be adjusted for 16- or 64-bit architectures. */ typedef unsigned char u_int8; typedef unsigned short u_int16; typedef unsigned int u_int32; typedef short int16; /* * Current protocol version. */ #define RTP_VERSION 2 #define RTP_SEQ_MOD (1<<16) #define RTP_MAX_SDES 255 /* maximum text length for SDES */ typedef enum { RTCP_SR = 200, RTCP_RR = 201, RTCP_SDES = 202, RTCP_BYE = 203, RTCP_APP = 204 } rtcp_type_t; typedef enum { RTCP_SDES_END = 0, RTCP_SDES_CNAME = 1,
RTCP_SDES_NAME = 2, RTCP_SDES_EMAIL = 3, RTCP_SDES_PHONE = 4, RTCP_SDES_LOC = 5, RTCP_SDES_TOOL = 6, RTCP_SDES_NOTE = 7, RTCP_SDES_PRIV = 8 } rtcp_sdes_type_t; /* * RTP data header */ typedef struct { unsigned int version:2; /* protocol version */ unsigned int p:1; /* padding flag */ unsigned int x:1; /* header extension flag */ unsigned int cc:4; /* CSRC count */ unsigned int m:1; /* marker bit */ unsigned int pt:7; /* payload type */ u_int16 seq; /* sequence number */ u_int32 ts; /* timestamp */ u_int32 ssrc; /* synchronization source */ u_int32 csrc[1]; /* optional CSRC list */ } rtp_hdr_t; /* * RTCP common header word */ typedef struct { unsigned int version:2; /* protocol version */ unsigned int p:1; /* padding flag */ unsigned int count:5; /* varies by packet type */ unsigned int pt:8; /* RTCP packet type */ u_int16 length; /* pkt len in words, w/o this word */ } rtcp_common_t; /* * Big-endian mask for version, padding bit and packet type pair */ #define RTCP_VALID_MASK (0xc000 | 0x2000 | 0xfe) #define RTCP_VALID_VALUE ((RTP_VERSION << 14) | RTCP_SR) /* * Reception report block */ typedef struct { u_int32 ssrc; /* data source being reported */ unsigned int fraction:8; /* fraction lost since last SR/RR */
int lost:24; /* cumul. no. pkts lost (signed!) */ u_int32 last_seq; /* extended last seq. no. received */ u_int32 jitter; /* interarrival jitter */ u_int32 lsr; /* last SR packet from this source */ u_int32 dlsr; /* delay since last SR packet */ } rtcp_rr_t; /* * SDES item */ typedef struct { u_int8 type; /* type of item (rtcp_sdes_type_t) */ u_int8 length; /* length of item (in octets) */ char data[1]; /* text, not null-terminated */ } rtcp_sdes_item_t; /* * One RTCP packet */ typedef struct { rtcp_common_t common; /* common header */ union { /* sender report (SR) */ struct { u_int32 ssrc; /* sender generating this report */ u_int32 ntp_sec; /* NTP timestamp */ u_int32 ntp_frac; u_int32 rtp_ts; /* RTP timestamp */ u_int32 psent; /* packets sent */ u_int32 osent; /* octets sent */ rtcp_rr_t rr[1]; /* variable-length list */ } sr; /* reception report (RR) */ struct { u_int32 ssrc; /* receiver generating this report */ rtcp_rr_t rr[1]; /* variable-length list */ } rr; /* source description (SDES) */ struct rtcp_sdes { u_int32 src; /* first SSRC/CSRC */ rtcp_sdes_item_t item[1]; /* list of SDES items */ } sdes; /* BYE */ struct { u_int32 src[1]; /* list of sources */
/* can't express trailing text for reason */ } bye; } r; } rtcp_t; typedef struct rtcp_sdes rtcp_sdes_t; /* * Per-source state information */ typedef struct { u_int16 max_seq; /* highest seq. number seen */ u_int32 cycles; /* shifted count of seq. number cycles */ u_int32 base_seq; /* base seq number */ u_int32 bad_seq; /* last 'bad' seq number + 1 */ u_int32 probation; /* sequ. packets till source is valid */ u_int32 received; /* packets received */ u_int32 expected_prior; /* packet expected at last interval */ u_int32 received_prior; /* packet received at last interval */ u_int32 transit; /* relative trans time for prev pkt */ u_int32 jitter; /* estimated jitter */ /* ... */ } source; A.1 RTP Data Header Validity Checks An RTP receiver should check the validity of the RTP header on incoming packets since they might be encrypted or might be from a different application that happens to be misaddressed. Similarly, if encryption is enabled, the header validity check is needed to verify that incoming packets have been correctly decrypted, although a failure of the header validity check (e.g., unknown payload type) may not necessarily indicate decryption failure. Only weak validity checks are possible on an RTP data packet from a source that has not been heard before: o RTP version field must equal 2. o The payload type must be known, in particular it must not be equal to SR or RR. o If the P bit is set, then the last octet of the packet must contain a valid octet count, in particular, less than the total packet length minus the header size. o The X bit must be zero if the profile does not specify that the header extension mechanism may be used. Otherwise, the
extension length field must be less than the total packet size minus the fixed header length and padding. o The length of the packet must be consistent with CC and payload type (if payloads have a known length). The last three checks are somewhat complex and not always possible, leaving only the first two which total just a few bits. If the SSRC identifier in the packet is one that has been received before, then the packet is probably valid and checking if the sequence number is in the expected range provides further validation. If the SSRC identifier has not been seen before, then data packets carrying that identifier may be considered invalid until a small number of them arrive with consecutive sequence numbers. The routine update_seq shown below ensures that a source is declared valid only after MIN_SEQUENTIAL packets have been received in sequence. It also validates the sequence number seq of a newly received packet and updates the sequence state for the packet's source in the structure to which s points. When a new source is heard for the first time, that is, its SSRC identifier is not in the table (see Section 8.2), and the per-source state is allocated for it, s->probation should be set to the number of sequential packets required before declaring a source valid (parameter MIN_SEQUENTIAL ) and s->max_seq initialized to seq-1 s- >probation marks the source as not yet valid so the state may be discarded after a short timeout rather than a long one, as discussed in Section 6.2.1. After a source is considered valid, the sequence number is considered valid if it is no more than MAX_DROPOUT ahead of s->max_seq nor more than MAX_MISORDER behind. If the new sequence number is ahead of max_seq modulo the RTP sequence number range (16 bits), but is smaller than max_seq , it has wrapped around and the (shifted) count of sequence number cycles is incremented. A value of one is returned to indicate a valid sequence number. Otherwise, the value zero is returned to indicate that the validation failed, and the bad sequence number is stored. If the next packet received carries the next higher sequence number, it is considered the valid start of a new packet sequence presumably caused by an extended dropout or a source restart. Since multiple complete sequence number cycles may have been missed, the packet loss statistics are reset. Typical values for the parameters are shown, based on a maximum misordering time of 2 seconds at 50 packets/second and a maximum
dropout of 1 minute. The dropout parameter MAX_DROPOUT should be a small fraction of the 16-bit sequence number space to give a reasonable probability that new sequence numbers after a restart will not fall in the acceptable range for sequence numbers from before the restart. void init_seq(source *s, u_int16 seq) { s->base_seq = seq - 1; s->max_seq = seq; s->bad_seq = RTP_SEQ_MOD + 1; s->cycles = 0; s->received = 0; s->received_prior = 0; s->expected_prior = 0; /* other initialization */ } int update_seq(source *s, u_int16 seq) { u_int16 udelta = seq - s->max_seq; const int MAX_DROPOUT = 3000; const int MAX_MISORDER = 100; const int MIN_SEQUENTIAL = 2; /* * Source is not valid until MIN_SEQUENTIAL packets with * sequential sequence numbers have been received. */ if (s->probation) { /* packet is in sequence */ if (seq == s->max_seq + 1) { s->probation--; s->max_seq = seq; if (s->probation == 0) { init_seq(s, seq); s->received++; return 1; } } else { s->probation = MIN_SEQUENTIAL - 1; s->max_seq = seq; } return 0; } else if (udelta < MAX_DROPOUT) { /* in order, with permissible gap */ if (seq < s->max_seq) { /*
* Sequence number wrapped - count another 64K cycle. */ s->cycles += RTP_SEQ_MOD; } s->max_seq = seq; } else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) { /* the sequence number made a very large jump */ if (seq == s->bad_seq) { /* * Two sequential packets -- assume that the other side * restarted without telling us so just re-sync * (i.e., pretend this was the first packet). */ init_seq(s, seq); } else { s->bad_seq = (seq + 1) & (RTP_SEQ_MOD-1); return 0; } } else { /* duplicate or reordered packet */ } s->received++; return 1; } The validity check can be made stronger requiring more than two packets in sequence. The disadvantages are that a larger number of initial packets will be discarded and that high packet loss rates could prevent validation. However, because the RTCP header validation is relatively strong, if an RTCP packet is received from a source before the data packets, the count could be adjusted so that only two packets are required in sequence. If initial data loss for a few seconds can be tolerated, an application could choose to discard all data packets from a source until a valid RTCP packet has been received from that source. Depending on the application and encoding, algorithms may exploit additional knowledge about the payload format for further validation. For payload types where the timestamp increment is the same for all packets, the timestamp values can be predicted from the previous packet received from the same source using the sequence number difference (assuming no change in payload type). A strong "fast-path" check is possible since with high probability the first four octets in the header of a newly received RTP data packet will be just the same as that of the previous packet from the same SSRC except that the sequence number will have increased by one.
Similarly, a single-entry cache may be used for faster SSRC lookups in applications where data is typically received from one source at a time. A.2 RTCP Header Validity Checks The following checks can be applied to RTCP packets. o RTP version field must equal 2. o The payload type field of the first RTCP packet in a compound packet must be equal to SR or RR. o The padding bit (P) should be zero for the first packet of a compound RTCP packet because only the last should possibly need padding. o The length fields of the individual RTCP packets must total to the overall length of the compound RTCP packet as received. This is a fairly strong check. The code fragment below performs all of these checks. The packet type is not checked for subsequent packets since unknown packet types may be present and should be ignored. u_int32 len; /* length of compound RTCP packet in words */ rtcp_t *r; /* RTCP header */ rtcp_t *end; /* end of compound RTCP packet */ if ((*(u_int16 *)r & RTCP_VALID_MASK) != RTCP_VALID_VALUE) { /* something wrong with packet format */ } end = (rtcp_t *)((u_int32 *)r + len); do r = (rtcp_t *)((u_int32 *)r + r->common.length + 1); while (r < end && r->common.version == 2); if (r != end) { /* something wrong with packet format */ } A.3 Determining the Number of RTP Packets Expected and Lost In order to compute packet loss rates, the number of packets expected and actually received from each source needs to be known, using per- source state information defined in struct source referenced via pointer s in the code below. The number of packets received is simply the count of packets as they arrive, including any late or duplicate
packets. The number of packets expected can be computed by the receiver as the difference between the highest sequence number received ( s->max_seq ) and the first sequence number received ( s- >base_seq ). Since the sequence number is only 16 bits and will wrap around, it is necessary to extend the highest sequence number with the (shifted) count of sequence number wraparounds ( s->cycles ). Both the received packet count and the count of cycles are maintained the RTP header validity check routine in Appendix A.1. extended_max = s->cycles + s->max_seq; expected = extended_max - s->base_seq + 1; The number of packets lost is defined to be the number of packets expected less the number of packets actually received: lost = expected - s->received; Since this number is carried in 24 bits, it should be clamped at 0xffffff rather than wrap around to zero. The fraction of packets lost during the last reporting interval (since the previous SR or RR packet was sent) is calculated from differences in the expected and received packet counts across the interval, where expected_prior and received_prior are the values saved when the previous reception report was generated: expected_interval = expected - s->expected_prior; s->expected_prior = expected; received_interval = s->received - s->received_prior; s->received_prior = s->received; lost_interval = expected_interval - received_interval; if (expected_interval == 0 || lost_interval <= 0) fraction = 0; else fraction = (lost_interval << 8) / expected_interval; The resulting fraction is an 8-bit fixed point number with the binary point at the left edge. A.4 Generating SDES RTCP Packets This function builds one SDES chunk into buffer b composed of argc items supplied in arrays type , value and length b char *rtp_write_sdes(char *b, u_int32 src, int argc, rtcp_sdes_type_t type[], char *value[], int length[]) { rtcp_sdes_t *s = (rtcp_sdes_t *)b; rtcp_sdes_item_t *rsp;
int i; int len; int pad; /* SSRC header */ s->src = src; rsp = &s->item[0]; /* SDES items */ for (i = 0; i < argc; i++) { rsp->type = type[i]; len = length[i]; if (len > RTP_MAX_SDES) { /* invalid length, may want to take other action */ len = RTP_MAX_SDES; } rsp->length = len; memcpy(rsp->data, value[i], len); rsp = (rtcp_sdes_item_t *)&rsp->data[len]; } /* terminate with end marker and pad to next 4-octet boundary */ len = ((char *) rsp) - b; pad = 4 - (len & 0x3); b = (char *) rsp; while (pad--) *b++ = RTCP_SDES_END; return b; } A.5 Parsing RTCP SDES Packets This function parses an SDES packet, calling functions find_member() to find a pointer to the information for a session member given the SSRC identifier and member_sdes() to store the new SDES information for that member. This function expects a pointer to the header of the RTCP packet. void rtp_read_sdes(rtcp_t *r) { int count = r->common.count; rtcp_sdes_t *sd = &r->r.sdes; rtcp_sdes_item_t *rsp, *rspn; rtcp_sdes_item_t *end = (rtcp_sdes_item_t *) ((u_int32 *)r + r->common.length + 1); source *s; while (--count >= 0) {
rsp = &sd->item[0]; if (rsp >= end) break; s = find_member(sd->src); for (; rsp->type; rsp = rspn ) { rspn = (rtcp_sdes_item_t *)((char*)rsp+rsp->length+2); if (rspn >= end) { rsp = rspn; break; } member_sdes(s, rsp->type, rsp->data, rsp->length); } sd = (rtcp_sdes_t *) ((u_int32 *)sd + (((char *)rsp - (char *)sd) >> 2)+1); } if (count >= 0) { /* invalid packet format */ } } A.6 Generating a Random 32-bit Identifier The following subroutine generates a random 32-bit identifier using the MD5 routines published in RFC 1321 [23]. The system routines may not be present on all operating systems, but they should serve as hints as to what kinds of information may be used. Other system calls that may be appropriate include o getdomainname() , o getwd() , or o getrusage() "Live" video or audio samples are also a good source of random numbers, but care must be taken to avoid using a turned-off microphone or blinded camera as a source [7]. Use of this or similar routine is suggested to generate the initial seed for the random number generator producing the RTCP period (as shown in Appendix A.7), to generate the initial values for the sequence number and timestamp, and to generate SSRC values. Since this routine is likely to be CPU-intensive, its direct use to generate RTCP periods is inappropriate because predictability is not an issue. Note that this routine produces the same result on repeated calls until the value of the system clock changes unless different values are supplied for the type argument.
/* * Generate a random 32-bit quantity. */ #include <sys/types.h> /* u_long */ #include <sys/time.h> /* gettimeofday() */ #include <unistd.h> /* get..() */ #include <stdio.h> /* printf() */ #include <time.h> /* clock() */ #include <sys/utsname.h> /* uname() */ #include "global.h" /* from RFC 1321 */ #include "md5.h" /* from RFC 1321 */ #define MD_CTX MD5_CTX #define MDInit MD5Init #define MDUpdate MD5Update #define MDFinal MD5Final static u_long md_32(char *string, int length) { MD_CTX context; union { char c[16]; u_long x[4]; } digest; u_long r; int i; MDInit (&context); MDUpdate (&context, string, length); MDFinal ((unsigned char *)&digest, &context); r = 0; for (i = 0; i < 3; i++) { r ^= digest.x[i]; } return r; } /* md_32 */ /* * Return random unsigned 32-bit quantity. Use 'type' argument if you * need to generate several different values in close succession. */ u_int32 random32(int type) { struct { int type; struct timeval tv; clock_t cpu;
pid_t pid; u_long hid; uid_t uid; gid_t gid; struct utsname name; } s; gettimeofday(&s.tv, 0); uname(&s.name); s.type = type; s.cpu = clock(); s.pid = getpid(); s.hid = gethostid(); s.uid = getuid(); s.gid = getgid(); return md_32((char *)&s, sizeof(s)); } /* random32 */ A.7 Computing the RTCP Transmission Interval The following function returns the time between transmissions of RTCP packets, measured in seconds. It should be called after sending one compound RTCP packet to calculate the delay until the next should be sent. This function should also be called to calculate the delay before sending the first RTCP packet upon startup rather than send the packet immediately. This avoids any burst of RTCP packets if an application is started at many sites simultaneously, for example as a result of a session announcement. The parameters have the following meaning: rtcp_bw: The target RTCP bandwidth, i.e., the total bandwidth that will be used for RTCP packets by all members of this session, in octets per second. This should be 5% of the "session bandwidth" parameter supplied to the application at startup. senders: Number of active senders since sending last report, known from construction of receiver reports for this RTCP packet. Includes ourselves, if we also sent during this interval. members: The estimated number of session members, including ourselves. Incremented as we discover new session members from the receipt of RTP or RTCP packets, and decremented as session members leave (via RTCP BYE) or their state is timed out (30 minutes is recommended). On the first call, this parameter should have the value 1.
we_sent: Flag that is true if we have sent data during the last two RTCP intervals. If the flag is true, the compound RTCP packet just sent contained an SR packet. packet_size: The size of the compound RTCP packet just sent, in octets, including the network encapsulation (e.g., 28 octets for UDP over IP). avg_rtcp_size: Pointer to estimator for compound RTCP packet size; initialized and updated by this function for the packet just sent, and also updated by an identical line of code in the RTCP receive routine for every RTCP packet received from other participants in the session. initial: Flag that is true for the first call upon startup to calculate the time until the first report should be sent. #include <math.h> double rtcp_interval(int members, int senders, double rtcp_bw, int we_sent, int packet_size, int *avg_rtcp_size, int initial) { /* * Minimum time between RTCP packets from this site (in seconds). * This time prevents the reports from `clumping' when sessions * are small and the law of large numbers isn't helping to smooth * out the traffic. It also keeps the report interval from * becoming ridiculously small during transient outages like a * network partition. */ double const RTCP_MIN_TIME = 5.; /* * Fraction of the RTCP bandwidth to be shared among active * senders. (This fraction was chosen so that in a typical * session with one or two active senders, the computed report * time would be roughly equal to the minimum report time so that * we don't unnecessarily slow down receiver reports.) The * receiver fraction must be 1 - the sender fraction. */ double const RTCP_SENDER_BW_FRACTION = 0.25; double const RTCP_RCVR_BW_FRACTION = (1-RTCP_SENDER_BW_FRACTION); /* * Gain (smoothing constant) for the low-pass filter that
* estimates the average RTCP packet size (see Cadzow reference). */ double const RTCP_SIZE_GAIN = (1./16.); double t; /* interval */ double rtcp_min_time = RTCP_MIN_TIME; int n; /* no. of members for computation */ /* * Very first call at application start-up uses half the min * delay for quicker notification while still allowing some time * before reporting for randomization and to learn about other * sources so the report interval will converge to the correct * interval more quickly. The average RTCP size is initialized * to 128 octets which is conservative (it assumes everyone else * is generating SRs instead of RRs: 20 IP + 8 UDP + 52 SR + 48 * SDES CNAME). */ if (initial) { rtcp_min_time /= 2; *avg_rtcp_size = 128; } /* * If there were active senders, give them at least a minimum * share of the RTCP bandwidth. Otherwise all participants share * the RTCP bandwidth equally. */ n = members; if (senders > 0 && senders < members * RTCP_SENDER_BW_FRACTION) { if (we_sent) { rtcp_bw *= RTCP_SENDER_BW_FRACTION; n = senders; } else { rtcp_bw *= RTCP_RCVR_BW_FRACTION; n -= senders; } } /* * Update the average size estimate by the size of the report * packet we just sent. */ *avg_rtcp_size += (packet_size - *avg_rtcp_size)*RTCP_SIZE_GAIN; /* * The effective number of sites times the average packet size is * the total number of octets sent when each site sends a report.
* Dividing this by the effective bandwidth gives the time * interval over which those packets must be sent in order to * meet the bandwidth target, with a minimum enforced. In that * time interval we send one report so this time is also our * average time between reports. */ t = (*avg_rtcp_size) * n / rtcp_bw; if (t < rtcp_min_time) t = rtcp_min_time; /* * To avoid traffic bursts from unintended synchronization with * other sites, we then pick our actual next report interval as a * random number uniformly distributed between 0.5*t and 1.5*t. */ return t * (drand48() + 0.5); } A.8 Estimating the Interarrival Jitter The code fragments below implement the algorithm given in Section 6.3.1 for calculating an estimate of the statistical variance of the RTP data interarrival time to be inserted in the interarrival jitter field of reception reports. The inputs are r->ts , the timestamp from the incoming packet, and arrival , the current time in the same units. Here s points to state for the source; s->transit holds the relative transit time for the previous packet, and s->jitter holds the estimated jitter. The jitter field of the reception report is measured in timestamp units and expressed as an unsigned integer, but the jitter estimate is kept in a floating point. As each data packet arrives, the jitter estimate is updated: int transit = arrival - r->ts; int d = transit - s->transit; s->transit = transit; if (d < 0) d = -d; s->jitter += (1./16.) * ((double)d - s->jitter); When a reception report block (to which rr points) is generated for this member, the current jitter estimate is returned: rr->jitter = (u_int32) s->jitter; Alternatively, the jitter estimate can be kept as an integer, but scaled to reduce round-off error. The calculation is the same except for the last line: s->jitter += d - ((s->jitter + 8) >> 4);
In this case, the estimate is sampled for the reception report as: rr->jitter = s->jitter >> 4; B. Security Considerations RTP suffers from the same security liabilities as the underlying protocols. For example, an impostor can fake source or destination network addresses, or change the header or payload. Within RTCP, the CNAME and NAME information may be used to impersonate another participant. In addition, RTP may be sent via IP multicast, which provides no direct means for a sender to know all the receivers of the data sent and therefore no measure of privacy. Rightly or not, users may be more sensitive to privacy concerns with audio and video communication than they have been with more traditional forms of network communication [24]. Therefore, the use of security mechanisms with RTP is important. These mechanisms are discussed in Section 9. RTP-level translators or mixers may be used to allow RTP traffic to reach hosts behind firewalls. Appropriate firewall security principles and practices, which are beyond the scope of this document, should be followed in the design and installation of these devices and in the admission of RTP applications for use behind the firewall. C. Authors' Addresses Henning Schulzrinne GMD Fokus Hardenbergplatz 2 D-10623 Berlin Germany EMail: schulzrinne@fokus.gmd.de Stephen L. Casner Precept Software, Inc. 21580 Stevens Creek Boulevard, Suite 207 Cupertino, CA 95014 United States EMail: casner@precept.com
Ron Frederick Xerox Palo Alto Research Center 3333 Coyote Hill Road Palo Alto, CA 94304 United States EMail: frederic@parc.xerox.com Van Jacobson MS 46a-1121 Lawrence Berkeley National Laboratory Berkeley, CA 94720 United States EMail: van@ee.lbl.gov Acknowledgments This memorandum is based on discussions within the IETF Audio/Video Transport working group chaired by Stephen Casner. The current protocol has its origins in the Network Voice Protocol and the Packet Video Protocol (Danny Cohen and Randy Cole) and the protocol implemented by the vat application (Van Jacobson and Steve McCanne). Christian Huitema provided ideas for the random identifier generator. D. Bibliography [1] D. D. Clark and D. L. Tennenhouse, "Architectural considerations for a new generation of protocols," in SIGCOMM Symposium on Communications Architectures and Protocols , (Philadelphia, Pennsylvania), pp. 200--208, IEEE, Sept. 1990. Computer Communications Review, Vol. 20(4), Sept. 1990. [2] H. Schulzrinne, "Issues in designing a transport protocol for audio and video conferences and other multiparticipant real-time applications", Work in Progress. [3] D. E. Comer, Internetworking with TCP/IP , vol. 1. Englewood Cliffs, New Jersey: Prentice Hall, 1991. [4] Postel, J., "Internet Protocol", STD 5, RFC 791, USC/Information Sciences Institute, September 1981. [5] Mills, D., "Network Time Protocol Version 3", RFC 1305, UDEL, March 1992.
[6] Reynolds, J., and J. Postel, "Assigned Numbers", STD 2, RFC 1700, USC/Information Sciences Institute, October 1994. [7] Eastlake, D., Crocker, S., and J. Schiller, "Randomness Recommendations for Security", RFC 1750, DEC, Cybercash, MIT, December 1994. [8] J.-C. Bolot, T. Turletti, and I. Wakeman, "Scalable feedback control for multicast video distribution in the internet," in SIGCOMM Symposium on Communications Architectures and Protocols , (London, England), pp. 58--67, ACM, Aug. 1994. [9] I. Busse, B. Deffner, and H. Schulzrinne, "Dynamic QoS control of multimedia applications based on RTP," Computer Communications , Jan. 1996. [10] S. Floyd and V. Jacobson, "The synchronization of periodic routing messages," in SIGCOMM Symposium on Communications Architectures and Protocols (D. P. Sidhu, ed.), (San Francisco, California), pp. 33--44, ACM, Sept. 1993. also in [25]. [11] J. A. Cadzow, Foundations of digital signal processing and data analysis New York, New York: Macmillan, 1987. [12] International Standards Organization, "ISO/IEC DIS 10646-1:1993 information technology -- universal multiple-octet coded character set (UCS) -- part I: Architecture and basic multilingual plane," 1993. [13] The Unicode Consortium, The Unicode Standard New York, New York: Addison-Wesley, 1991. [14] Mockapetris, P., "Domain Names - Concepts and Facilities", STD 13, RFC 1034, USC/Information Sciences Institute, November 1987. [15] Mockapetris, P., "Domain Names - Implementation and Specification", STD 13, RFC 1035, USC/Information Sciences Institute, November 1987. [16] Braden, R., "Requirements for Internet Hosts - Application and Support", STD 3, RFC 1123, Internet Engineering Task Force, October 1989. [17] Rekhter, Y., Moskowitz, R., Karrenberg, D., and G. de Groot, "Address Allocation for Private Internets", RFC 1597, T.J. Watson Research Center, IBM Corp., Chrysler Corp., RIPE NCC, March 1994.
[18] Lear, E., Fair, E., Crocker, D., and T. Kessler, "Network 10 Considered Harmful (Some Practices Shouldn't be Codified)", RFC 1627, Silicon Graphics, Inc., Apple Computer, Inc., Silicon Graphics, Inc., July 1994. [19] Crocker, D., "Standard for the Format of ARPA Internet Text Messages", STD 11, RFC 822, UDEL, August 1982. [20] W. Feller, An Introduction to Probability Theory and its Applications, Volume 1 , vol. 1. New York, New York: John Wiley and Sons, third ed., 1968. [21] Balenson, D., "Privacy Enhancement for Internet Electronic Mail: Part III: Algorithms, Modes, and Identifiers", RFC 1423, TIS, IAB IRTF PSRG, IETF PEM WG, February 1993. [22] V. L. Voydock and S. T. Kent, "Security mechanisms in high-level network protocols," ACM Computing Surveys , vol. 15, pp. 135-- 171, June 1983. [23] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321, MIT Laboratory for Computer Science and RSA Data Security, Inc., April 1992. [24] S. Stubblebine, "Security services for multimedia conferencing," in 16th National Computer Security Conference , (Baltimore, Maryland), pp. 391--395, Sept. 1993. [25] S. Floyd and V. Jacobson, "The synchronization of periodic routing messages," IEEE/ACM Transactions on Networking , vol. 2, pp. 122-136, April 1994.