mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 17:39:26 +02:00
handle codec prioritization, handle multiple codec choices
This commit is contained in:
parent
126e5c2926
commit
a71baf5601
12 changed files with 149 additions and 65 deletions
|
@ -466,34 +466,61 @@ void saveInputPluginSettings(const InputPluginList& plugins) {
|
||||||
void AudioMixer::handleNegotiateAudioFormat(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
|
void AudioMixer::handleNegotiateAudioFormat(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) {
|
||||||
qDebug() << __FUNCTION__;
|
qDebug() << __FUNCTION__;
|
||||||
|
|
||||||
// read the codecs requested by the client
|
QStringList availableCodecs;
|
||||||
quint8 numberOfCodecs = 0;
|
|
||||||
message->readPrimitive(&numberOfCodecs);
|
|
||||||
QStringList codecList;
|
|
||||||
for (quint16 i = 0; i < numberOfCodecs; i++) {
|
|
||||||
QString requestedCodec = message->readString();
|
|
||||||
qDebug() << "requestedCodec:" << requestedCodec;
|
|
||||||
codecList.append(requestedCodec);
|
|
||||||
}
|
|
||||||
qDebug() << "all requested codecs:" << codecList;
|
|
||||||
|
|
||||||
CodecPluginPointer selectedCoded;
|
|
||||||
QString selectedCodecName;
|
|
||||||
auto codecPlugins = PluginManager::getInstance()->getCodecPlugins();
|
auto codecPlugins = PluginManager::getInstance()->getCodecPlugins();
|
||||||
if (codecPlugins.size() > 0) {
|
if (codecPlugins.size() > 0) {
|
||||||
for (auto& plugin : codecPlugins) {
|
for (auto& plugin : codecPlugins) {
|
||||||
qDebug() << "Codec available:" << plugin->getName();
|
auto codecName = plugin->getName();
|
||||||
|
qDebug() << "Codec available:" << codecName;
|
||||||
// choose first codec
|
availableCodecs.append(codecName);
|
||||||
if (!selectedCoded) {
|
|
||||||
selectedCoded = plugin;
|
|
||||||
selectedCodecName = plugin->getName();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "No Codecs available...";
|
qDebug() << "No Codecs available...";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CodecPluginPointer selectedCoded;
|
||||||
|
QString selectedCodecName;
|
||||||
|
|
||||||
|
QStringList codecPreferenceList = _codecPreferenceOrder.split(",");
|
||||||
|
|
||||||
|
// read the codecs requested by the client
|
||||||
|
const int MAX_PREFERENCE = 99999;
|
||||||
|
int preferredCodecIndex = MAX_PREFERENCE;
|
||||||
|
QString preferredCodec;
|
||||||
|
quint8 numberOfCodecs = 0;
|
||||||
|
message->readPrimitive(&numberOfCodecs);
|
||||||
|
qDebug() << "numberOfCodecs:" << numberOfCodecs;
|
||||||
|
QStringList codecList;
|
||||||
|
for (quint16 i = 0; i < numberOfCodecs; i++) {
|
||||||
|
QString requestedCodec = message->readString();
|
||||||
|
int preferenceOfThisCodec = codecPreferenceList.indexOf(requestedCodec);
|
||||||
|
bool codecAvailable = availableCodecs.contains(requestedCodec);
|
||||||
|
qDebug() << "requestedCodec:" << requestedCodec << "preference:" << preferenceOfThisCodec << "available:" << codecAvailable;
|
||||||
|
if (codecAvailable) {
|
||||||
|
codecList.append(requestedCodec);
|
||||||
|
if (preferenceOfThisCodec >= 0 && preferenceOfThisCodec < preferredCodecIndex) {
|
||||||
|
qDebug() << "This codec is preferred...";
|
||||||
|
selectedCodecName = requestedCodec;
|
||||||
|
preferredCodecIndex = preferenceOfThisCodec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qDebug() << "all requested and available codecs:" << codecList;
|
||||||
|
|
||||||
|
// choose first codec
|
||||||
|
if (!selectedCodecName.isEmpty()) {
|
||||||
|
if (codecPlugins.size() > 0) {
|
||||||
|
for (auto& plugin : codecPlugins) {
|
||||||
|
if (selectedCodecName == plugin->getName()) {
|
||||||
|
qDebug() << "Selecting codec:" << selectedCodecName;
|
||||||
|
selectedCoded = plugin;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
auto clientData = dynamic_cast<AudioMixerClientData*>(sendingNode->getLinkedData());
|
auto clientData = dynamic_cast<AudioMixerClientData*>(sendingNode->getLinkedData());
|
||||||
|
|
||||||
// FIXME - why would we not have client data at this point??
|
// FIXME - why would we not have client data at this point??
|
||||||
|
@ -882,6 +909,12 @@ void AudioMixer::parseSettingsObject(const QJsonObject &settingsObject) {
|
||||||
if (settingsObject.contains(AUDIO_ENV_GROUP_KEY)) {
|
if (settingsObject.contains(AUDIO_ENV_GROUP_KEY)) {
|
||||||
QJsonObject audioEnvGroupObject = settingsObject[AUDIO_ENV_GROUP_KEY].toObject();
|
QJsonObject audioEnvGroupObject = settingsObject[AUDIO_ENV_GROUP_KEY].toObject();
|
||||||
|
|
||||||
|
const QString CODEC_PREFERENCE_ORDER = "codec_preference_order";
|
||||||
|
if (audioEnvGroupObject[CODEC_PREFERENCE_ORDER].isString()) {
|
||||||
|
_codecPreferenceOrder = audioEnvGroupObject[CODEC_PREFERENCE_ORDER].toString();
|
||||||
|
qDebug() << "Codec preference order changed to" << _codecPreferenceOrder;
|
||||||
|
}
|
||||||
|
|
||||||
const QString ATTENATION_PER_DOULING_IN_DISTANCE = "attenuation_per_doubling_in_distance";
|
const QString ATTENATION_PER_DOULING_IN_DISTANCE = "attenuation_per_doubling_in_distance";
|
||||||
if (audioEnvGroupObject[ATTENATION_PER_DOULING_IN_DISTANCE].isString()) {
|
if (audioEnvGroupObject[ATTENATION_PER_DOULING_IN_DISTANCE].isString()) {
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
|
|
|
@ -92,6 +92,8 @@ private:
|
||||||
int _manualEchoMixes { 0 };
|
int _manualEchoMixes { 0 };
|
||||||
int _totalMixes { 0 };
|
int _totalMixes { 0 };
|
||||||
|
|
||||||
|
QString _codecPreferenceOrder;
|
||||||
|
|
||||||
float _mixedSamples[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO];
|
float _mixedSamples[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO];
|
||||||
int16_t _clampedSamples[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO];
|
int16_t _clampedSamples[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO];
|
||||||
|
|
||||||
|
|
|
@ -718,6 +718,14 @@
|
||||||
"placeholder": "(in percent)"
|
"placeholder": "(in percent)"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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",
|
||||||
|
"advanced": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -507,19 +507,14 @@ void AudioClient::handleMuteEnvironmentPacket(QSharedPointer<ReceivedMessage> me
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::negotiateAudioFormat() {
|
void AudioClient::negotiateAudioFormat() {
|
||||||
qDebug() << __FUNCTION__;
|
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
auto negotiateFormatPacket = NLPacket::create(PacketType::NegotiateAudioFormat);
|
auto negotiateFormatPacket = NLPacket::create(PacketType::NegotiateAudioFormat);
|
||||||
|
|
||||||
auto codecPlugins = PluginManager::getInstance()->getCodecPlugins();
|
auto codecPlugins = PluginManager::getInstance()->getCodecPlugins();
|
||||||
|
|
||||||
quint8 numberOfCodecs = (quint8)codecPlugins.size();
|
quint8 numberOfCodecs = (quint8)codecPlugins.size();
|
||||||
negotiateFormatPacket->writePrimitive(numberOfCodecs);
|
negotiateFormatPacket->writePrimitive(numberOfCodecs);
|
||||||
for (auto& plugin : codecPlugins) {
|
for (auto& plugin : codecPlugins) {
|
||||||
qDebug() << "Codec available:" << plugin->getName();
|
auto codecName = plugin->getName();
|
||||||
negotiateFormatPacket->writeString(plugin->getName());
|
negotiateFormatPacket->writeString(codecName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// grab our audio mixer from the NodeList, if it exists
|
// grab our audio mixer from the NodeList, if it exists
|
||||||
|
|
|
@ -131,7 +131,7 @@ int InboundAudioStream::parseData(ReceivedMessage& message) {
|
||||||
if (message.getType() == PacketType::SilentAudioFrame) {
|
if (message.getType() == PacketType::SilentAudioFrame) {
|
||||||
writeDroppableSilentSamples(networkSamples);
|
writeDroppableSilentSamples(networkSamples);
|
||||||
} else {
|
} else {
|
||||||
parseAudioData(message.getType(), message.readWithoutCopy(message.getBytesLeftToRead()), networkSamples);
|
parseAudioData(message.getType(), message.readWithoutCopy(message.getBytesLeftToRead()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -177,25 +177,14 @@ int InboundAudioStream::parseStreamProperties(PacketType type, const QByteArray&
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int InboundAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) {
|
int InboundAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties) {
|
||||||
|
|
||||||
// codec decode goes here
|
|
||||||
QByteArray decodedBuffer;
|
QByteArray decodedBuffer;
|
||||||
if (_codec) {
|
if (_codec) {
|
||||||
_codec->decode(packetAfterStreamProperties, decodedBuffer);
|
_codec->decode(packetAfterStreamProperties, decodedBuffer);
|
||||||
} else {
|
} else {
|
||||||
decodedBuffer = packetAfterStreamProperties;
|
decodedBuffer = packetAfterStreamProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto actualSize = decodedBuffer.size();
|
auto actualSize = decodedBuffer.size();
|
||||||
|
|
||||||
/*
|
|
||||||
auto expectedSize = numAudioSamples * sizeof(int16_t);
|
|
||||||
if (expectedSize != actualSize) {
|
|
||||||
qDebug() << "DECODED SIZE NOT EXPECTED!!!! ----- buffer size:" << actualSize << "expected:" << expectedSize;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
return _ringBuffer.writeData(decodedBuffer.data(), actualSize);
|
return _ringBuffer.writeData(decodedBuffer.data(), actualSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -207,7 +207,7 @@ protected:
|
||||||
|
|
||||||
/// parses the audio data in the network packet.
|
/// parses the audio data in the network packet.
|
||||||
/// default implementation assumes packet contains raw audio samples after stream properties
|
/// default implementation assumes packet contains raw audio samples after stream properties
|
||||||
virtual int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int networkSamples);
|
virtual int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties);
|
||||||
|
|
||||||
/// writes silent samples to the buffer that may be dropped to reduce latency caused by the buffer
|
/// writes silent samples to the buffer that may be dropped to reduce latency caused by the buffer
|
||||||
virtual int writeDroppableSilentSamples(int silentSamples);
|
virtual int writeDroppableSilentSamples(int silentSamples);
|
||||||
|
|
|
@ -42,9 +42,7 @@ int MixedProcessedAudioStream::writeLastFrameRepeatedWithFade(int samples) {
|
||||||
return deviceSamplesWritten;
|
return deviceSamplesWritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MixedProcessedAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int networkSamples) {
|
int MixedProcessedAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties) {
|
||||||
|
|
||||||
// TODO - codec decode goes here
|
|
||||||
QByteArray decodedBuffer;
|
QByteArray decodedBuffer;
|
||||||
if (_codec) {
|
if (_codec) {
|
||||||
_codec->decode(packetAfterStreamProperties, decodedBuffer);
|
_codec->decode(packetAfterStreamProperties, decodedBuffer);
|
||||||
|
@ -52,9 +50,6 @@ int MixedProcessedAudioStream::parseAudioData(PacketType type, const QByteArray&
|
||||||
decodedBuffer = packetAfterStreamProperties;
|
decodedBuffer = packetAfterStreamProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << __FUNCTION__ << "packetAfterStreamProperties:" << packetAfterStreamProperties.size() << "networkSamples:" << networkSamples << "decodedBuffer:" << decodedBuffer.size();
|
|
||||||
|
|
||||||
|
|
||||||
emit addedStereoSamples(decodedBuffer);
|
emit addedStereoSamples(decodedBuffer);
|
||||||
|
|
||||||
QByteArray outputBuffer;
|
QByteArray outputBuffer;
|
||||||
|
|
|
@ -35,7 +35,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
int writeDroppableSilentSamples(int silentSamples);
|
int writeDroppableSilentSamples(int silentSamples);
|
||||||
int writeLastFrameRepeatedWithFade(int samples);
|
int writeLastFrameRepeatedWithFade(int samples);
|
||||||
int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int networkSamples);
|
int parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int networkToDeviceSamples(int networkSamples);
|
int networkToDeviceSamples(int networkSamples);
|
||||||
|
|
|
@ -152,8 +152,11 @@ QByteArray BasePacket::readWithoutCopy(qint64 maxSize) {
|
||||||
|
|
||||||
qint64 BasePacket::writeString(const QString& string) {
|
qint64 BasePacket::writeString(const QString& string) {
|
||||||
QByteArray data = string.toUtf8();
|
QByteArray data = string.toUtf8();
|
||||||
writePrimitive(static_cast<uint32_t>(data.length()));
|
uint32_t length = data.length();
|
||||||
return writeData(data.constData(), data.length());
|
writePrimitive(length);
|
||||||
|
auto result = writeData(data.constData(), data.length());
|
||||||
|
seek(pos() + length);
|
||||||
|
return length + sizeof(uint32_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString BasePacket::readString() {
|
QString BasePacket::readString() {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// PCMCodecManager.cpp
|
// PCMCodec.cpp
|
||||||
// plugins/pcmCodec/src
|
// plugins/pcmCodec/src
|
||||||
//
|
//
|
||||||
// Created by Brad Hefta-Gaub on 6/9/2016
|
// Created by Brad Hefta-Gaub on 6/9/2016
|
||||||
|
@ -15,35 +15,64 @@
|
||||||
|
|
||||||
#include "PCMCodecManager.h"
|
#include "PCMCodecManager.h"
|
||||||
|
|
||||||
const QString PCMCodecManager::NAME = "zlib";
|
const QString PCMCodec::NAME = "pcm";
|
||||||
|
|
||||||
void PCMCodecManager::init() {
|
void PCMCodec::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PCMCodecManager::deinit() {
|
void PCMCodec::deinit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PCMCodecManager::activate() {
|
bool PCMCodec::activate() {
|
||||||
CodecPlugin::activate();
|
CodecPlugin::activate();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PCMCodecManager::deactivate() {
|
void PCMCodec::deactivate() {
|
||||||
CodecPlugin::deactivate();
|
CodecPlugin::deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PCMCodecManager::isSupported() const {
|
bool PCMCodec::isSupported() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PCMCodecManager::decode(const QByteArray& encodedBuffer, QByteArray& decodedBuffer) {
|
void PCMCodec::decode(const QByteArray& encodedBuffer, QByteArray& decodedBuffer) {
|
||||||
//decodedBuffer = encodedBuffer;
|
decodedBuffer = encodedBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCMCodec::encode(const QByteArray& decodedBuffer, QByteArray& encodedBuffer) {
|
||||||
|
encodedBuffer = decodedBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const QString zLibCodec::NAME = "zlib";
|
||||||
|
|
||||||
|
void zLibCodec::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void zLibCodec::deinit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool zLibCodec::activate() {
|
||||||
|
CodecPlugin::activate();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void zLibCodec::deactivate() {
|
||||||
|
CodecPlugin::deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool zLibCodec::isSupported() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void zLibCodec::decode(const QByteArray& encodedBuffer, QByteArray& decodedBuffer) {
|
||||||
decodedBuffer = qUncompress(encodedBuffer);
|
decodedBuffer = qUncompress(encodedBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PCMCodecManager::encode(const QByteArray& decodedBuffer, QByteArray& encodedBuffer) {
|
void zLibCodec::encode(const QByteArray& decodedBuffer, QByteArray& encodedBuffer) {
|
||||||
//encodedBuffer = decodedBuffer;
|
|
||||||
encodedBuffer = qCompress(decodedBuffer);
|
encodedBuffer = qCompress(decodedBuffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
#include <plugins/CodecPlugin.h>
|
#include <plugins/CodecPlugin.h>
|
||||||
|
|
||||||
class PCMCodecManager : public CodecPlugin {
|
class PCMCodec : public CodecPlugin {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -38,4 +38,27 @@ private:
|
||||||
static const QString NAME;
|
static const QString NAME;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class zLibCodec : 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 void decode(const QByteArray& encodedBuffer, QByteArray& decodedBuffer) override;
|
||||||
|
virtual void encode(const QByteArray& decodedBuffer, QByteArray& encodedBuffer) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const QString NAME;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // hifi__PCMCodecManager_h
|
#endif // hifi__PCMCodecManager_h
|
||||||
|
|
|
@ -29,10 +29,17 @@ public:
|
||||||
virtual CodecPluginList getCodecPlugins() override {
|
virtual CodecPluginList getCodecPlugins() override {
|
||||||
static std::once_flag once;
|
static std::once_flag once;
|
||||||
std::call_once(once, [&] {
|
std::call_once(once, [&] {
|
||||||
CodecPluginPointer plugin(new PCMCodecManager());
|
|
||||||
if (plugin->isSupported()) {
|
CodecPluginPointer pcmCodec(new PCMCodec());
|
||||||
_codecPlugins.push_back(plugin);
|
if (pcmCodec->isSupported()) {
|
||||||
|
_codecPlugins.push_back(pcmCodec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CodecPluginPointer zlibCodec(new zLibCodec());
|
||||||
|
if (zlibCodec->isSupported()) {
|
||||||
|
_codecPlugins.push_back(zlibCodec);
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
return _codecPlugins;
|
return _codecPlugins;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue