/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set et sw=2 ts=2: */ /*************************************************************************** * rtp.cc * * Mon Sep 2 15:24:09 CEST 2013 * Copyright 2013 Bent Bisballe Nyeng * deva@aasimon.org ****************************************************************************/ /* * This file is part of lrtp. * * lrtp is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * lrtp is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with lrtp; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "rtp.h" #include #include // For ntoh et al. #ifdef WIN32 #include #else #include #endif RTP::RTP() { memset(&header, 0, sizeof(header)); pads = 0; header.version = 2; memset(pload, 0, sizeof(pload)); pload_size = 0; is_valid = false; } void RTP::setPadding(unsigned char padding) { if(padding == 0) { header.p = 0; pads = 0; return; } header.p = 1; pads = padding; } unsigned char RTP::padding() const { return pads; } void RTP::setPayloadType(unsigned char pt) { header.pt = pt; } unsigned char RTP::payloadType() const { return header.pt; } void RTP::setMarker(bool bit) { header.m = bit?1:0; } bool RTP::marker() const { return header.m; } void RTP::setSeq(uint16_t seq) { header.seq = htons(seq); } uint16_t RTP::seq() const { return ntohs(header.seq); } void RTP::setTimestamp(uint32_t ts) { header.ts = htonl(ts); } uint32_t RTP::timestamp() const { return ntohl(header.ts); } void RTP::setSSrc(uint32_t ssrc) { header.ssrc = htonl(ssrc); } uint32_t RTP::SSrc() const { return ntohl(header.ssrc); } void RTP::addCSrc(csrc_t csrc) { if(csrcs.size() == 15) { printf("ERROR: Too many CSRCs (max 15).\n"); return; // TODO: Report error! } csrcs.push_back(csrc); header.cc = csrcs.size(); } std::list RTP::getCSrcs() const { return csrcs; } void RTP::removeCSrc(csrc_t csrc) { csrcs.remove(csrc); header.cc = csrcs.size(); } void RTP::clearCSrcs() { csrcs.clear(); header.cc = csrcs.size(); } int RTP::setPayload(const char *pl, size_t size) { if(size > MAX_RTP_PAYLOAD_SIZE) { printf("ERROR: Payload is too big for RTP packet (%d bytes, max is %d).\n", size, MAX_RTP_PAYLOAD_SIZE); // TODO: Report error. return -1; } memcpy(pload, pl, size); pload_size = size; setValid(true); return size; } size_t RTP::payload(char *payload, size_t maxsize) const { if(pload_size > maxsize) { printf("ERROR: Payload is too big for the buffer.\n"); return 0; // TODO: Report error. } memcpy(payload, pload, pload_size); return pload_size; } size_t RTP::payloadSize() const { return pload_size; } const char *RTP::payloadData() const { return pload; } size_t RTP::packet(char *packet, size_t maxsize) const { memset(packet, 0, maxsize); size_t total_packet_size = sizeof(header) + sizeof(csrc_t) * csrcs.size() + pload_size + pads; if(total_packet_size > maxsize) { printf("ERROR: Packet is too big for the buffer.\n"); return 0; // TODO: Report error. } char *p = packet; // Copy header fields. memcpy(p, &header, sizeof(header)); p += sizeof(header); // Write CSrcs to packet csrc_t *pcsrc = (csrc_t*)p; std::list::const_iterator i = csrcs.begin(); while(i != csrcs.end()) { *pcsrc++ = htonl(*i); i++; } p += sizeof(csrc_t) * csrcs.size(); // TODO: Insert header extension here (if it exists) // Write payload to body. memcpy(p, pload, pload_size); p += pload_size; if(pads) { for(int i = 0; i < pads - 1; i++) *p++ = '\0'; *p++ = (unsigned char)pads; } return p - packet; } int RTP::fromPacket(const char *packet, size_t size) { rtp_header_t *hdr = (rtp_header_t *)packet; if(hdr->version != 2) { printf("ERROR: Wrong RTP header version.\n"); return -1; // TODO: Invalid RTP version error } setMarker(hdr->m); setPayloadType(hdr->pt); setSeq(ntohs(hdr->seq)); setTimestamp(ntohl(hdr->ts)); setSSrc(ntohl(hdr->ssrc)); if(hdr->p) { setPadding(*(unsigned char*)&packet[size - 1]); } // TODO: Use header extension flag: hdr->x // Read out CSrc's: csrc_t *pcsrc = (csrc_t*)(packet + sizeof(rtp_header_t)); for(int i = 0; i < hdr->cc; i++) { addCSrc(ntohl(*pcsrc)); pcsrc++; } // Read out payload size_t plsz = size - (sizeof(rtp_header_t) + hdr->cc*sizeof(csrc_t) + pads); char *pl = (char*)pcsrc; if(setPayload(pl, plsz) < 0) return -1; setValid(true); return size; } bool RTP::isValid() { return is_valid; } void RTP::setValid(bool valid) { is_valid = valid; }