7.2 RTCP Processing in Translators
In addition to forwarding data packets, perhaps modified, translators
and mixers must also process RTCP packets. In many cases, they will
take apart the compound RTCP packets received from end systems to
aggregate SDES information and to modify the SR or RR packets.
Retransmission of this information may be triggered by the packet
arrival or by the RTCP interval timer of the translator or mixer
itself.
A translator that does not modify the data packets, for example one
that just replicates between a multicast address and a unicast
address, may simply forward RTCP packets unmodified as well. A
translator that transforms the payload in some way must make
corresponding transformations in the SR and RR information so that it
still reflects the characteristics of the data and the reception
quality. These translators must not simply forward RTCP packets. In
general, a translator should not aggregate SR and RR packets from
different sources into one packet since that would reduce the
accuracy of the propagation delay measurements based on the LSR and
DLSR fields.
SR sender information: A translator does not generate its own sender
information, but forwards the SR packets received from one cloud
to the others. The SSRC is left intact but the sender
information must be modified if required by the translation. If
a translator changes the data encoding, it must change the
"sender's byte count" field. If it also combines several data
packets into one output packet, it must change the "sender's
packet count" field. If it changes the timestamp frequency, it
must change the "RTP timestamp" field in the SR packet.
SR/RR reception report blocks: A translator forwards reception
reports received from one cloud to the others. Note that these
flow in the direction opposite to the data. The SSRC is left
intact. If a translator combines several data packets into one
output packet, and therefore changes the sequence numbers, it
must make the inverse manipulation for the packet loss fields
and the "extended last sequence number" field. This may be
complex. In the extreme case, there may be no meaningful way to
translate the reception reports, so the translator may pass on
no reception report at all or a synthetic report based on its
own reception. The general rule is to do what makes sense for a
particular translation.
A translator does not require an SSRC identifier of its own, but may
choose to allocate one for the purpose of sending reports about what
it has received. These would be sent to all the connected clouds,
each corresponding to the translation of the data stream as sent to
that cloud, since reception reports are normally multicast to all
participants.
SDES: Translators typically forward without change the SDES
information they receive from one cloud to the others, but may,
for example, decide to filter non-CNAME SDES information if
bandwidth is limited. The CNAMEs must be forwarded to allow SSRC
identifier collision detection to work. A translator that
generates its own RR packets must send SDES CNAME information
about itself to the same clouds that it sends those RR packets.
BYE: Translators forward BYE packets unchanged. Translators with
their own SSRC should generate BYE packets with that SSRC
identifier if they are about to cease forwarding packets.
APP: Translators forward APP packets unchanged.
7.3 RTCP Processing in Mixers
Since a mixer generates a new data stream of its own, it does not
pass through SR or RR packets at all and instead generates new
information for both sides.
SR sender information: A mixer does not pass through sender
information from the sources it mixes because the
characteristics of the source streams are lost in the mix. As a
synchronization source, the mixer generates its own SR packets
with sender information about the mixed data stream and sends
them in the same direction as the mixed stream.
SR/RR reception report blocks: A mixer generates its own reception
reports for sources in each cloud and sends them out only to the
same cloud. It does not send these reception reports to the
other clouds and does not forward reception reports from one
cloud to the others because the sources would not be SSRCs there
(only CSRCs).
SDES: Mixers typically forward without change the SDES information
they receive from one cloud to the others, but may, for example,
decide to filter non-CNAME SDES information if bandwidth is
limited. The CNAMEs must be forwarded to allow SSRC identifier
collision detection to work. (An identifier in a CSRC list
generated by a mixer might collide with an SSRC identifier
generated by an end system.) A mixer must send SDES CNAME
information about itself to the same clouds that it sends SR or
RR packets.
Since mixers do not forward SR or RR packets, they will typically be
extracting SDES packets from a compound RTCP packet. To minimize
overhead, chunks from the SDES packets may be aggregated into a
single SDES packet which is then stacked on an SR or RR packet
originating from the mixer. The RTCP packet rate may be different on
each side of the mixer.
A mixer that does not insert CSRC identifiers may also refrain from
forwarding SDES CNAMEs. In this case, the SSRC identifier spaces in
the two clouds are independent. As mentioned earlier, this mode of
operation creates a danger that loops can't be detected.
BYE: Mixers need to forward BYE packets. They should generate BYE
packets with their own SSRC identifiers if they are about to
cease forwarding packets.
APP: The treatment of APP packets by mixers is application-specific.
7.4 Cascaded Mixers
An RTP session may involve a collection of mixers and translators as
shown in Figure 3. If two mixers are cascaded, such as M2 and M3 in
the figure, packets received by a mixer may already have been mixed
and may include a CSRC list with multiple identifiers. The second
mixer should build the CSRC list for the outgoing packet using the
CSRC identifiers from already-mixed input packets and the SSRC
identifiers from unmixed input packets. This is shown in the output
arc from mixer M3 labeled M3:89(64,45) in the figure. As in the case
of mixers that are not cascaded, if the resulting CSRC list has more
than 15 identifiers, the remainder cannot be included.
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 RFC1423 [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 (RFCXXXX)
*/
#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);