/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set et sw=2 ts=2: */ /*************************************************************************** * lrtp.cc * * Wed Aug 28 09:50:55 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 General Public License as published by * the Free Software Foundation; either version 2 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with lrtp; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "lrtp.h" #include #include #include #include #include "rtp_profile.h" #include "rtp_profile_amrwb.h" #include "rtp_profile_opus.h" #include "rtp_profile_raw.h" #include "srtp.h" #ifdef __cplusplus extern "C" { #endif typedef std::map profile_map_t; struct lrtp_t { SRTP *srtp; csrc_t ssrc; unsigned short seq; profile_map_t profiles; csrc_t next_csrc; // for frame iterator (see get_next_frame) std::list framelist; }; typedef struct { lrtp_profile_id_t id; struct lrtp_profile_t *(*create)(struct lrtp_t *lrtp, unsigned int csrc, va_list ap); } profile_class_t; static const profile_class_t registered_profiles[] = { { PROFILE_AMRWB, profile_amrwb_create }, { PROFILE_OPUS, profile_opus_create }, { PROFILE_RAW, profile_raw_create }, { } }; EXPORT struct lrtp_t *lrtp_init(const char *key, unsigned int ssrc) { struct lrtp_t *lrtp = new struct lrtp_t; lrtp->srtp = new SRTP(key, ssrc); lrtp->ssrc = ssrc; lrtp->seq = 0; return lrtp; } EXPORT void lrtp_close(struct lrtp_t *lrtp) { delete lrtp->srtp; delete lrtp; } EXPORT struct lrtp_profile_t *lrtp_create_profile(struct lrtp_t *lrtp, lrtp_profile_id_t profile_id, unsigned int csrc, ...) { struct lrtp_profile_t *profile = NULL; if(lrtp->profiles.find(csrc) != lrtp->profiles.end()) { // TODO: CSRC already active printf("ERROR: CSRC already active\n"); return NULL; } va_list ap; va_start(ap, csrc); const profile_class_t *p = registered_profiles; while(p->create) { if(p->id == profile_id) { profile = p->create(lrtp, csrc, ap); profile->process_finished = NULL; // TODO: Figure out a way to set non-profile specific options. break; } p++; } va_end(ap); if(profile) { profile->id = PROFILE_RAW; profile->lrtp = lrtp; profile->csrc = csrc; lrtp->profiles[csrc] = profile; } return profile; } EXPORT void lrtp_destroy_profile(struct lrtp_t *lrtp, unsigned int csrc) { if(lrtp->profiles.find(csrc) == lrtp->profiles.end()) { // TODO: CSRC not found printf("ERROR: CSRC not found\n"); return; } struct lrtp_profile_t *profile = lrtp->profiles[csrc]; profile->destroy(profile); lrtp->profiles.erase(csrc); } EXPORT int lrtp_enqueue_frame(struct lrtp_profile_t *profile, const char *data, size_t size) { inputframe_t *frame = new inputframe_t(); frame->data = data; frame->size = size; frame->offset = 0; profile->framelist.push_back(frame); return 0; } static lrtp_profile_t *get_next_profile(struct lrtp_t *lrtp) { // TODO: This function /should/ return the next profile containing frame data, // not just the next profile in the list (regardless of it's framequeue being // empty!). if(lrtp->profiles.size() == 0) return NULL; // No profiles profile_map_t::iterator i = lrtp->profiles.find(lrtp->next_csrc); if(i == lrtp->profiles.end()) { i = lrtp->profiles.begin(); } struct lrtp_profile_t *profile = i->second; i++; if(i == lrtp->profiles.end()) { i = lrtp->profiles.begin(); } lrtp->next_csrc = i->second->csrc; return profile; } EXPORT int lrtp_pack(struct lrtp_t *lrtp, char *packet, size_t maxsize) { //if(!profile) return PACK_MISSING_PROFILE; // TODO: Check profile magic word struct lrtp_profile_t *profile = get_next_profile(lrtp); if(profile == NULL || profile->framelist.size() == 0) return 0; inputframe_t *frame = profile->framelist.front(); RTP rtp; rtp.setSSrc(lrtp->ssrc); //rtp.setTimestamp(ts); // TODO... rtp.setSeq(lrtp->seq); rtp.addCSrc(profile->csrc); int ret = profile->pack(profile, frame->data + frame->offset, frame->size - frame->offset, rtp); if(ret < 0) return ret; frame->offset += ret; if(frame->size == frame->offset) { if(profile->process_finished) { profile->process_finished(profile, frame->data, profile->process_finished_ptr); } profile->framelist.pop_front(); delete frame; } if(rtp.isValid()) { size_t size = rtp.packet(packet, maxsize); size = lrtp->srtp->encrypt(packet, size); lrtp->seq++; return size; } return 0; } EXPORT int lrtp_dequeue_frame(struct lrtp_t *lrtp, char *frame, size_t maxsize, unsigned int *csrc, unsigned int *ts) { if(lrtp->framelist.size() == 0) return 0; outputframe_t *f = lrtp->framelist.front(); if(f->size > maxsize) { printf("Buffer is too small\n"); return -1; // Buffer too small. } memcpy(frame, f->data, f->size); lrtp->framelist.pop_front(); free(f->data); delete f; return f->size; } EXPORT int lrtp_unpack(struct lrtp_t *lrtp, const char *packet, size_t size) { if(!lrtp) return UNPACK_MISSING_HANDLE; // TODO: Check lrtp magic word char pkg[16*1024]; memcpy(pkg, packet, size); size = lrtp->srtp->decrypt(pkg, size); RTP rtp; rtp.fromPacket(pkg, size); std::list csrcs = rtp.getCSrcs(); if(csrcs.size() == 0) return UNPACK_MISSING_CSRC; if(csrcs.size() > 1) return UNPACK_TOO_MANY_CSRCS; csrc_t csrc = *csrcs.begin(); struct lrtp_profile_t *profile = NULL; if(lrtp->profiles.find(csrc) == lrtp->profiles.end()) { return UNPACK_MISSING_PROFILE; } profile = lrtp->profiles[csrc]; std::list framelist; int ret = profile->unpack(profile, rtp, framelist); lrtp->framelist.splice(lrtp->framelist.end(), framelist); return ret; } #ifdef __cplusplus } #endif