Commit 1401bc93 authored by Adrien Béraud's avatar Adrien Béraud
Browse files

SDP protocol support for Opus; using only one codec class for mono/stereo in Opus

parent 34e79486
......@@ -44,13 +44,6 @@ libcodec_opus_so_CXXFLAGS = -fPIC -g -Wall $(opus_CFLAGS)
libcodec_opus_so_LDFLAGS = --shared -lc -ldl -lstdc++ $(opus_LIBS)
libcodec_opus_so_LDADD = libcodecdescriptor.la
INSTALL_OPUS_RULE = install-libcodec_opus_so
OPUS_STEREO_LIB = libcodec_opus_stereo.so
libcodec_opus_stereo_so_SOURCES = opus_stereo.cpp opus_stereo.h
libcodec_opus_stereo_so_CXXFLAGS = -fPIC -g -Wall $(opus_CFLAGS)
libcodec_opus_stereo_so_LDFLAGS = --shared -lc -ldl -lstdc++ $(opus_LIBS)
libcodec_opus_stereo_so_LDADD = libcodecdescriptor.la
INSTALL_OPUS_STEREO_RULE = install-libcodec_opus_stereo_so
endif
if BUILD_ILBC
......@@ -63,7 +56,7 @@ libcodec_ilbc_so_LDADD = libcodecdescriptor.la
INSTALL_ILBC_RULE = install-libcodec_ilbc_so
endif
noinst_PROGRAMS = libcodec_ulaw.so libcodec_alaw.so libcodec_g722.so libcodec_g729.so $(OPUS_LIB) $(OPUS_STEREO_LIB) $(GSM_LIB) $(SPEEX_NB_LIB) $(SPEEX_WB_LIB) $(SPEEX_UB_LIB) $(ILBC_LIB)
noinst_PROGRAMS = libcodec_ulaw.so libcodec_alaw.so libcodec_g722.so libcodec_g729.so $(OPUS_LIB) $(GSM_LIB) $(SPEEX_NB_LIB) $(SPEEX_WB_LIB) $(SPEEX_UB_LIB) $(ILBC_LIB)
libcodec_ulaw_so_SOURCES = ulaw.cpp
libcodec_ulaw_so_CXXFLAGS = -fPIC -g -Wall
......@@ -85,8 +78,8 @@ libcodec_g729_so_CXXFLAGS = -fPIC -g -Wall
libcodec_g729_so_LDADD = libcodecdescriptor.la
libcodec_g729_so_LDFLAGS = --shared -lc -ldl -lstdc++
install-exec-local: install-libcodec_ulaw_so install-libcodec_alaw_so install-libcodec_g722_so install-libcodec_g729_so $(INSTALL_OPUS_RULE) $(INSTALL_OPUS_STEREO_RULE) $(INSTALL_GSM_RULE) $(INSTALL_SPEEX_NB_RULE) $(INSTALL_SPEEX_WB_RULE) $(INSTALL_SPEEX_UB_RULE) $(INSTALL_ILBC_RULE)
uninstall-local: uninstall-libcodec_ulaw_so uninstall-libcodec_alaw_so uninstall-libcodec_g722_so uninstall-libcodec_g729_so uninstall-libcodec_opus_so uninstall-libcodec_opus_stereo_so uninstall-libcodec_gsm_so uninstall-libcodec_speex_nb_so uninstall-libcodec_speex_wb_so uninstall-libcodec_speex_ub_so uninstall-libcodec_ilbc_so
install-exec-local: install-libcodec_ulaw_so install-libcodec_alaw_so install-libcodec_g722_so install-libcodec_g729_so $(INSTALL_OPUS_RULE) $(INSTALL_GSM_RULE) $(INSTALL_SPEEX_NB_RULE) $(INSTALL_SPEEX_WB_RULE) $(INSTALL_SPEEX_UB_RULE) $(INSTALL_ILBC_RULE)
uninstall-local: uninstall-libcodec_ulaw_so uninstall-libcodec_alaw_so uninstall-libcodec_g722_so uninstall-libcodec_g729_so uninstall-libcodec_opus_so uninstall-libcodec_gsm_so uninstall-libcodec_speex_nb_so uninstall-libcodec_speex_wb_so uninstall-libcodec_speex_ub_so uninstall-libcodec_ilbc_so
install-libcodec_ulaw_so: libcodec_ulaw.so
mkdir -p $(sflcodecdir)
......@@ -103,9 +96,6 @@ install-libcodec_g729_so: libcodec_g729.so
install-libcodec_opus_so: libcodec_opus.so
mkdir -p $(sflcodecdir)
$(INSTALL_PROGRAM) libcodec_opus.so $(sflcodecdir)
install-libcodec_opus_stereo_so: libcodec_opus_stereo.so
mkdir -p $(sflcodecdir)
$(INSTALL_PROGRAM) libcodec_opus_stereo.so $(sflcodecdir)
install-libcodec_gsm_so: libcodec_gsm.so
mkdir -p $(sflcodecdir)
$(INSTALL_PROGRAM) libcodec_gsm.so $(sflcodecdir)
......@@ -132,8 +122,6 @@ uninstall-libcodec_g729_so:
rm -f $(sflcodecdir)/libcodec_g729.so
uninstall-libcodec_opus_so:
rm -f $(sflcodecdir)/libcodec_opus.so
uninstall-libcodec_opus_stereo_so:
rm -f $(sflcodecdir)/libcodec_opus_stereo.so
uninstall-libcodec_gsm_so:
rm -f $(sflcodecdir)/libcodec_gsm.so
uninstall-libcodec_speex_nb_so:
......
......@@ -31,9 +31,8 @@
#include <stdexcept>
#include <iostream>
static const int Opus_PAYLOAD_TYPE = 104; // dynamic payload type, out of range of video (96-99)
Opus::Opus() : sfl::AudioCodec(Opus_PAYLOAD_TYPE, "Opus", CLOCK_RATE, FRAME_SIZE, CHANNELS),
Opus::Opus() : sfl::AudioCodec(payloadType, "Opus", CLOCK_RATE, FRAME_SIZE, CHANNELS),
encoder_(0),
decoder_(0)
{
......@@ -67,6 +66,43 @@ int Opus::encode(unsigned char *dst, short *src, size_t buffer_size)
return opus_encode(encoder_, src, FRAME_SIZE, dst, buffer_size * 2);
}
int Opus::decode(std::vector<std::vector<short> > *dst, unsigned char *buf, size_t buffer_size, size_t dst_offset /* = 0 */)
{
if(dst == NULL || buf == NULL || dst->size()<2) return 0;
interleaved_.resize(4*FRAME_SIZE);
//return decode(&(*((*dst)[0].begin()+dst_offset)), buf, buffer_size);
unsigned samples = opus_decode(decoder_, buf, buffer_size, interleaved_.data(), 2*FRAME_SIZE, 0);
std::vector<opus_int16>::iterator left_it = dst->at(0).begin()+dst_offset;
std::vector<opus_int16>::iterator right_it = dst->at(1).begin()+dst_offset;
std::vector<opus_int16>::iterator it = interleaved_.begin();
// hard-coded 2-channels as it is the stereo version
for(unsigned i=0; i<samples; i++) {
*left_it++ = *it++;
*right_it++ = *it++;
}
return samples;
}
int Opus::encode(unsigned char *dst, std::vector<std::vector<short> > *src, size_t buffer_size)
{
if(dst == NULL || src == NULL || src->size()<2) return 0;
const unsigned samples = src->at(0).size();
interleaved_.resize(2*samples);
std::vector<opus_int16>::iterator it = interleaved_.begin();
// hard-coded 2-channels as it is the stereo version
for(unsigned i=0; i<samples; i++) {
*it++ = src->at(0)[i];
*it++ = src->at(1)[i];
}
return opus_encode(encoder_, interleaved_.data(), FRAME_SIZE, dst, buffer_size * 2);
}
// cppcheck-suppress unusedFunction
extern "C" sfl::AudioCodec* AUDIO_CODEC_ENTRY()
{
......
......@@ -40,17 +40,26 @@ class Opus : public sfl::AudioCodec {
public:
Opus();
~Opus();
static const int payloadType = 104; // dynamic payload type, out of range of video (96-99)
private:
virtual int decode(short *dst, unsigned char *buf, size_t buffer_size);
virtual int encode(unsigned char *dst, short *src, size_t buffer_size);
//multichannel version
virtual int decode(std::vector<std::vector<short> > *dst, unsigned char *buf, size_t buffer_size, size_t dst_offset=0);
virtual int encode(unsigned char *dst, std::vector<std::vector<short> > *src, size_t buffer_size);
NON_COPYABLE(Opus);
//Attributes
OpusEncoder *encoder_;
OpusDecoder *decoder_;
std::vector<opus_int16> interleaved_;
static const int FRAME_SIZE = 160;
static const int CLOCK_RATE = 16000;
static const int CHANNELS = 1;
static const int CHANNELS = 2;
};
#endif
/*
* Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
* Author: Adrien Beraud <adrienberaud@gmail.com>
* Author: Emmanuel Lepage <emmanuel.lepage@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Additional permission under GNU GPL version 3 section 7:
*
* If you modify this program, or any covered work, by linking or
* combining it with the OpenSSL project's OpenSSL library (or a
* modified version of that library), containing parts covered by the
* terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
* grants you additional permission to convey the resulting work.
* Corresponding Source for a non-source form of such a combination
* shall include the source code for the parts of OpenSSL used as well
* as that of the covered work.
*/
#include "opus_stereo.h"
#include <stdexcept>
#include <iostream>
static const int OpusStereo_PAYLOAD_TYPE = 105; // dynamic payload type, out of range of video (96-99)
OpusStereo::OpusStereo() : sfl::AudioCodec(OpusStereo_PAYLOAD_TYPE, "Opus", CLOCK_RATE, FRAME_SIZE, CHANNELS),
encoder_(0),
decoder_(0),
interleaved_(FRAME_SIZE*CHANNELS)
{
hasDynamicPayload_ = true;
int err = 0;
encoder_ = opus_encoder_create(CLOCK_RATE, CHANNELS, OPUS_APPLICATION_VOIP, &err);
if (err)
throw std::runtime_error("opus: could not create encoder");
decoder_ = opus_decoder_create(CLOCK_RATE, CHANNELS, &err);
if (err)
throw std::runtime_error("opus: could not create decoder");
}
OpusStereo::~OpusStereo()
{
if (encoder_)
opus_encoder_destroy(encoder_);
if (decoder_)
opus_decoder_destroy(decoder_);
}
int OpusStereo::decode(short *dst, unsigned char *buf, size_t buffer_size)
{
return 0;
}
int OpusStereo::encode(unsigned char *dst, short *src, size_t buffer_size)
{
return 0;
}
int OpusStereo::decode(std::vector<std::vector<short> > *dst, unsigned char *buf, size_t buffer_size, size_t dst_offset /* = 0 */)
{
if(dst == NULL || buf == NULL || dst->size()<2) return 0;
interleaved_.resize(4*FRAME_SIZE);
//return decode(&(*((*dst)[0].begin()+dst_offset)), buf, buffer_size);
unsigned samples = opus_decode(decoder_, buf, buffer_size, interleaved_.data(), 2*FRAME_SIZE, 0);
std::vector<opus_int16>::iterator left_it = dst->at(0).begin()+dst_offset;
std::vector<opus_int16>::iterator right_it = dst->at(1).begin()+dst_offset;
std::vector<opus_int16>::iterator it = interleaved_.begin();
// hard-coded 2-channels as it is the stereo version
for(unsigned i=0; i<samples; i++) {
*left_it++ = *it++;
*right_it++ = *it++;
}
return samples;
}
int OpusStereo::encode(unsigned char *dst, std::vector<std::vector<short> > *src, size_t buffer_size)
{
if(dst == NULL || src == NULL || src->size()<2) return 0;
const unsigned samples = src->at(0).size();
interleaved_.resize(2*samples);
std::vector<opus_int16>::iterator it = interleaved_.begin();
// hard-coded 2-channels as it is the stereo version
for(unsigned i=0; i<samples; i++) {
*it++ = src->at(0)[i];
*it++ = src->at(1)[i];
}
return opus_encode(encoder_, interleaved_.data(), FRAME_SIZE, dst, buffer_size * 2);
}
// cppcheck-suppress unusedFunction
extern "C" sfl::AudioCodec* AUDIO_CODEC_ENTRY()
{
try {
return new OpusStereo;
} catch (const std::runtime_error &e) {
std::cerr << e.what() << std::endl;
return 0;
}
}
// cppcheck-suppress unusedFunction
extern "C" void destroy(sfl::AudioCodec* a)
{
delete a;
}
/*
* Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
* Author: Adrien Beraud <adrienberaud@gmail.com>
* Author: Emmanuel Lepage <emmanuel.lepage@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Additional permission under GNU GPL version 3 section 7:
*
* If you modify this program, or any covered work, by linking or
* combining it with the OpenSSL project's OpenSSL library (or a
* modified version of that library), containing parts covered by the
* terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
* grants you additional permission to convey the resulting work.
* Corresponding Source for a non-source form of such a combination
* shall include the source code for the parts of OpenSSL used as well
* as that of the covered work.
*/
#ifndef OPUS_H_
#define OPUS_H_
#include "noncopyable.h"
#include "audiocodec.h"
#include <opus/opus.h>
class OpusStereo : public sfl::AudioCodec {
public:
OpusStereo();
~OpusStereo();
private:
virtual int decode(short *dst, unsigned char *buf, size_t buffer_size);
virtual int encode(unsigned char *dst, short *src, size_t buffer_size);
//multichannel version
virtual int decode(std::vector<std::vector<short> > *dst, unsigned char *buf, size_t buffer_size, size_t dst_offset=0);
virtual int encode(unsigned char *dst, std::vector<std::vector<short> > *src, size_t buffer_size);
NON_COPYABLE(OpusStereo);
//Attributes
OpusEncoder *encoder_;
OpusDecoder *decoder_;
std::vector<opus_int16> interleaved_;
static const int FRAME_SIZE = 160;
static const int CLOCK_RATE = 16000;
static const int CHANNELS = 2;
};
#endif
......@@ -40,6 +40,10 @@
#include <algorithm>
#ifdef HAVE_OPUS
#include "audio/codecs/opus.h"
#endif
#ifdef SFL_VIDEO
#include "video/libav_utils.h"
#endif
......@@ -216,12 +220,14 @@ Sdp::setMediaDescriptorLines(bool audio)
unsigned clock_rate;
string enc_name;
int payload;
unsigned channels;
if (audio) {
sfl::AudioCodec *codec = audio_codec_list_[i];
payload = codec->getPayloadType();
enc_name = codec->getMimeSubtype();
clock_rate = codec->getClockRate();
channels = codec->getChannels();
// G722 require G722/8000 media description even if it is 16000 codec
if (codec->getPayloadType () == 9)
clock_rate = 8000;
......@@ -245,13 +251,34 @@ Sdp::setMediaDescriptorLines(bool audio)
rtpmap.pt = med->desc.fmt[i];
rtpmap.enc_name = pj_str((char*) enc_name.c_str());
rtpmap.clock_rate = clock_rate;
rtpmap.param.ptr = ((char* const)"");
rtpmap.param.slen = 0;
#ifdef HAVE_OPUS
// Opus sample rate is allways declared as 48000 and channel num is allways 2 in rtpmap as per
// http://tools.ietf.org/html/draft-spittka-payload-rtp-opus-03#section-6.2
if(payload == Opus::payloadType) {
rtpmap.clock_rate = 48000;
rtpmap.param.ptr = ((char* const)"2");
rtpmap.param.slen = 1;
} else
#endif
{
rtpmap.param.ptr = ((char* const)"");
rtpmap.param.slen = 0;
}
pjmedia_sdp_attr *attr;
pjmedia_sdp_rtpmap_to_attr(memPool_, &rtpmap, &attr);
med->attr[med->attr_count++] = attr;
#ifdef HAVE_OPUS
// Declare stereo support for opus
if(payload == Opus::payloadType) {
std::ostringstream os;
os << "fmtp:" << dynamic_payload << " stereo=1; sprop-stereo=" << (channels>1 ? 1 : 0);
med->attr[med->attr_count++] = pjmedia_sdp_attr_create(memPool_, os.str().c_str(), NULL);
}
#endif
#ifdef SFL_VIDEO
if (enc_name == "H264") {
std::ostringstream os;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment