=========================== RDT Data recovery mechanism =========================== This document discusses the data recovery mechanism used within the RealNetworks Data Transport(RDT). It covers the method used by the client to notify the server of packets not received as well as the method the server used to notify the client of a packet lost before transport that is unrecoverable. ------------------------------------------------------------------------------- Table A. RDT DATA PACKET (non-aggregated) 012 78 24 32 64 80 +++----++---------------+++-----+-------...+-----------...+--...+ ||| ||SeqNo |||Rule |Timestamp |Reliable SeqNo|Data | +++----++---------------+++-----+-------...+-----------...+--...+ ^^^ ^^ ^^^ ||| || ||| ||| || ||ASM Rule ||| || |slow_data ||| || back_to_back_packet ||| || ||| |RDT Sequence Number ||| is_reliable ||stream_id |need_reliable (always true) length_included_flag ------------------------------------------------------------------------------- I. RDT data packets The RDT stream consists of one or more streams each with a set of sequence numbers. Each stream has it's own set of sequence numbers that start at 0 and wrap at 0xff00. Thus a packet's uniqueness is determined by the combination of stream_id and sequence number. Some streams are denoted by the datatype as high priority or less loss tolerant through the is_reliable flag. There is a second sequence number is global to the stream and is the sum total of all packets with the is_reliable flag set. This second sequence number is application specific. If the length_included_flag is set on an RDT data packet, then packet aggregation is occurring. Packet aggregation is inclusion of more than one RDT packet within a UDP datagram to reduce system calls in the server. See the chart below for aggregation rules. Aggregated packets have a slightly different format than non-aggregated. They contain a length field allowing the client to jump to the next RDT header. Packet aggregation can be disabled at the server with the option --dpa. ------------------------------------------------------------------------------- Table B. PACKET AGGREGATION VALUES IN RealSystem Server 8.01 Normal LoadState Minimum size size to aggregate 200 bytes Maximum size to aggregate to 300 bytes High LoadState Minimum size size to aggregate 700 bytes Maximum size to aggregate to 1000 bytes Extreme LoadState (or high load state and bitrate > 100Kbps) Minimum size size to aggregate 1000 bytes Maximum size to aggregate to 1350 bytes Note: The server will only aggregate if the sum of two or more packet lies within the minimum and maximum values for the given server condition ------------------------------------------------------------------------------- II. Packets lost before transport All RealNetworks datatypes are tolerant to loss. Sometimes in a live presentation, a packet will be lost en route to the server. If unrecoverable packet loss occurs between the encoder and server, for example, the server will not have all the packets to send to the client. The server cannot, however, just increment the sequence number as though the lost packet never existed since the datatype needs to know this data is missing. The server also cannot simply increment the sequence number as the client will issue a NAK packet assuming the packet was lost in transport. To solve this the server sends a data packet with the missing sequence number, but no payload data. The client is aware of this convention and marks this packet as lost, but does not try to recover by sending a NAK packet. Note that in TCP mode the server just leaves a gap in the sequence number as there is no ambiguity the packet is assumed lost before transport. ------------------------------------------------------------------------------- Table C. RDT NAK/ACK PACKET RDT NAK PACKET 012 78 24 40 56 72 +++----++---------------+------...+---...+------...+-------+ ||| ||0xff02 |stream_id|seq_no|bit_count|map_len| +++----++---------------+------...+---...+------...+-------+ ^ | lost_high (1 for NAK) - First three bytes of NAK packet are always 0x40ff02 - bit_count and map_len are always 0 for NAK - packet indicates that packet on stream stream_id with seq_no was not received. - lost_high means that the sequence number listed for the stream was lost. Since the NAK is always for one packet, it is always set. RDT ACK PACKET |<---Repeated for each stream in session--->| 012 78 24 40 56 72 80 +++----++---------------+------...+---...+------...+-------+-----...+ ||| ||0xff02 |stream id|seq_no|bit_count|map_len|bitfield| +++----++---------------+------...+---...+------...+-------+-----...+ ^ | lost_high (almost always 0 for ACK) - lost_high is basically never set for ACK packets. See section III. - data portion contains one section per stream - stream_id is the stream being ACKed - seq_no is the highest sequence number in the bitfield. - bit_count indicates number bits in bitfield (packets being ACKed) - map_len is the length in bytes (rounded up) of the bitfield - There is one bitfield for every packet ACKed. 1 indicates packet was received. 0 indicates packet was not received. ------------------------------------------------------------------------------- III. Packets lost in transport Data recovery is achieved through the client's issuance of ACK/NAK packets. As soon as a gap in sequence numbers is detected on the client, the client issues a NAK packet for each missing sequence number. Note this means the server will issue a NAK for packets received out of order. In addition the client, at an interval of 1 second, will issue an ACK packet. The ACK packet contains a bitfield for each stream in the session. 1 in the field indicates the packet was received, 0 indicates it was not. If the server receives either a NAK packet or a ACK with a a packet designated as missing, it will resend the packet. Every packet marked as received is removed from the server's resend buffer. This document has referred ACK and NAK packets as if they were differing packet formats, which they aren't. They can, however, be effectively distinguished by the lost_high flag. This flag indicates that the sequence number listed was lost. Since ACK packets are generated based on the highest number sequence received, the highest sequence number would not be treated as lost, just not received. The only exception would be a rare situation in which a stream ACK exceeded the maximum bitset size and had to be sent in 2 ACK packets AND the last packet in the first ACK section happened to be lost. The maximum bitset is 48 bytes or 384 packets. Since ACK are generated once per second, this cannot realisticly happen for streams les than 1.5Mbps. IV. Identifying RDT data recovery on the wire NAK packets always begin with 0x40ff02 and are issued once per lost packet. ACK packets always begin with 0x00ff02 and are issued about once per second. Placeholder packets for data lost before transport are always 10 bytes long. ------------------------------------------------------------------------------- Appendix - packet definitions and field summaries (if expressions indicate differing packet formats based on values in static fields) packlen struct TNGDataPacket { bit[1] length_included_flag; /* Inc. length field */ bit[1] need_reliable_flag; /* Inc. rel. seq no */ bit[5] stream_id; /* 31 == expansion */ bit[1] is_reliable; u_int16 seq_no; /* overload for packet type*/ if(length_included_flag == 1) { u_int16 rdt_packet_length; // payload length if // length flag is set } bit[1] back_to_back_packet; bit[1] slow_data; bit[6] asm_rule_number; /* 63 is expansion */ u_int32 timestamp; if(stream_id == 31) { u_int16 stream_id_expansion; } if(need_reliable_flag == 1) { u_int16 total_reliable; } if(asm_rule_number == 63) { u_int16 asm_rule_number_expansion; } buffer data; } - length_included_flag is only set when using packet aggregation (i.e. more than one payload packet per datagram). When not set size of datagram is used to infer size of payload - need_reliable_flag is always set - stream_id is datatype specific (usually 0 for audio, 1 for video) stream_id 31 is reserved for future exapansion for sessions with more than 31 streams. It is not currently used. - is_reliable is set for certain rules deemed less tolerant to loss - seq_no starts at 0 and wraps at 0xff00. seq_nos are per stream. Values higher than 0xff00 are used to designate special packet types (such as ACK 0xff02) - back_to_back_packet is used for timing and is set one out of ten data packets - slow_data is reserved for future use and is not currently set - asm_rule_number is used by SureStream in conjunction with ASM rulebook in file headers to allow client to subscribe to streams catering to the client bandwidth. asm_rule_number 63 is reserved for future exapansion for streams with more than 63 rules. It is not currently used. - timestamp is datatype specific, but tends to increase over time. - total_reliable is a separate sequence number kept for all packets with is_reliable set for a given stream. struct TNGACKPacket { bit[1] length_included_flag; bit[1] lost_high; bit[5] dummy0; /* 0 */ bit[1] dummy1; /* 0 */ u_int16 packet_type; /* 0xff02 */ if(length_included_flag == 1) { u_int16 length; } /* * data consists of header + bitmap repeated for each stream: * u_int16 stream_number * u_int16 last_seq_no * u_int16 bit_count * u_int8 bitmap_length * buffer bitmap */ buffer data; } - length_included_flag is always 0 for ACK - lost_high indicates that the sequence number in the data segment is a lost packet. These packets have no ACK component. These packets will only have a data segment for 1 stream. - packet_type is 0xff02 for ACK/NAK packets.