Merge pull request #86 from MarcusLlewellyn/opus-plugin

Add support for the Opus audio plugin.
This commit is contained in:
Thijs Wenker 2020-01-31 01:04:47 +01:00 committed by GitHub
commit dcb575a178
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 744 additions and 5 deletions

View file

@ -0,0 +1,13 @@
#
# Created by Michael Bailey on 12/20/2019
# Copyright 2019 Michael Bailey
#
# Distributed under the Apache License, Version 2.0.
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
#
macro(TARGET_opus)
find_library(OPUS_LIBRARY_RELEASE NAMES opus PATHS ${VCPKG_INSTALL_ROOT}/lib)
find_library(OPUS_LIBRARY_DEBUG NAMES opus PATHS ${VCPKG_INSTALL_ROOT}/debug/lib)
select_library_configurations(OPUS)
target_link_libraries(${TARGET_NAME} ${OPUS_LIBRARY})
endmacro()

View file

@ -1,4 +1,4 @@
Source: hifi-deps
Version: 0.3
Version: 0.4
Description: Collected dependencies for High Fidelity applications
Build-Depends: bullet3, draco, etc2comp, glm, nvtt, openexr (!android), openssl (windows), tbb (!android&!osx), zlib, webrtc (!android)
Build-Depends: bullet3, draco, etc2comp, glm, nvtt, openexr (!android), openssl (windows), opus, tbb (!android&!osx), zlib, webrtc (!android)

3
cmake/ports/opus/CONTROL Normal file
View file

@ -0,0 +1,3 @@
Source: opus
Version: 1.3.1
Description: Totally open, royalty-free, highly versatile audio codec

View file

@ -0,0 +1,28 @@
include(vcpkg_common_functions)
vcpkg_from_github(
OUT_SOURCE_PATH
SOURCE_PATH
REPO
xiph/opus
REF
e85ed7726db5d677c9c0677298ea0cb9c65bdd23
SHA512
a8c7e5bf383c06f1fdffd44d9b5f658f31eb4800cb59d12da95ddaeb5646f7a7b03025f4663362b888b1374d4cc69154f006ba07b5840ec61ddc1a1af01d6c54
HEAD_REF
master)
vcpkg_configure_cmake(SOURCE_PATH ${SOURCE_PATH} PREFER_NINJA)
vcpkg_install_cmake()
vcpkg_fixup_cmake_targets(CONFIG_PATH lib/cmake/Opus)
vcpkg_copy_pdbs()
file(INSTALL
${SOURCE_PATH}/COPYING
DESTINATION
${CURRENT_PACKAGES_DIR}/share/opus
RENAME copyright)
file(REMOVE_RECURSE ${CURRENT_PACKAGES_DIR}/debug/lib/cmake
${CURRENT_PACKAGES_DIR}/lib/cmake
${CURRENT_PACKAGES_DIR}/debug/include)

View file

@ -1227,8 +1227,8 @@
"name": "codec_preference_order",
"label": "Audio Codec Preference Order",
"help": "List of codec names in order of preferred usage",
"placeholder": "hifiAC, zlib, pcm",
"default": "hifiAC,zlib,pcm",
"placeholder": "opus, hifiAC, zlib, pcm",
"default": "opus,hifiAC,zlib,pcm",
"advanced": true
}
]

View file

@ -43,6 +43,8 @@ set(DIR "pcmCodec")
add_subdirectory(${DIR})
set(DIR "hifiCodec")
add_subdirectory(${DIR})
set(DIR "opusCodec")
add_subdirectory(${DIR})
# example plugins
set(DIR "KasenAPIExample")

View file

@ -8,7 +8,7 @@
set(TARGET_NAME hifiCodec)
setup_hifi_client_server_plugin()
link_hifi_libraries(audio plugins)
link_hifi_libraries(shared audio plugins)
target_hifiAudioCodec()
if (BUILD_SERVER)
install_beside_console()

View file

