mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 01:24:03 +02:00
Merge pull request #3661 from Atlante45/reverb_fixed
Audio Environment packets
This commit is contained in:
commit
e5c9ad4525
9 changed files with 110 additions and 57 deletions
|
@ -640,6 +640,7 @@ void AudioMixer::run() {
|
|||
timer.start();
|
||||
|
||||
char clientMixBuffer[MAX_PACKET_SIZE];
|
||||
char clientEnvBuffer[MAX_PACKET_SIZE];
|
||||
|
||||
int usecToSleep = BUFFER_SEND_INTERVAL_USECS;
|
||||
|
||||
|
@ -719,65 +720,90 @@ void AudioMixer::run() {
|
|||
|
||||
int streamsMixed = prepareMixForListeningNode(node.data());
|
||||
|
||||
char* dataAt;
|
||||
char* mixDataAt;
|
||||
if (streamsMixed > 0) {
|
||||
// pack header
|
||||
int numBytesPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeMixedAudio);
|
||||
dataAt = clientMixBuffer + numBytesPacketHeader;
|
||||
int numBytesMixPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeMixedAudio);
|
||||
mixDataAt = clientMixBuffer + numBytesMixPacketHeader;
|
||||
|
||||
// pack sequence number
|
||||
quint16 sequence = nodeData->getOutgoingSequenceNumber();
|
||||
memcpy(dataAt, &sequence, sizeof(quint16));
|
||||
dataAt += sizeof(quint16);
|
||||
memcpy(mixDataAt, &sequence, sizeof(quint16));
|
||||
mixDataAt += sizeof(quint16);
|
||||
|
||||
// pack mixed audio samples
|
||||
memcpy(mixDataAt, _mixSamples, NETWORK_BUFFER_LENGTH_BYTES_STEREO);
|
||||
mixDataAt += NETWORK_BUFFER_LENGTH_BYTES_STEREO;
|
||||
|
||||
// Pack stream properties
|
||||
bool inAZone = false;
|
||||
// Send stream properties
|
||||
bool hasReverb = false;
|
||||
float reverbTime, wetLevel;
|
||||
// find reverb properties
|
||||
for (int i = 0; i < _zoneReverbSettings.size(); ++i) {
|
||||
AudioMixerClientData* data = static_cast<AudioMixerClientData*>(node->getLinkedData());
|
||||
glm::vec3 streamPosition = data->getAvatarAudioStream()->getPosition();
|
||||
if (_audioZones[_zoneReverbSettings[i].zone].contains(streamPosition)) {
|
||||
bool hasReverb = true;
|
||||
float reverbTime = _zoneReverbSettings[i].reverbTime;
|
||||
float wetLevel = _zoneReverbSettings[i].wetLevel;
|
||||
|
||||
memcpy(dataAt, &hasReverb, sizeof(bool));
|
||||
dataAt += sizeof(bool);
|
||||
memcpy(dataAt, &reverbTime, sizeof(float));
|
||||
dataAt += sizeof(float);
|
||||
memcpy(dataAt, &wetLevel, sizeof(float));
|
||||
dataAt += sizeof(float);
|
||||
|
||||
inAZone = true;
|
||||
hasReverb = true;
|
||||
reverbTime = _zoneReverbSettings[i].reverbTime;
|
||||
wetLevel = _zoneReverbSettings[i].wetLevel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!inAZone) {
|
||||
bool hasReverb = false;
|
||||
memcpy(dataAt, &hasReverb, sizeof(bool));
|
||||
dataAt += sizeof(bool);
|
||||
AvatarAudioStream* stream = nodeData->getAvatarAudioStream();
|
||||
bool dataChanged = (stream->hasReverb() != hasReverb) ||
|
||||
(stream->hasReverb() && (stream->getRevebTime() != reverbTime ||
|
||||
stream->getWetLevel() != wetLevel));
|
||||
if (dataChanged) {
|
||||
// Update stream
|
||||
if (hasReverb) {
|
||||
stream->setReverb(reverbTime, wetLevel);
|
||||
} else {
|
||||
stream->clearReverb();
|
||||
}
|
||||
}
|
||||
|
||||
// pack mixed audio samples
|
||||
memcpy(dataAt, _mixSamples, NETWORK_BUFFER_LENGTH_BYTES_STEREO);
|
||||
dataAt += NETWORK_BUFFER_LENGTH_BYTES_STEREO;
|
||||
// Send at change or every so often
|
||||
float CHANCE_OF_SEND = 0.01f;
|
||||
bool sendData = dataChanged || (randFloat() < CHANCE_OF_SEND);
|
||||
|
||||
if (sendData) {
|
||||
int numBytesEnvPacketHeader = populatePacketHeader(clientEnvBuffer, PacketTypeAudioEnvironment);
|
||||
char* envDataAt = clientEnvBuffer + numBytesEnvPacketHeader;
|
||||
|
||||
unsigned char bitset = 0;
|
||||
if (hasReverb) {
|
||||
setAtBit(bitset, HAS_REVERB_BIT);
|
||||
}
|
||||
|
||||
memcpy(envDataAt, &bitset, sizeof(unsigned char));
|
||||
envDataAt += sizeof(unsigned char);
|
||||
|
||||
if (hasReverb) {
|
||||
memcpy(envDataAt, &reverbTime, sizeof(float));
|
||||
envDataAt += sizeof(float);
|
||||
memcpy(envDataAt, &wetLevel, sizeof(float));
|
||||
envDataAt += sizeof(float);
|
||||
}
|
||||
nodeList->writeDatagram(clientEnvBuffer, envDataAt - clientEnvBuffer, node);
|
||||
}
|
||||
} else {
|
||||
// pack header
|
||||
int numBytesPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeSilentAudioFrame);
|
||||
dataAt = clientMixBuffer + numBytesPacketHeader;
|
||||
mixDataAt = clientMixBuffer + numBytesPacketHeader;
|
||||
|
||||
// pack sequence number
|
||||
quint16 sequence = nodeData->getOutgoingSequenceNumber();
|
||||
memcpy(dataAt, &sequence, sizeof(quint16));
|
||||
dataAt += sizeof(quint16);
|
||||
memcpy(mixDataAt, &sequence, sizeof(quint16));
|
||||
mixDataAt += sizeof(quint16);
|
||||
|
||||
// pack number of silent audio samples
|
||||
quint16 numSilentSamples = NETWORK_BUFFER_LENGTH_SAMPLES_STEREO;
|
||||
memcpy(dataAt, &numSilentSamples, sizeof(quint16));
|
||||
dataAt += sizeof(quint16);
|
||||
memcpy(mixDataAt, &numSilentSamples, sizeof(quint16));
|
||||
mixDataAt += sizeof(quint16);
|
||||
}
|
||||
|
||||
// send mixed audio packet
|
||||
nodeList->writeDatagram(clientMixBuffer, dataAt - clientMixBuffer, node);
|
||||
nodeList->writeDatagram(clientMixBuffer, mixDataAt - clientMixBuffer, node);
|
||||
nodeData->incrementOutgoingMixedAudioSequenceNumber();
|
||||
|
||||
// send an audio stream stats packet if it's time
|
||||
|
|
2
interface/external/gverb/readme.txt
vendored
2
interface/external/gverb/readme.txt
vendored
|
@ -1,7 +1,7 @@
|
|||
|
||||
Instructions for adding the Gverb library to Interface
|
||||
(This is a required library)
|
||||
Clément Brisset, Octobre 22nd, 2014
|
||||
Clément Brisset, October 22nd, 2014
|
||||
|
||||
1. Go to https://github.com/highfidelity/gverb
|
||||
Or download the sources directly via this link:
|
||||
|
|
|
@ -1018,6 +1018,27 @@ void Audio::parseAudioStreamStatsPacket(const QByteArray& packet) {
|
|||
}
|
||||
}
|
||||
|
||||
void Audio::parseAudioEnvironmentData(const QByteArray &packet) {
|
||||
int numBytesPacketHeader = numBytesForPacketHeader(packet);
|
||||
const char* dataAt = packet.constData() + numBytesPacketHeader;
|
||||
|
||||
char bitset;
|
||||
memcpy(&bitset, dataAt, sizeof(char));
|
||||
dataAt += sizeof(char);
|
||||
|
||||
bool hasReverb = oneAtBit(bitset, HAS_REVERB_BIT);;
|
||||
if (hasReverb) {
|
||||
float reverbTime, wetLevel;
|
||||
memcpy(&reverbTime, dataAt, sizeof(float));
|
||||
dataAt += sizeof(float);
|
||||
memcpy(&wetLevel, dataAt, sizeof(float));
|
||||
dataAt += sizeof(float);
|
||||
_receivedAudioStream.setReverb(reverbTime, wetLevel);
|
||||
} else {
|
||||
_receivedAudioStream.clearReverb();
|
||||
}
|
||||
}
|
||||
|
||||
void Audio::sendDownstreamAudioStatsPacket() {
|
||||
|
||||
// since this function is called every second, we'll sample for some of our stats here
|
||||
|
|
|
@ -125,6 +125,7 @@ public slots:
|
|||
void stop();
|
||||
void addReceivedAudioToStream(const QByteArray& audioByteArray);
|
||||
void parseAudioStreamStatsPacket(const QByteArray& packet);
|
||||
void parseAudioEnvironmentData(const QByteArray& packet);
|
||||
void addSpatialAudioToBuffer(unsigned int sampleTime, const QByteArray& spatialAudio, unsigned int numSamples);
|
||||
void handleAudioInput();
|
||||
void reset();
|
||||
|
|
|
@ -49,14 +49,18 @@ void DatagramProcessor::processDatagrams() {
|
|||
PacketType incomingType = packetTypeForPacket(incomingPacket);
|
||||
// only process this packet if we have a match on the packet version
|
||||
switch (incomingType) {
|
||||
case PacketTypeAudioEnvironment:
|
||||
case PacketTypeAudioStreamStats:
|
||||
case PacketTypeMixedAudio:
|
||||
case PacketTypeSilentAudioFrame:
|
||||
case PacketTypeAudioStreamStats: {
|
||||
if (incomingType != PacketTypeAudioStreamStats) {
|
||||
QMetaObject::invokeMethod(&application->_audio, "addReceivedAudioToStream", Qt::QueuedConnection,
|
||||
case PacketTypeSilentAudioFrame: {
|
||||
if (incomingType == PacketTypeAudioStreamStats) {
|
||||
QMetaObject::invokeMethod(&application->_audio, "parseAudioStreamStatsPacket", Qt::QueuedConnection,
|
||||
Q_ARG(QByteArray, incomingPacket));
|
||||
} else if (incomingType == PacketTypeAudioEnvironment) {
|
||||
QMetaObject::invokeMethod(&application->_audio, "parseAudioEnvironmentData", Qt::QueuedConnection,
|
||||
Q_ARG(QByteArray, incomingPacket));
|
||||
} else {
|
||||
QMetaObject::invokeMethod(&application->_audio, "parseAudioStreamStatsPacket", Qt::QueuedConnection,
|
||||
QMetaObject::invokeMethod(&application->_audio, "addReceivedAudioToStream", Qt::QueuedConnection,
|
||||
Q_ARG(QByteArray, incomingPacket));
|
||||
}
|
||||
|
||||
|
|
|
@ -83,6 +83,12 @@ void InboundAudioStream::clearBuffer() {
|
|||
_currentJitterBufferFrames = 0;
|
||||
}
|
||||
|
||||
void InboundAudioStream::setReverb(float reverbTime, float wetLevel) {
|
||||
_hasReverb = true;
|
||||
_reverbTime = reverbTime;
|
||||
_wetLevel = wetLevel;
|
||||
}
|
||||
|
||||
void InboundAudioStream::perSecondCallbackForUpdatingStats() {
|
||||
_incomingSequenceNumberStats.pushStatsToHistory();
|
||||
_timeGapStatsForDesiredCalcOnTooManyStarves.currentIntervalComplete();
|
||||
|
@ -163,22 +169,9 @@ int InboundAudioStream::parseData(const QByteArray& packet) {
|
|||
}
|
||||
|
||||
int InboundAudioStream::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) {
|
||||
int read = 0;
|
||||
if (type == PacketTypeMixedAudio) {
|
||||
memcpy(&_hasReverb, packetAfterSeqNum.data() + read, sizeof(bool));
|
||||
read += sizeof(bool);
|
||||
|
||||
if (_hasReverb) {
|
||||
memcpy(&_reverbTime, packetAfterSeqNum.data() + read, sizeof(float));
|
||||
read += sizeof(float);
|
||||
memcpy(&_wetLevel, packetAfterSeqNum.data() + read, sizeof(float));
|
||||
read += sizeof(float);
|
||||
}
|
||||
}
|
||||
|
||||
// mixed audio packets do not have any info between the seq num and the audio data.
|
||||
numAudioSamples = (packetAfterSeqNum.size() - read) / sizeof(int16_t);
|
||||
return read;
|
||||
numAudioSamples = packetAfterSeqNum.size() / sizeof(int16_t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int InboundAudioStream::parseAudioData(PacketType type, const QByteArray& packetAfterStreamProperties, int numAudioSamples) {
|
||||
|
|
|
@ -45,6 +45,9 @@ const int DEFAULT_WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES = 50;
|
|||
const int DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION = 10;
|
||||
const bool DEFAULT_REPETITION_WITH_FADE = true;
|
||||
|
||||
// Audio Env bitset
|
||||
const int HAS_REVERB_BIT = 0; // 1st bit
|
||||
|
||||
class InboundAudioStream : public NodeData {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -158,6 +161,8 @@ public:
|
|||
bool hasReverb() const { return _hasReverb; }
|
||||
float getRevebTime() const { return _reverbTime; }
|
||||
float getWetLevel() const { return _wetLevel; }
|
||||
void setReverb(float reverbTime, float wetLevel);
|
||||
void clearReverb() { _hasReverb = false; }
|
||||
|
||||
public slots:
|
||||
/// This function should be called every second for all the stats to function properly. If dynamic jitter buffers
|
||||
|
|
|
@ -53,7 +53,7 @@ PacketVersion versionForPacketType(PacketType type) {
|
|||
case PacketTypeSilentAudioFrame:
|
||||
return 4;
|
||||
case PacketTypeMixedAudio:
|
||||
return 2;
|
||||
return 1;
|
||||
case PacketTypeAvatarData:
|
||||
return 3;
|
||||
case PacketTypeAvatarIdentity:
|
||||
|
@ -71,11 +71,9 @@ PacketVersion versionForPacketType(PacketType type) {
|
|||
return 1;
|
||||
case PacketTypeOctreeStats:
|
||||
return 1;
|
||||
|
||||
case PacketTypeEntityAddOrEdit:
|
||||
case PacketTypeEntityData:
|
||||
return VERSION_ENTITIES_SUPPORT_DIMENSIONS;
|
||||
|
||||
case PacketTypeEntityErase:
|
||||
return 2;
|
||||
case PacketTypeAudioStreamStats:
|
||||
|
@ -135,8 +133,13 @@ QString nameForPacketType(PacketType type) {
|
|||
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAddResponse);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeOctreeDataNack);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeVoxelEditNack);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeAudioEnvironment);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityEditNack);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeSignedTransactionPayment);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeIceServerHeartbeat);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeIceServerHeartbeatResponse);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPing);
|
||||
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPingReply);
|
||||
default:
|
||||
return QString("Type: ") + QString::number((int)type);
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ enum PacketType {
|
|||
PacketTypeEntityAddResponse,
|
||||
PacketTypeOctreeDataNack, // 45
|
||||
PacketTypeVoxelEditNack,
|
||||
UNUSED_6,
|
||||
PacketTypeAudioEnvironment,
|
||||
PacketTypeEntityEditNack, // 48
|
||||
PacketTypeSignedTransactionPayment,
|
||||
PacketTypeIceServerHeartbeat,
|
||||
|
|
Loading…
Reference in a new issue