// RFC3550 6.5 SDES: Source Description RTCP Packet #include "rtp-internal.h" #include "rtp-util.h" void rtcp_sdes_unpack(struct rtp_context *ctx, const rtcp_header_t *header, const uint8_t* ptr, size_t bytes) { uint32_t i; struct rtcp_msg_t msg; struct rtp_member *member; const unsigned char *p, *end; p = ptr; end = ptr + bytes; assert(header->length >= header->rc); for (i = 0; i < header->rc && p + 8 /*4-ssrc + 1-PT*/ <= end; i++) { msg.ssrc = nbo_r32(p); member = rtp_member_fetch(ctx, msg.ssrc); if (!member) { //continue; } p += 4; while(p + 2 <= end && RTCP_SDES_END != p[0] /*PT*/) { msg.u.sdes.pt = p[0]; msg.u.sdes.len = p[1]; msg.u.sdes.data = (unsigned char*)(p+2); if (p + 2 + msg.u.sdes.len > end) { assert(0); return; // error } ctx->handler.on_rtcp(ctx->cbparam, &msg); switch(msg.u.sdes.pt) { case RTCP_SDES_CNAME: case RTCP_SDES_NAME: case RTCP_SDES_EMAIL: case RTCP_SDES_PHONE: case RTCP_SDES_LOC: case RTCP_SDES_TOOL: case RTCP_SDES_NOTE: rtp_member_setvalue(member, msg.u.sdes.pt, msg.u.sdes.data, msg.u.sdes.len); break; case RTCP_SDES_PRIVATE: //assert(0); break; default: //assert(0); break; } // RFC3550 6.5 SDES: Source Description RTCP Packet // Items are contiguous, i.e., items are not individually padded to a 32-bit boundary. // Text is not null terminated because some multi-octet encodings include null octets. p += 2 + msg.u.sdes.len; } // RFC3550 6.5 SDES: Source Description RTCP Packet // The list of items in each chunk must be terminated by one or more null octets, // the first of which is interpreted as an item type of zero to denote the end of the list. // No length octet follows the null item type octet, // but additional null octets must be included if needed to pad until the next 32-bit boundary. // offset sizeof(SSRC) + sizeof(chunk type) + sizeof(chunk length) p = (const unsigned char *)((p - (const unsigned char *)0 + 3) / 4 * 4); } } static size_t rtcp_sdes_append_item(unsigned char *ptr, size_t bytes, rtcp_sdes_item_t *sdes) { assert(sdes->data); if(bytes >= (size_t)sdes->len+2) { ptr[0] = sdes->pt; ptr[1] = sdes->len; memcpy(ptr+2,sdes->data, sdes->len); } return sdes->len+2; } int rtcp_sdes_pack(struct rtp_context *ctx, uint8_t* ptr, int bytes) { int n; rtcp_header_t header; // must have CNAME if(!ctx->self->sdes[RTCP_SDES_CNAME].data) return 0; header.v = 2; header.p = 0; header.pt = RTCP_SDES; header.rc = 1; // self only header.length = 0; n = (int)rtcp_sdes_append_item(ptr+8, bytes-8, &ctx->self->sdes[RTCP_SDES_CNAME]); if(bytes < 8 + n) return 8 + n; // RFC3550 6.3.9 Allocation of Source Description Bandwidth (p29) // Every third interval (15 seconds), one extra item would be included in the SDES packet if(0 == ctx->rtcp_cycle % 3 && ctx->rtcp_cycle/3 > 0) // skip CNAME { assert(ctx->rtcp_cycle/3 < RTCP_SDES_PRIVATE); if(ctx->self->sdes[ctx->rtcp_cycle/3+1].data) // skip RTCP_SDES_END { n += (int)rtcp_sdes_append_item(ptr+8+n, bytes-n-8, &ctx->self->sdes[ctx->rtcp_cycle/3+1]); if(n + 8 > bytes) return n + 8; } } ctx->rtcp_cycle = (ctx->rtcp_cycle+1) % 24; // 3 * SDES item number header.length = (uint16_t)((n+4+3)/4); // see 6.4.1 SR: Sender Report RTCP Packet nbo_write_rtcp_header(ptr, &header); nbo_w32(ptr+4, ctx->self->ssrc); return (header.length+1)*4; }