aboutsummaryrefslogtreecommitdiff
path: root/src/base/QXmppCodec.cpp
diff options
context:
space:
mode:
authorGonzalo Exequiel Pedone <hipersayan.x@gmail.com>2014-11-26 19:44:50 -0300
committerGonzalo Exequiel Pedone <hipersayan.x@gmail.com>2014-11-26 19:44:50 -0300
commit6f5d29ac16ada8ba290f9278211ea9ab96850d36 (patch)
tree9e250bcc435c7f548a14fd2e1afe500cc930e48c /src/base/QXmppCodec.cpp
parentdf9a166a0f1657ebe8e529de692ba20558f23f13 (diff)
downloadqxmpp-6f5d29ac16ada8ba290f9278211ea9ab96850d36.tar.gz
Added Opus codec.
Diffstat (limited to 'src/base/QXmppCodec.cpp')
-rw-r--r--src/base/QXmppCodec.cpp124
1 files changed, 124 insertions, 0 deletions
diff --git a/src/base/QXmppCodec.cpp b/src/base/QXmppCodec.cpp
index 2a2c6c1a..9cd520c6 100644
--- a/src/base/QXmppCodec.cpp
+++ b/src/base/QXmppCodec.cpp
@@ -38,6 +38,10 @@
#include <speex/speex.h>
#endif
+#ifdef QXMPP_USE_OPUS
+#include <opus/opus.h>
+#endif
+
#ifdef QXMPP_USE_THEORA
#include <theora/theoradec.h>
#include <theora/theoraenc.h>
@@ -386,6 +390,126 @@ qint64 QXmppSpeexCodec::decode(QDataStream &input, QDataStream &output)
#endif
+#ifdef QXMPP_USE_OPUS
+QXmppOpusCodec::QXmppOpusCodec(int clockrate, int channels):
+ sampleRate(clockrate),
+ nChannels(channels)
+{
+ // https://tools.ietf.org/html/draft-ietf-payload-rtp-opus-04
+
+ int error;
+ encoder = opus_encoder_create(clockrate, channels, OPUS_APPLICATION_VOIP, &error);
+
+ if (encoder || error == OPUS_OK) {
+ opus_encoder_ctl(encoder, OPUS_SET_INBAND_FEC(1));
+ opus_encoder_ctl(encoder, OPUS_SET_PACKET_LOSS_PERC(20));
+ opus_encoder_ctl(encoder, OPUS_SET_DTX(1));
+ opus_encoder_ctl(encoder, OPUS_SET_PREDICTION_DISABLED(1));
+ }
+ else
+ qCritical() << "Opus encoder initialization error:" << opus_strerror(error);
+
+ decoder = opus_decoder_create(clockrate, channels, &error);
+
+ if (!encoder || error != OPUS_OK)
+ qCritical() << "Opus decoder initialization error:" << opus_strerror(error);
+
+ validFrameSize << 2.5e-3 << 5e-3 << 10e-3 << 20e-3 << 40e-3 << 60e-3;
+
+ for (int i = 0; i < validFrameSize.size(); i++)
+ validFrameSize[i] *= clockrate;
+
+ nSamples = validFrameSize.last();
+}
+
+QXmppOpusCodec::~QXmppOpusCodec()
+{
+ if (encoder) {
+ opus_encoder_destroy(encoder);
+ encoder = NULL;
+ }
+
+ if (decoder) {
+ opus_decoder_destroy(decoder);
+ decoder = NULL;
+ }
+}
+
+qint64 QXmppOpusCodec::encode(QDataStream &input, QDataStream &output)
+{
+ QByteArray pcm_buffer(input.device()->bytesAvailable(), 0);
+ int length = input.readRawData(pcm_buffer.data(), pcm_buffer.size());
+ sampleBuffer.append(pcm_buffer.left(length));
+ int samples = readWindow(sampleBuffer.size());
+
+ if (samples < 1)
+ return 0;
+
+ QByteArray opus_buffer(sampleBuffer.size(), 0);
+
+ length = opus_encode(encoder,
+ (opus_int16 *) sampleBuffer.constData(),
+ samples,
+ (uchar *) opus_buffer.data(),
+ opus_buffer.size());
+
+ if (length < 1)
+ qWarning() << "Opus encoding error:" << opus_strerror(length);
+ else
+ output.writeRawData(opus_buffer.constData(), length);
+
+ sampleBuffer.remove(0, samples * nChannels * 2);
+
+ if (length < 1)
+ return 0;
+
+ return samples;
+}
+
+qint64 QXmppOpusCodec::decode(QDataStream &input, QDataStream &output)
+{
+ QByteArray opus_buffer(input.device()->bytesAvailable(), 0);
+ int length = input.readRawData(opus_buffer.data(), opus_buffer.size());
+
+ if (length < 1)
+ return 0;
+
+ QByteArray pcm_buffer(nSamples * nChannels * 2, 0);
+
+ int samples = opus_decode(decoder,
+ (uchar *) opus_buffer.constData(),
+ length,
+ (opus_int16 *) pcm_buffer.data(),
+ pcm_buffer.size(),
+ 0);
+
+ if (samples < 1) {
+ qWarning() << "Opus decoding error:" << opus_strerror(samples);
+
+ return 0;
+ }
+
+ output.writeRawData(pcm_buffer.constData(), samples * nChannels * 2);
+
+ return samples;
+}
+
+int QXmppOpusCodec::readWindow(int bufferSize)
+{
+ // WARNING: We are expecting 2 bytes signed samples, but this is wrong since
+ // input stream can have a different sample formats.
+
+ int nFrames = bufferSize / nChannels / 2;
+
+ for (int i = validFrameSize.size() - 1; i >= 0; i--)
+ if (validFrameSize[i] <= nFrames)
+ return validFrameSize[i];
+
+ return 0;
+}
+
+#endif
+
#ifdef QXMPP_USE_THEORA
class QXmppTheoraDecoderPrivate