aboutsummaryrefslogtreecommitdiff
path: root/src/base
diff options
context:
space:
mode:
authorNiels Ole Salscheider <niels_ole@salscheider-online.de>2019-05-17 14:30:02 -0700
committerLNJ <lnj@kaidan.im>2020-03-16 22:22:59 +0100
commit90036fc2cf5918c028f043edff7f5d38d1efb4cc (patch)
tree4818d8c4e6ec3778e2dd8a2e356faf1b9e062902 /src/base
parentc67ccc6d939b8f1efd118f92baea997fe1b7f1a6 (diff)
downloadqxmpp-90036fc2cf5918c028f043edff7f5d38d1efb4cc.tar.gz
Port QXmppCallManager to use GStreamer
Diffstat (limited to 'src/base')
-rw-r--r--src/base/QXmppCodec.cpp1433
-rw-r--r--src/base/QXmppCodec_p.h243
-rw-r--r--src/base/QXmppRtcpPacket.cpp660
-rw-r--r--src/base/QXmppRtcpPacket.h169
-rw-r--r--src/base/QXmppRtpChannel.cpp999
-rw-r--r--src/base/QXmppRtpChannel.h304
-rw-r--r--src/base/QXmppRtpPacket.cpp224
-rw-r--r--src/base/QXmppRtpPacket.h75
8 files changed, 0 insertions, 4107 deletions
diff --git a/src/base/QXmppCodec.cpp b/src/base/QXmppCodec.cpp
deleted file mode 100644
index d6396bee..00000000
--- a/src/base/QXmppCodec.cpp
+++ /dev/null
@@ -1,1433 +0,0 @@
-/*
- * Copyright (C) 2008-2020 The QXmpp developers
- *
- * Author:
- * Jeremy Lainé
- *
- * Source:
- * https://github.com/qxmpp-project/qxmpp
- *
- * This file is a part of QXmpp library.
- *
- * This library 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.
- *
- * This library 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.
- *
- */
-
-/*
- * G.711 based on reference implementation by Sun Microsystems, Inc.
- */
-
-#include "QXmppCodec_p.h"
-#include "QXmppRtpChannel.h"
-#include "QXmppRtpPacket.h"
-
-#include <cstring>
-
-#include <QDataStream>
-#include <QDebug>
-#include <QSize>
-#include <QThread>
-
-#ifdef QXMPP_USE_SPEEX
-#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>
-#endif
-
-#ifdef QXMPP_USE_VPX
-#define VPX_CODEC_DISABLE_COMPAT 1
-#include <vpx/vp8cx.h>
-#include <vpx/vp8dx.h>
-#include <vpx/vpx_decoder.h>
-#include <vpx/vpx_encoder.h>
-#endif
-
-#define BIAS (0x84) /* Bias for linear code. */
-#define CLIP 8159
-
-#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */
-#define QUANT_MASK (0xf) /* Quantization field mask. */
-#define NSEGS (8) /* Number of A-law segments. */
-#define SEG_SHIFT (4) /* Left shift for segment number. */
-#define SEG_MASK (0x70) /* Segment field mask. */
-
-// Distance (in frames) between two key frames (video only).
-#define GOPSIZE 32
-
-enum FragmentType {
- NoFragment = 0,
- StartFragment,
- MiddleFragment,
- EndFragment
-};
-
-static qint16 seg_aend[8] = { 0x1F, 0x3F, 0x7F, 0xFF,
- 0x1FF, 0x3FF, 0x7FF, 0xFFF };
-static qint16 seg_uend[8] = { 0x3F, 0x7F, 0xFF, 0x1FF,
- 0x3FF, 0x7FF, 0xFFF, 0x1FFF };
-
-static qint16 search(qint16 val, qint16 *table, qint16 size)
-{
- qint16 i;
-
- for (i = 0; i < size; i++) {
- if (val <= *table++)
- return (i);
- }
- return (size);
-}
-
-/*
- * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
- *
- * Accepts a 16-bit integer and encodes it as A-law data.
- *
- * Linear Input Code Compressed Code
- * ------------------------ ---------------
- * 0000000wxyza 000wxyz
- * 0000001wxyza 001wxyz
- * 000001wxyzab 010wxyz
- * 00001wxyzabc 011wxyz
- * 0001wxyzabcd 100wxyz
- * 001wxyzabcde 101wxyz
- * 01wxyzabcdef 110wxyz
- * 1wxyzabcdefg 111wxyz
- *
- * For further information see John C. Bellamy's Digital Telephony, 1982,
- * John Wiley & Sons, pps 98-111 and 472-476.
- */
-static quint8 linear2alaw(qint16 pcm_val)
-{
- qint16 mask;
- qint16 seg;
- quint8 aval;
-
- pcm_val = pcm_val >> 3;
-
- if (pcm_val >= 0) {
- mask = 0xD5; /* sign (7th) bit = 1 */
- } else {
- mask = 0x55; /* sign bit = 0 */
- pcm_val = -pcm_val - 1;
- }
-
- /* Convert the scaled magnitude to segment number. */
- seg = search(pcm_val, seg_aend, 8);
-
- /* Combine the sign, segment, and quantization bits. */
-
- if (seg >= 8) /* out of range, return maximum value. */
- return (quint8)(0x7F ^ mask);
- else {
- aval = (quint8)seg << SEG_SHIFT;
- if (seg < 2)
- aval |= (pcm_val >> 1) & QUANT_MASK;
- else
- aval |= (pcm_val >> seg) & QUANT_MASK;
- return (aval ^ mask);
- }
-}
-
-/*
- * alaw2linear() - Convert an A-law value to 16-bit linear PCM
- *
- */
-static qint16 alaw2linear(quint8 a_val)
-{
- qint16 t;
- qint16 seg;
-
- a_val ^= 0x55;
-
- t = (a_val & QUANT_MASK) << 4;
- seg = ((qint16)a_val & SEG_MASK) >> SEG_SHIFT;
- switch (seg) {
- case 0:
- t += 8;
- break;
- case 1:
- t += 0x108;
- break;
- default:
- t += 0x108;
- t <<= seg - 1;
- }
- return ((a_val & SIGN_BIT) ? t : -t);
-}
-
-/*
- * linear2ulaw() - Convert a linear PCM value to u-law
- *
- * In order to simplify the encoding process, the original linear magnitude
- * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
- * (33 - 8191). The result can be seen in the following encoding table:
- *
- * Biased Linear Input Code Compressed Code
- * ------------------------ ---------------
- * 00000001wxyza 000wxyz
- * 0000001wxyzab 001wxyz
- * 000001wxyzabc 010wxyz
- * 00001wxyzabcd 011wxyz
- * 0001wxyzabcde 100wxyz
- * 001wxyzabcdef 101wxyz
- * 01wxyzabcdefg 110wxyz
- * 1wxyzabcdefgh 111wxyz
- *
- * Each biased linear code has a leading 1 which identifies the segment
- * number. The value of the segment number is equal to 7 minus the number
- * of leading 0's. The quantization interval is directly available as the
- * four bits wxyz. * The trailing bits (a - h) are ignored.
- *
- * Ordinarily the complement of the resulting code word is used for
- * transmission, and so the code word is complemented before it is returned.
- *
- * For further information see John C. Bellamy's Digital Telephony, 1982,
- * John Wiley & Sons, pps 98-111 and 472-476.
- */
-static quint8 linear2ulaw(qint16 pcm_val)
-{
- qint16 mask;
- qint16 seg;
- quint8 uval;
-
- /* Get the sign and the magnitude of the value. */
- pcm_val = pcm_val >> 2;
- if (pcm_val < 0) {
- pcm_val = -pcm_val;
- mask = 0x7F;
- } else {
- mask = 0xFF;
- }
- if (pcm_val > CLIP)
- pcm_val = CLIP; /* clip the magnitude */
- pcm_val += (BIAS >> 2);
-
- /* Convert the scaled magnitude to segment number. */
- seg = search(pcm_val, seg_uend, 8);
-
- /*
- * Combine the sign, segment, quantization bits;
- * and complement the code word.
- */
- if (seg >= 8) /* out of range, return maximum value. */
- return (quint8)(0x7F ^ mask);
- else {
- uval = (quint8)(seg << 4) | ((pcm_val >> (seg + 1)) & 0xF);
- return (uval ^ mask);
- }
-}
-
-/*
- * ulaw2linear() - Convert a u-law value to 16-bit linear PCM
- *
- * First, a biased linear code is derived from the code word. An unbiased
- * output can then be obtained by subtracting 33 from the biased code.
- *
- * Note that this function expects to be passed the complement of the
- * original code word. This is in keeping with ISDN conventions.
- */
-static qint16 ulaw2linear(quint8 u_val)
-{
- qint16 t;
-
- /* Complement to obtain normal u-law value. */
- u_val = ~u_val;
-
- /*
- * Extract and bias the quantization bits. Then
- * shift up by the segment number and subtract out the bias.
- */
- t = ((u_val & QUANT_MASK) << 3) + BIAS;
- t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
-
- return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
-}
-
-QXmppCodec::~QXmppCodec()
-{
-}
-
-QXmppVideoDecoder::~QXmppVideoDecoder()
-{
-}
-
-QXmppVideoEncoder::~QXmppVideoEncoder()
-{
-}
-
-QXmppG711aCodec::QXmppG711aCodec(int clockrate)
-{
- m_frequency = clockrate;
-}
-
-qint64 QXmppG711aCodec::encode(QDataStream &input, QDataStream &output)
-{
- qint64 samples = 0;
- qint16 pcm;
- while (!input.atEnd()) {
- input >> pcm;
- output << linear2alaw(pcm);
- ++samples;
- }
- return samples;
-}
-
-qint64 QXmppG711aCodec::decode(QDataStream &input, QDataStream &output)
-{
- qint64 samples = 0;
- quint8 g711;
- while (!input.atEnd()) {
- input >> g711;
- output << alaw2linear(g711);
- ++samples;
- }
- return samples;
-}
-
-QXmppG711uCodec::QXmppG711uCodec(int clockrate)
-{
- m_frequency = clockrate;
-}
-
-qint64 QXmppG711uCodec::encode(QDataStream &input, QDataStream &output)
-{
- qint64 samples = 0;
- qint16 pcm;
- while (!input.atEnd()) {
- input >> pcm;
- output << linear2ulaw(pcm);
- ++samples;
- }
- return samples;
-}
-
-qint64 QXmppG711uCodec::decode(QDataStream &input, QDataStream &output)
-{
- qint64 samples = 0;
- quint8 g711;
- while (!input.atEnd()) {
- input >> g711;
- output << ulaw2linear(g711);
- ++samples;
- }
- return samples;
-}
-
-#ifdef QXMPP_USE_SPEEX
-QXmppSpeexCodec::QXmppSpeexCodec(int clockrate)
-{
- const SpeexMode *mode = &speex_nb_mode;
- if (clockrate == 32000)
- mode = &speex_uwb_mode;
- else if (clockrate == 16000)
- mode = &speex_wb_mode;
- else if (clockrate == 8000)
- mode = &speex_nb_mode;
- else
- qWarning() << "QXmppSpeexCodec got invalid clockrate" << clockrate;
-
- // encoder
- encoder_bits = new SpeexBits;
- speex_bits_init(encoder_bits);
- encoder_state = speex_encoder_init(mode);
-
- // decoder
- decoder_bits = new SpeexBits;
- speex_bits_init(decoder_bits);
- decoder_state = speex_decoder_init(mode);
-
- // get frame size in samples
- speex_encoder_ctl(encoder_state, SPEEX_GET_FRAME_SIZE, &frame_samples);
-}
-
-QXmppSpeexCodec::~QXmppSpeexCodec()
-{
- delete encoder_bits;
- delete decoder_bits;
-}
-
-qint64 QXmppSpeexCodec::encode(QDataStream &input, QDataStream &output)
-{
- QByteArray pcm_buffer(frame_samples * 2, 0);
- const int length = input.readRawData(pcm_buffer.data(), pcm_buffer.size());
- if (length != pcm_buffer.size()) {
- qWarning() << "Read only read" << length << "bytes";
- return 0;
- }
- speex_bits_reset(encoder_bits);
- speex_encode_int(encoder_state, (short *)pcm_buffer.data(), encoder_bits);
- QByteArray speex_buffer(speex_bits_nbytes(encoder_bits), 0);
- speex_bits_write(encoder_bits, speex_buffer.data(), speex_buffer.size());
- output.writeRawData(speex_buffer.data(), speex_buffer.size());
- return frame_samples;
-}
-
-qint64 QXmppSpeexCodec::decode(QDataStream &input, QDataStream &output)
-{
- const int length = input.device()->bytesAvailable();
- QByteArray speex_buffer(length, 0);
- input.readRawData(speex_buffer.data(), speex_buffer.size());
- speex_bits_read_from(decoder_bits, speex_buffer.data(), speex_buffer.size());
- QByteArray pcm_buffer(frame_samples * 2, 0);
- speex_decode_int(decoder_state, decoder_bits, (short *)pcm_buffer.data());
- output.writeRawData(pcm_buffer.data(), pcm_buffer.size());
- return frame_samples;
-}
-
-#endif
-
-#ifdef QXMPP_USE_OPUS
-QXmppOpusCodec::QXmppOpusCodec(int clockrate, int channels) : sampleRate(clockrate),
- nChannels(channels)
-{
- int error;
- encoder = opus_encoder_create(clockrate, channels, OPUS_APPLICATION_VOIP, &error);
-
- if (encoder || error == OPUS_OK) {
- // Add some options for error correction.
- 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));
-#ifdef OPUS_SET_PREDICTION_DISABLED
- opus_encoder_ctl(encoder, OPUS_SET_PREDICTION_DISABLED(1));
-#endif
- } else
- qCritical() << "Opus encoder initialization error:" << opus_strerror(error);
-
- // Here, clockrate is synonym of sampleRate.
- decoder = opus_decoder_create(clockrate, channels, &error);
-
- if (!encoder || error != OPUS_OK)
- qCritical() << "Opus decoder initialization error:" << opus_strerror(error);
-
- // Opus only supports fixed frame durations from 2.5ms to 60ms.
- //
- // NOTE: https://mf4.xiph.org/jenkins/view/opus/job/opus/ws/doc/html/group__opus__encoder.html
- validFrameSize << 2.5e-3 << 5e-3 << 10e-3 << 20e-3 << 40e-3 << 60e-3;
-
- // so now, calculate the equivalent number of samples to process in each
- // frame.
- //
- // nSamples = t * sampleRate
- for (int i = 0; i < validFrameSize.size(); i++)
- validFrameSize[i] *= clockrate;
-
- // Maxmimum number of samples for the audio buffer.
- 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)
-{
- // Read an audio frame.
- QByteArray pcm_buffer(input.device()->bytesAvailable(), 0);
- int length = input.readRawData(pcm_buffer.data(), pcm_buffer.size());
-
- // and append it to the sample buffer.
- sampleBuffer.append(pcm_buffer.left(length));
-
- // Get the maximum number of samples to encode. It must be a number
- // accepted by the Opus encoder
- int samples = readWindow(sampleBuffer.size());
-
- if (samples < 1)
- return 0;
-
- // The encoded stream is supposed to be smaller than the raw stream, so
- 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
- // Write the encoded stream to the output.
- output.writeRawData(opus_buffer.constData(), length);
-
- // Remove the frame from the sample buffer.
- 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;
-
- // Audio frame is nSamples at maximum, so
- QByteArray pcm_buffer(nSamples * nChannels * 2, 0);
-
- // The last argumment must be 1 to enable FEC, but I don't why it results
- // in a SIGSEV.
- 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;
- }
-
- // Write the audio frame to the output.
- 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.
-
- // Get the number of frames in the buffer.
- int samples = bufferSize / nChannels / 2;
-
- // Find an appropriate number of samples to read, according to Opus specs.
- for (int i = validFrameSize.size() - 1; i >= 0; i--)
- if (validFrameSize[i] <= samples)
- return validFrameSize[i];
-
- return 0;
-}
-
-#endif
-
-#ifdef QXMPP_USE_THEORA
-
-class QXmppTheoraDecoderPrivate
-{
-public:
- bool decodeFrame(const QByteArray &buffer, QXmppVideoFrame *frame);
-
- th_comment comment;
- th_info info;
- th_setup_info *setup_info;
- th_dec_ctx *ctx;
-
- QByteArray packetBuffer;
-};
-
-bool QXmppTheoraDecoderPrivate::decodeFrame(const QByteArray &buffer, QXmppVideoFrame *frame)
-{
- if (!ctx)
- return false;
-
- ogg_packet packet;
- packet.packet = (unsigned char *)buffer.data();
- packet.bytes = buffer.size();
- packet.b_o_s = 1;
- packet.e_o_s = 0;
- packet.granulepos = -1;
- packet.packetno = 0;
- if (th_decode_packetin(ctx, &packet, 0) != 0) {
- qWarning("Theora packet could not be decoded");
- return false;
- }
-
- th_ycbcr_buffer ycbcr_buffer;
- if (th_decode_ycbcr_out(ctx, ycbcr_buffer) != 0) {
- qWarning("Theora packet has no Y'CbCr");
- return false;
- }
-
- if (info.pixel_fmt == TH_PF_420) {
- if (!frame->isValid()) {
- const int bytes = ycbcr_buffer[0].stride * ycbcr_buffer[0].height + ycbcr_buffer[1].stride * ycbcr_buffer[1].height + ycbcr_buffer[2].stride * ycbcr_buffer[2].height;
-
- *frame = QXmppVideoFrame(bytes,
- QSize(ycbcr_buffer[0].width, ycbcr_buffer[0].height),
- ycbcr_buffer[0].stride,
- QXmppVideoFrame::Format_YUV420P);
- }
- uchar *output = frame->bits();
- for (int i = 0; i < 3; ++i) {
- const int length = ycbcr_buffer[i].stride * ycbcr_buffer[i].height;
- memcpy(output, ycbcr_buffer[i].data, length);
- output += length;
- }
- return true;
- } else if (info.pixel_fmt == TH_PF_422) {
- if (!frame->isValid()) {
- const int bytes = ycbcr_buffer[0].width * ycbcr_buffer[0].height * 2;
-
- *frame = QXmppVideoFrame(bytes,
- QSize(ycbcr_buffer[0].width, ycbcr_buffer[0].height),
- ycbcr_buffer[0].width * 2,
- QXmppVideoFrame::Format_YUYV);
- }
-
- // YUV 4:2:2 packing
- const int width = ycbcr_buffer[0].width;
- const int height = ycbcr_buffer[0].height;
- const int y_stride = ycbcr_buffer[0].stride;
- const int c_stride = ycbcr_buffer[1].stride;
- const uchar *y_row = ycbcr_buffer[0].data;
- const uchar *cb_row = ycbcr_buffer[1].data;
- const uchar *cr_row = ycbcr_buffer[2].data;
- uchar *output = frame->bits();
- for (int y = 0; y < height; ++y) {
- const uchar *y_ptr = y_row;
- const uchar *cb_ptr = cb_row;
- const uchar *cr_ptr = cr_row;
- for (int x = 0; x < width; x += 2) {
- *(output++) = *(y_ptr++);
- *(output++) = *(cb_ptr++);
- *(output++) = *(y_ptr++);
- *(output++) = *(cr_ptr++);
- }
- y_row += y_stride;
- cb_row += c_stride;
- cr_row += c_stride;
- }
- return true;
- } else {
- qWarning("Theora decoder received an unsupported frame format");
- return false;
- }
-}
-
-QXmppTheoraDecoder::QXmppTheoraDecoder()
-{
- d = new QXmppTheoraDecoderPrivate;
- th_comment_init(&d->comment);
- th_info_init(&d->info);
- d->setup_info = 0;
- d->ctx = 0;
-}
-
-QXmppTheoraDecoder::~QXmppTheoraDecoder()
-{
- th_comment_clear(&d->comment);
- th_info_clear(&d->info);
- if (d->setup_info)
- th_setup_free(d->setup_info);
- if (d->ctx)
- th_decode_free(d->ctx);
- delete d;
-}
-
-QXmppVideoFormat QXmppTheoraDecoder::format() const
-{
- QXmppVideoFormat format;
- format.setFrameSize(QSize(d->info.frame_width, d->info.frame_height));
- if (d->info.pixel_fmt == TH_PF_420)
- format.setPixelFormat(QXmppVideoFrame::Format_YUV420P);
- else if (d->info.pixel_fmt == TH_PF_422)
- format.setPixelFormat(QXmppVideoFrame::Format_YUYV);
- else
- format.setPixelFormat(QXmppVideoFrame::Format_Invalid);
- if (d->info.fps_denominator > 0)
- format.setFrameRate(qreal(d->info.fps_numerator) / qreal(d->info.fps_denominator));
- return format;
-}
-
-QList<QXmppVideoFrame> QXmppTheoraDecoder::handlePacket(const QXmppRtpPacket &packet)
-{
- QList<QXmppVideoFrame> frames;
-
- // theora deframing: draft-ietf-avt-rtp-theora-00
- QDataStream stream(packet.payload());
- quint32 theora_header;
- stream >> theora_header;
-
- quint32 theora_ident = (theora_header >> 8) & 0xffffff;
- Q_UNUSED(theora_ident);
- quint8 theora_frag = (theora_header & 0xc0) >> 6;
- quint8 theora_type = (theora_header & 0x30) >> 4;
- quint8 theora_packets = (theora_header & 0x0f);
-
- //qDebug("ident: 0x%08x, F: %d, TDT: %d, packets: %d", theora_ident, theora_frag, theora_type, theora_packets);
-
- // We only handle raw theora data
- if (theora_type != 0)
- return frames;
-
- QXmppVideoFrame frame;
- quint16 packetLength;
-
- if (theora_frag == NoFragment) {
- // unfragmented packet(s)
- for (int i = 0; i < theora_packets; ++i) {
- stream >> packetLength;
- if (packetLength > stream.device()->bytesAvailable()) {
- qWarning("Theora unfragmented packet has an invalid length");
- return frames;
- }
-
- d->packetBuffer.resize(packetLength);
- stream.readRawData(d->packetBuffer.data(), packetLength);
- if (d->decodeFrame(d->packetBuffer, &frame))
- frames << frame;
- d->packetBuffer.resize(0);
- }
- } else {
- // fragments
- stream >> packetLength;
- if (packetLength > stream.device()->bytesAvailable()) {
- qWarning("Theora packet has an invalid length");
- return frames;
- }
-
- int pos;
- if (theora_frag == StartFragment) {
- // start fragment
- pos = 0;
- d->packetBuffer.resize(packetLength);
- } else {
- // continuation or end fragment
- pos = d->packetBuffer.size();
- d->packetBuffer.resize(pos + packetLength);
- }
- stream.readRawData(d->packetBuffer.data() + pos, packetLength);
-
- if (theora_frag == EndFragment) {
- // end fragment
- if (d->decodeFrame(d->packetBuffer, &frame))
- frames << frame;
- d->packetBuffer.resize(0);
- }
- }
- return frames;
-}
-
-bool QXmppTheoraDecoder::setParameters(const QMap<QString, QString> &parameters)
-{
- QByteArray config = QByteArray::fromBase64(parameters.value("configuration").toLatin1());
- QDataStream stream(config);
- const QIODevice *device = stream.device();
-
- if (device->bytesAvailable() < 4) {
- qWarning("Theora configuration is too small");
- return false;
- }
-
- // Process packed headers
- int done = 0;
- quint32 header_count;
- stream >> header_count;
- for (quint32 i = 0; i < header_count; ++i) {
- if (device->bytesAvailable() < 6) {
- qWarning("Theora configuration is too small");
- return false;
- }
- QByteArray ident(3, 0);
- quint16 length;
- quint8 h_count;
-
- stream.readRawData(ident.data(), ident.size());
- stream >> length;
- stream >> h_count;
-#ifdef QXMPP_DEBUG_THEORA
- qDebug("Theora packed header %u ident=%s bytes=%u count=%u", i, ident.toHex().data(), length, h_count);
-#endif
-
- // get header sizes
- QList<qint64> h_sizes;
- for (int h = 0; h < h_count; ++h) {
- quint16 h_size = 0;
- quint8 b;
- do {
- if (device->bytesAvailable() < 1) {
- qWarning("Theora configuration is too small");
- return false;
- }
- stream >> b;
- h_size = (h_size << 7) | (b & 0x7f);
- } while (b & 0x80);
- h_sizes << h_size;
-#ifdef QXMPP_DEBUG_THEORA
- qDebug("Theora header %d size %u", h_sizes.size() - 1, h_sizes.last());
-#endif
- length -= h_size;
- }
- h_sizes << length;
-#ifdef QXMPP_DEBUG_THEORA
- qDebug("Theora header %d size %u", h_sizes.size() - 1, h_sizes.last());
-#endif
-
- // decode headers
- ogg_packet packet;
- packet.b_o_s = 1;
- packet.e_o_s = 0;
- packet.granulepos = -1;
- packet.packetno = 0;
-
- for (const auto h_size : h_sizes) {
- if (device->bytesAvailable() < h_size) {
- qWarning("Theora configuration is too small");
- return false;
- }
-
- packet.packet = (unsigned char *)(config.data() + device->pos());
- packet.bytes = h_size;
- int ret = th_decode_headerin(&d->info, &d->comment, &d->setup_info, &packet);
- if (ret < 0) {
- qWarning("Theora header could not be decoded");
- return false;
- }
- done += ret;
- stream.skipRawData(h_size);
- }
- }
-
- // check for completion
- if (done < 3) {
- qWarning("Theora configuration did not contain enough headers");
- return false;
- }
-
-#ifdef QXMPP_DEBUG_THEORA
- qDebug("Theora frame_width %i, frame_height %i, colorspace %i, pixel_fmt: %i, target_bitrate: %i, quality: %i, keyframe_granule_shift: %i",
- d->info.frame_width,
- d->info.frame_height,
- d->info.colorspace,
- d->info.pixel_fmt,
- d->info.target_bitrate,
- d->info.quality,
- d->info.keyframe_granule_shift);
-#endif
- if (d->info.pixel_fmt != TH_PF_420 && d->info.pixel_fmt != TH_PF_422) {
- qWarning("Theora frames have an unsupported pixel format %d", d->info.pixel_fmt);
- return false;
- }
- if (d->ctx)
- th_decode_free(d->ctx);
- d->ctx = th_decode_alloc(&d->info, d->setup_info);
- if (!d->ctx) {
- qWarning("Theora decoder could not be allocated");
- return false;
- }
- return true;
-}
-
-class QXmppTheoraEncoderPrivate
-{
-public:
- void writeFragment(QDataStream &stream, FragmentType frag_type, quint8 theora_packets, const char *data, quint16 length);
-
- th_comment comment;
- th_info info;
- th_setup_info *setup_info;
- th_enc_ctx *ctx;
- th_ycbcr_buffer ycbcr_buffer;
-
- QByteArray buffer;
- QByteArray configuration;
- QByteArray ident;
-};
-
-void QXmppTheoraEncoderPrivate::writeFragment(QDataStream &stream, FragmentType frag_type, quint8 theora_packets, const char *data, quint16 length)
-{
- // theora framing: draft-ietf-avt-rtp-theora-00
- const quint8 theora_type = 0; // raw data
- stream.writeRawData(ident.constData(), ident.size());
- stream << quint8(((frag_type << 6) & 0xc0) |
- ((theora_type << 4) & 0x30) |
- (theora_packets & 0x0f));
- stream << quint16(length);
- stream.writeRawData(data, length);
-}
-
-QXmppTheoraEncoder::QXmppTheoraEncoder()
-{
- d = new QXmppTheoraEncoderPrivate;
- d->ident = QByteArray("\xc3\x45\xae");
- th_comment_init(&d->comment);
- th_info_init(&d->info);
- d->setup_info = 0;
- d->ctx = 0;
-}
-
-QXmppTheoraEncoder::~QXmppTheoraEncoder()
-{
- th_comment_clear(&d->comment);
- th_info_clear(&d->info);
- if (d->setup_info)
- th_setup_free(d->setup_info);
- if (d->ctx)
- th_encode_free(d->ctx);
- delete d;
-}
-
-bool QXmppTheoraEncoder::setFormat(const QXmppVideoFormat &format)
-{
- const QXmppVideoFrame::PixelFormat pixelFormat = format.pixelFormat();
- if ((pixelFormat != QXmppVideoFrame::Format_YUV420P) &&
- (pixelFormat != QXmppVideoFrame::Format_YUYV)) {
- qWarning("Theora encoder does not support the given format");
- return false;
- }
-
- d->info.frame_width = format.frameSize().width();
- d->info.frame_height = format.frameSize().height();
- d->info.pic_height = format.frameSize().height();
- d->info.pic_width = format.frameSize().width();
- d->info.pic_x = 0;
- d->info.pic_y = 0;
- d->info.colorspace = TH_CS_UNSPECIFIED;
- d->info.target_bitrate = 0;
- d->info.quality = 48;
- d->info.keyframe_granule_shift = 6;
-
- // FIXME: how do we handle floating point frame rates?
- d->info.fps_numerator = format.frameRate();
- d->info.fps_denominator = 1;
-
- if (pixelFormat == QXmppVideoFrame::Format_YUV420P) {
- d->info.pixel_fmt = TH_PF_420;
- d->ycbcr_buffer[0].width = d->info.frame_width;
- d->ycbcr_buffer[0].height = d->info.frame_height;
- d->ycbcr_buffer[1].width = d->ycbcr_buffer[0].width / 2;
- d->ycbcr_buffer[1].height = d->ycbcr_buffer[0].height / 2;
- d->ycbcr_buffer[2].width = d->ycbcr_buffer[1].width;
- d->ycbcr_buffer[2].height = d->ycbcr_buffer[1].height;
- } else if (pixelFormat == QXmppVideoFrame::Format_YUYV) {
- d->info.pixel_fmt = TH_PF_422;
- d->buffer.resize(d->info.frame_width * d->info.frame_height * 2);
- d->ycbcr_buffer[0].width = d->info.frame_width;
- d->ycbcr_buffer[0].height = d->info.frame_height;
- d->ycbcr_buffer[0].stride = d->info.frame_width;
- d->ycbcr_buffer[0].data = (uchar *)d->buffer.data();
- d->ycbcr_buffer[1].width = d->ycbcr_buffer[0].width / 2;
- d->ycbcr_buffer[1].height = d->ycbcr_buffer[0].height;
- d->ycbcr_buffer[1].stride = d->ycbcr_buffer[0].stride / 2;
- d->ycbcr_buffer[1].data = d->ycbcr_buffer[0].data + d->ycbcr_buffer[0].stride * d->ycbcr_buffer[0].height;
- d->ycbcr_buffer[2].width = d->ycbcr_buffer[1].width;
- d->ycbcr_buffer[2].height = d->ycbcr_buffer[1].height;
- d->ycbcr_buffer[2].stride = d->ycbcr_buffer[1].stride;
- d->ycbcr_buffer[2].data = d->ycbcr_buffer[1].data + d->ycbcr_buffer[1].stride * d->ycbcr_buffer[1].height;
- }
-
- // create encoder
- if (d->ctx) {
- th_encode_free(d->ctx);
- d->ctx = 0;
- }
- d->ctx = th_encode_alloc(&d->info);
- if (!d->ctx) {
- qWarning("Theora encoder could not be allocated");
- return false;
- }
-
- // fetch headers
- QList<QByteArray> headers;
- ogg_packet packet;
- while (th_encode_flushheader(d->ctx, &d->comment, &packet) > 0)
- headers << QByteArray((const char *)packet.packet, packet.bytes);
-
- // store configuration
- d->configuration.clear();
- QDataStream stream(&d->configuration, QIODevice::WriteOnly);
- stream << quint32(1);
-
- quint16 length = 0;
- for (const auto &header : headers)
- length += header.size();
-
- quint8 h_count = headers.size() - 1;
- stream.writeRawData(d->ident.constData(), d->ident.size());
- stream << length;
- stream << h_count;
-#ifdef QXMPP_DEBUG_THEORA
- qDebug("Theora packed header %u ident=%s bytes=%u count=%u", 0, d->ident.toHex().data(), length, h_count);
-#endif
-
- // write header sizes
- for (int h = 0; h < h_count; ++h) {
- quint16 h_size = headers[h].size();
- do {
- quint8 b = (h_size & 0x7f);
- h_size >>= 7;
- if (h_size)
- b |= 0x80;
- stream << b;
- } while (h_size);
- }
-
- // write headers
- for (int h = 0; h < headers.size(); ++h) {
-#ifdef QXMPP_DEBUG_THEORA
- qDebug("Header %d size %d", h, headers[h].size());
-#endif
- stream.writeRawData(headers[h].data(), headers[h].size());
- }
-
- return true;
-}
-
-QList<QByteArray> QXmppTheoraEncoder::handleFrame(const QXmppVideoFrame &frame)
-{
- QList<QByteArray> packets;
- const int PACKET_MAX = 1388;
-
- if (!d->ctx)
- return packets;
-
- if (d->info.pixel_fmt == TH_PF_420) {
- d->ycbcr_buffer[0].stride = frame.bytesPerLine();
- d->ycbcr_buffer[0].data = (unsigned char *)frame.bits();
- d->ycbcr_buffer[1].stride = d->ycbcr_buffer[0].stride / 2;
- d->ycbcr_buffer[1].data = d->ycbcr_buffer[0].data + d->ycbcr_buffer[0].stride * d->ycbcr_buffer[0].height;
- d->ycbcr_buffer[2].stride = d->ycbcr_buffer[1].stride;
- d->ycbcr_buffer[2].data = d->ycbcr_buffer[1].data + d->ycbcr_buffer[1].stride * d->ycbcr_buffer[1].height;
- } else if (d->info.pixel_fmt == TH_PF_422) {
- // YUV 4:2:2 unpacking
- const int width = frame.width();
- const int height = frame.height();
- const int stride = frame.bytesPerLine();
- const uchar *row = frame.bits();
- uchar *y_out = d->ycbcr_buffer[0].data;
- uchar *cb_out = d->ycbcr_buffer[1].data;
- uchar *cr_out = d->ycbcr_buffer[2].data;
- for (int y = 0; y < height; ++y) {
- const uchar *ptr = row;
- for (int x = 0; x < width; x += 2) {
- *(y_out++) = *(ptr++);
- *(cb_out++) = *(ptr++);
- *(y_out++) = *(ptr++);
- *(cr_out++) = *(ptr++);
- }
- row += stride;
- }
- } else {
- qWarning("Theora encoder received an unsupported frame format");
- return packets;
- }
-
- if (th_encode_ycbcr_in(d->ctx, d->ycbcr_buffer) != 0) {
- qWarning("Theora encoder could not handle frame");
- return packets;
- }
-
- QByteArray payload;
- ogg_packet packet;
- while (th_encode_packetout(d->ctx, 0, &packet) > 0) {
-#ifdef QXMPP_DEBUG_THEORA
- qDebug("Theora encoded packet %d bytes", packet.bytes);
-#endif
- QDataStream stream(&payload, QIODevice::WriteOnly);
- const char *data = (const char *)packet.packet;
- int size = packet.bytes;
- if (size <= PACKET_MAX) {
- // no fragmentation
- stream.device()->reset();
- payload.resize(0);
- d->writeFragment(stream, NoFragment, 1, data, size);
- packets << payload;
- } else {
- // fragmentation
- FragmentType frag_type = StartFragment;
- while (size) {
- const int length = qMin(PACKET_MAX, size);
- stream.device()->reset();
- payload.resize(0);
- d->writeFragment(stream, frag_type, 0, data, length);
- data += length;
- size -= length;
- frag_type = (size > PACKET_MAX) ? MiddleFragment : EndFragment;
- packets << payload;
- }
- }
- }
-
- return packets;
-}
-
-QMap<QString, QString> QXmppTheoraEncoder::parameters() const
-{
- QMap<QString, QString> params;
- if (d->ctx) {
- params.insert("delivery-method", "inline");
- params.insert("configuration", d->configuration.toBase64());
- }
- return params;
-}
-
-#endif
-
-#ifdef QXMPP_USE_VPX
-
-class QXmppVpxDecoderPrivate
-{
-public:
- bool decodeFrame(const QByteArray &buffer, QXmppVideoFrame *frame);
-
- vpx_codec_ctx_t codec;
- QByteArray packetBuffer;
-};
-
-bool QXmppVpxDecoderPrivate::decodeFrame(const QByteArray &buffer, QXmppVideoFrame *frame)
-{
- // With the VPX_DL_REALTIME option, tries to decode the frame as quick as
- // possible, if not possible discard it.
- if (vpx_codec_decode(&codec,
- (const uint8_t *)buffer.constData(),
- buffer.size(),
- NULL,
- VPX_DL_REALTIME) != VPX_CODEC_OK) {
- qWarning("Vpx packet could not be decoded: %s", vpx_codec_error_detail(&codec));
- return false;
- }
-
- vpx_codec_iter_t iter = NULL;
- vpx_image_t *img;
- while ((img = vpx_codec_get_frame(&codec, &iter))) {
- if (img->fmt == VPX_IMG_FMT_I420) {
- if (!frame->isValid()) {
- const int bytes = img->d_w * img->d_h * 3 / 2;
-
- *frame = QXmppVideoFrame(bytes,
- QSize(img->d_w, img->d_h),
- img->d_w,
- QXmppVideoFrame::Format_YUV420P);
- }
- uchar *output = frame->bits();
-
- for (int i = 0; i < 3; ++i) {
- uchar *input = img->planes[i];
- const int div = (i == 0) ? 1 : 2;
- for (unsigned int y = 0; y < img->d_h / div; ++y) {
- memcpy(output, input, img->d_w / div);
- input += img->stride[i];
- output += img->d_w / div;
- }
- }
- } else {
- qWarning("Vpx decoder received an unsupported frame format: %d", img->fmt);
- }
- }
-
- return true;
-}
-
-QXmppVpxDecoder::QXmppVpxDecoder()
-{
- d = new QXmppVpxDecoderPrivate;
- vpx_codec_flags_t flags = 0;
-
- // Enable FEC if codec support it.
- if (vpx_codec_get_caps(vpx_codec_vp8_dx()) & VPX_CODEC_CAP_ERROR_CONCEALMENT)
- flags |= VPX_CODEC_USE_ERROR_CONCEALMENT;
-
- if (vpx_codec_dec_init(&d->codec,
- vpx_codec_vp8_dx(),
- NULL,
- flags) != VPX_CODEC_OK) {
- qWarning("Vpx decoder could not be initialised");
- }
-}
-
-QXmppVpxDecoder::~QXmppVpxDecoder()
-{
- vpx_codec_destroy(&d->codec);
- delete d;
-}
-
-QXmppVideoFormat QXmppVpxDecoder::format() const
-{
- QXmppVideoFormat format;
- format.setFrameRate(15.0);
- format.setFrameSize(QSize(320, 240));
- format.setPixelFormat(QXmppVideoFrame::Format_YUV420P);
- return format;
-}
-
-QList<QXmppVideoFrame> QXmppVpxDecoder::handlePacket(const QXmppRtpPacket &packet)
-{
- QList<QXmppVideoFrame> frames;
- const QByteArray payload = packet.payload();
-
- // vp8 deframing: http://tools.ietf.org/html/draft-westin-payload-vp8-00
- QDataStream stream(payload);
- quint8 vpx_header;
- stream >> vpx_header;
-
- const bool have_id = (vpx_header & 0x10) != 0;
- const quint8 frag_type = (vpx_header & 0x6) >> 1;
- if (have_id) {
- qWarning("Vpx decoder does not support pictureId yet");
- return frames;
- }
-
- const int packetLength = payload.size() - 1;
-#ifdef QXMPP_DEBUG_VPX
- qDebug("Vpx fragment FI: %d, size %d", frag_type, packetLength);
-#endif
-
- QXmppVideoFrame frame;
- static quint16 sequence = 0;
-
- // If the incoming packet sequence is wrong discard all packets until a
- // complete keyframe arrives.
- // If a partition of a keyframe is missing, discard it until a next
- // keyframe.
- //
- // NOTE: https://tools.ietf.org/html/draft-ietf-payload-vp8-13#section-4.3
- // Sections: 4.3, 4.5, 4.5.1
-
- if (frag_type == NoFragment) {
- // unfragmented packet
- if ((payload[1] & 0x1) == 0 // is key frame
- || packet.sequence() == sequence) {
- if (d->decodeFrame(payload.mid(1), &frame))
- frames << frame;
-
- sequence = packet.sequence() + 1;
- }
-
- d->packetBuffer.resize(0);
- } else {
- // fragments
- if (frag_type == StartFragment) {
- // start fragment
- if ((payload[1] & 0x1) == 0 // is key frame
- || packet.sequence() == sequence) {
- d->packetBuffer = payload.mid(1);
- sequence = packet.sequence() + 1;
- }
- } else {
- // continuation or end fragment
- if (packet.sequence() == sequence) {
- const int packetPos = d->packetBuffer.size();
- d->packetBuffer.resize(packetPos + packetLength);
- stream.readRawData(d->packetBuffer.data() + packetPos, packetLength);
-
- if (frag_type == EndFragment) {
- // end fragment
- if (d->decodeFrame(d->packetBuffer, &frame)) {
- frames << frame;
- d->packetBuffer.resize(0);
- }
- }
-
- sequence++;
- }
- }
- }
-
- return frames;
-}
-
-bool QXmppVpxDecoder::setParameters(const QMap<QString, QString> &parameters)
-{
- Q_UNUSED(parameters);
- return true;
-}
-
-class QXmppVpxEncoderPrivate
-{
-public:
- void writeFragment(QDataStream &stream, FragmentType frag_type, const char *data, quint16 length);
-
- vpx_codec_ctx_t codec;
- vpx_codec_enc_cfg_t cfg;
- vpx_image_t *imageBuffer;
- int frameCount;
-};
-
-void QXmppVpxEncoderPrivate::writeFragment(QDataStream &stream, FragmentType frag_type, const char *data, quint16 length)
-{
- // vp8 framing: http://tools.ietf.org/html/draft-westin-payload-vp8-00
-#ifdef QXMPP_DEBUG_VPX
- qDebug("Vpx encoder writing packet frag: %i, size: %u", frag_type, length);
-#endif
- stream << quint8(((frag_type << 1) & 0x6) |
- (frag_type == NoFragment || frag_type == StartFragment));
- stream.writeRawData(data, length);
-}
-
-QXmppVpxEncoder::QXmppVpxEncoder(uint clockrate)
-{
- d = new QXmppVpxEncoderPrivate;
- d->frameCount = 0;
- d->imageBuffer = 0;
- vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &d->cfg, 0);
-
- // Set the encoding threads number to use
- int nThreads = QThread::idealThreadCount();
-
- if (nThreads > 0)
- d->cfg.g_threads = nThreads - 1;
-
- // Make stream error resiliant
- d->cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT | VPX_ERROR_RESILIENT_PARTITIONS;
-
- d->cfg.g_pass = VPX_RC_ONE_PASS;
- d->cfg.kf_mode = VPX_KF_AUTO;
-
- // Reduce GOP size
- if (d->cfg.kf_max_dist > GOPSIZE)
- d->cfg.kf_max_dist = GOPSIZE;
-
- // Here, clockrate is synonym of bitrate.
- d->cfg.rc_target_bitrate = clockrate / 1000;
-}
-
-QXmppVpxEncoder::~QXmppVpxEncoder()
-{
- vpx_codec_destroy(&d->codec);
- if (d->imageBuffer)
- vpx_img_free(d->imageBuffer);
- delete d;
-}
-
-bool QXmppVpxEncoder::setFormat(const QXmppVideoFormat &format)
-{
- const QXmppVideoFrame::PixelFormat pixelFormat = format.pixelFormat();
- if (pixelFormat != QXmppVideoFrame::Format_YUYV) {
- qWarning("Vpx encoder does not support the given format");
- return false;
- }
- d->cfg.g_w = format.frameSize().width();
- d->cfg.g_h = format.frameSize().height();
- if (vpx_codec_enc_init(&d->codec, vpx_codec_vp8_cx(), &d->cfg, 0) != VPX_CODEC_OK) {
- qWarning("Vpx encoder could not be initialised");
- return false;
- }
-
- d->imageBuffer = vpx_img_alloc(NULL, VPX_IMG_FMT_I420,
- format.frameSize().width(), format.frameSize().height(), 1);
- return true;
-}
-
-QList<QByteArray> QXmppVpxEncoder::handleFrame(const QXmppVideoFrame &frame)
-{
- const int PACKET_MAX = 1388;
- QList<QByteArray> packets;
-
- // try to encode frame
- if (frame.pixelFormat() == QXmppVideoFrame::Format_YUYV) {
- // YUYV -> YUV420P
- const int width = frame.width();
- const int height = frame.height();
- const int stride = frame.bytesPerLine();
- const uchar *row = frame.bits();
- uchar *y_row = d->imageBuffer->planes[VPX_PLANE_Y];
- uchar *cb_row = d->imageBuffer->planes[VPX_PLANE_U];
- uchar *cr_row = d->imageBuffer->planes[VPX_PLANE_V];
- for (int y = 0; y < height; y += 2) {
- // odd row
- const uchar *ptr = row;
- uchar *y_out = y_row;
- uchar *cb_out = cb_row;
- uchar *cr_out = cr_row;
- for (int x = 0; x < width; x += 2) {
- *(y_out++) = *(ptr++);
- *(cb_out++) = *(ptr++);
- *(y_out++) = *(ptr++);
- *(cr_out++) = *(ptr++);
- }
- row += stride;
- y_row += d->imageBuffer->stride[VPX_PLANE_Y];
- cb_row += d->imageBuffer->stride[VPX_PLANE_U];
- cr_row += d->imageBuffer->stride[VPX_PLANE_V];
-
- // even row
- ptr = row;
- y_out = y_row;
- for (int x = 0; x < width; x += 2) {
- *(y_out++) = *(ptr++);
- ptr++;
- *(y_out++) = *(ptr++);
- ptr++;
- }
- row += stride;
- y_row += d->imageBuffer->stride[VPX_PLANE_Y];
- }
- } else {
- qWarning("Vpx encoder does not support the given format");
- return packets;
- }
-
- if (vpx_codec_encode(&d->codec, d->imageBuffer, d->frameCount, 1, 0, VPX_DL_REALTIME) != VPX_CODEC_OK) {
- qWarning("Vpx encoder could not handle frame: %s", vpx_codec_error_detail(&d->codec));
- return packets;
- }
-
- // extract data
- QByteArray payload;
- vpx_codec_iter_t iter = NULL;
- const vpx_codec_cx_pkt_t *pkt;
- while ((pkt = vpx_codec_get_cx_data(&d->codec, &iter))) {
- if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
-#ifdef QXMPP_DEBUG_VPX
- qDebug("Vpx encoded packet %lu bytes", pkt->data.frame.sz);
-#endif
- QDataStream stream(&payload, QIODevice::WriteOnly);
- const char *data = (const char *)pkt->data.frame.buf;
- int size = pkt->data.frame.sz;
- if (size <= PACKET_MAX) {
- // no fragmentation
- stream.device()->reset();
- payload.resize(0);
- d->writeFragment(stream, NoFragment, data, size);
- packets << payload;
- } else {
- // fragmentation
- FragmentType frag_type = StartFragment;
- while (size) {
- const int length = qMin(PACKET_MAX, size);
- stream.device()->reset();
- payload.resize(0);
- d->writeFragment(stream, frag_type, data, length);
- data += length;
- size -= length;
- frag_type = (size > PACKET_MAX) ? MiddleFragment : EndFragment;
- packets << payload;
- }
- }
- }
- }
- d->frameCount++;
-
- return packets;
-}
-
-QMap<QString, QString> QXmppVpxEncoder::parameters() const
-{
- return QMap<QString, QString>();
-}
-
-#endif
diff --git a/src/base/QXmppCodec_p.h b/src/base/QXmppCodec_p.h
deleted file mode 100644
index d9a8e3c2..00000000
--- a/src/base/QXmppCodec_p.h
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Copyright (C) 2008-2020 The QXmpp developers
- *
- * Author:
- * Jeremy Lainé
- *
- * Source:
- * https://github.com/qxmpp-project/qxmpp
- *
- * This file is a part of QXmpp library.
- *
- * This library 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.
- *
- * This library 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.
- *
- */
-
-#ifndef QXMPPCODEC_H
-#define QXMPPCODEC_H
-
-#include "QXmppGlobal.h"
-
-#include <QMap>
-
-class QXmppRtpPacket;
-class QXmppVideoFormat;
-class QXmppVideoFrame;
-
-/// \brief The QXmppCodec class is the base class for audio codecs capable of
-/// encoding and decoding audio samples.
-///
-/// Samples must be 16-bit little endian.
-
-class QXMPP_AUTOTEST_EXPORT QXmppCodec
-{
-public:
- virtual ~QXmppCodec();
-
- /// Reads samples from the input stream, encodes them and writes the
- /// encoded data to the output stream.
- virtual qint64 encode(QDataStream &input, QDataStream &output) = 0;
-
- /// Reads encoded data from the input stream, decodes it and writes the
- /// decoded samples to the output stream.
- virtual qint64 decode(QDataStream &input, QDataStream &output) = 0;
-};
-
-/// \internal
-///
-/// The QXmppG711aCodec class represent a G.711 a-law PCM codec.
-
-class QXmppG711aCodec : public QXmppCodec
-{
-public:
- QXmppG711aCodec(int clockrate);
-
- qint64 encode(QDataStream &input, QDataStream &output) override;
- qint64 decode(QDataStream &input, QDataStream &output) override;
-
-private:
- int m_frequency;
-};
-
-/// \internal
-///
-/// The QXmppG711uCodec class represent a G.711 u-law PCM codec.
-
-class QXmppG711uCodec : public QXmppCodec
-{
-public:
- QXmppG711uCodec(int clockrate);
-
- qint64 encode(QDataStream &input, QDataStream &output) override;
- qint64 decode(QDataStream &input, QDataStream &output) override;
-
-private:
- int m_frequency;
-};
-
-#ifdef QXMPP_USE_SPEEX
-typedef struct SpeexBits SpeexBits;
-
-/// \internal
-///
-/// The QXmppSpeexCodec class represent a SPEEX codec.
-
-class QXMPP_AUTOTEST_EXPORT QXmppSpeexCodec : public QXmppCodec
-{
-public:
- QXmppSpeexCodec(int clockrate);
- ~QXmppSpeexCodec();
-
- qint64 encode(QDataStream &input, QDataStream &output);
- qint64 decode(QDataStream &input, QDataStream &output);
-
-private:
- SpeexBits *encoder_bits;
- void *encoder_state;
- SpeexBits *decoder_bits;
- void *decoder_state;
- int frame_samples;
-};
-#endif
-
-#ifdef QXMPP_USE_OPUS
-typedef struct OpusEncoder OpusEncoder;
-typedef struct OpusDecoder OpusDecoder;
-
-/// \internal
-///
-/// The QXmppOpusCodec class represent a Opus codec.
-
-class QXMPP_AUTOTEST_EXPORT QXmppOpusCodec : public QXmppCodec
-{
-public:
- QXmppOpusCodec(int clockrate, int channels);
- ~QXmppOpusCodec();
-
- qint64 encode(QDataStream &input, QDataStream &output);
- qint64 decode(QDataStream &input, QDataStream &output);
-
-private:
- OpusEncoder *encoder;
- OpusDecoder *decoder;
- int sampleRate;
- int nChannels;
- QList<float> validFrameSize;
- int nSamples;
- QByteArray sampleBuffer;
-
- int readWindow(int bufferSize);
-};
-#endif
-
-/// \brief The QXmppVideoDecoder class is the base class for video decoders.
-///
-
-class QXMPP_AUTOTEST_EXPORT QXmppVideoDecoder
-{
-public:
- virtual ~QXmppVideoDecoder();
-
- /// Returns the format of the video stream.
- virtual QXmppVideoFormat format() const = 0;
-
- /// Handles an RTP \a packet and returns a list of decoded video frames.
- virtual QList<QXmppVideoFrame> handlePacket(const QXmppRtpPacket &packet) = 0;
-
- /// Sets the video stream's \a parameters.
- virtual bool setParameters(const QMap<QString, QString> &parameters) = 0;
-};
-
-/// \brief The QXmppVideoEncoder class is the base class for video encoders.
-///
-
-class QXMPP_AUTOTEST_EXPORT QXmppVideoEncoder
-{
-public:
- virtual ~QXmppVideoEncoder();
-
- /// Sets the \a format of the video stream.
- virtual bool setFormat(const QXmppVideoFormat &format) = 0;
-
- /// Handles a video \a frame and returns a list of RTP packet payloads.
- virtual QList<QByteArray> handleFrame(const QXmppVideoFrame &frame) = 0;
-
- /// Returns the video stream's parameters.
- virtual QMap<QString, QString> parameters() const = 0;
-};
-
-#ifdef QXMPP_USE_THEORA
-class QXmppTheoraDecoderPrivate;
-class QXmppTheoraEncoderPrivate;
-
-class QXMPP_AUTOTEST_EXPORT QXmppTheoraDecoder : public QXmppVideoDecoder
-{
-public:
- QXmppTheoraDecoder();
- ~QXmppTheoraDecoder();
-
- QXmppVideoFormat format() const;
- QList<QXmppVideoFrame> handlePacket(const QXmppRtpPacket &packet);
- bool setParameters(const QMap<QString, QString> &parameters);
-
-private:
- QXmppTheoraDecoderPrivate *d;
-};
-
-class QXMPP_AUTOTEST_EXPORT QXmppTheoraEncoder : public QXmppVideoEncoder
-{
-public:
- QXmppTheoraEncoder();
- ~QXmppTheoraEncoder();
-
- bool setFormat(const QXmppVideoFormat &format);
- QList<QByteArray> handleFrame(const QXmppVideoFrame &frame);
- QMap<QString, QString> parameters() const;
-
-private:
- QXmppTheoraEncoderPrivate *d;
-};
-#endif
-
-#ifdef QXMPP_USE_VPX
-class QXmppVpxDecoderPrivate;
-class QXmppVpxEncoderPrivate;
-
-class QXMPP_AUTOTEST_EXPORT QXmppVpxDecoder : public QXmppVideoDecoder
-{
-public:
- QXmppVpxDecoder();
- ~QXmppVpxDecoder();
-
- QXmppVideoFormat format() const;
- QList<QXmppVideoFrame> handlePacket(const QXmppRtpPacket &packet);
- bool setParameters(const QMap<QString, QString> &parameters);
-
-private:
- QXmppVpxDecoderPrivate *d;
-};
-
-class QXMPP_AUTOTEST_EXPORT QXmppVpxEncoder : public QXmppVideoEncoder
-{
-public:
- QXmppVpxEncoder(uint clockrate = 0);
- ~QXmppVpxEncoder();
-
- bool setFormat(const QXmppVideoFormat &format);
- QList<QByteArray> handleFrame(const QXmppVideoFrame &frame);
- QMap<QString, QString> parameters() const;
-
-private:
- QXmppVpxEncoderPrivate *d;
-};
-#endif
-
-#endif
diff --git a/src/base/QXmppRtcpPacket.cpp b/src/base/QXmppRtcpPacket.cpp
deleted file mode 100644
index 5ddb96f0..00000000
--- a/src/base/QXmppRtcpPacket.cpp
+++ /dev/null
@@ -1,660 +0,0 @@
-/*
- * Copyright (C) 2008-2020 The QXmpp developers
- *
- * Author:
- * Jeremy Lainé
- *
- * Source:
- * https://github.com/qxmpp-project/qxmpp
- *
- * This file is a part of QXmpp library.
- *
- * This library 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.
- *
- * This library 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.
- *
- */
-
-#include "QXmppRtcpPacket.h"
-
-#include <QDataStream>
-#include <QDebug>
-
-#define RTP_VERSION 2
-
-enum DescriptionType {
- CnameType = 1,
- NameType = 2
-};
-
-class QXmppRtcpPacketPrivate : public QSharedData
-{
-public:
- QXmppRtcpPacketPrivate();
-
- /// Number of report blocks.
- quint8 count;
- /// Payload type.
- quint8 type;
- /// Raw payload data.
- QByteArray payload;
-
- QString goodbyeReason;
- QList<quint32> goodbyeSsrcs;
- QXmppRtcpSenderInfo senderInfo;
- QList<QXmppRtcpReceiverReport> receiverReports;
- QList<QXmppRtcpSourceDescription> sourceDescriptions;
- quint32 ssrc;
-};
-
-class QXmppRtcpReceiverReportPrivate : public QSharedData
-{
-public:
- QXmppRtcpReceiverReportPrivate();
- bool read(QDataStream &stream);
- void write(QDataStream &stream) const;
-
- quint32 ssrc;
- quint8 fractionLost;
- quint32 totalLost;
- quint32 highestSequence;
- quint32 jitter;
- quint32 lsr;
- quint32 dlsr;
-};
-
-class QXmppRtcpSenderInfoPrivate : public QSharedData
-{
-public:
- QXmppRtcpSenderInfoPrivate();
- bool read(QDataStream &stream);
- void write(QDataStream &stream) const;
-
- quint64 ntpStamp;
- quint32 rtpStamp;
- quint32 packetCount;
- quint32 octetCount;
-};
-
-class QXmppRtcpSourceDescriptionPrivate : public QSharedData
-{
-public:
- QXmppRtcpSourceDescriptionPrivate();
- bool read(QDataStream &stream);
- void write(QDataStream &stream) const;
-
- quint32 ssrc;
- QString cname;
- QString name;
-};
-
-static bool readPadding(QDataStream &stream, int dataLength)
-{
- if (dataLength % 4) {
- QByteArray buffer;
- buffer.resize(4 - dataLength % 4);
- if (stream.readRawData(buffer.data(), buffer.size()) != buffer.size())
- return false;
- if (buffer != QByteArray(buffer.size(), '\0'))
- return false;
- }
- return true;
-}
-
-static void writePadding(QDataStream &stream, int dataLength)
-{
- if (dataLength % 4) {
- const QByteArray buffer = QByteArray(4 - dataLength % 4, '\0');
- stream.writeRawData(buffer.constData(), buffer.size());
- }
-}
-
-/// Constructs an empty RTCP packet
-
-QXmppRtcpPacket::QXmppRtcpPacket()
- : d(new QXmppRtcpPacketPrivate())
-{
-}
-
-/// Constructs a copy of other.
-///
-/// \param other
-
-QXmppRtcpPacket::QXmppRtcpPacket(const QXmppRtcpPacket &other)
- : d(other.d)
-{
-}
-
-QXmppRtcpPacket::~QXmppRtcpPacket()
-{
-}
-
-/// Parses an RTCP packet.
-///
-/// \param ba
-bool QXmppRtcpPacket::decode(const QByteArray &ba)
-{
- QDataStream stream(ba);
- return read(stream);
-}
-
-/// Encodes an RTCP packet.
-
-QByteArray QXmppRtcpPacket::encode() const
-{
- QByteArray ba;
- ba.resize(4 + d->payload.size());
-
- QDataStream stream(&ba, QIODevice::WriteOnly);
- write(stream);
- return ba;
-}
-
-bool QXmppRtcpPacket::read(QDataStream &stream)
-{
- quint8 tmp, type;
- quint16 len;
-
- // fixed header
- stream >> tmp;
- stream >> type;
- stream >> len;
- if (stream.status() != QDataStream::Ok)
- return false;
-
- // check version
- if ((tmp >> 6) != RTP_VERSION)
- return false;
-
- const int payloadLength = len << 2;
- d->count = (tmp & 0x1f);
- d->type = type;
- d->payload.resize(payloadLength);
- if (stream.readRawData(d->payload.data(), payloadLength) != payloadLength)
- return false;
-
- QDataStream s(d->payload);
- d->goodbyeReason.clear();
- d->goodbyeSsrcs.clear();
- d->receiverReports.clear();
- d->senderInfo = QXmppRtcpSenderInfo();
- d->sourceDescriptions.clear();
- d->ssrc = 0;
- if (d->type == Goodbye) {
- quint32 ssrc;
- for (int i = 0; i < d->count; ++i) {
- s >> ssrc;
- if (stream.status() != QDataStream::Ok)
- return false;
- d->goodbyeSsrcs << ssrc;
- }
- quint8 reasonLength;
- s >> reasonLength;
- if (reasonLength) {
- QByteArray buffer;
- buffer.resize(reasonLength);
- if (s.readRawData(buffer.data(), buffer.size()) != buffer.size())
- return false;
- if (!readPadding(s, 1 + buffer.size()))
- return false;
- d->goodbyeReason = QString::fromUtf8(buffer);
- }
- } else if (d->type == ReceiverReport || d->type == SenderReport) {
- s >> d->ssrc;
- if (d->type == SenderReport && !d->senderInfo.d->read(s))
- return false;
- for (int i = 0; i < d->count; ++i) {
- QXmppRtcpReceiverReport receiverReport;
- if (!receiverReport.d->read(s))
- return false;
- d->receiverReports << receiverReport;
- }
- } else if (d->type == SourceDescription) {
- for (int i = 0; i < d->count; ++i) {
- QXmppRtcpSourceDescription desc;
- if (!desc.d->read(s))
- return false;
- d->sourceDescriptions << desc;
- }
- }
- return true;
-}
-
-void QXmppRtcpPacket::write(QDataStream &stream) const
-{
- QByteArray payload;
- quint8 count;
-
- QDataStream s(&payload, QIODevice::WriteOnly);
- if (d->type == Goodbye) {
- count = d->goodbyeSsrcs.size();
- for (const auto ssrc : d->goodbyeSsrcs)
- s << ssrc;
- if (!d->goodbyeReason.isEmpty()) {
- const QByteArray reason = d->goodbyeReason.toUtf8();
- s << quint8(reason.size());
- s.writeRawData(reason.constData(), reason.size());
- writePadding(s, 1 + reason.size());
- }
- } else if (d->type == ReceiverReport || d->type == SenderReport) {
- count = d->receiverReports.size();
- s << d->ssrc;
- if (d->type == SenderReport)
- d->senderInfo.d->write(s);
- for (const auto &report : d->receiverReports)
- report.d->write(s);
- } else if (d->type == SourceDescription) {
- count = d->sourceDescriptions.size();
- for (const auto &desc : d->sourceDescriptions)
- desc.d->write(s);
- } else {
- count = d->count;
- payload = d->payload;
- }
-
- stream << quint8((RTP_VERSION << 6) | (count & 0x1f));
- stream << d->type;
- stream << quint16(payload.size() >> 2);
- stream.writeRawData(payload.constData(), payload.size());
-}
-
-QString QXmppRtcpPacket::goodbyeReason() const
-{
- return d->goodbyeReason;
-}
-
-void QXmppRtcpPacket::setGoodbyeReason(const QString &goodbyeReason)
-{
- d->goodbyeReason = goodbyeReason;
-}
-
-QList<quint32> QXmppRtcpPacket::goodbyeSsrcs() const
-{
- return d->goodbyeSsrcs;
-}
-
-void QXmppRtcpPacket::setGoodbyeSsrcs(const QList<quint32> &goodbyeSsrcs)
-{
- d->goodbyeSsrcs = goodbyeSsrcs;
-}
-
-QList<QXmppRtcpReceiverReport> QXmppRtcpPacket::receiverReports() const
-{
- return d->receiverReports;
-}
-
-void QXmppRtcpPacket::setReceiverReports(const QList<QXmppRtcpReceiverReport> &reports)
-{
- d->receiverReports = reports;
-}
-
-QXmppRtcpSenderInfo QXmppRtcpPacket::senderInfo() const
-{
- return d->senderInfo;
-}
-
-void QXmppRtcpPacket::setSenderInfo(const QXmppRtcpSenderInfo &senderInfo)
-{
- d->senderInfo = senderInfo;
-}
-
-QList<QXmppRtcpSourceDescription> QXmppRtcpPacket::sourceDescriptions() const
-{
- return d->sourceDescriptions;
-}
-
-void QXmppRtcpPacket::setSourceDescriptions(const QList<QXmppRtcpSourceDescription> &descriptions)
-{
- d->sourceDescriptions = descriptions;
-}
-
-/// Returns the RTCP packet's source SSRC.
-///
-/// This is only applicable for Sender Reports or Receiver Reports.
-
-quint32 QXmppRtcpPacket::ssrc() const
-{
- return d->ssrc;
-}
-
-/// Sets the RTCP packet's source SSRC.
-///
-/// This is only applicable for Sender Reports or Receiver Reports.
-
-void QXmppRtcpPacket::setSsrc(quint32 ssrc)
-{
- d->ssrc = ssrc;
-}
-
-/// Returns the RTCP packet type.
-
-quint8 QXmppRtcpPacket::type() const
-{
- return d->type;
-}
-
-/// Sets the RTCP packet type.
-///
-/// \param type
-
-void QXmppRtcpPacket::setType(quint8 type)
-{
- d->type = type;
-}
-
-QXmppRtcpPacketPrivate::QXmppRtcpPacketPrivate()
- : count(0), type(0), ssrc(0)
-{
-}
-
-/// Constructs an empty receiver report.
-
-QXmppRtcpReceiverReport::QXmppRtcpReceiverReport()
- : d(new QXmppRtcpReceiverReportPrivate())
-{
-}
-
-/// Constructs a copy of other.
-///
-/// \param other
-
-QXmppRtcpReceiverReport::QXmppRtcpReceiverReport(const QXmppRtcpReceiverReport &other)
- : d(other.d)
-{
-}
-
-QXmppRtcpReceiverReport::~QXmppRtcpReceiverReport()
-{
-}
-
-quint32 QXmppRtcpReceiverReport::dlsr() const
-{
- return d->dlsr;
-}
-
-void QXmppRtcpReceiverReport::setDlsr(quint32 dlsr)
-{
- d->dlsr = dlsr;
-}
-
-quint8 QXmppRtcpReceiverReport::fractionLost() const
-{
- return d->fractionLost;
-}
-
-void QXmppRtcpReceiverReport::setFractionLost(quint8 fractionLost)
-{
- d->fractionLost = fractionLost;
-}
-
-quint32 QXmppRtcpReceiverReport::jitter() const
-{
- return d->jitter;
-}
-
-void QXmppRtcpReceiverReport::setJitter(quint32 jitter)
-{
- d->jitter = jitter;
-}
-
-quint32 QXmppRtcpReceiverReport::lsr() const
-{
- return d->lsr;
-}
-
-void QXmppRtcpReceiverReport::setLsr(quint32 lsr)
-{
- d->lsr = lsr;
-}
-
-quint32 QXmppRtcpReceiverReport::ssrc() const
-{
- return d->ssrc;
-}
-
-void QXmppRtcpReceiverReport::setSsrc(quint32 ssrc)
-{
- d->ssrc = ssrc;
-}
-
-quint32 QXmppRtcpReceiverReport::totalLost() const
-{
- return d->totalLost;
-}
-
-void QXmppRtcpReceiverReport::setTotalLost(quint32 totalLost)
-{
- d->totalLost = totalLost;
-}
-
-QXmppRtcpReceiverReportPrivate::QXmppRtcpReceiverReportPrivate()
- : ssrc(0), fractionLost(0), totalLost(0), highestSequence(0), jitter(0), lsr(0), dlsr(0)
-{
-}
-
-bool QXmppRtcpReceiverReportPrivate::read(QDataStream &stream)
-{
- quint32 tmp;
- stream >> ssrc;
- stream >> tmp;
- fractionLost = (tmp >> 24) & 0xff;
- totalLost = tmp & 0xffffff;
- stream >> highestSequence;
- stream >> jitter;
- stream >> lsr;
- stream >> dlsr;
- return stream.status() == QDataStream::Ok;
-}
-
-void QXmppRtcpReceiverReportPrivate::write(QDataStream &stream) const
-{
- stream << ssrc;
- stream << quint32((fractionLost << 24) | (totalLost & 0xffffff));
- stream << highestSequence;
- stream << jitter;
- stream << lsr;
- stream << dlsr;
-}
-
-/// Constructs an empty sender report.
-
-QXmppRtcpSenderInfo::QXmppRtcpSenderInfo()
- : d(new QXmppRtcpSenderInfoPrivate())
-{
-}
-
-/// Constructs a copy of other.
-///
-/// \param other
-
-QXmppRtcpSenderInfo::QXmppRtcpSenderInfo(const QXmppRtcpSenderInfo &other)
- : d(other.d)
-{
-}
-
-QXmppRtcpSenderInfo::~QXmppRtcpSenderInfo()
-{
-}
-
-quint64 QXmppRtcpSenderInfo::ntpStamp() const
-{
- return d->ntpStamp;
-}
-
-void QXmppRtcpSenderInfo::setNtpStamp(quint64 ntpStamp)
-{
- d->ntpStamp = ntpStamp;
-}
-
-quint32 QXmppRtcpSenderInfo::rtpStamp() const
-{
- return d->rtpStamp;
-}
-
-void QXmppRtcpSenderInfo::setRtpStamp(quint32 rtpStamp)
-{
- d->rtpStamp = rtpStamp;
-}
-
-quint32 QXmppRtcpSenderInfo::octetCount() const
-{
- return d->octetCount;
-}
-
-void QXmppRtcpSenderInfo::setOctetCount(quint32 count)
-{
- d->octetCount = count;
-}
-
-quint32 QXmppRtcpSenderInfo::packetCount() const
-{
- return d->packetCount;
-}
-
-void QXmppRtcpSenderInfo::setPacketCount(quint32 count)
-{
- d->packetCount = count;
-}
-
-QXmppRtcpSenderInfoPrivate::QXmppRtcpSenderInfoPrivate()
- : ntpStamp(0), rtpStamp(0), packetCount(0), octetCount(0)
-{
-}
-
-bool QXmppRtcpSenderInfoPrivate::read(QDataStream &stream)
-{
- stream >> ntpStamp;
- stream >> rtpStamp;
- stream >> packetCount;
- stream >> octetCount;
- return stream.status() == QDataStream::Ok;
-}
-
-void QXmppRtcpSenderInfoPrivate::write(QDataStream &stream) const
-{
- stream << ntpStamp;
- stream << rtpStamp;
- stream << packetCount;
- stream << octetCount;
-}
-
-/// Constructs an empty source description
-
-QXmppRtcpSourceDescription::QXmppRtcpSourceDescription()
- : d(new QXmppRtcpSourceDescriptionPrivate())
-{
-}
-
-/// Constructs a copy of other.
-///
-/// \param other
-
-QXmppRtcpSourceDescription::QXmppRtcpSourceDescription(const QXmppRtcpSourceDescription &other)
- : d(other.d)
-{
-}
-
-QXmppRtcpSourceDescription::~QXmppRtcpSourceDescription()
-{
-}
-
-QString QXmppRtcpSourceDescription::cname() const
-{
- return d->cname;
-}
-
-void QXmppRtcpSourceDescription::setCname(const QString &cname)
-{
- d->cname = cname;
-}
-
-QString QXmppRtcpSourceDescription::name() const
-{
- return d->name;
-}
-
-void QXmppRtcpSourceDescription::setName(const QString &name)
-{
- d->name = name;
-}
-
-quint32 QXmppRtcpSourceDescription::ssrc() const
-{
- return d->ssrc;
-}
-
-void QXmppRtcpSourceDescription::setSsrc(quint32 ssrc)
-{
- d->ssrc = ssrc;
-}
-
-QXmppRtcpSourceDescriptionPrivate::QXmppRtcpSourceDescriptionPrivate()
- : ssrc(0)
-{
-}
-
-bool QXmppRtcpSourceDescriptionPrivate::read(QDataStream &stream)
-{
- QByteArray buffer;
- quint8 itemType, itemLength;
- quint16 chunkLength = 0;
-
- stream >> ssrc;
- if (stream.status() != QDataStream::Ok)
- return false;
- while (true) {
- stream >> itemType;
- if (stream.status() != QDataStream::Ok)
- return false;
- if (!itemType) {
- chunkLength++;
- break;
- }
-
- stream >> itemLength;
- if (stream.status() != QDataStream::Ok)
- return false;
-
- buffer.resize(itemLength);
- if (stream.readRawData(buffer.data(), itemLength) != itemLength)
- return false;
- chunkLength += itemLength + 2;
-
- if (itemType == CnameType)
- cname = QString::fromUtf8(buffer);
- else if (itemType == NameType)
- name = QString::fromUtf8(buffer);
- }
- return readPadding(stream, chunkLength);
-}
-
-void QXmppRtcpSourceDescriptionPrivate::write(QDataStream &stream) const
-{
- QByteArray buffer;
- quint16 chunkLength = 0;
-
- stream << ssrc;
- if (!cname.isEmpty()) {
- buffer = cname.toUtf8();
- stream << quint8(CnameType);
- stream << quint8(buffer.size());
- stream.writeRawData(buffer.constData(), buffer.size());
- chunkLength += 2 + buffer.size();
- }
- if (!name.isEmpty()) {
- buffer = name.toUtf8();
- stream << quint8(NameType);
- stream << quint8(buffer.size());
- stream.writeRawData(buffer.constData(), buffer.size());
- chunkLength += 2 + buffer.size();
- }
- stream << quint8(0);
- chunkLength++;
- writePadding(stream, chunkLength);
-}
diff --git a/src/base/QXmppRtcpPacket.h b/src/base/QXmppRtcpPacket.h
deleted file mode 100644
index a2041672..00000000
--- a/src/base/QXmppRtcpPacket.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2008-2020 The QXmpp developers
- *
- * Author:
- * Jeremy Lainé
- *
- * Source:
- * https://github.com/qxmpp-project/qxmpp
- *
- * This file is a part of QXmpp library.
- *
- * This library 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.
- *
- * This library 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.
- *
- */
-
-#ifndef QXMPPRTCPPACKET_H
-#define QXMPPRTCPPACKET_H
-
-#include "QXmppGlobal.h"
-
-#include <QSharedDataPointer>
-
-class QXmppRtcpPacketPrivate;
-class QXmppRtcpReceiverReport;
-class QXmppRtcpReceiverReportPrivate;
-class QXmppRtcpSenderInfo;
-class QXmppRtcpSenderInfoPrivate;
-class QXmppRtcpSourceDescription;
-class QXmppRtcpSourceDescriptionPrivate;
-
-/// \internal
-///
-/// The QXmppRtcpPacket class represents an RTCP packet.
-
-class QXMPP_EXPORT QXmppRtcpPacket
-{
-public:
- enum Type {
- SenderReport = 200,
- ReceiverReport = 201,
- SourceDescription = 202,
- Goodbye = 203,
- };
-
- QXmppRtcpPacket();
- QXmppRtcpPacket(const QXmppRtcpPacket &other);
- ~QXmppRtcpPacket();
-
- bool decode(const QByteArray &ba);
- QByteArray encode() const;
-
- bool read(QDataStream &stream);
- void write(QDataStream &stream) const;
-
- QString goodbyeReason() const;
- void setGoodbyeReason(const QString &goodbyeReason);
-
- QList<quint32> goodbyeSsrcs() const;
- void setGoodbyeSsrcs(const QList<quint32> &goodbyeSsrcs);
-
- QList<QXmppRtcpReceiverReport> receiverReports() const;
- void setReceiverReports(const QList<QXmppRtcpReceiverReport> &reports);
-
- QXmppRtcpSenderInfo senderInfo() const;
- void setSenderInfo(const QXmppRtcpSenderInfo &senderInfo);
-
- QList<QXmppRtcpSourceDescription> sourceDescriptions() const;
- void setSourceDescriptions(const QList<QXmppRtcpSourceDescription> &descriptions);
-
- quint32 ssrc() const;
- void setSsrc(quint32 ssrc);
-
- quint8 type() const;
- void setType(quint8 type);
-
-private:
- QSharedDataPointer<QXmppRtcpPacketPrivate> d;
-};
-
-/// \internal
-
-class QXMPP_EXPORT QXmppRtcpReceiverReport
-{
-public:
- QXmppRtcpReceiverReport();
- QXmppRtcpReceiverReport(const QXmppRtcpReceiverReport &other);
- ~QXmppRtcpReceiverReport();
-
- quint32 dlsr() const;
- void setDlsr(quint32 dlsr);
-
- quint8 fractionLost() const;
- void setFractionLost(quint8 fractionLost);
-
- quint32 jitter() const;
- void setJitter(quint32 jitter);
-
- quint32 lsr() const;
- void setLsr(quint32 lsr);
-
- quint32 ssrc() const;
- void setSsrc(quint32 ssrc);
-
- quint32 totalLost() const;
- void setTotalLost(quint32 totalLost);
-
-private:
- friend class QXmppRtcpPacket;
- QSharedDataPointer<QXmppRtcpReceiverReportPrivate> d;
-};
-
-/// \internal
-
-class QXMPP_EXPORT QXmppRtcpSenderInfo
-{
-public:
- QXmppRtcpSenderInfo();
- QXmppRtcpSenderInfo(const QXmppRtcpSenderInfo &other);
- ~QXmppRtcpSenderInfo();
-
- quint64 ntpStamp() const;
- void setNtpStamp(quint64 ntpStamp);
-
- quint32 rtpStamp() const;
- void setRtpStamp(quint32 rtpStamp);
-
- quint32 octetCount() const;
- void setOctetCount(quint32 count);
-
- quint32 packetCount() const;
- void setPacketCount(quint32 count);
-
-private:
- friend class QXmppRtcpPacket;
- QSharedDataPointer<QXmppRtcpSenderInfoPrivate> d;
-};
-
-/// \internal
-
-class QXMPP_EXPORT QXmppRtcpSourceDescription
-{
-public:
- QXmppRtcpSourceDescription();
- QXmppRtcpSourceDescription(const QXmppRtcpSourceDescription &other);
- ~QXmppRtcpSourceDescription();
-
- QString cname() const;
- void setCname(const QString &name);
-
- QString name() const;
- void setName(const QString &name);
-
- quint32 ssrc() const;
- void setSsrc(const quint32 ssrc);
-
-private:
- friend class QXmppRtcpPacket;
- QSharedDataPointer<QXmppRtcpSourceDescriptionPrivate> d;
-};
-
-#endif
diff --git a/src/base/QXmppRtpChannel.cpp b/src/base/QXmppRtpChannel.cpp
deleted file mode 100644
index 848cd3d3..00000000
--- a/src/base/QXmppRtpChannel.cpp
+++ /dev/null
@@ -1,999 +0,0 @@
-/*
- * Copyright (C) 2008-2020 The QXmpp developers
- *
- * Author:
- * Jeremy Lainé
- *
- * Source:
- * https://github.com/qxmpp-project/qxmpp
- *
- * This file is a part of QXmpp library.
- *
- * This library 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.
- *
- * This library 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.
- *
- */
-
-#include "QXmppRtpChannel.h"
-
-#include "QXmppCodec_p.h"
-#include "QXmppJingleIq.h"
-#include "QXmppRtpPacket.h"
-
-#include <cmath>
-
-#include <QDataStream>
-#include <QMetaType>
-#include <QTimer>
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846264338327950288
-#endif
-
-//#define QXMPP_DEBUG_RTP
-//#define QXMPP_DEBUG_RTP_BUFFER
-#define SAMPLE_BYTES 2
-
-/// Creates a new RTP channel.
-
-QXmppRtpChannel::QXmppRtpChannel()
- : m_outgoingPayloadNumbered(false)
-{
- m_outgoingSsrc = qrand();
-}
-
-/// Returns the local payload types.
-///
-
-QList<QXmppJinglePayloadType> QXmppRtpChannel::localPayloadTypes()
-{
- m_outgoingPayloadNumbered = true;
- return m_outgoingPayloadTypes;
-}
-
-/// Sets the remote payload types.
-///
-/// \param remotePayloadTypes
-
-void QXmppRtpChannel::setRemotePayloadTypes(const QList<QXmppJinglePayloadType> &remotePayloadTypes)
-{
- QList<QXmppJinglePayloadType> commonOutgoingTypes;
- QList<QXmppJinglePayloadType> commonIncomingTypes;
-
- for (const auto &incomingType : remotePayloadTypes) {
- // check we support this payload type
- int outgoingIndex = m_outgoingPayloadTypes.indexOf(incomingType);
- if (outgoingIndex < 0)
- continue;
- QXmppJinglePayloadType outgoingType = m_outgoingPayloadTypes[outgoingIndex];
-
- // be kind and try to adopt the other agent's numbering
- if (!m_outgoingPayloadNumbered && outgoingType.id() > 95) {
- outgoingType.setId(incomingType.id());
- }
- commonIncomingTypes << incomingType;
- commonOutgoingTypes << outgoingType;
- }
- if (commonOutgoingTypes.isEmpty()) {
- qWarning("QXmppRtpChannel could not negotiate a common codec");
- return;
- }
- m_incomingPayloadTypes = commonIncomingTypes;
- m_outgoingPayloadTypes = commonOutgoingTypes;
- m_outgoingPayloadNumbered = true;
-
- // call hook
- payloadTypesChanged();
-}
-
-/// Returns the local SSRC.
-
-quint32 QXmppRtpChannel::localSsrc() const
-{
- return m_outgoingSsrc;
-}
-
-/// Sets the local SSRC.
-///
-/// \param ssrc
-
-void QXmppRtpChannel::setLocalSsrc(quint32 ssrc)
-{
- m_outgoingSsrc = ssrc;
-}
-
-enum CodecId {
- G711u = 0,
- GSM = 3,
- G723 = 4,
- G711a = 8,
- G722 = 9,
- L16Stereo = 10,
- L16Mono = 11,
- G728 = 15,
- G729 = 18
-};
-
-struct ToneInfo {
- QXmppRtpAudioChannel::Tone tone;
- quint32 incomingStart;
- quint32 outgoingStart;
- bool finished;
-};
-
-static QPair<int, int> toneFreqs(QXmppRtpAudioChannel::Tone tone)
-{
- switch (tone) {
- case QXmppRtpAudioChannel::Tone_1:
- return qMakePair(697, 1209);
- case QXmppRtpAudioChannel::Tone_2:
- return qMakePair(697, 1336);
- case QXmppRtpAudioChannel::Tone_3:
- return qMakePair(697, 1477);
- case QXmppRtpAudioChannel::Tone_A:
- return qMakePair(697, 1633);
- case QXmppRtpAudioChannel::Tone_4:
- return qMakePair(770, 1209);
- case QXmppRtpAudioChannel::Tone_5:
- return qMakePair(770, 1336);
- case QXmppRtpAudioChannel::Tone_6:
- return qMakePair(770, 1477);
- case QXmppRtpAudioChannel::Tone_B:
- return qMakePair(770, 1633);
- case QXmppRtpAudioChannel::Tone_7:
- return qMakePair(852, 1209);
- case QXmppRtpAudioChannel::Tone_8:
- return qMakePair(852, 1336);
- case QXmppRtpAudioChannel::Tone_9:
- return qMakePair(852, 1477);
- case QXmppRtpAudioChannel::Tone_C:
- return qMakePair(852, 1633);
- case QXmppRtpAudioChannel::Tone_Star:
- return qMakePair(941, 1209);
- case QXmppRtpAudioChannel::Tone_0:
- return qMakePair(941, 1336);
- case QXmppRtpAudioChannel::Tone_Pound:
- return qMakePair(941, 1477);
- case QXmppRtpAudioChannel::Tone_D:
- return qMakePair(941, 1633);
- }
- return qMakePair(0, 0);
-}
-
-QByteArray renderTone(QXmppRtpAudioChannel::Tone tone, int clockrate, quint32 clockTick, qint64 samples)
-{
- QPair<int, int> tf = toneFreqs(tone);
- const float clockMult = 2.0 * M_PI / float(clockrate);
- QByteArray chunk;
- chunk.reserve(samples * SAMPLE_BYTES);
- QDataStream output(&chunk, QIODevice::WriteOnly);
- output.setByteOrder(QDataStream::LittleEndian);
- for (quint32 i = 0; i < samples; ++i) {
- quint16 val = 16383.0 * (sin(clockMult * clockTick * tf.first) + sin(clockMult * clockTick * tf.second));
- output << val;
- clockTick++;
- }
- return chunk;
-}
-
-class QXmppRtpAudioChannelPrivate
-{
-public:
- QXmppRtpAudioChannelPrivate();
- QXmppCodec *codecForPayloadType(const QXmppJinglePayloadType &payloadType);
-
- // signals
- bool signalsEmitted;
- qint64 writtenSinceLastEmit;
-
- // RTP
- QHostAddress remoteHost;
- quint16 remotePort;
-
- QByteArray incomingBuffer;
- bool incomingBuffering;
- QMap<int, QXmppCodec *> incomingCodecs;
- int incomingMinimum;
- int incomingMaximum;
- // position of the head of the incoming buffer, in bytes
- qint64 incomingPos;
- quint16 incomingSequence;
-
- QByteArray outgoingBuffer;
- quint16 outgoingChunk;
- QXmppCodec *outgoingCodec;
- bool outgoingMarker;
- bool outgoingPayloadNumbered;
- quint16 outgoingSequence;
- quint32 outgoingStamp;
- QTimer *outgoingTimer;
- QList<ToneInfo> outgoingTones;
- QXmppJinglePayloadType outgoingTonesType;
-
- QXmppJinglePayloadType payloadType;
-};
-
-QXmppRtpAudioChannelPrivate::QXmppRtpAudioChannelPrivate()
- : signalsEmitted(false), writtenSinceLastEmit(0), incomingBuffering(true), incomingMinimum(0), incomingMaximum(0), incomingPos(0), incomingSequence(0), outgoingCodec(nullptr), outgoingMarker(true), outgoingPayloadNumbered(false), outgoingSequence(1), outgoingStamp(0), outgoingTimer(nullptr)
-{
- qRegisterMetaType<QXmppRtpAudioChannel::Tone>("QXmppRtpAudioChannel::Tone");
-}
-
-/// Returns the audio codec for the given payload type.
-///
-
-QXmppCodec *QXmppRtpAudioChannelPrivate::codecForPayloadType(const QXmppJinglePayloadType &payloadType)
-{
- if (payloadType.id() == G711u)
- return new QXmppG711uCodec(payloadType.clockrate());
- else if (payloadType.id() == G711a)
- return new QXmppG711aCodec(payloadType.clockrate());
-#ifdef QXMPP_USE_SPEEX
- else if (payloadType.name().toLower() == "speex")
- return new QXmppSpeexCodec(payloadType.clockrate());
-#endif
-#ifdef QXMPP_USE_OPUS
- else if (payloadType.name().toLower() == "opus")
- return new QXmppOpusCodec(payloadType.clockrate(), payloadType.channels());
-#endif
- return nullptr;
-}
-
-/// Constructs a new RTP audio channel with the given \a parent.
-
-QXmppRtpAudioChannel::QXmppRtpAudioChannel(QObject *parent)
- : QIODevice(parent), d(new QXmppRtpAudioChannelPrivate())
-{
- auto *logParent = qobject_cast<QXmppLoggable *>(parent);
- if (logParent) {
- connect(this, &QXmppRtpAudioChannel::logMessage,
- logParent, &QXmppLoggable::logMessage);
- }
- d->outgoingTimer = new QTimer(this);
- connect(d->outgoingTimer, &QTimer::timeout, this, &QXmppRtpAudioChannel::writeDatagram);
-
- // set supported codecs
- QXmppJinglePayloadType payload;
-
-#ifdef QXMPP_USE_OPUS
- payload.setId(100); // NOTE: I don't know if this Id is ok for Opus.
- payload.setChannels(1);
- payload.setName("opus");
- payload.setClockrate(8000);
- m_outgoingPayloadTypes << payload;
-#endif
-
-#ifdef QXMPP_USE_SPEEX
- payload.setId(96);
- payload.setChannels(1);
- payload.setName("speex");
- payload.setClockrate(8000);
- m_outgoingPayloadTypes << payload;
-#endif
-
- payload.setId(G711u);
- payload.setChannels(1);
- payload.setName("PCMU");
- payload.setClockrate(8000);
- m_outgoingPayloadTypes << payload;
-
- payload.setId(G711a);
- payload.setChannels(1);
- payload.setName("PCMA");
- payload.setClockrate(8000);
- m_outgoingPayloadTypes << payload;
-
- QMap<QString, QString> parameters;
- parameters.insert("events", "0-15");
- payload.setId(101);
- payload.setChannels(1);
- payload.setName("telephone-event");
- payload.setClockrate(8000);
- payload.setParameters(parameters);
- m_outgoingPayloadTypes << payload;
-}
-
-/// Destroys an RTP audio channel.
-///
-
-QXmppRtpAudioChannel::~QXmppRtpAudioChannel()
-{
- qDeleteAll(d->incomingCodecs);
-
- if (d->outgoingCodec)
- delete d->outgoingCodec;
- delete d;
-}
-
-/// Returns the number of bytes that are available for reading.
-
-qint64 QXmppRtpAudioChannel::bytesAvailable() const
-{
- return QIODevice::bytesAvailable() + d->incomingBuffer.size();
-}
-
-/// Closes the RTP audio channel.
-
-void QXmppRtpAudioChannel::close()
-{
- d->outgoingTimer->stop();
- QIODevice::close();
-}
-
-/// Processes an incoming RTP packet.
-///
-/// \param ba
-
-void QXmppRtpAudioChannel::datagramReceived(const QByteArray &ba)
-{
- QXmppRtpPacket packet;
- if (!packet.decode(ba))
- return;
-
-#ifdef QXMPP_DEBUG_RTP
- logReceived(packet.toString());
-#endif
-
- // check sequence number
-#if 0
- if (d->incomingSequence && packet.sequence() != d->incomingSequence + 1)
- warning(QString("RTP packet seq %1 is out of order, previous was %2")
- .arg(QString::number(packet.sequence()))
- .arg(QString::number(d->incomingSequence)));
-#endif
- d->incomingSequence = packet.sequence();
-
- // get or create codec
- QXmppCodec *codec = nullptr;
- const quint8 packetType = packet.type();
- if (!d->incomingCodecs.contains(packetType)) {
- for (const auto &payload : m_incomingPayloadTypes) {
- if (packetType == payload.id()) {
- codec = d->codecForPayloadType(payload);
- break;
- }
- }
- if (codec)
- d->incomingCodecs.insert(packetType, codec);
- else
- warning(QString("Could not find codec for RTP type %1").arg(QString::number(packetType)));
- } else {
- codec = d->incomingCodecs.value(packetType);
- }
- if (!codec)
- return;
-
- // determine packet's position in the buffer (in bytes)
- qint64 packetOffset = 0;
- if (!d->incomingBuffer.isEmpty()) {
- packetOffset = packet.stamp() * SAMPLE_BYTES - d->incomingPos;
- if (packetOffset < 0) {
-#ifdef QXMPP_DEBUG_RTP_BUFFER
- warning(QString("RTP packet stamp %1 is too old, buffer start is %2")
- .arg(QString::number(packet.stamp()))
- .arg(QString::number(d->incomingPos)));
-#endif
- return;
- }
- } else {
- d->incomingPos = packet.stamp() * SAMPLE_BYTES + (d->incomingPos % SAMPLE_BYTES);
- }
-
- // allocate space for new packet
- // FIXME: this is wrong, we want the decoded data size!
- const qint64 packetLength = packet.payload().size();
- if (packetOffset + packetLength > d->incomingBuffer.size())
- d->incomingBuffer += QByteArray(packetOffset + packetLength - d->incomingBuffer.size(), 0);
- QDataStream input(packet.payload());
- QDataStream output(&d->incomingBuffer, QIODevice::WriteOnly);
- output.device()->seek(packetOffset);
- output.setByteOrder(QDataStream::LittleEndian);
- codec->decode(input, output);
-
- // check whether we are running late
- if (d->incomingBuffer.size() > d->incomingMaximum) {
- qint64 droppedSize = d->incomingBuffer.size() - d->incomingMinimum;
- const int remainder = droppedSize % SAMPLE_BYTES;
- if (remainder)
- droppedSize -= remainder;
-#ifdef QXMPP_DEBUG_RTP_BUFFER
- warning(QString("Incoming RTP buffer is too full, dropping %1 bytes")
- .arg(QString::number(droppedSize)));
-#endif
- d->incomingBuffer.remove(0, droppedSize);
- d->incomingPos += droppedSize;
- }
- // check whether we have filled the initial buffer
- if (d->incomingBuffer.size() >= d->incomingMinimum)
- d->incomingBuffering = false;
- if (!d->incomingBuffering)
- emit readyRead();
-}
-
-void QXmppRtpAudioChannel::emitSignals()
-{
- emit bytesWritten(d->writtenSinceLastEmit);
- d->writtenSinceLastEmit = 0;
- d->signalsEmitted = false;
-}
-
-/// Returns true, as the RTP channel is a sequential device.
-///
-
-bool QXmppRtpAudioChannel::isSequential() const
-{
- return true;
-}
-
-/// Returns the mode in which the channel has been opened.
-
-QIODevice::OpenMode QXmppRtpAudioChannel::openMode() const
-{
- return QIODevice::openMode();
-}
-
-/// Returns the RTP channel's payload type.
-///
-/// You can use this to determine the QAudioFormat to use with your
-/// QAudioInput/QAudioOutput.
-
-QXmppJinglePayloadType QXmppRtpAudioChannel::payloadType() const
-{
- return d->payloadType;
-}
-
-/// \cond
-qint64 QXmppRtpAudioChannel::readData(char *data, qint64 maxSize)
-{
- // if we are filling the buffer, return empty samples
- if (d->incomingBuffering) {
- // FIXME: if we are asked for a non-integer number of samples,
- // we will return junk on next read as we don't increment d->incomingPos
- memset(data, 0, maxSize);
- return maxSize;
- }
-
- qint64 readSize = qMin(maxSize, qint64(d->incomingBuffer.size()));
- memcpy(data, d->incomingBuffer.constData(), readSize);
- d->incomingBuffer.remove(0, readSize);
- if (readSize < maxSize) {
-#ifdef QXMPP_DEBUG_RTP
- debug(QString("QXmppRtpAudioChannel::readData missing %1 bytes").arg(QString::number(maxSize - readSize)));
-#endif
- memset(data + readSize, 0, maxSize - readSize);
- }
-
- // add local DTMF echo
- if (!d->outgoingTones.isEmpty()) {
- const int headOffset = d->incomingPos % SAMPLE_BYTES;
- const int samples = (headOffset + maxSize + SAMPLE_BYTES - 1) / SAMPLE_BYTES;
- const QByteArray chunk = renderTone(
- d->outgoingTones[0].tone,
- d->payloadType.clockrate(),
- d->incomingPos / SAMPLE_BYTES - d->outgoingTones[0].incomingStart,
- samples);
- memcpy(data, chunk.constData() + headOffset, maxSize);
- }
-
- d->incomingPos += maxSize;
- return maxSize;
-}
-
-void QXmppRtpAudioChannel::payloadTypesChanged()
-{
- // delete incoming codecs
- qDeleteAll(d->incomingCodecs);
-
- // delete outgoing codec
- if (d->outgoingCodec) {
- delete d->outgoingCodec;
- d->outgoingCodec = nullptr;
- }
-
- // create outgoing codec
- for (const auto &outgoingType : m_outgoingPayloadTypes) {
- // check for telephony events
- if (outgoingType.name() == "telephone-event") {
- d->outgoingTonesType = outgoingType;
- } else if (!d->outgoingCodec) {
- QXmppCodec *codec = d->codecForPayloadType(outgoingType);
- if (codec) {
- d->payloadType = outgoingType;
- d->outgoingCodec = codec;
- }
- }
- }
-
- // size in bytes of an decoded packet
- d->outgoingChunk = SAMPLE_BYTES * d->payloadType.ptime() * d->payloadType.clockrate() / 1000;
- d->outgoingTimer->setInterval(d->payloadType.ptime());
-
- d->incomingMinimum = d->outgoingChunk * 5;
- d->incomingMaximum = d->outgoingChunk * 15;
-
- open(QIODevice::ReadWrite | QIODevice::Unbuffered);
-}
-/// \endcond
-
-/// Returns the position in the received audio data.
-
-qint64 QXmppRtpAudioChannel::pos() const
-{
- return d->incomingPos;
-}
-
-/// Seeks in the received audio data.
-///
-/// Seeking backwards will result in empty samples being added at the start
-/// of the buffer.
-///
-/// \param pos
-
-bool QXmppRtpAudioChannel::seek(qint64 pos)
-{
- qint64 delta = pos - d->incomingPos;
- if (delta < 0)
- d->incomingBuffer.prepend(QByteArray(-delta, 0));
- else
- d->incomingBuffer.remove(0, delta);
- d->incomingPos = pos;
- return true;
-}
-
-/// Starts sending the specified DTMF tone.
-///
-/// \param tone
-
-void QXmppRtpAudioChannel::startTone(QXmppRtpAudioChannel::Tone tone)
-{
- ToneInfo info;
- info.tone = tone;
- info.incomingStart = d->incomingPos / SAMPLE_BYTES;
- info.outgoingStart = d->outgoingStamp;
- info.finished = false;
- d->outgoingTones << info;
-}
-
-/// Stops sending the specified DTMF tone.
-///
-/// \param tone
-
-void QXmppRtpAudioChannel::stopTone(QXmppRtpAudioChannel::Tone tone)
-{
- for (auto &outgoingTone : d->outgoingTones) {
- if (outgoingTone.tone == tone) {
- outgoingTone.finished = true;
- break;
- }
- }
-}
-
-/// \cond
-qint64 QXmppRtpAudioChannel::writeData(const char *data, qint64 maxSize)
-{
- if (!d->outgoingCodec) {
- warning("QXmppRtpAudioChannel::writeData before codec was set");
- return -1;
- }
-
- d->outgoingBuffer += QByteArray::fromRawData(data, maxSize);
-
- // start sending audio chunks
- if (!d->outgoingTimer->isActive())
- d->outgoingTimer->start();
-
- return maxSize;
-}
-/// \endcond
-
-void QXmppRtpAudioChannel::writeDatagram()
-{
- // read audio chunk
- QByteArray chunk;
- if (d->outgoingBuffer.size() < d->outgoingChunk) {
-#ifdef QXMPP_DEBUG_RTP_BUFFER
- warning("Outgoing RTP buffer is starved");
-#endif
- chunk = QByteArray(d->outgoingChunk, 0);
- } else {
- chunk = d->outgoingBuffer.left(d->outgoingChunk);
- d->outgoingBuffer.remove(0, d->outgoingChunk);
- }
-
- bool sendAudio = true;
- if (!d->outgoingTones.isEmpty()) {
- const quint32 packetTicks = (d->payloadType.clockrate() * d->payloadType.ptime()) / 1000;
- const ToneInfo info = d->outgoingTones[0];
-
- if (d->outgoingTonesType.id()) {
- // send RFC 2833 DTMF
- QXmppRtpPacket packet;
- packet.setMarker(info.outgoingStart == d->outgoingStamp);
- packet.setType(d->outgoingTonesType.id());
- packet.setSequence(d->outgoingSequence);
- packet.setStamp(info.outgoingStart);
- packet.setSsrc(localSsrc());
-
- QByteArray payload;
- QDataStream output(&payload, QIODevice::WriteOnly);
- output << quint8(info.tone);
- output << quint8(info.finished ? 0x80 : 0x00);
- output << quint16(d->outgoingStamp + packetTicks - info.outgoingStart);
- packet.setPayload(payload);
-#ifdef QXMPP_DEBUG_RTP
- logSent(packet.toString());
-#endif
- emit sendDatagram(packet.encode());
- d->outgoingSequence++;
- d->outgoingStamp += packetTicks;
-
- sendAudio = false;
- } else {
- // generate in-band DTMF
- chunk = renderTone(info.tone, d->payloadType.clockrate(), d->outgoingStamp - info.outgoingStart, packetTicks);
- }
-
- // if the tone is finished, remove it
- if (info.finished)
- d->outgoingTones.removeFirst();
- }
-
- if (sendAudio) {
- // send audio data
- QXmppRtpPacket packet;
- if (d->outgoingMarker) {
- packet.setMarker(true);
- d->outgoingMarker = false;
- } else {
- packet.setMarker(false);
- }
- packet.setType(d->payloadType.id());
- packet.setSequence(d->outgoingSequence);
- packet.setStamp(d->outgoingStamp);
- packet.setSsrc(localSsrc());
-
- // encode audio chunk
- QDataStream input(chunk);
- input.setByteOrder(QDataStream::LittleEndian);
- QByteArray payload;
- QDataStream output(&payload, QIODevice::WriteOnly);
- const qint64 packetTicks = d->outgoingCodec->encode(input, output);
- packet.setPayload(payload);
-
-#ifdef QXMPP_DEBUG_RTP
- logSent(packet.toString());
-#endif
- emit sendDatagram(packet.encode());
- d->outgoingSequence++;
- d->outgoingStamp += packetTicks;
- }
-
- // queue signals
- d->writtenSinceLastEmit += chunk.size();
- if (!d->signalsEmitted && !signalsBlocked()) {
- d->signalsEmitted = true;
- QMetaObject::invokeMethod(this, "emitSignals", Qt::QueuedConnection);
- }
-}
-
-/** Constructs a null video frame.
- */
-QXmppVideoFrame::QXmppVideoFrame()
- : m_bytesPerLine(0),
- m_height(0),
- m_mappedBytes(0),
- m_pixelFormat(Format_Invalid),
- m_width(0)
-{
-}
-
-/** Constructs a video frame of the given pixel format and size in pixels.
- *
- * @param bytes
- * @param size
- * @param bytesPerLine
- * @param format
- */
-QXmppVideoFrame::QXmppVideoFrame(int bytes, const QSize &size, int bytesPerLine, PixelFormat format)
- : m_bytesPerLine(bytesPerLine),
- m_height(size.height()),
- m_mappedBytes(bytes),
- m_pixelFormat(format),
- m_width(size.width())
-{
- m_data.resize(bytes);
-}
-
-/// Returns a pointer to the start of the frame data buffer.
-
-uchar *QXmppVideoFrame::bits()
-{
- return (uchar *)m_data.data();
-}
-
-/// Returns a pointer to the start of the frame data buffer.
-
-const uchar *QXmppVideoFrame::bits() const
-{
- return (const uchar *)m_data.constData();
-}
-
-/// Returns the number of bytes in a scan line.
-
-int QXmppVideoFrame::bytesPerLine() const
-{
- return m_bytesPerLine;
-}
-
-/// Returns the height of a video frame.
-
-int QXmppVideoFrame::height() const
-{
- return m_height;
-}
-
-/// Returns true if the frame is valid.
-
-bool QXmppVideoFrame::isValid() const
-{
- return m_pixelFormat != Format_Invalid &&
- m_height > 0 && m_width > 0 &&
- m_mappedBytes > 0;
-}
-
-/// Returns the number of bytes occupied by the mapped frame data.
-
-int QXmppVideoFrame::mappedBytes() const
-{
- return m_mappedBytes;
-}
-
-/// Returns the color format of a video frame.
-
-QXmppVideoFrame::PixelFormat QXmppVideoFrame::pixelFormat() const
-{
- return m_pixelFormat;
-}
-
-/// Returns the size of a video frame.
-
-QSize QXmppVideoFrame::size() const
-{
- return QSize(m_width, m_height);
-}
-
-/// Returns the width of a video frame.
-
-int QXmppVideoFrame::width() const
-{
- return m_width;
-}
-
-class QXmppRtpVideoChannelPrivate
-{
-public:
- QXmppRtpVideoChannelPrivate();
- QMap<int, QXmppVideoDecoder *> decoders;
- QXmppVideoEncoder *encoder;
- QList<QXmppVideoFrame> frames;
-
- // local
- QXmppVideoFormat outgoingFormat;
- quint8 outgoingId;
- quint16 outgoingSequence;
- quint32 outgoingStamp;
-};
-
-QXmppRtpVideoChannelPrivate::QXmppRtpVideoChannelPrivate()
- : encoder(nullptr),
- outgoingId(0),
- outgoingSequence(1),
- outgoingStamp(0)
-{
-}
-
-/// Constructs a new RTP video channel with the given \a parent.
-
-QXmppRtpVideoChannel::QXmppRtpVideoChannel(QObject *parent)
- : QXmppLoggable(parent)
-{
- d = new QXmppRtpVideoChannelPrivate;
- d->outgoingFormat.setFrameRate(15.0);
- d->outgoingFormat.setFrameSize(QSize(320, 240));
- d->outgoingFormat.setPixelFormat(QXmppVideoFrame::Format_YUYV);
-
- // set supported codecs
- QXmppVideoEncoder *encoder;
- QXmppJinglePayloadType payload;
- Q_UNUSED(encoder);
- Q_UNUSED(payload);
-
-#ifdef QXMPP_USE_VPX
- encoder = new QXmppVpxEncoder;
- encoder->setFormat(d->outgoingFormat);
- payload.setId(96);
- payload.setName("vp8");
- payload.setClockrate(256000);
- payload.setParameters(encoder->parameters());
- m_outgoingPayloadTypes << payload;
- delete encoder;
-#endif
-
-#ifdef QXMPP_USE_THEORA
- encoder = new QXmppTheoraEncoder;
- encoder->setFormat(d->outgoingFormat);
- payload.setId(97);
- payload.setName("theora");
- payload.setClockrate(90000);
- payload.setParameters(encoder->parameters());
- m_outgoingPayloadTypes << payload;
- delete encoder;
-#endif
-}
-
-QXmppRtpVideoChannel::~QXmppRtpVideoChannel()
-{
- qDeleteAll(d->decoders);
- if (d->encoder)
- delete d->encoder;
- delete d;
-}
-
-/// Closes the RTP video channel.
-
-void QXmppRtpVideoChannel::close()
-{
-}
-
-/// Processes an incoming RTP video packet.
-///
-/// \param ba
-
-void QXmppRtpVideoChannel::datagramReceived(const QByteArray &ba)
-{
- QXmppRtpPacket packet;
- if (!packet.decode(ba))
- return;
-
-#ifdef QXMPP_DEBUG_RTP
- logReceived(packet.toString());
-#endif
-
- // get codec
- QXmppVideoDecoder *decoder = d->decoders.value(packet.type());
- if (!decoder)
- return;
- d->frames << decoder->handlePacket(packet);
-}
-
-/// Returns the video format used by the encoder.
-
-QXmppVideoFormat QXmppRtpVideoChannel::decoderFormat() const
-{
- if (d->decoders.isEmpty())
- return QXmppVideoFormat();
- const int key = d->decoders.keys().first();
- return d->decoders.value(key)->format();
-}
-
-/// Returns the video format used by the encoder.
-
-QXmppVideoFormat QXmppRtpVideoChannel::encoderFormat() const
-{
- return d->outgoingFormat;
-}
-
-/// Sets the video format used by the encoder.
-
-void QXmppRtpVideoChannel::setEncoderFormat(const QXmppVideoFormat &format)
-{
- if (d->encoder && !d->encoder->setFormat(format))
- return;
- d->outgoingFormat = format;
-}
-
-/// Returns the mode in which the channel has been opened.
-
-QIODevice::OpenMode QXmppRtpVideoChannel::openMode() const
-{
- QIODevice::OpenMode mode = QIODevice::NotOpen;
- if (!d->decoders.isEmpty())
- mode |= QIODevice::ReadOnly;
- if (d->encoder)
- mode |= QIODevice::WriteOnly;
- return mode;
-}
-
-/// \cond
-void QXmppRtpVideoChannel::payloadTypesChanged()
-{
- // refresh decoders
- qDeleteAll(d->decoders);
- d->decoders.clear();
-
- for (const auto &payload : qAsConst(m_incomingPayloadTypes)) {
- QXmppVideoDecoder *decoder = nullptr;
- if (false) {
- }
-#ifdef QXMPP_USE_THEORA
- else if (payload.name().toLower() == "theora")
- decoder = new QXmppTheoraDecoder;
-#endif
-#ifdef QXMPP_USE_VPX
- else if (payload.name().toLower() == "vp8")
- decoder = new QXmppVpxDecoder;
-#endif
- if (decoder) {
- decoder->setParameters(payload.parameters());
- d->decoders.insert(payload.id(), decoder);
- }
- }
-
- // refresh encoder
- if (d->encoder) {
- delete d->encoder;
- d->encoder = nullptr;
- }
- for (const auto &payload : m_outgoingPayloadTypes) {
- QXmppVideoEncoder *encoder = nullptr;
- if (false) {
- }
-#ifdef QXMPP_USE_THEORA
- else if (payload.name().toLower() == "theora")
- encoder = new QXmppTheoraEncoder;
-#endif
-#ifdef QXMPP_USE_VPX
- else if (payload.name().toLower() == "vp8") {
- encoder = new QXmppVpxEncoder(payload.clockrate());
- }
-#endif
- if (encoder) {
- encoder->setFormat(d->outgoingFormat);
- d->encoder = encoder;
- d->outgoingId = payload.id();
- break;
- }
- }
-}
-/// \endcond
-
-/// Decodes buffered RTP packets and returns a list of video frames.
-
-QList<QXmppVideoFrame> QXmppRtpVideoChannel::readFrames()
-{
- const QList<QXmppVideoFrame> frames = d->frames;
- d->frames.clear();
- return frames;
-}
-
-/// Encodes a video \a frame and sends RTP packets.
-
-void QXmppRtpVideoChannel::writeFrame(const QXmppVideoFrame &frame)
-{
- if (!d->encoder) {
- warning("QXmppRtpVideoChannel::writeFrame before codec was set");
- return;
- }
-
- QXmppRtpPacket packet;
- packet.setMarker(false);
- packet.setType(d->outgoingId);
- packet.setSsrc(localSsrc());
- for (const auto &payload : d->encoder->handleFrame(frame)) {
- packet.setSequence(d->outgoingSequence++);
- packet.setStamp(d->outgoingStamp);
- packet.setPayload(payload);
-#ifdef QXMPP_DEBUG_RTP
- logSent(packet.toString());
-#endif
- emit sendDatagram(packet.encode());
- }
- d->outgoingStamp += 1;
-}
diff --git a/src/base/QXmppRtpChannel.h b/src/base/QXmppRtpChannel.h
deleted file mode 100644
index cc934a59..00000000
--- a/src/base/QXmppRtpChannel.h
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright (C) 2008-2020 The QXmpp developers
- *
- * Author:
- * Jeremy Lainé
- *
- * Source:
- * https://github.com/qxmpp-project/qxmpp
- *
- * This file is a part of QXmpp library.
- *
- * This library 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.
- *
- * This library 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.
- *
- */
-
-#ifndef QXMPPRTPCHANNEL_H
-#define QXMPPRTPCHANNEL_H
-
-#include "QXmppJingleIq.h"
-#include "QXmppLogger.h"
-
-#include <QIODevice>
-#include <QSize>
-
-class QXmppCodec;
-class QXmppJinglePayloadType;
-class QXmppRtpAudioChannelPrivate;
-class QXmppRtpVideoChannelPrivate;
-
-class QXMPP_EXPORT QXmppRtpChannel
-{
-public:
- QXmppRtpChannel();
-
- /// Closes the RTP channel.
- virtual void close() = 0;
-
- /// Returns the mode in which the channel has been opened.
- virtual QIODevice::OpenMode openMode() const = 0;
-
- QList<QXmppJinglePayloadType> localPayloadTypes();
- void setRemotePayloadTypes(const QList<QXmppJinglePayloadType> &remotePayloadTypes);
-
- quint32 localSsrc() const;
- void setLocalSsrc(quint32 ssrc);
-
-protected:
- /// \cond
- virtual void payloadTypesChanged() = 0;
-
- QList<QXmppJinglePayloadType> m_incomingPayloadTypes;
- QList<QXmppJinglePayloadType> m_outgoingPayloadTypes;
- bool m_outgoingPayloadNumbered;
- /// \endcond
-
-private:
- quint32 m_outgoingSsrc;
-};
-
-/// \brief The QXmppRtpAudioChannel class represents an RTP audio channel to a remote party.
-///
-/// It acts as a QIODevice so that you can read / write audio samples, for
-/// instance using a QAudioOutput and a QAudioInput.
-///
-/// \note THIS API IS NOT FINALIZED YET
-
-class QXMPP_EXPORT QXmppRtpAudioChannel : public QIODevice, public QXmppRtpChannel
-{
- Q_OBJECT
-
-public:
- /// This enum is used to describe a DTMF tone.
- enum Tone {
- Tone_0 = 0, ///< Tone for the 0 key.
- Tone_1, ///< Tone for the 1 key.
- Tone_2, ///< Tone for the 2 key.
- Tone_3, ///< Tone for the 3 key.
- Tone_4, ///< Tone for the 4 key.
- Tone_5, ///< Tone for the 5 key.
- Tone_6, ///< Tone for the 6 key.
- Tone_7, ///< Tone for the 7 key.
- Tone_8, ///< Tone for the 8 key.
- Tone_9, ///< Tone for the 9 key.
- Tone_Star, ///< Tone for the * key.
- Tone_Pound, ///< Tone for the # key.
- Tone_A, ///< Tone for the A key.
- Tone_B, ///< Tone for the B key.
- Tone_C, ///< Tone for the C key.
- Tone_D ///< Tone for the D key.
- };
- Q_ENUM(Tone)
-
- QXmppRtpAudioChannel(QObject *parent = nullptr);
- ~QXmppRtpAudioChannel() override;
-
- qint64 bytesAvailable() const override;
- void close() override;
- bool isSequential() const override;
- QIODevice::OpenMode openMode() const override;
- QXmppJinglePayloadType payloadType() const;
- qint64 pos() const override;
- bool seek(qint64 pos) override;
-
-Q_SIGNALS:
- /// \brief This signal is emitted when a datagram needs to be sent.
- void sendDatagram(const QByteArray &ba);
-
- /// \brief This signal is emitted to send logging messages.
- void logMessage(QXmppLogger::MessageType type, const QString &msg);
-
-public Q_SLOTS:
- void datagramReceived(const QByteArray &ba);
- void startTone(QXmppRtpAudioChannel::Tone tone);
- void stopTone(QXmppRtpAudioChannel::Tone tone);
-
-protected:
- /// \cond
- void debug(const QString &message)
- {
- emit logMessage(QXmppLogger::DebugMessage, qxmpp_loggable_trace(message));
- }
-
- void warning(const QString &message)
- {
- emit logMessage(QXmppLogger::WarningMessage, qxmpp_loggable_trace(message));
- }
-
- void logReceived(const QString &message)
- {
- emit logMessage(QXmppLogger::ReceivedMessage, qxmpp_loggable_trace(message));
- }
-
- void logSent(const QString &message)
- {
- emit logMessage(QXmppLogger::SentMessage, qxmpp_loggable_trace(message));
- }
-
- void payloadTypesChanged() override;
- qint64 readData(char *data, qint64 maxSize) override;
- qint64 writeData(const char *data, qint64 maxSize) override;
- /// \endcond
-
-private Q_SLOTS:
- void emitSignals();
- void writeDatagram();
-
-private:
- friend class QXmppRtpAudioChannelPrivate;
- QXmppRtpAudioChannelPrivate *d;
-};
-
-/// \brief The QXmppVideoFrame class provides a representation of a frame of video data.
-///
-/// \note THIS API IS NOT FINALIZED YET
-
-class QXMPP_EXPORT QXmppVideoFrame
-{
-public:
- /// This enum describes a pixel format.
- enum PixelFormat {
- Format_Invalid = 0, ///< The frame is invalid.
- Format_RGB32 = 3, ///< The frame stored using a 32-bit RGB format (0xffRRGGBB).
- Format_RGB24 = 4, ///< The frame is stored using a 24-bit RGB format (8-8-8).
- Format_YUV420P = 18, ///< The frame is stored using an 8-bit per component planar
- ///< YUV format with the U and V planes horizontally and
- ///< vertically sub-sampled, i.e. the height and width of the
- ///< U and V planes are half that of the Y plane.
- Format_UYVY = 20, ///< The frame is stored using an 8-bit per component packed
- ///< YUV format with the U and V planes horizontally
- ///< sub-sampled (U-Y-V-Y), i.e. two horizontally adjacent
- ///< pixels are stored as a 32-bit macropixel which has a Y
- ///< value for each pixel and common U and V values.
- Format_YUYV = 21 ///< The frame is stored using an 8-bit per component packed
- ///< YUV format with the U and V planes horizontally
- ///< sub-sampled (Y-U-Y-V), i.e. two horizontally adjacent
- ///< pixels are stored as a 32-bit macropixel which has a Y
- ///< value for each pixel and common U and V values.
- };
-
- QXmppVideoFrame();
- QXmppVideoFrame(int bytes, const QSize &size, int bytesPerLine, PixelFormat format);
- uchar *bits();
- const uchar *bits() const;
- int bytesPerLine() const;
- int height() const;
- bool isValid() const;
- int mappedBytes() const;
- PixelFormat pixelFormat() const;
- QSize size() const;
- int width() const;
-
-private:
- int m_bytesPerLine;
- QByteArray m_data;
- int m_height;
- int m_mappedBytes;
- PixelFormat m_pixelFormat;
- int m_width;
-};
-
-class QXMPP_EXPORT QXmppVideoFormat
-{
-public:
- QXmppVideoFormat()
- : m_frameRate(15.0), m_frameSize(QSize(320, 240)), m_pixelFormat(QXmppVideoFrame::Format_YUYV)
- {
- }
-
- int frameHeight() const
- {
- return m_frameSize.height();
- }
-
- int frameWidth() const
- {
- return m_frameSize.width();
- }
-
- qreal frameRate() const
- {
- return m_frameRate;
- }
-
- void setFrameRate(qreal frameRate)
- {
- m_frameRate = frameRate;
- }
-
- QSize frameSize() const
- {
- return m_frameSize;
- }
-
- void setFrameSize(const QSize &frameSize)
- {
- m_frameSize = frameSize;
- }
-
- QXmppVideoFrame::PixelFormat pixelFormat() const
- {
- return m_pixelFormat;
- }
-
- void setPixelFormat(QXmppVideoFrame::PixelFormat pixelFormat)
- {
- m_pixelFormat = pixelFormat;
- }
-
-private:
- qreal m_frameRate;
- QSize m_frameSize;
- QXmppVideoFrame::PixelFormat m_pixelFormat;
-};
-
-/// \brief The QXmppRtpVideoChannel class represents an RTP video channel to a remote party.
-///
-/// \note THIS API IS NOT FINALIZED YET
-
-class QXMPP_EXPORT QXmppRtpVideoChannel : public QXmppLoggable, public QXmppRtpChannel
-{
- Q_OBJECT
-
-public:
- QXmppRtpVideoChannel(QObject *parent = nullptr);
- ~QXmppRtpVideoChannel() override;
-
- void close() override;
- QIODevice::OpenMode openMode() const override;
-
- // incoming stream
- QXmppVideoFormat decoderFormat() const;
- QList<QXmppVideoFrame> readFrames();
-
- // outgoing stream
- QXmppVideoFormat encoderFormat() const;
- void setEncoderFormat(const QXmppVideoFormat &format);
- void writeFrame(const QXmppVideoFrame &frame);
-
-Q_SIGNALS:
- /// \brief This signal is emitted when a datagram needs to be sent.
- void sendDatagram(const QByteArray &ba);
-
-public Q_SLOTS:
- void datagramReceived(const QByteArray &ba);
-
-protected:
- /// \cond
- void payloadTypesChanged() override;
- /// \endcond
-
-private:
- friend class QXmppRtpVideoChannelPrivate;
- QXmppRtpVideoChannelPrivate *d;
-};
-
-#endif
diff --git a/src/base/QXmppRtpPacket.cpp b/src/base/QXmppRtpPacket.cpp
deleted file mode 100644
index 0a467a7f..00000000
--- a/src/base/QXmppRtpPacket.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2008-2020 The QXmpp developers
- *
- * Author:
- * Jeremy Lainé
- *
- * Source:
- * https://github.com/qxmpp-project/qxmpp
- *
- * This file is a part of QXmpp library.
- *
- * This library 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.
- *
- * This library 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.
- *
- */
-
-#include "QXmppRtpPacket.h"
-
-#include <QDataStream>
-#include <QSharedData>
-
-#define RTP_VERSION 2
-
-class QXmppRtpPacketPrivate : public QSharedData
-{
-public:
- QXmppRtpPacketPrivate();
-
- /// Marker flag.
- bool marker;
- /// Payload type.
- quint8 type;
- /// Synchronization source.
- quint32 ssrc;
- /// Contributing sources.
- QList<quint32> csrc;
- /// Sequence number.
- quint16 sequence;
- /// Timestamp.
- quint32 stamp;
- /// Raw payload data.
- QByteArray payload;
-};
-
-QXmppRtpPacketPrivate::QXmppRtpPacketPrivate()
- : marker(false), type(0), ssrc(0), sequence(0), stamp(0)
-{
-}
-
-/// Constructs an empty RTP packet
-
-QXmppRtpPacket::QXmppRtpPacket()
- : d(new QXmppRtpPacketPrivate())
-{
-}
-
-/// Constructs a copy of other.
-///
-/// \param other
-///
-QXmppRtpPacket::QXmppRtpPacket(const QXmppRtpPacket &other)
- : d(other.d)
-{
-}
-
-QXmppRtpPacket::~QXmppRtpPacket()
-{
-}
-
-/// Assigns the other packet to this one.
-///
-/// \param other
-///
-QXmppRtpPacket &QXmppRtpPacket::operator=(const QXmppRtpPacket &other)
-{
- d = other.d;
- return *this;
-}
-
-/// Parses an RTP packet.
-///
-/// \param ba
-
-bool QXmppRtpPacket::decode(const QByteArray &ba)
-{
- if (ba.isEmpty())
- return false;
-
- // fixed header
- quint8 tmp;
- QDataStream stream(ba);
- stream >> tmp;
- const quint8 cc = (tmp & 0xf);
- const int hlen = 12 + 4 * cc;
- if ((tmp >> 6) != RTP_VERSION || ba.size() < hlen)
- return false;
- stream >> tmp;
- d->marker = (tmp >> 7);
- d->type = tmp & 0x7f;
- stream >> d->sequence;
- stream >> d->stamp;
- stream >> d->ssrc;
-
- // contributing source IDs
- d->csrc.clear();
- quint32 src;
- for (int i = 0; i < cc; ++i) {
- stream >> src;
- d->csrc << src;
- }
-
- // retrieve payload
- d->payload = ba.right(ba.size() - hlen);
- return true;
-}
-
-/// Encodes an RTP packet.
-
-QByteArray QXmppRtpPacket::encode() const
-{
- Q_ASSERT(d->csrc.size() < 16);
-
- // fixed header
- QByteArray ba;
- ba.resize(d->payload.size() + 12 + 4 * d->csrc.size());
- QDataStream stream(&ba, QIODevice::WriteOnly);
- stream << quint8((RTP_VERSION << 6) |
- (d->csrc.size() & 0xf));
- stream << quint8((d->type & 0x7f) | (d->marker << 7));
- stream << d->sequence;
- stream << d->stamp;
- stream << d->ssrc;
-
- // contributing source ids
- for (const auto &src : d->csrc)
- stream << src;
-
- stream.writeRawData(d->payload.constData(), d->payload.size());
- return ba;
-}
-
-QList<quint32> QXmppRtpPacket::csrc() const
-{
- return d->csrc;
-}
-
-void QXmppRtpPacket::setCsrc(const QList<quint32> &csrc)
-{
- d->csrc = csrc;
-}
-
-bool QXmppRtpPacket::marker() const
-{
- return d->marker;
-}
-
-void QXmppRtpPacket::setMarker(bool marker)
-{
- d->marker = marker;
-}
-
-QByteArray QXmppRtpPacket::payload() const
-{
- return d->payload;
-}
-
-void QXmppRtpPacket::setPayload(const QByteArray &payload)
-{
- d->payload = payload;
-}
-
-quint32 QXmppRtpPacket::ssrc() const
-{
- return d->ssrc;
-}
-
-void QXmppRtpPacket::setSsrc(quint32 ssrc)
-{
- d->ssrc = ssrc;
-}
-
-quint16 QXmppRtpPacket::sequence() const
-{
- return d->sequence;
-}
-
-void QXmppRtpPacket::setSequence(quint16 sequence)
-{
- d->sequence = sequence;
-}
-
-quint32 QXmppRtpPacket::stamp() const
-{
- return d->stamp;
-}
-
-void QXmppRtpPacket::setStamp(quint32 stamp)
-{
- d->stamp = stamp;
-}
-
-quint8 QXmppRtpPacket::type() const
-{
- return d->type;
-}
-
-void QXmppRtpPacket::setType(quint8 type)
-{
- d->type = type;
-}
-
-/// Returns a string representation of the RTP header.
-
-QString QXmppRtpPacket::toString() const
-{
- return QString("RTP packet seq %1 stamp %2 marker %3 type %4 size %5").arg(QString::number(d->sequence), QString::number(d->stamp), QString::number(d->marker), QString::number(d->type), QString::number(d->payload.size()));
-}
diff --git a/src/base/QXmppRtpPacket.h b/src/base/QXmppRtpPacket.h
deleted file mode 100644
index dd479eeb..00000000
--- a/src/base/QXmppRtpPacket.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2008-2020 The QXmpp developers
- *
- * Author:
- * Jeremy Lainé
- *
- * Source:
- * https://github.com/qxmpp-project/qxmpp
- *
- * This file is a part of QXmpp library.
- *
- * This library 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.
- *
- * This library 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.
- *
- */
-
-#ifndef QXMPPRTPPACKET_H
-#define QXMPPRTPPACKET_H
-
-#include "QXmppGlobal.h"
-
-#include <QSharedDataPointer>
-
-class QXmppRtpPacketPrivate;
-
-/// \internal
-///
-/// The QXmppRtpPacket class represents an RTP packet.
-
-class QXMPP_EXPORT QXmppRtpPacket
-{
-public:
- QXmppRtpPacket();
- QXmppRtpPacket(const QXmppRtpPacket &other);
- ~QXmppRtpPacket();
-
- QXmppRtpPacket &operator=(const QXmppRtpPacket &other);
-
- bool decode(const QByteArray &ba);
- QByteArray encode() const;
- QString toString() const;
-
- QList<quint32> csrc() const;
- void setCsrc(const QList<quint32> &csrc);
-
- bool marker() const;
- void setMarker(bool marker);
-
- QByteArray payload() const;
- void setPayload(const QByteArray &payload);
-
- quint16 sequence() const;
- void setSequence(quint16 sequence);
-
- quint32 ssrc() const;
- void setSsrc(quint32 ssrc);
-
- quint32 stamp() const;
- void setStamp(quint32 stamp);
-
- quint8 type() const;
- void setType(quint8 type);
-
-private:
- QSharedDataPointer<QXmppRtpPacketPrivate> d;
-};
-
-#endif