Squashed 'third_party/rawrtc/re/' content from commit f3163ce8b
Change-Id: I6a235e6ac0f03269d951026f9d195da05c40fdab
git-subtree-dir: third_party/rawrtc/re
git-subtree-split: f3163ce8b526a13b35ef71ce4dd6f43585064d8a
diff --git a/src/rtp/rtcp.c b/src/rtp/rtcp.c
new file mode 100644
index 0000000..6e708de
--- /dev/null
+++ b/src/rtp/rtcp.c
@@ -0,0 +1,285 @@
+/**
+ * @file rtcp.c Real-time Transport Control Protocol
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <string.h>
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_mem.h>
+#include <re_mbuf.h>
+#include <re_list.h>
+#include <re_sa.h>
+#include <re_rtp.h>
+#include "rtcp.h"
+
+
+static int rtcp_quick_send(struct rtp_sock *rs, enum rtcp_type type,
+ uint32_t count, ...)
+{
+ struct mbuf *mb;
+ va_list ap;
+ int err;
+
+ mb = mbuf_alloc(32);
+ if (!mb)
+ return ENOMEM;
+
+ mb->pos = RTCP_HEADROOM;
+
+ va_start(ap, count);
+ err = rtcp_vencode(mb, type, count, ap);
+ va_end(ap);
+
+ mb->pos = RTCP_HEADROOM;
+
+ if (!err)
+ err = rtcp_send(rs, mb);
+
+ mem_deref(mb);
+
+ return err;
+}
+
+
+/**
+ * Send an RTCP Application-Defined (APP) packet
+ *
+ * @param rs RTP Socket
+ * @param name Ascii name (4 octets)
+ * @param data Application-dependent data
+ * @param len Number of bytes of data
+ *
+ * @return 0 for success, otherwise errorcode
+ */
+int rtcp_send_app(struct rtp_sock *rs, const char name[4],
+ const uint8_t *data, size_t len)
+{
+ return rtcp_quick_send(rs, RTCP_APP, 0, rtp_sess_ssrc(rs),
+ name, data, len);
+}
+
+
+/**
+ * Send a Full INTRA-frame Request (FIR) packet
+ *
+ * @param rs RTP Socket
+ * @param ssrc Synchronization source identifier for the sender of this packet
+ *
+ * @return 0 for success, otherwise errorcode
+ */
+int rtcp_send_fir(struct rtp_sock *rs, uint32_t ssrc)
+{
+ return rtcp_quick_send(rs, RTCP_FIR, 0, ssrc);
+}
+
+
+/**
+ * Send an RTCP NACK packet
+ *
+ * @param rs RTP Socket
+ * @param fsn First Sequence Number lost
+ * @param blp Bitmask of lost packets
+ *
+ * @return 0 for success, otherwise errorcode
+ */
+int rtcp_send_nack(struct rtp_sock *rs, uint16_t fsn, uint16_t blp)
+{
+ return rtcp_quick_send(rs, RTCP_NACK, 0, rtp_sess_ssrc(rs), fsn, blp);
+}
+
+
+/**
+ * Send an RTCP Picture Loss Indication (PLI) packet
+ *
+ * @param rs RTP Socket
+ * @param fb_ssrc Feedback SSRC
+ *
+ * @return 0 for success, otherwise errorcode
+ */
+int rtcp_send_pli(struct rtp_sock *rs, uint32_t fb_ssrc)
+{
+ return rtcp_quick_send(rs, RTCP_PSFB, RTCP_PSFB_PLI,
+ rtp_sess_ssrc(rs), fb_ssrc, NULL, NULL);
+}
+
+
+const char *rtcp_type_name(enum rtcp_type type)
+{
+ switch (type) {
+
+ case RTCP_FIR: return "FIR";
+ case RTCP_NACK: return "NACK";
+ case RTCP_SR: return "SR";
+ case RTCP_RR: return "RR";
+ case RTCP_SDES: return "SDES";
+ case RTCP_BYE: return "BYE";
+ case RTCP_APP: return "APP";
+ case RTCP_RTPFB: return "RTPFB";
+ case RTCP_PSFB: return "PSFB";
+ case RTCP_XR: return "XR";
+ case RTCP_AVB: return "AVB";
+ default: return "?";
+ }
+}
+
+
+const char *rtcp_sdes_name(enum rtcp_sdes_type sdes)
+{
+ switch (sdes) {
+
+ case RTCP_SDES_END: return "END";
+ case RTCP_SDES_CNAME: return "CNAME";
+ case RTCP_SDES_NAME: return "NAME";
+ case RTCP_SDES_EMAIL: return "EMAIL";
+ case RTCP_SDES_PHONE: return "PHONE";
+ case RTCP_SDES_LOC: return "LOC";
+ case RTCP_SDES_TOOL: return "TOOL";
+ case RTCP_SDES_NOTE: return "NOTE";
+ case RTCP_SDES_PRIV: return "PRIV";
+ default: return "?";
+ }
+}
+
+
+/**
+ * Print an RTCP Message
+ *
+ * @param pf Print handler for debug output
+ * @param msg RTCP Message
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int rtcp_msg_print(struct re_printf *pf, const struct rtcp_msg *msg)
+{
+ size_t i, j;
+ int err;
+
+ if (!msg)
+ return 0;
+
+ err = re_hprintf(pf, "%8s pad=%d count=%-2d pt=%-3d len=%u ",
+ rtcp_type_name((enum rtcp_type)msg->hdr.pt),
+ msg->hdr.p,
+ msg->hdr.count, msg->hdr.pt, msg->hdr.length);
+ if (err)
+ return err;
+
+ switch (msg->hdr.pt) {
+
+ case RTCP_SR:
+ err = re_hprintf(pf, "%08x %u %u %u %u %u",
+ msg->r.sr.ssrc,
+ msg->r.sr.ntp_sec,
+ msg->r.sr.ntp_frac,
+ msg->r.sr.rtp_ts,
+ msg->r.sr.psent,
+ msg->r.sr.osent);
+ for (i=0; i<msg->hdr.count && !err; i++) {
+ const struct rtcp_rr *rr = &msg->r.sr.rrv[i];
+ err = re_hprintf(pf, " {%08x %u %d %u %u %u %u}",
+ rr->ssrc, rr->fraction, rr->lost,
+ rr->last_seq, rr->jitter,
+ rr->lsr, rr->dlsr);
+ }
+ break;
+
+ case RTCP_RR:
+ err = re_hprintf(pf, "%08x", msg->r.rr.ssrc);
+ for (i=0; i<msg->hdr.count && !err; i++) {
+ const struct rtcp_rr *rr = &msg->r.rr.rrv[i];
+ err = re_hprintf(pf, " {0x%08x %u %d %u %u %u %u}",
+ rr->ssrc, rr->fraction, rr->lost,
+ rr->last_seq, rr->jitter,
+ rr->lsr, rr->dlsr);
+ }
+ break;
+
+ case RTCP_SDES:
+ for (i=0; i<msg->hdr.count; i++) {
+ const struct rtcp_sdes *sdes = &msg->r.sdesv[i];
+
+ err = re_hprintf(pf, " {0x%08x n=%u",
+ sdes->src, sdes->n);
+ for (j=0; j<sdes->n && !err; j++) {
+ const struct rtcp_sdes_item *item;
+ item = &sdes->itemv[j];
+ err = re_hprintf(pf, " <%s:%b>",
+ rtcp_sdes_name(item->type),
+ item->data,
+ (size_t)item->length);
+ }
+ err |= re_hprintf(pf, "}");
+ }
+ break;
+
+ case RTCP_BYE:
+ err = re_hprintf(pf, "%u srcs:", msg->hdr.count);
+ for (i=0; i<msg->hdr.count && !err; i++) {
+ err = re_hprintf(pf, " %08x",
+ msg->r.bye.srcv[i]);
+ }
+ err |= re_hprintf(pf, " '%s'", msg->r.bye.reason);
+ break;
+
+ case RTCP_APP:
+ err = re_hprintf(pf, "src=%08x '%b' data=%zu",
+ msg->r.app.src,
+ msg->r.app.name, sizeof(msg->r.app.name),
+ msg->r.app.data_len);
+ break;
+
+ case RTCP_FIR:
+ err = re_hprintf(pf, "ssrc=%08x", msg->r.fir.ssrc);
+ break;
+
+ case RTCP_NACK:
+ err = re_hprintf(pf, "ssrc=%08x fsn=%04x blp=%04x",
+ msg->r.nack.ssrc, msg->r.nack.fsn,
+ msg->r.nack.blp);
+ break;
+
+ case RTCP_RTPFB:
+ err = re_hprintf(pf, "pkt=%08x med=%08x n=%u",
+ msg->r.fb.ssrc_packet,
+ msg->r.fb.ssrc_media,
+ msg->r.fb.n);
+ if (msg->hdr.count == RTCP_RTPFB_GNACK) {
+ err |= re_hprintf(pf, " GNACK");
+ for (i=0; i<msg->r.fb.n; i++) {
+ err |= re_hprintf(pf, " {%04x %04x}",
+ msg->r.fb.fci.gnackv[i].pid,
+ msg->r.fb.fci.gnackv[i].blp);
+ }
+ }
+ break;
+
+ case RTCP_PSFB:
+ err = re_hprintf(pf, "pkt=%08x med=%08x n=%u",
+ msg->r.fb.ssrc_packet,
+ msg->r.fb.ssrc_media,
+ msg->r.fb.n);
+ if (msg->hdr.count == RTCP_PSFB_SLI) {
+ err |= re_hprintf(pf, " SLI");
+ for (i=0; i<msg->r.fb.n; i++) {
+ err |= re_hprintf(pf, " {%04x %04x %02x}",
+ msg->r.fb.fci.sliv[i].first,
+ msg->r.fb.fci.sliv[i].number,
+ msg->r.fb.fci.sliv[i].picid);
+ }
+ }
+ else if (msg->hdr.count == RTCP_PSFB_AFB) {
+ err |= re_hprintf(pf, " AFB %u bytes",
+ msg->r.fb.n * 4);
+ }
+ break;
+
+ default:
+ err = re_hprintf(pf, "<len=%u>", msg->hdr.length);
+ break;
+ }
+
+ err |= re_hprintf(pf, "\n");
+
+ return err;
+}