@ -13,6 +13,7 @@
#include <AudioCodec.h>
#include <AudioConstants.h>
#include <PerfStat.h>
const char* HiFiCodec::NAME { "hifiAC" };
@ -44,6 +45,8 @@ public:
}
virtual void encode(const QByteArray& decodedBuffer, QByteArray& encodedBuffer) override {
PerformanceTimer perfTimer("HiFiEncoder::encode");
encodedBuffer.resize(_encodedSize);
AudioEncoder::process((const int16_t*)decodedBuffer.constData(), (int16_t*)encodedBuffer.data(), AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL);
}
@ -58,11 +61,15 @@ public:
}
virtual void decode(const QByteArray& encodedBuffer, QByteArray& decodedBuffer) override {
PerformanceTimer perfTimer("HiFiEncoder::decode");
decodedBuffer.resize(_decodedSize);
AudioDecoder::process((const int16_t*)encodedBuffer.constData(), (int16_t*)decodedBuffer.data(), AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL, true);
}
virtual void lostFrame(QByteArray& decodedBuffer) override {
PerformanceTimer perfTimer("HiFiEncoder::lostFrame");
decodedBuffer.resize(_decodedSize);
// this performs packet loss interpolation
AudioDecoder::process(nullptr, (int16_t*)decodedBuffer.data(), AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL, false);

View file

@ -0,0 +1,16 @@
#
# Created by Michael Bailey on 12/20/2019
# Copyright 2019 Michael Bailey
#
# Distributed under the Apache License, Version 2.0.
# See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
#
set(TARGET_NAME opusCodec)
setup_hifi_client_server_plugin()
link_hifi_libraries(shared audio plugins)
target_opus()
if (BUILD_SERVER)
install_beside_console()
endif ()

View file

@ -0,0 +1,58 @@
//
// opusCodec.cpp
// plugins/opusCodec/src
//
// Created by Michael Bailey on 12/20/2019
// Copyright 2019 Michael Bailey
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "OpusCodecManager.h"
#include <QtCore/QCoreApplication>
#include <PerfStat.h>
#include "OpusEncoder.h"
#include "OpusDecoder.h"
const char* AthenaOpusCodec::NAME { "opus" };
void AthenaOpusCodec::init() {
}
void AthenaOpusCodec::deinit() {
}
bool AthenaOpusCodec::activate() {
CodecPlugin::activate();
return true;
}
void AthenaOpusCodec::deactivate() {
CodecPlugin::deactivate();
}
bool AthenaOpusCodec::isSupported() const {
return true;
}
Encoder* AthenaOpusCodec::createEncoder(int sampleRate, int numChannels) {
return new AthenaOpusEncoder(sampleRate, numChannels);
}
Decoder* AthenaOpusCodec::createDecoder(int sampleRate, int numChannels) {
return new AthenaOpusDecoder(sampleRate, numChannels);
}
void AthenaOpusCodec::releaseEncoder(Encoder* encoder) {
delete encoder;
}
void AthenaOpusCodec::releaseDecoder(Decoder* decoder) {
delete decoder;
}

View file

@ -0,0 +1,42 @@
//
// OpusCodecManager.h
// plugins/opusCodec/src
//
// Created by Michael Bailey on 12/20/2019
// Copyright 2019 Michael Bailey
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi__OpusCodecManager_h
#define hifi__OpusCodecManager_h
#include <plugins/CodecPlugin.h>
class AthenaOpusCodec : public CodecPlugin {
Q_OBJECT
public:
// Plugin functions
bool isSupported() const override;
const QString getName() const override { return NAME; }
void init() override;
void deinit() override;
/// Called when a plugin is being activated for use. May be called multiple times.
bool activate() override;
/// Called when a plugin is no longer being used. May be called multiple times.
void deactivate() override;
virtual Encoder* createEncoder(int sampleRate, int numChannels) override;
virtual Decoder* createDecoder(int sampleRate, int numChannels) override;
virtual void releaseEncoder(Encoder* encoder) override;
virtual void releaseDecoder(Decoder* decoder) override;
private:
static const char* NAME;
};
#endif // hifi__opusCodecManager_h

View file

@ -0,0 +1,45 @@
//
// Created by Michael Bailey on 12/20/2019
// Copyright 2019 Michael Bailey
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <mutex>
#include <QtCore/QObject>
#include <QtCore/QtPlugin>
#include <QtCore/QStringList>
#include <plugins/RuntimePlugin.h>
#include <plugins/CodecPlugin.h>
#include "OpusCodecManager.h"
class AthenaOpusCodecProvider : public QObject, public CodecProvider {
Q_OBJECT
Q_PLUGIN_METADATA(IID CodecProvider_iid FILE "plugin.json")
Q_INTERFACES(CodecProvider)
public:
AthenaOpusCodecProvider(QObject* parent = nullptr) : QObject(parent) {}
virtual ~AthenaOpusCodecProvider() {}
virtual CodecPluginList getCodecPlugins() override {
static std::once_flag once;
std::call_once(once, [&] {
CodecPluginPointer opusCodec(new AthenaOpusCodec());
if (opusCodec->isSupported()) {
_codecPlugins.push_back(opusCodec);
}
});
return _codecPlugins;
}
private:
CodecPluginList _codecPlugins;
};
#include "OpusCodecProvider.moc"

View file

@ -0,0 +1,131 @@
//
// OpusCodecManager.h
// plugins/opusCodec/src
//
// Copyright 2020 Dale Glass
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <PerfStat.h>
#include <QtCore/QLoggingCategory>
#include <AudioConstants.h>
#include "OpusDecoder.h"
static QLoggingCategory decoder("AthenaOpusDecoder");
static QString error_to_string(int error) {
switch (error) {
case OPUS_OK:
return "OK";
case OPUS_BAD_ARG:
return "One or more invalid/out of range arguments.";
case OPUS_BUFFER_TOO_SMALL:
return "The mode struct passed is invalid.";
case OPUS_INTERNAL_ERROR:
return "An internal error was detected.";
case OPUS_INVALID_PACKET:
return "The compressed data passed is corrupted.";
case OPUS_UNIMPLEMENTED:
return "Invalid/unsupported request number.";
case OPUS_INVALID_STATE:
return "An encoder or decoder structure is invalid or already freed.";
default:
return QString("Unknown error code: %i").arg(error);
}
}
AthenaOpusDecoder::AthenaOpusDecoder(int sampleRate, int numChannels) {
int error;
_opusSampleRate = sampleRate;
_opusNumChannels = numChannels;
_decoder = opus_decoder_create(sampleRate, numChannels, &error);
if (error != OPUS_OK) {
qCCritical(decoder) << "Failed to initialize Opus encoder: " << error_to_string(error);
_decoder = nullptr;
return;
}
qCDebug(decoder) << "Opus decoder initialized, sampleRate = " << sampleRate << "; numChannels = " << numChannels;
}
AthenaOpusDecoder::~AthenaOpusDecoder() {
if (_decoder) {
opus_decoder_destroy(_decoder);
}
}
void AthenaOpusDecoder::decode(const QByteArray &encodedBuffer, QByteArray &decodedBuffer) {
assert(_decoder);
PerformanceTimer perfTimer("AthenaOpusDecoder::decode");
// The audio system encodes and decodes always in fixed size chunks
int bufferSize = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * static_cast<int>(sizeof(int16_t))
* _opusNumChannels;
decodedBuffer.resize(bufferSize);
int bufferFrames = decodedBuffer.size() / _opusNumChannels / static_cast<int>(sizeof(opus_int16));
int decoded_frames = opus_decode(_decoder, reinterpret_cast<const unsigned char*>(encodedBuffer.data()),
encodedBuffer.length(), reinterpret_cast<opus_int16*>(decodedBuffer.data()), bufferFrames, 0);
if (decoded_frames >= 0) {
if (decoded_frames < bufferFrames) {
qCWarning(decoder) << "Opus decoder returned " << decoded_frames << ", but " << bufferFrames
<< " were expected!";
int start = decoded_frames * static_cast<int>(sizeof(int16_t)) * _opusNumChannels;
memset( &decodedBuffer.data()[start], 0, static_cast<size_t>(decodedBuffer.length() - start));
} else if (decoded_frames > bufferFrames) {
// This should never happen
qCCritical(decoder) << "Opus decoder returned " << decoded_frames << ", but only " << bufferFrames
<< " were expected! Buffer overflow!?";
}
} else {
qCCritical(decoder) << "Failed to decode audio: " << error_to_string(decoded_frames);
decodedBuffer.fill('\0');
}
}
void AthenaOpusDecoder::lostFrame(QByteArray &decodedBuffer) {
assert(_decoder);
PerformanceTimer perfTimer("AthenaOpusDecoder::lostFrame");
int bufferSize = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * static_cast<int>(sizeof(int16_t))
* _opusNumChannels;
decodedBuffer.resize(bufferSize);
int bufferFrames = decodedBuffer.size() / _opusNumChannels / static_cast<int>(sizeof(opus_int16));
int decoded_frames = opus_decode(_decoder, nullptr, 0, reinterpret_cast<opus_int16*>(decodedBuffer.data()),
bufferFrames, 1);
if (decoded_frames >= 0) {
if ( decoded_frames < bufferFrames ) {
qCWarning(decoder) << "Opus decoder returned " << decoded_frames << ", but " << bufferFrames
<< " were expected!";
int start = decoded_frames * static_cast<int>(sizeof(int16_t)) * _opusNumChannels;
memset( &decodedBuffer.data()[start], 0, static_cast<size_t>(decodedBuffer.length() - start));
} else if (decoded_frames > bufferFrames) {
// This should never happen
qCCritical(decoder) << "Opus decoder returned " << decoded_frames << ", but only " << bufferFrames
<< " were expected! Buffer overflow!?";
}
} else {
qCCritical(decoder) << "Failed to decode lost frame: " << error_to_string(decoded_frames);
decodedBuffer.fill('\0');
}
}

View file

@ -0,0 +1,39 @@
//
// OpusCodecManager.h
// plugins/opusCodec/src
//
// Copyright 2020 Dale Glass
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef OPUSDECODER_H
#define OPUSDECODER_H
#include <plugins/CodecPlugin.h>
#include <opus/opus.h>
class AthenaOpusDecoder : public Decoder {
public:
AthenaOpusDecoder(int sampleRate, int numChannels);
~AthenaOpusDecoder() override;
virtual void decode(const QByteArray& encodedBuffer, QByteArray& decodedBuffer) override;
virtual void lostFrame(QByteArray &decodedBuffer) override;
private:
int _encodedSize;
OpusDecoder* _decoder = nullptr;
int _opusSampleRate = 0;
int _opusNumChannels = 0;
int _decodedSize = 0;
};
#endif // OPUSDECODER_H

View file

@ -0,0 +1,273 @@
//
// OpusCodecManager.h
// plugins/opusCodec/src
//
// Copyright 2020 Dale Glass
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <PerfStat.h>
#include <QtCore/QLoggingCategory>
#include <opus/opus.h>
#include "OpusEncoder.h"
static QLoggingCategory encoder("AthenaOpusEncoder");
static QString errorToString(int error) {
switch (error) {
case OPUS_OK:
return "OK";
case OPUS_BAD_ARG:
return "One or more invalid/out of range arguments.";
case OPUS_BUFFER_TOO_SMALL:
return "The mode struct passed is invalid.";
case OPUS_INTERNAL_ERROR:
return "An internal error was detected.";
case OPUS_INVALID_PACKET:
return "The compressed data passed is corrupted.";
case OPUS_UNIMPLEMENTED:
return "Invalid/unsupported request number.";
case OPUS_INVALID_STATE:
return "An encoder or decoder structure is invalid or already freed.";
default:
return QString("Unknown error code: %i").arg(error);
}
}
AthenaOpusEncoder::AthenaOpusEncoder(int sampleRate, int numChannels) {
_opusSampleRate = sampleRate;
_opusChannels = numChannels;
int error;
_encoder = opus_encoder_create(sampleRate, numChannels, DEFAULT_APPLICATION, &error);
if (error != OPUS_OK) {
qCCritical(encoder) << "Failed to initialize Opus encoder: " << errorToString(error);
_encoder = nullptr;
return;
}
setBitrate(DEFAULT_BITRATE);
setComplexity(DEFAULT_COMPLEXITY);
setApplication(DEFAULT_APPLICATION);
setSignal(DEFAULT_SIGNAL);
qCDebug(encoder) << "Opus encoder initialized, sampleRate = " << sampleRate << "; numChannels = " << numChannels;
}
AthenaOpusEncoder::~AthenaOpusEncoder() {
opus_encoder_destroy(_encoder);
}
void AthenaOpusEncoder::encode(const QByteArray& decodedBuffer, QByteArray& encodedBuffer) {
PerformanceTimer perfTimer("AthenaOpusEncoder::encode");
assert(_encoder);
encodedBuffer.resize(decodedBuffer.size());
int frameSize = decodedBuffer.length() / _opusChannels / static_cast<int>(sizeof(opus_int16));
int bytes = opus_encode(_encoder, reinterpret_cast<const opus_int16*>(decodedBuffer.constData()), frameSize,
reinterpret_cast<unsigned char*>(encodedBuffer.data()), encodedBuffer.size() );
if (bytes >= 0) {
encodedBuffer.resize(bytes);
} else {
encodedBuffer.resize(0);
qCWarning(encoder) << "Error when encoding " << decodedBuffer.length() << " bytes of audio: "
<< errorToString(bytes);
}
}
int AthenaOpusEncoder::getComplexity() const {
assert(_encoder);
int returnValue;
opus_encoder_ctl(_encoder, OPUS_GET_COMPLEXITY(&returnValue));
return returnValue;
}
void AthenaOpusEncoder::setComplexity(int complexity) {
assert(_encoder);
int returnValue = opus_encoder_ctl(_encoder, OPUS_SET_COMPLEXITY(complexity));
if (returnValue != OPUS_OK) {
qCWarning(encoder) << "Error when setting complexity to " << complexity << ": " << errorToString(returnValue);
}
}
int AthenaOpusEncoder::getBitrate() const {
assert(_encoder);
int returnValue;
opus_encoder_ctl(_encoder, OPUS_GET_BITRATE(&returnValue));
return returnValue;
}
void AthenaOpusEncoder::setBitrate(int bitrate) {
assert(_encoder);
int errorCode = opus_encoder_ctl(_encoder, OPUS_SET_BITRATE(bitrate));
if (errorCode != OPUS_OK) {
qCWarning(encoder) << "Error when setting bitrate to " << bitrate << ": " << errorToString(errorCode);
}
}
int AthenaOpusEncoder::getVBR() const {
assert(_encoder);
int returnValue;
opus_encoder_ctl(_encoder, OPUS_GET_VBR(&returnValue));
return returnValue;
}
void AthenaOpusEncoder::setVBR(int vbr) {
assert(_encoder);
int errorCode = opus_encoder_ctl(_encoder, OPUS_SET_VBR(vbr));
if (errorCode != OPUS_OK) {
qCWarning(encoder) << "Error when setting VBR to " << vbr << ": " << errorToString(errorCode);
}
}
int AthenaOpusEncoder::getVBRConstraint() const {
assert(_encoder);
int returnValue;
opus_encoder_ctl(_encoder, OPUS_GET_VBR_CONSTRAINT(&returnValue));
return returnValue;
}
void AthenaOpusEncoder::setVBRConstraint(int vbr_const) {
assert(_encoder);
int errorCode = opus_encoder_ctl(_encoder, OPUS_SET_VBR_CONSTRAINT(vbr_const));
if (errorCode != OPUS_OK) {
qCWarning(encoder) << "Error when setting VBR constraint to " << vbr_const << ": " << errorToString(errorCode);
}
}
int AthenaOpusEncoder::getMaxBandwidth() const {
assert(_encoder);
int returnValue;
opus_encoder_ctl(_encoder, OPUS_GET_MAX_BANDWIDTH(&returnValue));
return returnValue;
}
void AthenaOpusEncoder::setMaxBandwidth(int maxBandwidth) {
assert(_encoder);
int errorCode = opus_encoder_ctl(_encoder, OPUS_SET_MAX_BANDWIDTH(maxBandwidth));
if (errorCode != OPUS_OK) {
qCWarning(encoder) << "Error when setting max bandwidth to " << maxBandwidth << ": " << errorToString(errorCode);
}
}
int AthenaOpusEncoder::getBandwidth() const {
assert(_encoder);
int bandwidth;
opus_encoder_ctl(_encoder, OPUS_GET_BANDWIDTH(&bandwidth));
return bandwidth;
}
void AthenaOpusEncoder::setBandwidth(int bandwidth) {
assert(_encoder);
int errorCode = opus_encoder_ctl(_encoder, OPUS_SET_BANDWIDTH(bandwidth));
if (errorCode != OPUS_OK) {
qCWarning(encoder) << "Error when setting bandwidth to " << bandwidth << ": " << errorToString(errorCode);
}
}
int AthenaOpusEncoder::getSignal() const {
assert(_encoder);
int signal;
opus_encoder_ctl(_encoder, OPUS_GET_SIGNAL(&signal));
return signal;
}
void AthenaOpusEncoder::setSignal(int signal) {
assert(_encoder);
int errorCode = opus_encoder_ctl(_encoder, OPUS_SET_SIGNAL(signal));
if (errorCode != OPUS_OK) {
qCWarning(encoder) << "Error when setting signal to " << signal << ": " << errorToString(errorCode);
}
}
int AthenaOpusEncoder::getApplication() const {
assert(_encoder);
int applicationValue;
opus_encoder_ctl(_encoder, OPUS_GET_APPLICATION(&applicationValue));
return applicationValue;
}
void AthenaOpusEncoder::setApplication(int application) {
assert(_encoder);
int errorCode = opus_encoder_ctl(_encoder, OPUS_SET_APPLICATION(application));
if (errorCode != OPUS_OK) {
qCWarning(encoder) << "Error when setting application to " << application << ": " << errorToString(errorCode);
}
}
int AthenaOpusEncoder::getLookahead() const {
assert(_encoder);
int lookAhead;
opus_encoder_ctl(_encoder, OPUS_GET_LOOKAHEAD(&lookAhead));
return lookAhead;
}
int AthenaOpusEncoder::getInbandFEC() const {
assert(_encoder);
int fec;
opus_encoder_ctl(_encoder, OPUS_GET_INBAND_FEC(&fec));
return fec;
}
void AthenaOpusEncoder::setInbandFEC(int inBandFEC) {
assert(_encoder);
int errorCode = opus_encoder_ctl(_encoder, OPUS_SET_INBAND_FEC(inBandFEC));
if (errorCode != OPUS_OK) {
qCWarning(encoder) << "Error when setting inband FEC to " << inBandFEC << ": " << errorToString(errorCode);
}
}
int AthenaOpusEncoder::getExpectedPacketLossPercentage() const {
assert(_encoder);
int lossPercentage;
opus_encoder_ctl(_encoder, OPUS_GET_PACKET_LOSS_PERC(&lossPercentage));
return lossPercentage;
}
void AthenaOpusEncoder::setExpectedPacketLossPercentage(int percentage) {
assert(_encoder);
int errorCode = opus_encoder_ctl(_encoder, OPUS_SET_PACKET_LOSS_PERC(percentage));
if (errorCode != OPUS_OK) {
qCWarning(encoder) << "Error when setting loss percent to " << percentage << ": " << errorToString(errorCode);
}
}
int AthenaOpusEncoder::getDTX() const {
assert(_encoder);
int dtx;
opus_encoder_ctl(_encoder, OPUS_GET_DTX(&dtx));
return dtx;
}
void AthenaOpusEncoder::setDTX(int dtx) {
assert(_encoder);
int errorCode = opus_encoder_ctl(_encoder, OPUS_SET_DTX(dtx));
if (errorCode != OPUS_OK) {
qCWarning(encoder) << "Error when setting DTX to " << dtx << ": " << errorToString(errorCode);
}
}

View file

@ -0,0 +1,78 @@
//
// OpusCodecManager.h
// plugins/opusCodec/src
//
// Copyright 2020 Dale Glass
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef OPUSENCODER_H
#define OPUSENCODER_H
#include <plugins/CodecPlugin.h>
#include <opus/opus.h>
class AthenaOpusEncoder : public Encoder {
public:
AthenaOpusEncoder(int sampleRate, int numChannels);
~AthenaOpusEncoder() override;
virtual void encode(const QByteArray& decodedBuffer, QByteArray& encodedBuffer) override;
int getComplexity() const;
void setComplexity(int complexity);
int getBitrate() const;
void setBitrate(int bitrate);
int getVBR() const;
void setVBR(int vbr);
int getVBRConstraint() const;
void setVBRConstraint(int vbrConstraint);
int getMaxBandwidth() const;
void setMaxBandwidth(int maxBandwidth);
int getBandwidth() const;
void setBandwidth(int bandwidth);
int getSignal() const;
void setSignal(int signal);
int getApplication() const;
void setApplication(int application);
int getLookahead() const;
int getInbandFEC() const;
void setInbandFEC(int inBandFEC);
int getExpectedPacketLossPercentage() const;
void setExpectedPacketLossPercentage(int percentage);
int getDTX() const;
void setDTX(int dtx);
private:
const int DEFAULT_BITRATE = 128000;
const int DEFAULT_COMPLEXITY = 10;
const int DEFAULT_APPLICATION = OPUS_APPLICATION_VOIP;
const int DEFAULT_SIGNAL = OPUS_AUTO;
int _opusSampleRate = 0;
int _opusChannels = 0;
int _opusExpectedLoss = 0;
OpusEncoder* _encoder = nullptr;
};
#endif // OPUSENCODER_H

View file

@ -0,0 +1,4 @@
{
"name": "Opus Codec",
"version": 1
}