259 lines
5.5 KiB
C++
259 lines
5.5 KiB
C++
#include "rtp-internal.h"
|
|
#include "rtp-packet.h"
|
|
#include "rtp-util.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
|
|
//enum {
|
|
// RTCP_MSG_MEMBER, /// new member(re-calculate RTCP Transmission Interval)
|
|
// RTCP_MSG_EXPIRED, /// member leave(re-calculate RTCP Transmission Interval)
|
|
//};
|
|
|
|
static void rtp_seq_init(struct rtp_member *sender, uint16_t seq)
|
|
{
|
|
sender->rtp_seq = seq;
|
|
sender->rtp_seq_bad = (1<<16) + 1; /* so seq == bad_seq is false */
|
|
sender->rtp_seq_base = seq;
|
|
sender->rtp_seq_cycles = 0;
|
|
sender->rtp_packets0 = 0;
|
|
sender->rtp_expected0 = 0;
|
|
sender->rtp_bytes = 0;
|
|
sender->rtp_packets = 0;
|
|
sender->rtp_probation = 0;
|
|
sender->jitter = 0.0;
|
|
}
|
|
|
|
static int rtp_seq_update(struct rtp_member *sender, uint16_t seq)
|
|
{
|
|
uint16_t delta;
|
|
delta = seq - sender->rtp_seq;
|
|
|
|
if(sender->rtp_probation > 0)
|
|
{
|
|
if(sender->rtp_seq + 1 == seq)
|
|
{
|
|
sender->rtp_seq = seq;
|
|
if(0 == --sender->rtp_probation)
|
|
{
|
|
rtp_seq_init(sender, seq);
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sender->rtp_probation = RTP_PROBATION;
|
|
sender->rtp_seq = seq;
|
|
}
|
|
return 0;
|
|
}
|
|
else if( delta < RTP_DROPOUT)
|
|
{
|
|
// in order, with permissible gap
|
|
if(seq < sender->rtp_seq)
|
|
{
|
|
// sequence number wrapped
|
|
sender->rtp_seq_cycles += (1 << 16);
|
|
}
|
|
|
|
sender->rtp_seq = seq;
|
|
}
|
|
else if( delta <= (1 << 16) - RTP_MISORDER )
|
|
{
|
|
/* the sequence number made a very large jump */
|
|
if(sender->rtp_seq_bad + 1 == seq)
|
|
{
|
|
rtp_seq_init(sender, seq);
|
|
}
|
|
else
|
|
{
|
|
sender->rtp_seq_bad = seq;
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// duplicate or reordered packet
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
struct rtp_member* rtp_member_fetch(struct rtp_context *ctx, uint32_t ssrc)
|
|
{
|
|
struct rtp_member *p;
|
|
p = rtp_member_list_find(ctx->members, ssrc);
|
|
if(!p)
|
|
{
|
|
// exist in sender list?
|
|
assert(!rtp_member_list_find(ctx->senders, ssrc));
|
|
|
|
p = rtp_member_create(ssrc);
|
|
if(p)
|
|
{
|
|
struct rtcp_msg_t msg;
|
|
|
|
// update members list
|
|
rtp_member_list_add(ctx->members, p);
|
|
rtp_member_release(p);
|
|
|
|
//msg.type = RTCP_MSG_MEMBER;
|
|
//msg.u.member.ssrc = ssrc;
|
|
//ctx->handler.on_rtcp(ctx->cbparam, &msg);
|
|
}
|
|
}
|
|
return p;
|
|
}
|
|
|
|
struct rtp_member* rtp_sender_fetch(struct rtp_context *ctx, uint32_t ssrc)
|
|
{
|
|
struct rtp_member *p;
|
|
p = rtp_member_list_find(ctx->senders, ssrc);
|
|
if(!p)
|
|
{
|
|
p = rtp_member_fetch(ctx, ssrc);
|
|
if(p)
|
|
{
|
|
// update senders list
|
|
rtp_member_list_add(ctx->senders, p);
|
|
}
|
|
}
|
|
return p;
|
|
}
|
|
|
|
static int rtcp_parse(struct rtp_context *ctx, const unsigned char* data, size_t bytes)
|
|
{
|
|
int n;
|
|
uint32_t rtcphd;
|
|
rtcp_header_t header;
|
|
|
|
assert(bytes >= sizeof(rtcphd));
|
|
rtcphd = nbo_r32(data);
|
|
|
|
header.v = RTCP_V(rtcphd);
|
|
header.p = RTCP_P(rtcphd);
|
|
header.rc = RTCP_RC(rtcphd);
|
|
header.pt = RTCP_PT(rtcphd);
|
|
header.length = RTCP_LEN(rtcphd);
|
|
n = header.length * 4 + 4;
|
|
|
|
// 1. RTP version field must equal 2 (p69)
|
|
// 2. The payload type filed of the first RTCP packet in a compound packet must be SR or RR (p69)
|
|
// 3. padding only valid at the last packet
|
|
if (n > bytes || 2 != header.v || (header.p && (header.length < 1 || header.length * 4 < data[n - 1])))
|
|
{
|
|
assert(0);
|
|
return -1;
|
|
}
|
|
|
|
if(header.p)
|
|
n -= data[n - 1];
|
|
|
|
switch(header.pt)
|
|
{
|
|
case RTCP_SR:
|
|
rtcp_sr_unpack(ctx, &header, data + 4, n - 4);
|
|
break;
|
|
|
|
case RTCP_RR:
|
|
rtcp_rr_unpack(ctx, &header, data + 4, n - 4);
|
|
break;
|
|
|
|
case RTCP_SDES:
|
|
rtcp_sdes_unpack(ctx, &header, data + 4, n - 4);
|
|
break;
|
|
|
|
case RTCP_BYE:
|
|
rtcp_bye_unpack(ctx, &header, data + 4, n - 4);
|
|
break;
|
|
|
|
case RTCP_APP:
|
|
rtcp_app_unpack(ctx, &header, data + 4, n - 4);
|
|
break;
|
|
|
|
case RTCP_RTPFB:
|
|
rtcp_rtpfb_unpack(ctx, &header, data + 4, n - 4);
|
|
break;
|
|
|
|
case RTCP_PSFB:
|
|
rtcp_psfb_unpack(ctx, &header, data + 4, n - 4);
|
|
break;
|
|
|
|
case RTCP_XR:
|
|
rtcp_xr_unpack(ctx, &header, data + 4, n - 4);
|
|
break;
|
|
|
|
default:
|
|
assert(0);
|
|
}
|
|
|
|
return (RTCP_LEN(rtcphd) + 1) * 4;
|
|
}
|
|
|
|
int rtcp_input_rtcp(struct rtp_context *ctx, const void* data, int bytes)
|
|
{
|
|
int r;
|
|
const unsigned char* p;
|
|
|
|
// RFC3550 6.1 RTCP Packet Format
|
|
// 1. The first RTCP packet in the compound packet must always be a report packet to facilitate header validation
|
|
// 2. An SDES packet containing a CNAME item must be included in each compound RTCP packet
|
|
// 3. BYE should be the last packet sent with a given SSRC/CSRC.
|
|
p = (const unsigned char*)data;
|
|
while(bytes > 4)
|
|
{
|
|
// compound RTCP packet
|
|
r = rtcp_parse(ctx, p, bytes);
|
|
if(r <= 0)
|
|
break;
|
|
|
|
// RFC3550 6.3.3 Receiving an RTP or Non-BYE RTCP Packet (p26)
|
|
ctx->avg_rtcp_size = (int)(ctx->avg_rtcp_size*1.0/16 + r * 15.0/16);
|
|
|
|
p += r;
|
|
bytes -= r;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int rtcp_input_rtp(struct rtp_context *ctx, const void* data, int bytes)
|
|
{
|
|
uint64_t clock;
|
|
struct rtp_packet_t pkt;
|
|
struct rtp_member *sender;
|
|
|
|
if(0 != rtp_packet_deserialize(&pkt, data, bytes))
|
|
return -1; // packet error
|
|
|
|
assert(2 == pkt.rtp.v);
|
|
sender = rtp_sender_fetch(ctx, pkt.rtp.ssrc);
|
|
if(!sender)
|
|
return -1; // memory error
|
|
|
|
clock = rtpclock();
|
|
|
|
// RFC3550 A.1 RTP Data Header Validity Checks
|
|
if(0 == rtp_seq_update(sender, (uint16_t)pkt.rtp.seq))
|
|
return 0; // disorder(need more data)
|
|
|
|
// RFC3550 A.8 Estimating the Interarrival Jitter
|
|
// the jitter estimate is updated:
|
|
if(0 != sender->rtp_packets)
|
|
{
|
|
int D;
|
|
D = (int)((unsigned int)((clock - sender->rtp_clock)*ctx->frequence/1000000) - (pkt.rtp.timestamp - sender->rtp_timestamp));
|
|
if(D < 0) D = -D;
|
|
sender->jitter += (D - sender->jitter)/16.0;
|
|
}
|
|
else
|
|
{
|
|
sender->jitter = 0.0;
|
|
}
|
|
|
|
sender->rtp_clock = clock;
|
|
sender->rtp_timestamp = pkt.rtp.timestamp;
|
|
sender->rtp_bytes += pkt.payloadlen;
|
|
sender->rtp_packets += 1;
|
|
return 1;
|
|
}
|