From 60f60cc76e43197a0825ffac9aff0b7007a94175 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Wed, 20 Nov 2013 12:57:17 +0100 Subject: Framework API now complete in its first iteration. So far with support for raw, opus and amrwb. --- .gitignore | 8 ++ Makefile.am | 4 + configure.in | 5 +- lrtp.pc.in | 13 ++ src/Makefile.am | 19 ++- src/asc2bin.cc | 64 ++++++++++ src/asc2bin.h | 50 ++++++++ src/compat.h | 37 ++++++ src/lrtp.cc | 273 +++++++++++++++++++++++++++++++++++++++-- src/lrtp.h | 104 ++++++++++++++++ src/lrtp_profiles.h | 72 +++++++++++ src/rtp.cc | 262 +++++++++++++++++++++++++++++++++++++++ src/rtp.h | 116 ++++++++++++++++++ src/rtp_profile.h | 86 +++++++++++++ src/rtp_profile_amrwb.cc | 307 ++++++++++++++++++++++++++++++++++++++++++++++ src/rtp_profile_amrwb.h | 39 ++++++ src/rtp_profile_opus.cc | 188 ++++++++++++++++++++++++++++ src/rtp_profile_opus.h | 39 ++++++ src/rtp_profile_raw.cc | 123 +++++++++++++++++++ src/rtp_profile_raw.h | 39 ++++++ src/srtp.cc | 230 ++++++++++++++++++++++++++++++++++ src/srtp.h | 54 ++++++++ test/Makefile | 29 +++++ test/test_amrwb.cc | 155 +++++++++++++++++++++++ test/test_connectivity.cc | 122 ++++++++++++++++++ test/test_init.cc | 63 ++++++++++ test/test_opus.cc | 272 ++++++++++++++++++++++++++++++++++++++++ test/test_raw.cc | 78 ++++++++++++ test/test_rtp.cc | 112 +++++++++++++++++ test/test_srtp.cc | 87 +++++++++++++ 30 files changed, 3032 insertions(+), 18 deletions(-) create mode 100644 lrtp.pc.in create mode 100644 src/asc2bin.cc create mode 100644 src/asc2bin.h create mode 100644 src/compat.h create mode 100644 src/lrtp_profiles.h create mode 100644 src/rtp.cc create mode 100644 src/rtp.h create mode 100644 src/rtp_profile.h create mode 100644 src/rtp_profile_amrwb.cc create mode 100644 src/rtp_profile_amrwb.h create mode 100644 src/rtp_profile_opus.cc create mode 100644 src/rtp_profile_opus.h create mode 100644 src/rtp_profile_raw.cc create mode 100644 src/rtp_profile_raw.h create mode 100644 src/srtp.cc create mode 100644 src/srtp.h create mode 100644 test/Makefile create mode 100644 test/test_amrwb.cc create mode 100644 test/test_connectivity.cc create mode 100644 test/test_init.cc create mode 100644 test/test_opus.cc create mode 100644 test/test_raw.cc create mode 100644 test/test_rtp.cc create mode 100644 test/test_srtp.cc diff --git a/.gitignore b/.gitignore index bb23159..6ffe871 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,11 @@ Makefile.in *.la *.lo *.o +lrtp.pc +test_amrwb +test_connectivity +test_init +test_opus +test_raw +test_rtp +test_srtp diff --git a/Makefile.am b/Makefile.am index 86e2080..d22e1ba 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,9 @@ AUTOMAKE_OPTIONS = gnu SUBDIRS = src DISTDIRS = src +EXTRA_DIST = lrtp.pc.in + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = lrtp.pc .PHONY: diff --git a/configure.in b/configure.in index ddf76b9..537aa37 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,6 @@ # Filename: configure.in -AC_INIT([lrtp], [1.0.0]) +AC_INIT([lrtp], [0.0.1]) AC_CONFIG_SRCDIR([src/lrtp.cc]) AM_INIT_AUTOMAKE @@ -69,5 +69,6 @@ AC_STDC_HEADERS AC_OUTPUT( Makefile - src/Makefile) + src/Makefile + lrtp.pc) diff --git a/lrtp.pc.in b/lrtp.pc.in new file mode 100644 index 0000000..568b498 --- /dev/null +++ b/lrtp.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: liblrtp +Description: LiteRTP: A (lite) library for handling sRTP transmissions. +Version: @VERSION@ +Requires: +Conflicts: +Libs: -L${libdir} -llrtp +Libs.private: +Cflags: -I${includedir} diff --git a/src/Makefile.am b/src/Makefile.am index 594b257..15a201f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,10 +5,23 @@ liblrtp_la_LIBADD = $(SRTP_LIBS) liblrtp_la_CXXFLAGS = $(SRTP_CXXFLAGS) liblrtp_la_SOURCES = \ - lrtp.cc + lrtp.cc \ + rtp.cc \ + srtp.cc \ + rtp_profile_amrwb.cc \ + rtp_profile_opus.cc \ + rtp_profile_raw.cc \ + asc2bin.cc include_HEADERS = \ - lrtp.h + lrtp.h \ + lrtp_profiles.h -EXTRA_DIST = +EXTRA_DIST = \ + rtp_profile_amrwb.h \ + rtp_profile_opus.h \ + rtp_profile_raw.h \ + rtp.h \ + srtp.h \ + asc2bin.h diff --git a/src/asc2bin.cc b/src/asc2bin.cc new file mode 100644 index 0000000..65efc31 --- /dev/null +++ b/src/asc2bin.cc @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * asc2bin.cc + * + * Thu Sep 5 11:12:50 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 "asc2bin.h" + +static int asc2nibble(unsigned char c) +{ + if(c >= '0' && c <= '9') return c - '0'; + if(c >= 'a' && c <= 'f') return c - 'a' + 0xa; + if(c >= 'A' && c <= 'F') return c - 'A' + 0xa; + return -1; +} + +ssize_t asc2bin(char *raw, size_t rawsz, const char *hex, size_t hexlen) +{ + if(hexlen % 2 != 0) return -1; + if(rawsz < hexlen / 2) return -1; + + unsigned char val; + int nibble; + size_t size = 0; + + while(size < hexlen / 2) { + nibble = asc2nibble(hex[0]); + if(nibble == -1) return -1; + val = (nibble << 4); + + nibble = asc2nibble(hex[1]); + if(nibble == -1) return -1; + val |= (nibble & 0xff); + + *raw = val; + raw++; + size++; + + hex += 2; + } + + return (ssize_t)size; +} diff --git a/src/asc2bin.h b/src/asc2bin.h new file mode 100644 index 0000000..42c3b54 --- /dev/null +++ b/src/asc2bin.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * asc2bin.h + * + * Thu Sep 5 11:12:50 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 + */ +#ifndef __LRTP_ASC2BIN_H__ +#define __LRTP_ASC2BIN_H__ + +#include + +#include "compat.h" + +/** + * asc2bin converts a hexadecimal string to a raw octet string. + * @param raw The char buffer that will contain the result. + * @param rawsz The size of the output buffer 'raw'. This size must be at + * least hexlen / 2. + * @param hex The input hex string. + * @param hexlen The length of the hex string. + * @return The length of the resulting raw data. -1 on error. + * Errors are one of the following: + * - Hex string contains invalid hex character (0-9, a-f and A-F allowed). + * - rawsz is less than hexlen / 2. + * - hexlen is not a multiplum of 2 (odd hex string lengths not supported). + */ +ssize_t asc2bin(char *raw, size_t rawsz, const char *hex, size_t hexlen); + +#endif/*__LRTP_ASC2BIN_H__*/ diff --git a/src/compat.h b/src/compat.h new file mode 100644 index 0000000..70a6286 --- /dev/null +++ b/src/compat.h @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * compat.h + * + * Thu Sep 5 11:14:38 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 + */ +#ifndef __LRTP_COMPAT_H__ +#define __LRTP_COMPAT_H__ + +#ifdef WIN32 +typedef signed int ssize_t; +#else + +#endif + +#endif/*__LRTP_COMPAT_H__*/ diff --git a/src/lrtp.cc b/src/lrtp.cc index 36da6f0..1f0b11d 100644 --- a/src/lrtp.cc +++ b/src/lrtp.cc @@ -27,20 +27,267 @@ */ #include "lrtp.h" -#ifdef TEST_LRTP -//Additional dependency files -//deps: -//Required cflags (autoconf vars may be used) -//cflags: -//Required link options (autoconf vars may be used) -//libs: -#include "test.h" +#include +#include +#include +#include -TEST_BEGIN; +#include "rtp_profile.h" +#include "rtp_profile_amrwb.h" +#include "rtp_profile_opus.h" +#include "rtp_profile_raw.h" -// TODO: Put some testcode here (see test.h for usable macros). -TEST_TRUE(false, "No tests yet!"); +#include "srtp.h" -TEST_END; +#ifdef __cplusplus +extern "C" { +#endif -#endif/*TEST_LRTP*/ +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 diff --git a/src/lrtp.h b/src/lrtp.h index 7428997..ce6b0e2 100644 --- a/src/lrtp.h +++ b/src/lrtp.h @@ -27,4 +27,108 @@ */ #ifndef __LRTP_LRTP_H__ #define __LRTP_LRTP_H__ + +#ifdef WIN32 +#ifdef BUILD_DLL +/* DLL export */ +#define EXPORT __declspec(dllexport) +#else +/* EXE import */ +#define EXPORT __declspec(dllimport) +#endif +#else +#define EXPORT +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "lrtp_profiles.h" + +struct lrtp_t; + +EXPORT +struct lrtp_t *lrtp_init(const char *key, unsigned int ssrc); + +EXPORT +void lrtp_close(struct lrtp_t *lrtp); + +struct lrtp_profile_t; + +/** + * @param ... + */ +EXPORT +struct lrtp_profile_t *lrtp_create_profile(struct lrtp_t *lrtp, + lrtp_profile_id_t profile_id, + unsigned int csrc, ...); + +EXPORT +void lrtp_destroy_profile(struct lrtp_t *lrtp, unsigned int csrc); + +typedef enum { + // Errors: + PACK_ERROR = 1000, // Error... + PACK_BUFFER_TOO_SMALL = 1001, // Packet buffer needs to be bigger. + PACK_UNKNOWN_PROFILE = 1002, // Illegal profile id + PACK_MISSING_PROFILE = 1003, // Profile pointer NULL or not valid. +} lrtp_pack_status_t; + +/** + * Enqueue a media frame for the packetiser. + * @param profile A pointer to profile needed for processing the frame type. + * @param framedate The frame data that needs encapsulation. + * @param framesize The size in bytes of the frame data. + * @return 0 on success, or a negative error code on error. + * NOTE: The frame pointer cannot be freed or overwritten until all frame data + * has been handled by lrtp_pack(). Either call lrtp_pack() until it returns 0 + * after each call to lrtp_enqueue_frame or use the + * OPTION_SET_PROCESS_FINISHED_HANDLER option to set a process finished handler. + * See lrtp_profiles.h for further details. + */ +EXPORT +int lrtp_enqueue_frame(struct lrtp_profile_t *profile, + const char *framedate, size_t framesize); + +/** + * Handle frame data from the frame queue and create at most a single sRTP + * packet. + * @param lrtp The lrtp context handle. + * @param packet A char buffer which will contain the resulting RTP data. + * @param maxsize the maximum number of bytes that can be contained within + * packet. + * @return Returns the number of bytes written in packet, if any (can be zero + * if no packet is available) or a negative error code on error. + */ +EXPORT int lrtp_pack(struct lrtp_t *lrtp, char *packet, size_t maxsize); + +typedef enum { + // Errors: + UNPACK_ERROR = 1000, // Error... + UNPACK_BUFFER_TOO_SMALL = 1001, // Frame buffer needs to be bigger. + UNPACK_MISSING_HANDLE = 1002, // Handle pointer NULL or not valid. + UNPACK_MISSING_CSRC = 1003, // Exactly one csrc must be present. + UNPACK_TOO_MANY_CSRCS = 1004, // Exactly one csrc must be present. + UNPACK_MISSING_PROFILE = 1005, // CSrc from packet could not be connected with a preofile.. +} lrtp_unpack_status_t; + +/** + */ +EXPORT +int lrtp_dequeue_frame(struct lrtp_t *lrtp, + char *frame, size_t maxsize, + unsigned int *csrc, unsigned int *ts); + +/** + */ +EXPORT +int lrtp_unpack(struct lrtp_t *lrtp, const char *packet, size_t size); + +#ifdef __cplusplus +} +#endif + #endif/*__LRTP_LRTP_H__*/ diff --git a/src/lrtp_profiles.h b/src/lrtp_profiles.h new file mode 100644 index 0000000..a3d6db1 --- /dev/null +++ b/src/lrtp_profiles.h @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * lrtp_profiles.h + * + * Mon Sep 9 13:29:04 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 + */ +#ifndef __LRTP_LRTP_PROFILES_H__ +#define __LRTP_LRTP_PROFILES_H__ + +// List of known RTP profiles: +typedef enum { + PROFILE_RAW = 0, // Dummy profile, for test + PROFILE_L16 = 1, + PROFILE_AMRWB = 2, + PROFILE_OPUS = 3, + PROFILE_JPEG = 4, +} lrtp_profile_id_t; + +// No more options. +#define OPTION_END 0 + +// Options relating to all profiles: +/** + * This option is used to set the custom processFinishedHandler + * It takes two arguments, the first being a function pointer of the type: + * void (*process_finished)(struct lrtp_profile_t *profile, + * const char *frame, size_t framesize, + * void *ptr); + * + * the second argument is the value of ptr, passed on to the callback function. + * See rtp_profile.h for further details. + */ +#define OPTION_SET_PROCESS_FINISHED_HANDLER 1000 + +// Raw profile options: +#define OPTION_RAW_PKG_SIZE 2000 // Integer argument. + // Number of bytes per rtp packet. + // Default is 100 + +// AMR-WB profile options: +#define OPTION_AMRWB_FRAME_TYPE_INDEX 3000 // Integer argument. + // Frame type index according to + // Table 1a in "3GPP TS 26.201" + // Default is 8: AMR-WB 23.85 kbit/s + +// Opus profile options: +// None + +// Jpeg profile options: + +#endif/*__LRTP_LRTP_PROFILES_H__*/ diff --git a/src/rtp.cc b/src/rtp.cc new file mode 100644 index 0000000..28a9203 --- /dev/null +++ b/src/rtp.cc @@ -0,0 +1,262 @@ +/* -*- 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 +#include + +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(); +} + +void RTP::setPayload(const char *pl, size_t size) +{ + if(size > MAX_RTP_PAYLOAD_SIZE) { + printf("ERROR: Payload is too big for RTP pakcet.\n"); + // TODO: Report error. + } + + memcpy(pload, pl, size); + pload_size = size; + + setValid(true); +} + +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; +} + +void 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; // 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; + setPayload(pl, plsz); + + setValid(true); +} + +bool RTP::isValid() +{ + return is_valid; +} + +void RTP::setValid(bool valid) +{ + is_valid = valid; +} diff --git a/src/rtp.h b/src/rtp.h new file mode 100644 index 0000000..b7aa8b4 --- /dev/null +++ b/src/rtp.h @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * rtp.h + * + * 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 + */ +#ifndef __LRTP_RTP_H__ +#define __LRTP_RTP_H__ + +#include +#include +#include + +typedef struct { + uint16_t cc:4; // CSRC count + uint16_t x:1; // Header extension flag + uint16_t p:1; // Padding flag + uint16_t version:2; // Protocol version + + uint16_t m:1; // Marker bit + uint16_t pt:7; // Payload type + + uint16_t seq; // Sequence number + + uint32_t ts; // Timestamp + uint32_t ssrc; // Synchronization source +} rtp_header_t; + +#define MAX_RTP_PACKET_SIZE (16 * 1024) +#define MAX_RTP_PAYLOAD_SIZE ( MAX_RTP_PACKET_SIZE - sizeof(rtp_header_t) ) + +typedef struct { + rtp_header_t header; + char body[MAX_RTP_PAYLOAD_SIZE]; +} rtp_t; + +typedef unsigned int csrc_t; + +class RTP { +public: + RTP(); + + /* // Not implemented + void setHeaderExtension(); + int headerExtension(); + */ + + void setPadding(unsigned char padding); + unsigned char padding() const; + + void setPayloadType(unsigned char pt); + unsigned char payloadType() const; + + void setMarker(bool bit); + bool marker() const; + + void setSeq(uint16_t seq); + uint16_t seq() const; + + void setTimestamp(uint32_t seq); + uint32_t timestamp() const; + + void setSSrc(uint32_t ssrc); + uint32_t SSrc() const; + + void addCSrc(csrc_t csrc); + std::list getCSrcs() const; + void removeCSrc(csrc_t csrc); + void clearCSrcs(); + + void setPayload(const char *payload, size_t size); + size_t payload(char *payload, size_t maxsize) const; + size_t payloadSize() const; + const char *payloadData() const; + + size_t packet(char *packet, size_t maxsize) const; + void fromPacket(const char *packet, size_t size); + + bool isValid(); + void setValid(bool valid); + +private: + std::list csrcs; + + rtp_header_t header; + + unsigned char pads; + + char pload[MAX_RTP_PAYLOAD_SIZE]; + size_t pload_size; + + bool is_valid; +}; + +#endif/*__LRTP_RTP_H__*/ diff --git a/src/rtp_profile.h b/src/rtp_profile.h new file mode 100644 index 0000000..96dc9eb --- /dev/null +++ b/src/rtp_profile.h @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * rtp_profile.h + * + * Wed Sep 11 08:40:11 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 + */ +#ifndef __LRTP_RTP_PROFILE_H__ +#define __LRTP_RTP_PROFILE_H__ + +#include +#include + +#include "rtp.h" + +struct lrtp_t; + +typedef struct { + const char *data; + size_t size; + size_t offset; +} inputframe_t; + +typedef struct { + char *data; + size_t size; + + csrc_t csrc; + unsigned int ts; + // TODO: Add other metadata ... + +} outputframe_t; + +struct lrtp_profile_t { + struct lrtp_t *lrtp; + lrtp_profile_id_t id; + unsigned int csrc; + + // Frames ready for packing with this profile: + std::list framelist; + + // Profile functions: + /** + * Custom callback used when a frame has been processed. + * This could be the place to call free(3), decrease a reference counter or + * re-add to a memory pool. + * Use ptr to pass custom parameters to the callback. + * If NULL, no call is performed. + */ + void (*process_finished)(struct lrtp_profile_t *profile, + const char *frame, void *ptr); + void *process_finished_ptr; + + int (*pack)(struct lrtp_profile_t *profile, + const char *frame, size_t framesize, + RTP &rtp); + + int (*unpack)(struct lrtp_profile_t *profile, + const RTP &rtp, + std::list &framelist); + + void (*destroy)(struct lrtp_profile_t *profile); + +}; + +#endif/*__LRTP_RTP_PROFILE_H__*/ diff --git a/src/rtp_profile_amrwb.cc b/src/rtp_profile_amrwb.cc new file mode 100644 index 0000000..f83b3c3 --- /dev/null +++ b/src/rtp_profile_amrwb.cc @@ -0,0 +1,307 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * rtp_profile_amrwb.cc + * + * Wed Oct 2 14:43:05 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_profile_amrwb.h" + +#include "rtp_profile.h" +#include "rtp.h" + +#include +#include + +/* +The timestamp clock frequency is the same as the sampling frequency, so the +timestamp unit is in samples. + +The duration of one speech frame-block is 20 ms for both AMR and AMR-WB. For +AMR, the sampling frequency is 8 kHz, corresponding to 160 encoded speech +samples per frame from each channel. For AMR-WB, the sampling frequency is +16 kHz, corresponding to 320 samples per frame from each channel. Thus, the +timestamp is increased by 160 for AMR and 320 for AMR-WB for each consecutive +frame-block. + +QUESTION: Should we use 16kHz or 19351Hz? +ANSWER: The encoder and decoder respectively should use 19531Hz, the rest of +the system can assume 16kHz without loss of quality. + */ + +struct lrtp_profile_amrwb_t { + struct lrtp_profile_t profile; // 'Inherit' lrtp_profile_t + + int frame_type_index; +}; + +// Frame sizes based on frame type index: +static const int wb_frame_size[16] = { + 17, 23, 32, 36, 40, 46, 50, 58, + 60, 5, -1, -1, -1, -1, -1, 0 +}; + +/* + * 0 1 2 3 4 5 6 7 + * +-+-+-+-+-+-+-+-+ + * |F| FT |Q|P|P| + * +-+-+-+-+-+-+-+-+ + */ + +/* + * F (1 bit): If set to 1, indicates that this frame is followed by + * another speech frame in this payload; if set to 0, indicates that + * this frame is the last frame in this payload. + */ +static int is_last_frame(const char *frame_header) +{ + return ( (*frame_header >> 7) & 0x1 ) == 0; +} + +static void set_is_last_frame(char *frame_header, int last) +{ + last = 1 - last; // Invert 'last': 0 means last, 1 means more + *frame_header = (*frame_header & 0x7f) | ( (last & 0x1) << 7); +} + +/* + * FT (4 bits): Frame type index, indicating either the AMR or AMR-WB + * speech coding mode or comfort noise (SID) mode of the + * corresponding frame carried in this payload. + */ +static int frame_type_index(const char *frame_header) +{ + return (*frame_header >> 3) & 0xf; +} + +static int set_frame_type_index(char *frame_header, int index) +{ + *frame_header = (*frame_header & 0x87) | ( (index & 0xf) << 3); +} + +/* + * Q (1 bit): Frame quality indicator. If set to 0, indicates the + * corresponding frame is severely damaged and the receiver should + * set the RX_TYPE (see [6]) to either SPEECH_BAD or SID_BAD + * depending on the frame type (FT). + */ +static int quality_indicator(const char *frame_header) +{ + return (*frame_header >> 2) & 0x1; +} + +static int set_quality_indicator(char *frame_header, int quality) +{ + *frame_header = (*frame_header & 0xf8) | ( (quality & 0x1) << 2); +} + + +// http://tools.ietf.org/html/rfc3267#section-4.4 +int profile_amrwb_pack(struct lrtp_profile_t *profile, + const char *input, size_t inputsize, + RTP &rtp) +{ + // NOTE: This implementation does not support frame interleaving... + + struct lrtp_profile_amrwb_t *p = (struct lrtp_profile_amrwb_t *)profile; + + size_t frameheader_size = 1; + size_t cmr_size = 1; + + // Frame size based on frame_type_index, + size_t frame_size = wb_frame_size[p->frame_type_index]; + + // This is the maximum number of frames we have room for in a single RTP + // payload. + size_t max_num_frames = + (MAX_RTP_PAYLOAD_SIZE - cmr_size) / (frame_size + frameheader_size); + + size_t cpsz = inputsize; + + printf("cpsz: %d\n", cpsz); + + size_t num_frames = cpsz / frame_size; + + if(num_frames == 0) { + printf("Garbage at the end of the buffer\n"); + rtp.setValid(false); + return -1; + } + + if(num_frames > max_num_frames) num_frames = max_num_frames; + + char *payload = (char*)malloc(MAX_RTP_PAYLOAD_SIZE); + + /* 0 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +-+-+-+-+-+-+-+-+- - - - - - - - + * | CMR |R|R|R|R| ILL | ILP | + * +-+-+-+-+-+-+-+-+- - - - - - - - + */ + // If a terminal has no preference in which mode to receive, it SHOULD set + // CMR=15 in all its outbound payloads. + char *CMR = payload; + *CMR = 15; + + // The ILL and ILP fields are not used (see note above). + + char *frame_header = CMR + cmr_size; + for(size_t i = 0; i < num_frames; i++) { + // 0 if this is the last frame. + set_is_last_frame(frame_header, i == (num_frames - 1) ); + + // Frame type index (4 bits): + set_frame_type_index(frame_header, p->frame_type_index); + + // Frame quality indicator (1 bit): Set to 0 to indicate damaged frame. + set_quality_indicator(frame_header, 1); + + frame_header += frameheader_size; + } + + char *frame_data = frame_header; + + size_t payload_size = cmr_size; + const char *frame_offset = input; + for(size_t i = 0; i < num_frames; i++) { + memcpy(frame_data, frame_offset, frame_size); + frame_data += frame_size; + frame_offset += frame_size; + payload_size += frameheader_size + frame_size; + } + + //size_t payload_size = cmr_size + num_frames*(frame_size + frameheader_size); + rtp.setPayload(payload, payload_size); + rtp.setValid(true); + + printf("payload (pack):\n"); + for(int i = 0; i < payload_size; i++) { + printf("%02x ", (unsigned char)payload[i]); + } + printf("\n"); + + free(payload); + + return cpsz; +} + +int profile_amrwb_unpack(struct lrtp_profile_t *profile, + const RTP &rtp, + std::list &framelist) +{ + struct lrtp_profile_amrwb_t *p = (struct lrtp_profile_amrwb_t *)profile; + + size_t size = rtp.payloadSize(); + const char *payload = rtp.payloadData(); + + printf("---------------------------------------- New packet:\n"); + printf("payload (unpack):\n"); + for(int i = 0; i < size; i++) { + printf("%02x ", (unsigned char)payload[i]); + } + printf("\n"); + + // Read CMR: + size_t cmr_size = 1; + char CMR = payload[0]; + if(CMR != 15) { + printf("CMR not 15\n"); + return UNPACK_ERROR; + } + + // TODO: What to do if there are 0 frames (and therefore no header to set the + // 'last frame' bit in....) + + // Read ToC: + size_t frameheader_size = 1; + const char *frame_toc; + frame_toc = payload + cmr_size; + + size_t frame_num = 0; + const char *frame_data = frame_toc; + while(!is_last_frame(frame_data)) { + frame_num++; + frame_data += frameheader_size; + } + frame_num++; + frame_data += frameheader_size; + + while(frame_num) { + size_t frame_size_idx = frame_type_index(frame_toc); + size_t frame_size = wb_frame_size[frame_size_idx]; + + outputframe_t *of = new outputframe_t(); + of->size = frame_size; + char *buf = (char*)malloc(of->size); + memcpy(buf, frame_data, frame_size); + of->data = buf; + + framelist.push_back(of); + + if(is_last_frame(frame_toc)) return 0; + + frame_toc += frameheader_size; + frame_data += frame_size; + + frame_num--; + } + + printf("Error, missed the last_frame bit\n"); + + return 1; // Error, missed the last_frame bit +} + +void profile_amrwb_destroy(struct lrtp_profile_t *profile) +{ + struct lrtp_profile_amrwb_t *p = (struct lrtp_profile_amrwb_t *)profile; + delete p; +} + +struct lrtp_profile_t *profile_amrwb_create(struct lrtp_t *lrtp, + unsigned int csrc, + va_list vp) +{ + struct lrtp_profile_amrwb_t *p = new struct lrtp_profile_amrwb_t; + + p->profile.pack = profile_amrwb_pack; + p->profile.unpack = profile_amrwb_unpack; + p->profile.destroy = profile_amrwb_destroy; + + p->frame_type_index = 8; // Default: AMR-WB 23.85 kbit/s + + while(true) { + int type = va_arg(vp, int); + if(type == OPTION_END) break; + + switch(type) { + case OPTION_AMRWB_FRAME_TYPE_INDEX: + p->frame_type_index = va_arg(vp, int); + break; + default: + // TODO: Unknown arg type + break; + } + } + + return (struct lrtp_profile_t *)p; +} diff --git a/src/rtp_profile_amrwb.h b/src/rtp_profile_amrwb.h new file mode 100644 index 0000000..38b20c1 --- /dev/null +++ b/src/rtp_profile_amrwb.h @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * rtp_profile_amrwb.h + * + * Wed Oct 2 14:43:05 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 + */ +#ifndef __LRTP_RTP_PROFILE_AMRWB_H__ +#define __LRTP_RTP_PROFILE_AMRWB_H__ + +#include + +#include "lrtp.h" + +struct lrtp_profile_t *profile_amrwb_create(struct lrtp_t *lrtp, + unsigned int csrc, + va_list ap); + +#endif/*__LRTP_RTP_PROFILE_AMRWB_H__*/ diff --git a/src/rtp_profile_opus.cc b/src/rtp_profile_opus.cc new file mode 100644 index 0000000..102d175 --- /dev/null +++ b/src/rtp_profile_opus.cc @@ -0,0 +1,188 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * rtp_profile_opus.cc + * + * Tue Sep 10 13:53:24 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 + * + * Part of this code is an adaptation of the GStreamer RTP profile code for Celt + * by Wim Taymans + * The original code can be found in the gst-plugins-good package version 1.1.3: + * http://gstreamer.freedesktop.org/src/gst-plugins-good + */ +#include "rtp_profile_opus.h" + +/* + +--------------+----------------+-----------+----------+ + | Abbreviation | Name | Bandwidth | Sampling | + +--------------+----------------+-----------+----------+ + | nb | Narrowband | 0 - 4000 | 8000 | + | | | | | + | mb | Mediumband | 0 - 6000 | 12000 | + | | | | | + | wb | Wideband | 0 - 8000 | 16000 | + | | | | | + | swb | Super-wideband | 0 - 12000 | 24000 | + | | | | | + | fb | Fullband | 0 - 20000 | 48000 | + +--------------+----------------+-----------+----------+ + + Audio bandwidth naming + + Table 1 +*/ +/* +Recommended Bitrate + + For a frame size of 20 ms, these are the bitrate "sweet spots" for + Opus in various configurations: + o 8-12 kb/s for NB speech, + o 16-20 kb/s for WB speech, + o 28-40 kb/s for FB speech, + o 48-64 kb/s for FB mono music, and + o 64-128 kb/s for FB stereo music. +*/ + +/* +Forward Error Correction (FEC) + + The voice mode of Opus allows for "in-band" forward error correction + (FEC) data to be embedded into the bit stream of Opus. +*/ + +/* +RTP Header Usage + + The format of the RTP header is specified in [RFC3550]. The Opus + payload format uses the fields of the RTP header consistent with this + specification. + + The payload length of Opus is a multiple number of octets and + therefore no padding is required. The payload MAY be padded by an + integer number of octets according to [RFC3550]. + + The marker bit (M) of the RTP header is used in accordance with + Section 4.1 of [RFC3551]. + + The RTP payload type for Opus has not been assigned statically and is + expected to be assigned dynamically. + + The receiving side MUST be prepared to receive duplicates of RTP + packets. Only one of those payloads MUST be provided to the Opus + decoder for decoding and others MUST be discarded. + + Opus supports 5 different audio bandwidths which may be adjusted + during the duration of a call. The RTP timestamp clock frequency is + defined as the highest supported sampling frequency of Opus, i.e. + 48000 Hz, for all modes and sampling rates of Opus. The unit for the + timestamp is samples per single (mono) channel. The RTP timestamp + corresponds to the sample time of the first encoded sample in the + encoded frame. For sampling rates lower than 48000 Hz the number of + samples has to be multiplied with a multiplier according to Table 2 + to determine the RTP timestamp. + + +---------+------------+ + | fs (Hz) | Multiplier | + +---------+------------+ + | 8000 | 6 | + | | | + | 12000 | 4 | + | | | + | 16000 | 3 | + | | | + | 24000 | 2 | + | | | + | 48000 | 1 | + +---------+------------+ + + Table 2: Timestamp multiplier +*/ + +#include "rtp_profile.h" + +#include +#include + +struct lrtp_profile_opus_t { + struct lrtp_profile_t profile; // 'Inherit' lrtp_profile_t +}; + +int profile_opus_pack(struct lrtp_profile_t *profile, + const char *frame, size_t framesize, + RTP &rtp) +{ + //struct lrtp_profile_opus_t *p = (struct lrtp_profile_opus_t *)profile; + (void)profile; + + rtp.setPayload(frame, framesize); + rtp.setValid(true); + + return framesize; +} + +int profile_opus_unpack(struct lrtp_profile_t *profile, + const RTP &rtp, + std::list &framelist) +{ + struct lrtp_profile_opus_t *p = (struct lrtp_profile_opus_t *)profile; + + outputframe_t *of = new outputframe_t(); + of->size = rtp.payloadSize(); + char *buf = (char*)malloc(of->size); + of->size = rtp.payload(buf, of->size); + of->data = buf; + + framelist.push_back(of); + + return 0; +} + +void profile_opus_destroy(struct lrtp_profile_t *profile) +{ + struct lrtp_profile_opus_t *p = (struct lrtp_profile_opus_t *)profile; + delete p; +} + +struct lrtp_profile_t *profile_opus_create(struct lrtp_t *lrtp, + unsigned int csrc, + va_list vp) +{ + struct lrtp_profile_opus_t *p = new struct lrtp_profile_opus_t; + + p->profile.pack = profile_opus_pack; + p->profile.unpack = profile_opus_unpack; + p->profile.destroy = profile_opus_destroy; + + while(true) { + int type = va_arg(vp, int); + if(type == OPTION_END) break; + + switch(type) { + default: + // TODO: Unknown arg type + break; + } + } + + return &p->profile; +} diff --git a/src/rtp_profile_opus.h b/src/rtp_profile_opus.h new file mode 100644 index 0000000..23002d3 --- /dev/null +++ b/src/rtp_profile_opus.h @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * rtp_profile_opus.h + * + * Tue Sep 10 13:53:24 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 + */ +#ifndef __LRTP_RTP_PROFILE_OPUS_H__ +#define __LRTP_RTP_PROFILE_OPUS_H__ + +#include + +#include "lrtp.h" + +struct lrtp_profile_t *profile_opus_create(struct lrtp_t *lrtp, + unsigned int csrc, + va_list ap); + +#endif/*__LRTP_RTP_PROFILE_OPUS_H__*/ diff --git a/src/rtp_profile_raw.cc b/src/rtp_profile_raw.cc new file mode 100644 index 0000000..cf34186 --- /dev/null +++ b/src/rtp_profile_raw.cc @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * rtp_profile_raw.cc + * + * Mon Sep 2 14:30:56 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_profile_raw.h" + +#include "rtp_profile.h" + +#include +#include + +struct lrtp_profile_raw_t { + struct lrtp_profile_t profile; // 'Inherit' lrtp_profile_t + + unsigned short int pkg_size; + + // Cache + char *pkg_cache; + int pkg_cache_size; +}; + +int profile_raw_pack(struct lrtp_profile_t *profile, + const char *frame, size_t framesize, + RTP &rtp) +{ + struct lrtp_profile_raw_t *p = (struct lrtp_profile_raw_t *)profile; + + size_t cpsz = p->pkg_size - p->pkg_cache_size; + + if(cpsz > framesize) cpsz = framesize; + + if(cpsz != 0) { + memcpy(p->pkg_cache, frame, cpsz); + p->pkg_cache_size += cpsz; + } + + if(p->pkg_cache_size == p->pkg_size) { + rtp.setPayload(p->pkg_cache, p->pkg_cache_size); + p->pkg_cache_size = 0; + } + + return cpsz; +} + +int profile_raw_unpack(struct lrtp_profile_t *profile, + const RTP &rtp, + std::list &framelist) +{ + struct lrtp_profile_raw_t *p = (struct lrtp_profile_raw_t *)profile; + + outputframe_t *of = new outputframe_t(); + of->size = rtp.payloadSize(); + char *buf = (char*)malloc(of->size); + of->size = rtp.payload(buf, of->size); + of->data = buf; + + framelist.push_back(of); + + return 0; +} + +void profile_raw_destroy(struct lrtp_profile_t *profile) +{ + struct lrtp_profile_raw_t *p = (struct lrtp_profile_raw_t *)profile; + delete p->pkg_cache; + delete p; +} + +struct lrtp_profile_t *profile_raw_create(struct lrtp_t *lrtp, + unsigned int csrc, + va_list vp) +{ + struct lrtp_profile_raw_t *p = new struct lrtp_profile_raw_t; + + p->profile.pack = profile_raw_pack; + p->profile.unpack = profile_raw_unpack; + p->profile.destroy = profile_raw_destroy; + + p->pkg_size = 100; + + while(true) { + int type = va_arg(vp, int); + if(type == OPTION_END) break; + + switch(type) { + case OPTION_RAW_PKG_SIZE: + p->pkg_size = va_arg(vp, int); + break; + default: + // TODO: Unknown arg type + break; + } + } + + p->pkg_cache = new char[p->pkg_size]; + p->pkg_cache_size = 0; + + return &p->profile; +} + diff --git a/src/rtp_profile_raw.h b/src/rtp_profile_raw.h new file mode 100644 index 0000000..febae5d --- /dev/null +++ b/src/rtp_profile_raw.h @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * rtp_profile_raw.h + * + * Mon Sep 2 14:30:56 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 + */ +#ifndef __LRTP_RTP_PROFILE_RAW_H__ +#define __LRTP_RTP_PROFILE_RAW_H__ + +#include + +#include "lrtp.h" + +struct lrtp_profile_t *profile_raw_create(struct lrtp_t *lrtp, + unsigned int csrc, + va_list ap); + +#endif/*__LRTP_RTP_PROFILE_RAW_H__*/ diff --git a/src/srtp.cc b/src/srtp.cc new file mode 100644 index 0000000..98c4002 --- /dev/null +++ b/src/srtp.cc @@ -0,0 +1,230 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * srtp.cc + * + * Thu Sep 5 10:46:10 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 "srtp.h" + +#ifdef WIN32 +#include +#include +#include +#else +#include +#include +#include +#endif + +#include "asc2bin.h" + +struct SRTP::prv { + char *key; + size_t key_len; + + unsigned int ssrc; + + srtp_t session; + srtp_policy_t policy; +}; + +static bool is_initialised = false; + +SRTP::SRTP(std::string key, unsigned int ssrc) +{ + prv = NULL; + + err_status_t status; + + if(!is_initialised) { + status = srtp_init(); + if(status != err_status_ok) { + // TODO: Error handling + printf("srtp_init failed %d\n", status); + } + is_initialised = true; + } + + prv = new struct prv; + + prv->ssrc = ssrc; + + setupKey(key); + setupPolicy(true, true); + + status = srtp_create(&prv->session, &prv->policy); + if(status != err_status_ok) { + // TODO: Error handling + printf("srtp_create %d\n", status); + } + + status = srtp_add_stream(prv->session, &prv->policy); + if(status != err_status_ok) { + // TODO: Error handling + printf("srtp_add_stream %d\n", status); + } +} + +SRTP::~SRTP() +{ + err_status_t status = srtp_remove_stream(prv->session, htonl(prv->ssrc)); + if(status != err_status_ok) { + // TODO: Error handling + printf("srtp_remove_stream failed %d\n", status); + } + + status = srtp_dealloc(prv->session); + if(status != err_status_ok) { + // TODO: Error handling + printf("srtp_dealloc failed %d\n", status); + } + + status = srtp_shutdown(); + if(status != err_status_ok) { + // TODO: Error handling + printf("srtp_shutdown failed %d\n", status); + } + + is_initialised = false; + + if(prv) { + free(prv->key); + delete prv; + } +} + +void SRTP::setupKey(const std::string &key) +{ + prv->key = (char *)calloc(MASTER_KEY_LEN, 1); + prv->key_len = MASTER_KEY_LEN; + + if(key.length() > MASTER_KEY_LEN * 2) printf("KeyTooLong\n"); // TODO + + // Read key from hexadecimal on command line into an octet string + ssize_t len = asc2bin(prv->key, prv->key_len, key.c_str(), key.size()); + + if(len == -1) printf("InvalidHexKeyString\n"); // TODO + prv->key_len = len; + + // check that hex string is the right length. + if(len < MASTER_KEY_LEN) printf("KeyTooShort\n"); // TODO +} + +void SRTP::setupPolicy(bool confidentiality, bool authentication) +{ +#ifndef USE_CRYPTO + confidentiality = authentication = false; + printf("No crypto!\n") +#endif + + /* + * create policy structure, using the default mechanisms but + * with only the security services requested on the command line, + * using the right SSRC value + */ + if(confidentiality && authentication) { + crypto_policy_set_aes_cm_128_hmac_sha1_80(&prv->policy.rtp); + prv->policy.rtp.sec_serv = sec_serv_conf_and_auth; + } else if(confidentiality && !authentication) { + crypto_policy_set_aes_cm_128_null_auth(&prv->policy.rtp); + prv->policy.rtp.sec_serv = sec_serv_conf; + } else if(!confidentiality && authentication) { + crypto_policy_set_null_cipher_hmac_sha1_80(&prv->policy.rtp); + prv->policy.rtp.sec_serv = sec_serv_auth; + } else { + /* + * we're not providing security services, so set the policy to the + * null policy + * + * Note that this policy does not conform to the SRTP + * specification, since RTCP authentication is required. However, + * the effect of this policy is to turn off SRTP, so that this + * application is now a vanilla-flavored RTP application. + */ + prv->policy.rtp.cipher_type = NULL_CIPHER; + prv->policy.rtp.cipher_key_len = 0; + prv->policy.rtp.auth_type = NULL_AUTH; + prv->policy.rtp.auth_key_len = 0; + prv->policy.rtp.auth_tag_len = 0; + prv->policy.rtp.sec_serv = sec_serv_none; + } + + crypto_policy_set_rtcp_default(&prv->policy.rtcp); + prv->policy.rtcp.sec_serv = sec_serv_none; // No need for RTCP + + prv->policy.key = (uint8_t *)prv->key; + prv->policy.ssrc.type = ssrc_specific; + prv->policy.ssrc.value = prv->ssrc; + prv->policy.next = NULL; +} + +int SRTP::encrypt(char *packet, size_t size) +{ + int sz = size; + err_status_t status = srtp_protect(prv->session, packet, &sz); + if(status != err_status_ok) { + // TODO: throw SRTP::UnprotectException(); + printf("srtp_protect failed %d\n", status); + } + + return sz; +} + +int SRTP::decrypt(char *packet, size_t size) +{ + int sz = size; + err_status_t status = srtp_unprotect(prv->session, packet, &sz); + switch(status) { + case err_status_ok: + // No errors. + break; + case err_status_replay_fail: + // TODO: throw SRTP::ReplayException();// (replay check failed) + printf("srtp_unprotect failed replay %d\n", status); + break; + case err_status_replay_old: + // TODO: throw SRTP::ReplayOldException();// (replay check failed) + printf("srtp_unprotect failed replay_old %d\n", status); + break; + case err_status_auth_fail: + // TODO: throw SRTP::AuthCheckException();// (auth check failed) + printf("srtp_unprotect failed auth %d\n", status); + break; + default: + // TODO: throw SRTP::UnprotectException(); + printf("srtp_unprotect failed %d\n", status); + break; + } + + /* + if(octets_recvd - RTP_HEADER_LEN > (ssize_t)size) { + printf("BufferSize %d\n", status); + } + */ + + // TODO: rtp.fromBuffer(packet, size); + //memcpy(buf, prv->receiver->message.body, octets_recvd - RTP_HEADER_LEN); + + return sz; +} diff --git a/src/srtp.h b/src/srtp.h new file mode 100644 index 0000000..3d8b697 --- /dev/null +++ b/src/srtp.h @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * srtp.h + * + * Thu Sep 5 10:46:10 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 + */ +#ifndef __LRTP_SRTP_H__ +#define __LRTP_SRTP_H__ + +#include + +#include "rtp.h" + +#define MAX_KEY_LEN 64 +#define MASTER_KEY_LEN 30 + +class SRTP { +public: + SRTP(std::string key, unsigned int ssrc); + ~SRTP(); + + int encrypt(char *packet, size_t size); + int decrypt(char *packet, size_t size); + +private: + struct prv; + struct prv *prv; + + void setupKey(const std::string &key); + void setupPolicy(bool confidentiality, bool authentication); +}; + +#endif/*__LRTP_SRTP_H__*/ diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..49bcf0d --- /dev/null +++ b/test/Makefile @@ -0,0 +1,29 @@ +all: connectivity amrwb init rtp srtp opus raw + +connectivity: + g++ -g test_$@.cc -L../src/.libs -llrtp -I../src -o test_$@ + LD_LIBRARY_PATH=../src/.libs ./test_$@ + +amrwb: + g++ -g test_$@.cc -L../src/.libs -llrtp -lm -I../src -o test_$@ + LD_LIBRARY_PATH=../src/.libs ./test_$@ + +opus: + g++ -g test_$@.cc -L../src/.libs -llrtp -lm -I../src -lopus -lao -o test_$@ + LD_LIBRARY_PATH=../src/.libs ./test_$@ + +init: + g++ -g test_$@.cc -L../src/.libs -llrtp -I../src -o test_$@ + LD_LIBRARY_PATH=../src/.libs ./test_$@ + +raw: + g++ -g test_$@.cc -L../src/.libs -llrtp -I../src -o test_$@ + LD_LIBRARY_PATH=../src/.libs ./test_$@ + +rtp: + g++ -g test_$@.cc ../src/rtp.cc -o test_$@ + ./test_$@ + +srtp: + g++ -g -DUSE_CRYPTO test_$@.cc ../src/rtp.cc ../src/srtp.cc ../src/asc2bin.cc -lsrtp -o test_$@ + ./test_$@ diff --git a/test/test_amrwb.cc b/test/test_amrwb.cc new file mode 100644 index 0000000..cf5a5a6 --- /dev/null +++ b/test/test_amrwb.cc @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * test_init.cc + * + * Mon Sep 2 14:02:16 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 + +#include + +#include +#include + +#include +#include +#include +#include + +#define KEY "123456789012345678901234567890123456789012345678901234567890" +#define SSRC 1234567890 + +#define FS 8000 + +#define F1 440 +#define AF1 0.3 + +#define F2 500 +#define AF2 0.7 + +void dump(const char *title, const char *buf, size_t size) +{ + printf("%12s: ", title); + for(int i = 0; i < size; i++) { + if(i % 8 == 0) printf(" "); + printf("%02x ", (unsigned char)*buf++); + } + printf("\n"); +} + +// Frame sizes based on frame type index: +static const int wb_frame_size[16] = { + 17, 23, 32, 36, 40, 46, 50, 58, + 60, 5, -1, -1, -1, -1, -1, 0 +}; + +int main() +{ + std::vector packets; + unsigned int csrc = 42; + + int frame_type_index = 8; + + printf("========== Encode ==========\n"); + + { // Encode + struct lrtp_t *lrtp = lrtp_init(KEY, SSRC); + + struct lrtp_profile_t *profile = + lrtp_create_profile(lrtp, PROFILE_AMRWB, csrc, + OPTION_AMRWB_FRAME_TYPE_INDEX, frame_type_index, + OPTION_END); + + char packet[16*1024]; + size_t packetsize = sizeof(packet); + + int cnt = 0; + + for(int i = 0; i < 10; i++) { + + size_t num_frames = 10; + char frame[wb_frame_size[frame_type_index] * num_frames]; + size_t framesize = wb_frame_size[frame_type_index] * num_frames; + + for(int i = 0; i < framesize; i++) frame[i] = cnt++; + + int timestamp = 0; + + int ret = lrtp_enqueue_frame(profile, frame, framesize); + while( (ret = lrtp_pack(lrtp, packet, sizeof(packet))) != 0) { + std::string p; + p.append(packet, ret); + packets.push_back(p); + } + } + + lrtp_destroy_profile(lrtp, csrc); + lrtp_close(lrtp); + } + + printf("========== Decode ==========\n"); + + { // Decode + struct lrtp_t *lrtp = lrtp_init(KEY, SSRC); + + struct lrtp_profile_t *profile = + lrtp_create_profile(lrtp, PROFILE_AMRWB, csrc, + OPTION_AMRWB_FRAME_TYPE_INDEX, frame_type_index, + OPTION_END); + + char frame[16*1024]; + size_t framesize = sizeof(frame); + + int cnt = 0; + + std::vector::iterator i = packets.begin(); + while(i != packets.end()) { + size_t packetsize = i->size(); + printf("unpack sz: %d\n", packetsize); + const char *packet = i->data(); + unsigned int ts; + + framesize = sizeof(frame); + + lrtp_unpack(lrtp, packet, packetsize); + int ret; + while((ret = lrtp_dequeue_frame(lrtp, frame, framesize, &csrc, &ts)) != 0) { + printf("Got %d bytes, csrc %d, ts: %d\n", ret, csrc, ts); + + printf("cnt:\n"); + for(int i = 0; i < ret; i++) { + printf("%02x ", (unsigned char)frame[i]); + } + printf("\n"); + } + + i++; + } + + lrtp_destroy_profile(lrtp, csrc); + lrtp_close(lrtp); + } + + return 0; +} diff --git a/test/test_connectivity.cc b/test/test_connectivity.cc new file mode 100644 index 0000000..e115748 --- /dev/null +++ b/test/test_connectivity.cc @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * test_init.cc + * + * Mon Sep 2 14:02:16 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 + +#include + +#include +#include + +#define KEY "123456789012345678901234567890123456789012345678901234567890" +#define SSRC 1234567890 + +void dump(const char *title, const char *buf, size_t size) +{ + printf("%12s: ", title); + for(int i = 0; i < size; i++) { + if(i % 8 == 0) printf(" "); + printf("%02x ", (unsigned char)*buf++); + } + printf("\n"); +} + +int main() +{ + char frame[5]; + int pkg_size = 4; + + std::vector packets; + unsigned int csrc = 42; + + { // Encode + struct lrtp_t *lrtp = lrtp_init(KEY, SSRC); + + struct lrtp_profile_t *profile = + lrtp_create_profile(lrtp, PROFILE_RAW, csrc, + OPTION_RAW_PKG_SIZE, pkg_size, + OPTION_END); + + char packet[16*1024]; + size_t size = sizeof(packet); + + for(unsigned int ts = 0; ts < 8; ts++) { + int ret = 0; + ret = lrtp_enqueue_frame(profile, frame, sizeof(frame)); + while( (ret = lrtp_pack(lrtp, packet, sizeof(packet))) != 0) { + std::string p; + p.append(packet, ret); + packets.push_back(p); + dump("pkg", packet, ret); + } + } + + lrtp_destroy_profile(lrtp, csrc); + + lrtp_close(lrtp); + } + + { // Decode + struct lrtp_t *lrtp = lrtp_init(KEY, SSRC); + + struct lrtp_profile_t *profile = + lrtp_create_profile(lrtp, PROFILE_RAW, csrc, + OPTION_RAW_PKG_SIZE, pkg_size, + OPTION_END); + + char frame[16*1024]; + size_t framesize = sizeof(frame); + + int cnt = 0; + + std::vector::iterator i = packets.begin(); + while(i != packets.end()) { + size_t packetsize = i->size(); + printf("unpack sz: %d\n", packetsize); + const char *packet = i->data(); + unsigned int ts; + + framesize = sizeof(frame); + + lrtp_unpack(lrtp, packet, packetsize); + int ret; + while((ret = lrtp_dequeue_frame(lrtp, frame, framesize, &csrc, &ts)) + != 0) { + printf("Got %d bytes, csrc %d, ts: %d\n", ret, csrc, ts); + dump("pkg", frame, ret); + } + + i++; + } + + lrtp_destroy_profile(lrtp, csrc); + lrtp_close(lrtp); + } + + return 0; +} + diff --git a/test/test_init.cc b/test/test_init.cc new file mode 100644 index 0000000..97ecd30 --- /dev/null +++ b/test/test_init.cc @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * test_init.cc + * + * Mon Sep 2 14:02:16 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 + +#include + +#define KEY "123456789012345678901234567890123456789012345678901234567890" +#define SSRC 1234567890 + +void dump(const char *title, const char *buf, size_t size) +{ + printf("%12s: ", title); + for(int i = 0; i < size; i++) { + if(i % 8 == 0) printf(" "); + printf("%02x ", (unsigned char)*buf++); + } + printf("\n"); +} + +int main() +{ + char frame[] = "foo"; + + struct lrtp_t *lrtp = lrtp_init(KEY, SSRC); + + unsigned int csrc = 42; + struct lrtp_profile_t *profile = + lrtp_create_profile(lrtp, PROFILE_RAW, csrc, + OPTION_RAW_PKG_SIZE, sizeof(frame), + OPTION_END); + + lrtp_destroy_profile(lrtp, csrc); + + lrtp_close(lrtp); + + return 0; +} + diff --git a/test/test_opus.cc b/test/test_opus.cc new file mode 100644 index 0000000..68ea0f4 --- /dev/null +++ b/test/test_opus.cc @@ -0,0 +1,272 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * test_init.cc + * + * Mon Sep 2 14:02:16 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 + +#include + +#include +#include + +#include +#include +#include +#include + +#define KEY "123456789012345678901234567890123456789012345678901234567890" +#define SSRC 1234567890 + +#define FS 8000 + +#define F1 440 +#define AF1 0.3 + +#define F2 500 +#define AF2 0.7 + +void dump(const char *title, const char *buf, size_t size) +{ + printf("%12s: ", title); + for(int i = 0; i < size; i++) { + if(i % 8 == 0) printf(" "); + printf("%02x ", (unsigned char)*buf++); + } + printf("\n"); +} + +class Audio { +public: + Audio() { + ao_initialize(); + + device = NULL; + ao_sample_format format; + + int default_driver = ao_default_driver_id(); + if(default_driver == -1) { + printf("Error could not default driver.\n"); + return; + } + printf("Default driver: %d\n", default_driver); + + format.bits = 16; + format.channels = 2; + format.rate = FS; + format.byte_format = AO_FMT_LITTLE; + + device = ao_open_live(default_driver, &format, NULL); + if(device == NULL) { + printf("Error opening device.\n"); + return; + } + } + + ~Audio() { + if(device) ao_close(device); + ao_shutdown(); + } + + void play(char *pcm, size_t size) { + ao_play(device, pcm, size); + } + +private: + ao_device *device; +}; + +int main() +{ + size_t channels = 2; + size_t ms[] = { 120, 240, 480, 960, 1920, 2880 }; + + std::vector packets; + unsigned int csrc = 42; + + double sin_x = 0; + size_t ts = 0; + + printf("========== Encode ==========\n"); + + { // Encode + struct lrtp_t *lrtp = lrtp_init(KEY, SSRC); + + struct lrtp_profile_t *profile = + lrtp_create_profile(lrtp, PROFILE_OPUS, csrc, + //OPTION_RAW_PKG_SIZE, pkg_size, + OPTION_END); + + char packet[16*1024]; + size_t packetsize = sizeof(packet); + + int err; + OpusEncoder *opus = opus_encoder_create(FS, channels, + OPUS_APPLICATION_AUDIO, &err); + printf("Opus create err: %d\n", err); + + opus_encoder_ctl(opus, OPUS_SET_BITRATE(64000));// [500;512000] + opus_encoder_ctl(opus, OPUS_SET_COMPLEXITY(10)); // [0;10] + opus_encoder_ctl(opus, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); + + int cnt = 0; + size_t timestamp = 0; + for(unsigned int ts = 0; ts < 120; ts++) { + printf("packet #%d\n", ts); + + size_t idx = rand() % (sizeof(ms)/sizeof(size_t)); + printf("idx: %d\n", idx); + size_t pcmsize = ms[idx] / (48000.0 / FS); // Number of samples pr channel + short *pcm = new short[100000/*pcmsize * channels*/]; + for(int i = 0 ; i < pcmsize; i++) { + sin_x++; + + double amp1 = sin((2*M_PI/(double)FS)*(double)sin_x * AF1) * SHRT_MAX; + double amp2 = sin((2*M_PI/(double)FS)*(double)sin_x * AF2) * SHRT_MAX; + + pcm[i*2] = (short)(sin(2*M_PI/FS*(double)sin_x * F1) * amp1); + pcm[i*2+1] = (short)(sin(2*M_PI/FS*(double)sin_x * F2) * amp2); + } + + // Master timestamp is sample number in 48kHz (Opus RFC states this) + timestamp += pcmsize * 48000 / FS; + + // size_t pcmsize = pcmsize * channels * sizeof(short); + + char frame[pcmsize]; + int framesize = sizeof(frame); + framesize = opus_encode(opus, pcm, pcmsize, + (unsigned char*)frame, framesize); + + if(framesize < 0) { + printf("Opus error: %s\n", opus_strerror(framesize)); + } + + printf("Opus Packet: %d bytes from %d bytes\n", pcmsize, framesize); + + int ret = lrtp_enqueue_frame(profile, frame, framesize); + while( (ret = lrtp_pack(lrtp, packet, sizeof(packet))) != 0) { + std::string p; + p.append(packet, ret); + packets.push_back(p); + } + + delete[] pcm; + } + + opus_encoder_destroy(opus); + lrtp_destroy_profile(lrtp, csrc); + lrtp_close(lrtp); + } + + printf("========== Decode ==========\n"); + + { // Decode + struct lrtp_t *lrtp = lrtp_init(KEY, SSRC); + + struct lrtp_profile_t *profile = + lrtp_create_profile(lrtp, PROFILE_OPUS, csrc, + //OPTION_RAW_PKG_SIZE, pkg_size, + OPTION_END); + + int err; + OpusDecoder *opus = opus_decoder_create(FS, channels, &err); + printf("Opus create err: %d\n", err); + + int idx = (sizeof(ms)/sizeof(size_t)) - 1; + printf("idx: %d\n", idx); + + Audio audio; + + char frame[16*1024]; + + int cnt = 0; + std::vector::iterator i = packets.begin(); + while(i != packets.end()) { + size_t packetsize = i->size(); + const char *packet = i->data(); + unsigned int ts; + + printf("unpack sz: %d - %p\n", packetsize, packet); + + lrtp_unpack(lrtp, packet, packetsize); + int ret; + while((ret = lrtp_dequeue_frame(lrtp, frame, sizeof(frame), &csrc, &ts)) + != 0) { + size_t pcmsize = 16*1024;//ms[idx] / (48000 / FS); + short *pcm = new short[pcmsize * channels]; + printf("pcmsize %d\n", pcmsize); fflush(stdout); + int res = opus_decode(opus, (const unsigned char*)frame, ret, + pcm, pcmsize, 0); + + printf("Decompressed %d bytes\n", res); + // pcmsize = res * channels * sizeof(short); + + audio.play((char *)pcm, res * channels * sizeof(short)); + + delete[] pcm; + } + + i++; + } + + + /* + + std::vector::iterator i = packets.begin(); + while(i != packets.end()) { + size_t packetsize = i->size(); + printf("unpack sz: %d\n", packetsize); + const char *packet = i->data(); + unsigned int ts; + + framesize = sizeof(frame); + + lrtp_unpack(lrtp, packet, packetsize, frame, &framesize, &csrc, &ts); + printf("Got %d bytes, csrc %d, ts: %d\n", framesize, csrc, ts); + + size_t pcmsize = 16*1024;//ms[idx] / (48000 / FS); + short *pcm = new short[pcmsize * channels]; + printf("pcmsize %d\n", pcmsize); fflush(stdout); + int res = opus_decode(opus, (const unsigned char*)frame, framesize, + pcm, pcmsize, 0); + framesize = sizeof(frame); + + printf("Decompressed %d bytes\n", res); + // pcmsize = res * channels * sizeof(short); + + audio.play((char *)pcm, res * channels * sizeof(short)); + + delete[] pcm; + i++; + } + */ + opus_decoder_destroy(opus); + lrtp_destroy_profile(lrtp, csrc); + lrtp_close(lrtp); + } + + return 0; +} diff --git a/test/test_raw.cc b/test/test_raw.cc new file mode 100644 index 0000000..c3dcb71 --- /dev/null +++ b/test/test_raw.cc @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * test_raw.cc + * + * Mon Sep 2 14:02:16 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 + +#include + +#define KEY "123456789012345678901234567890123456789012345678901234567890" +#define SSRC 1234567890 + +void dump(const char *title, const char *buf, size_t size) +{ + printf("%12s: ", title); + for(int i = 0; i < size; i++) { + if(i % 8 == 0) printf(" "); + printf("%02x ", (unsigned char)*buf++); + } + printf("\n"); +} + +int main() +{ + const char frame[] = "foo"; + + struct lrtp_t *lrtp = lrtp_init(KEY, SSRC); + + unsigned int csrc = 42; + struct lrtp_profile_t *profile = + lrtp_create_profile(lrtp, PROFILE_RAW, csrc, + OPTION_RAW_PKG_SIZE, 4, + OPTION_END); + if(profile == NULL) { + printf("Could not create profile!\n"); + return 1; + } + + char packet[16*1024]; + size_t size = sizeof(packet); + + for(unsigned int ts = 0; ts < 8; ts++) { + int ret = 0; + ret = lrtp_enqueue_frame(profile, frame, sizeof(frame)); + while( (ret = lrtp_pack(lrtp, packet, sizeof(packet))) != 0) { + dump("pkg", packet, ret); + } + } + + lrtp_destroy_profile(lrtp, csrc); + + lrtp_close(lrtp); + + return 0; +} + diff --git a/test/test_rtp.cc b/test/test_rtp.cc new file mode 100644 index 0000000..b3ef80d --- /dev/null +++ b/test/test_rtp.cc @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * test_rtp.cc + * + * Mon Sep 2 14:02:16 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 "../src/rtp.h" + +#include + +void dump(RTP &rtp, const char *title) +{ + char buf[16 * 1024]; + + unsigned char *p = (unsigned char *)buf; + size_t s = rtp.packet(buf, sizeof(buf)); + + printf("%12s: ", title); + for(int i = 0; i < s; i++) { + if(i % 8 == 0) printf(" "); + printf("%02x ", *p++); + } + printf("\n"); +} + +int main() +{ + RTP rtp; + dump(rtp, "Clean"); + + rtp.setMarker(true); + dump(rtp, "mark"); + + char payload[] = { 0xff, 0xff, 0xff }; + rtp.setPayload(payload, sizeof(payload)); + dump(rtp, "Payload[6*f]"); + + rtp.setPadding(5); + dump(rtp, "Padding(5)"); + + rtp.setPadding(0); + dump(rtp, "Padding(0)"); + + rtp.setPadding(3); + dump(rtp, "Padding(3)"); + + rtp.setMarker(true); + dump(rtp, "mark"); + + rtp.setPayloadType(1); + dump(rtp, "pt(1)"); + + rtp.setPayloadType(0x7f); + dump(rtp, "pt(7f)"); + + rtp.setPayloadType(2); + dump(rtp, "pt(2)"); + + rtp.addCSrc(1); + dump(rtp, "CSrc[1]"); + + rtp.removeCSrc(1); + dump(rtp, "CSrc[-]"); + + rtp.addCSrc(2); + rtp.addCSrc(4); + dump(rtp, "CSrc[2,4]"); + + rtp.removeCSrc(2); + dump(rtp, "CSrc[2]"); + + rtp.setSeq(0x0102); + dump(rtp, "seq"); + + rtp.setTimestamp(0x03040506); + dump(rtp, "ts"); + + rtp.setSSrc(0x0708090a); + dump(rtp, "ssrc"); + + char buf[MAX_RTP_PACKET_SIZE]; + size_t sz = rtp.packet(buf, sizeof(buf)); + + RTP rtp2; + rtp2.fromPacket(buf, sz); + + dump(rtp2, "fromPacket"); + + return 0; +} + diff --git a/test/test_srtp.cc b/test/test_srtp.cc new file mode 100644 index 0000000..962c18f --- /dev/null +++ b/test/test_srtp.cc @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * test_srtp.cc + * + * Mon Sep 2 14:02:16 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 + +#include "../src/rtp.h" +#include "../src/srtp.h" + +#define KEY "123456789012345678901234567890123456789012345678901234567890" +#define SSRC 1234567890 + +void dump(const char *title, const char *buf, size_t size) +{ + printf("%12s: ", title); + for(int i = 0; i < size; i++) { + if(i % 8 == 0) printf(" "); + printf("%02x ", (unsigned char)*buf++); + } + printf("\n"); +} + +int main() +{ + RTP rtp; + rtp.setSSrc(SSRC); + + char payload[] = { 0xde, 0xad, 0xbe, 0xef }; + rtp.setPayload(payload, sizeof(payload)); + + char buf[MAX_RTP_PACKET_SIZE]; + size_t sz = rtp.packet(buf, sizeof(buf)); + + dump("Vanilla", buf, sz); + + { + SRTP srtp(KEY, rtp.SSrc()); + sz = srtp.encrypt(buf, sz); + } + + dump("Encrypted", buf, sz); + + { + SRTP srtp(KEY, rtp.SSrc()); + sz = srtp.decrypt(buf, sz); + } + + + dump("Decrypted", buf, sz); + + printf("Compare:\n"); + char buf0[MAX_RTP_PACKET_SIZE]; + size_t sz0 = rtp.packet(buf0, sizeof(buf0)); + if(sz0 != sz) printf("Sizes differ (%d %d)...\n", sz0, sz); + unsigned int sum = 0; + for(int i = 0; i < sz0; i++) { + sum += abs(buf0[i] - buf[i]); + } + if(sum) printf("NOT EQUAL! diff = %d\n", sum); + else printf("Vanilla == Decrypted\n"); + + return 0; +} + -- cgit v1.2.3