This source file includes following definitions.
- gf_rtp_read_rtcp
- gf_rtp_decode_rtcp
- gf_rtp_get_ntp_frac
- RTCP_FormatReport
- RTCP_FormatSDES
- RTCP_FormatBYE
- gf_rtp_send_bye
- gf_rtp_send_rtcp_report
- gf_rtp_set_info_rtcp
#include <gpac/internal/ietf_dev.h>
#ifndef GPAC_DISABLE_STREAMING
#include <gpac/bitstream.h>
#ifndef _WIN32_WCE
#include <time.h>
#endif
GF_EXPORT
u32 gf_rtp_read_rtcp(GF_RTPChannel *ch, char *buffer, u32 buffer_size)
{
GF_Err e;
u32 res;
if (!ch || !ch->rtcp) return 0;
e = gf_sk_receive(ch->rtcp, buffer, buffer_size, 0, &res);
if (e) return 0;
return res;
}
GF_EXPORT
GF_Err gf_rtp_decode_rtcp(GF_RTPChannel *ch, char *pck, u32 pck_size, Bool *has_sr)
{
GF_RTCPHeader rtcp_hdr;
GF_BitStream *bs;
char sdes_buffer[300];
u32 i, sender_ssrc, cur_ssrc, val, sdes_type, sdes_len, res, first;
GF_Err e = GF_OK;
if (has_sr) *has_sr = GF_FALSE;
if (pck_size < 4 ) return GF_NON_COMPLIANT_BITSTREAM;
bs = gf_bs_new(pck, pck_size, GF_BITSTREAM_READ);
first = 1;
while (pck_size) {
rtcp_hdr.Version = gf_bs_read_int(bs, 2);
if (rtcp_hdr.Version != 2 ) {
gf_bs_del(bs);
return GF_NOT_SUPPORTED;
}
rtcp_hdr.Padding = gf_bs_read_int(bs, 1);
rtcp_hdr.Count = gf_bs_read_int(bs, 5);
rtcp_hdr.PayloadType = gf_bs_read_u8(bs);
rtcp_hdr.Length = 1 + gf_bs_read_u16(bs);
if (pck_size < (u32) rtcp_hdr.Length * 4) {
gf_bs_del(bs);
return GF_CORRUPTED_DATA;
}
pck_size -= rtcp_hdr.Length * 4;
rtcp_hdr.Length -= 1;
if (first) {
if ( ( (rtcp_hdr.PayloadType!=200) && (rtcp_hdr.PayloadType!=201) )
|| rtcp_hdr.Padding
) {
gf_bs_del(bs);
GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[RTCP] Corrupted RTCP packet: payload type %d (200 or 201 expected) - Padding %d (0 expected)\n", rtcp_hdr.PayloadType, rtcp_hdr.Padding));
return GF_CORRUPTED_DATA;
}
first = 0;
}
switch (rtcp_hdr.PayloadType) {
case 200:
sender_ssrc = gf_bs_read_u32(bs);
rtcp_hdr.Length -= 1;
if (ch->SenderSSRC && (ch->SenderSSRC != sender_ssrc)) break;
if (ch->first_SR) {
ch->first_SR = 0;
gf_rtp_get_next_report_time(ch);
ch->SenderSSRC = sender_ssrc;
}
ch->last_report_time = gf_rtp_get_report_time();
ch->last_SR_NTP_sec = gf_bs_read_u32(bs);
ch->last_SR_NTP_frac = gf_bs_read_u32(bs);
ch->last_SR_rtp_time = gf_bs_read_u32(bs);
gf_bs_read_u32(bs);
gf_bs_read_u32(bs);
rtcp_hdr.Length -= 5;
if (has_sr) *has_sr = GF_TRUE;
#ifndef GPAC_DISABLE_LOG
if (gf_log_tool_level_on(GF_LOG_RTP, GF_LOG_INFO)) {
#ifndef _WIN32_WCE
time_t gtime = ch->last_SR_NTP_sec - GF_NTP_SEC_1900_TO_1970;
const char *ascTime = asctime(gmtime(>ime));
#else
const char *ascTime = "Not Available";
#endif
GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTP] RTCP SR: SSRC %d - RTP Time %d - Nb Pck %d - Nb Bytes %d - Time %s\n",
ch->SenderSSRC,
ch->last_SR_rtp_time,
ch->total_pck,
ch->total_bytes,
ascTime
));
}
#endif
goto process_reports;
case 201:
gf_bs_read_u32(bs);
rtcp_hdr.Length -= 1;
process_reports:
#if 0
for (i=0; i<rtcp_hdr.Count; i++) {
cur_ssrc = gf_bs_read_u32(bs);
gf_bs_read_u8(bs);
gf_bs_read_u24(bs);
gf_bs_read_u32(bs);
gf_bs_read_u32(bs);
gf_bs_read_u32(bs);
gf_bs_read_u32(bs);
rtcp_hdr.Length -= 6;
}
#endif
break;
case 202:
for (i=0; i<rtcp_hdr.Count; i++) {
gf_bs_read_u32(bs);
rtcp_hdr.Length -= 1;
val = 0;
while (1) {
sdes_type = gf_bs_read_u8(bs);
val += 1;
if (!sdes_type) break;
sdes_len = gf_bs_read_u8(bs);
val += 1;
gf_bs_read_data(bs, sdes_buffer, sdes_len);
sdes_buffer[sdes_len] = 0;
val += sdes_len;
}
res = val%4;
if (res) {
gf_bs_skip_bytes(bs, (4-res));
val = val/4 + 1;
} else {
val = val/4;
}
rtcp_hdr.Length -= val;
}
break;
case 203:
for (i=0; i<rtcp_hdr.Count; i++) {
cur_ssrc = gf_bs_read_u32(bs);
rtcp_hdr.Length -= 1;
if (ch->SenderSSRC == cur_ssrc) {
e = GF_EOS;
break;
}
}
while (rtcp_hdr.Length) {
gf_bs_read_u32(bs);
rtcp_hdr.Length -= 1;
}
break;
default:
gf_bs_read_data(bs, sdes_buffer, rtcp_hdr.Length*4);
rtcp_hdr.Length = 0;
break;
}
if (rtcp_hdr.Length) {
gf_bs_del(bs);
return GF_CORRUPTED_DATA;
}
}
gf_bs_del(bs);
return e;
}
u32 gf_rtp_get_ntp_frac(u32 sec, u32 frac)
{
return ( ((sec & 0x0000ffff) << 16) | ((frac & 0xffff0000) >> 16));
}
static u32 RTCP_FormatReport(GF_RTPChannel *ch, GF_BitStream *bs, u32 NTP_Time)
{
u32 length, is_sr, sec, frac, expected, val, size;
s32 extended, expect_diff, loss_diff;
Double f;
is_sr = ch->pck_sent_since_last_sr ? 1 : 0;
if (ch->forced_ntp_sec) {
sec = ch->forced_ntp_sec;
frac = ch->forced_ntp_frac;
is_sr = 1;
} else {
gf_net_get_ntp(&sec, &frac);
}
gf_bs_write_int(bs, 2, 2);
gf_bs_write_int(bs, 0, 1);
gf_bs_write_int(bs, !is_sr, 5);
gf_bs_write_u8(bs, is_sr ? 200 : 201);
length = is_sr ? 6 : (1 + 6 * 1);
gf_bs_write_u16(bs, length);
gf_bs_write_u32(bs, ch->SSRC);
size = 8;
if (is_sr) {
gf_bs_write_u32(bs, sec);
gf_bs_write_u32(bs, frac);
f = 1000 * (sec - ch->last_pck_ntp_sec);
f += ((frac - ch->last_pck_ntp_frac) >> 4) / 0x10000;
f /= 1000;
f *= ch->TimeScale;
val = (u32) f + ch->last_pck_ts;
gf_bs_write_u32(bs, val);
gf_bs_write_u32(bs, ch->num_pck_sent);
gf_bs_write_u32(bs, ch->num_payload_bytes);
size += 20;
return size;
}
gf_bs_write_u32(bs, ch->SenderSSRC);
extended = ( (ch->num_sn_loops << 16) | ch->last_pck_sn);
expected = extended - ch->rtp_first_SN;
expect_diff = expected - ch->tot_num_pck_expected;
loss_diff = expect_diff - ch->last_num_pck_rcv;
if (!expect_diff || (loss_diff <= 0)) loss_diff = 0;
else loss_diff = (loss_diff<<8) / expect_diff;
gf_bs_write_u8(bs, loss_diff);
ch->tot_num_pck_rcv += ch->last_num_pck_rcv;
ch->tot_num_pck_expected = expected;
gf_bs_write_u24(bs, (expected - ch->tot_num_pck_rcv));
gf_bs_write_u32(bs, extended);
gf_bs_write_u32(bs, ( ch->Jitter >> 4));
val = ch->last_SR_NTP_sec ? gf_rtp_get_ntp_frac(ch->last_SR_NTP_sec, ch->last_SR_NTP_frac) : 0;
gf_bs_write_u32(bs, val);
gf_bs_write_u32(bs, (NTP_Time - ch->last_report_time));
#ifndef GPAC_DISABLE_LOG
if (gf_log_tool_level_on(GF_LOG_RTP, GF_LOG_DEBUG)) {
#ifndef _WIN32_WCE
time_t gtime = ch->last_SR_NTP_sec - GF_NTP_SEC_1900_TO_1970;
const char *ascTime = asctime(gmtime(>ime));
#else
const char *ascTime = "Not Available";
#endif
GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP] RTCP-RR\t%d\t%d\t%d\t%d\t%d\t%s\n",
ch->SSRC,
ch->Jitter >> 4,
extended,
expect_diff,
loss_diff,
ascTime
));
}
#endif
size += 24;
return size;
}
static u32 RTCP_FormatSDES(GF_RTPChannel *ch, GF_BitStream *bs)
{
u32 length, padd;
length = 8;
length += 2 + (u32) strlen(ch->CName) + 1;
padd = length % 4;
if (padd*4 != 0) {
padd = 4 - padd;
length = length/4 + 1;
} else {
padd = 0;
length = length/4;
}
gf_bs_write_int(bs, 2, 2);
gf_bs_write_int(bs, 0, 1);
gf_bs_write_int(bs, 1, 5);
gf_bs_write_u8(bs, 202);
gf_bs_write_u16(bs, length - 1);
gf_bs_write_u32(bs, ch->SSRC);
gf_bs_write_u8(bs, 1);
gf_bs_write_u8(bs, (u32) strlen(ch->CName));
gf_bs_write_data(bs, ch->CName, (u32) strlen(ch->CName));
gf_bs_write_u8(bs, 0);
gf_bs_write_int(bs, 0, 8*padd);
return (length + 1)*4;
}
static u32 RTCP_FormatBYE(GF_RTPChannel *ch, GF_BitStream *bs)
{
gf_bs_write_int(bs, 2, 2);
gf_bs_write_int(bs, 0, 1);
gf_bs_write_int(bs, 1, 5);
gf_bs_write_u8(bs, 203);
gf_bs_write_u16(bs, 1);
gf_bs_write_u32(bs, ch->SSRC);
return 8;
}
GF_EXPORT
GF_Err gf_rtp_send_bye(GF_RTPChannel *ch,
GF_Err (*RTP_TCPCallback)(void *cbk, char *pck, u32 pck_size),
void *rtsp_cbk)
{
GF_BitStream *bs;
u32 report_size;
char *report_buf;
GF_Err e = GF_OK;
bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
if (ch->last_num_pck_rcv || ch->pck_sent_since_last_sr) {
RTCP_FormatReport(ch, bs, gf_rtp_get_report_time());
}
RTCP_FormatSDES(ch, bs);
RTCP_FormatBYE(ch, bs);
report_buf = NULL;
report_size = 0;
gf_bs_get_content(bs, &report_buf, &report_size);
gf_bs_del(bs);
if (ch->rtcp) {
e = gf_sk_send(ch->rtcp, report_buf, report_size);
} else {
if (RTP_TCPCallback)
e = RTP_TCPCallback(rtsp_cbk, report_buf, report_size);
else
e = GF_BAD_PARAM;
}
gf_free(report_buf);
return e;
}
GF_EXPORT
GF_Err gf_rtp_send_rtcp_report(GF_RTPChannel *ch,
GF_Err (*RTP_TCPCallback)(void *cbk, char *pck, u32 pck_size),
void *rtsp_cbk)
{
u32 Time, report_size;
GF_BitStream *bs;
char *report_buf;
GF_Err e = GF_OK;
if (!ch->forced_ntp_sec && ch->first_SR) return GF_OK;
Time = gf_rtp_get_report_time();
if ( Time < ch->next_report_time) return GF_OK;
bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
if (ch->last_num_pck_rcv || ch->pck_sent_since_last_sr || ch->forced_ntp_sec) {
RTCP_FormatReport(ch, bs, Time);
}
RTCP_FormatSDES(ch, bs);
report_buf = NULL;
report_size = 0;
gf_bs_get_content(bs, &report_buf, &report_size);
gf_bs_del(bs);
if (ch->rtcp) {
e = gf_sk_send(ch->rtcp, report_buf, report_size);
} else {
if (RTP_TCPCallback)
e = RTP_TCPCallback(rtsp_cbk, report_buf, report_size);
else
e = GF_BAD_PARAM;
}
ch->rtcp_bytes_sent += report_size;
gf_free(report_buf);
if (!e) {
ch->last_num_pck_rcv = ch->last_num_pck_expected = ch->last_num_pck_loss = 0;
GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTCP] SSRC %d: sending RTCP report\n", ch->SSRC));
}
else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTCP] SSRC %d: error when sending RTCP report\n", ch->SSRC));
}
gf_rtp_get_next_report_time(ch);
return e;
}
#define RTCP_SAFE_FREE(p) if (p) gf_free(p); \
p = NULL;
GF_EXPORT
GF_Err gf_rtp_set_info_rtcp(GF_RTPChannel *ch, u32 InfoCode, char *info_string)
{
if (!ch) return GF_BAD_PARAM;
switch (InfoCode) {
case GF_RTCP_INFO_NAME:
RTCP_SAFE_FREE(ch->s_name);
if (info_string) ch->s_name = gf_strdup(info_string);
break;
case GF_RTCP_INFO_EMAIL:
RTCP_SAFE_FREE(ch->s_email);
if (info_string) ch->s_email = gf_strdup(info_string);
break;
case GF_RTCP_INFO_PHONE:
RTCP_SAFE_FREE(ch->s_phone);
if (info_string) ch->s_phone = gf_strdup(info_string);
break;
case GF_RTCP_INFO_LOCATION:
RTCP_SAFE_FREE(ch->s_location);
if (info_string) ch->s_location = gf_strdup(info_string);
break;
case GF_RTCP_INFO_TOOL:
RTCP_SAFE_FREE(ch->s_tool);
if (info_string) ch->s_tool = gf_strdup(info_string);
break;
case GF_RTCP_INFO_NOTE:
RTCP_SAFE_FREE(ch->s_note);
if (info_string) ch->s_note = gf_strdup(info_string);
break;
case GF_RTCP_INFO_PRIV:
RTCP_SAFE_FREE(ch->s_priv);
if (info_string) ch->s_name = gf_strdup(info_string);
break;
default:
return GF_BAD_PARAM;
}
return GF_OK;
}
#endif