diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 19 | ||||
| -rw-r--r-- | src/asc2bin.cc | 64 | ||||
| -rw-r--r-- | src/asc2bin.h | 50 | ||||
| -rw-r--r-- | src/compat.h | 37 | ||||
| -rw-r--r-- | src/lrtp.cc | 273 | ||||
| -rw-r--r-- | src/lrtp.h | 104 | ||||
| -rw-r--r-- | src/lrtp_profiles.h | 72 | ||||
| -rw-r--r-- | src/rtp.cc | 262 | ||||
| -rw-r--r-- | src/rtp.h | 116 | ||||
| -rw-r--r-- | src/rtp_profile.h | 86 | ||||
| -rw-r--r-- | src/rtp_profile_amrwb.cc | 307 | ||||
| -rw-r--r-- | src/rtp_profile_amrwb.h | 39 | ||||
| -rw-r--r-- | src/rtp_profile_opus.cc | 188 | ||||
| -rw-r--r-- | src/rtp_profile_opus.h | 39 | ||||
| -rw-r--r-- | src/rtp_profile_raw.cc | 123 | ||||
| -rw-r--r-- | src/rtp_profile_raw.h | 39 | ||||
| -rw-r--r-- | src/srtp.cc | 230 | ||||
| -rw-r--r-- | src/srtp.h | 54 | 
18 files changed, 2086 insertions, 16 deletions
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 <stdlib.h> + +#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 <string> +#include <string.h> +#include <map> +#include <stdio.h> -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<csrc_t, lrtp_profile_t *> 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<outputframe_t *> 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<csrc_t> 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<outputframe_t*> framelist; +  int ret = profile->unpack(profile, rtp, framelist); +  lrtp->framelist.splice(lrtp->framelist.end(), framelist); + +  return ret; +} + +#ifdef __cplusplus +} +#endif @@ -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 <stdlib.h> + +#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 <string.h> +#include <arpa/inet.h> +#include <stdio.h> + +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<csrc_t> 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<csrc_t>::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 <stdlib.h> +#include <stdint.h> +#include <list> + +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<csrc_t> 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<csrc_t> 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 <stdint.h> +#include <list> + +#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<inputframe_t *> 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<outputframe_t *> &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 <stdio.h> +#include <string.h> + +/* +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<outputframe_t *> &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 <stdarg.h> + +#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 <wim.taymans@gmail.com> + * 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 <stdio.h> +#include <string.h> + +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<outputframe_t *> &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 <stdarg.h> + +#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 <stdio.h> +#include <string.h> + +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<outputframe_t *> &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 <stdarg.h> + +#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 <srtp/crypto/include/datatypes.h> +#include <srtp/include/srtp.h> +#include <srtp/include/rtp_priv.h> +#else +#include <srtp/datatypes.h> +#include <srtp/srtp.h> +#include <srtp/rtp_priv.h> +#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 <string> + +#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__*/  | 
