diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 9e6ec1209c..23bee2c91a 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -474,24 +474,18 @@ void Agent::processAgentAvatar() { nodeList->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer); } } -void Agent::flushEncoder() { +void Agent::encodeFrameOfZeros(QByteArray& encodedZeros) { _flushEncoder = false; - static QByteArray zeros(AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL, 0); - static QByteArray encodedZeros; + static const QByteArray zeros(AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL, 0); if (_encoder) { _encoder->encode(zeros, encodedZeros); + } else { + encodedZeros = zeros; } } void Agent::processAgentAvatarAudio() { if (_isAvatar && (_isListeningToAudioStream || _avatarSound)) { - // after sound is done playing, encoder has a bit of state in it, - // and needs some 0s to forget or you get a little click next time - // you play something - if (_flushEncoder) { - flushEncoder(); - } - // if we have an avatar audio stream then send it out to our audio-mixer auto scriptedAvatar = DependencyManager::get(); bool silentFrame = true; @@ -528,7 +522,7 @@ void Agent::processAgentAvatarAudio() { } } - auto audioPacket = NLPacket::create(silentFrame + auto audioPacket = NLPacket::create(silentFrame && !_flushEncoder ? PacketType::SilentAudioFrame : PacketType::MicrophoneAudioNoEcho); @@ -564,13 +558,17 @@ void Agent::processAgentAvatarAudio() { glm::quat headOrientation = scriptedAvatar->getHeadOrientation(); audioPacket->writePrimitive(headOrientation); - QByteArray decodedBuffer(reinterpret_cast(nextSoundOutput), numAvailableSamples*sizeof(int16_t)); QByteArray encodedBuffer; - // encode it - if(_encoder) { - _encoder->encode(decodedBuffer, encodedBuffer); + if (_flushEncoder) { + encodeFrameOfZeros(encodedBuffer); } else { - encodedBuffer = decodedBuffer; + QByteArray decodedBuffer(reinterpret_cast(nextSoundOutput), numAvailableSamples*sizeof(int16_t)); + if (_encoder) { + // encode it + _encoder->encode(decodedBuffer, encodedBuffer); + } else { + encodedBuffer = decodedBuffer; + } } audioPacket->write(encodedBuffer.constData(), encodedBuffer.size()); } diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index b882ac3125..939b51625a 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -81,7 +81,7 @@ signals: private: void negotiateAudioFormat(); void selectAudioFormat(const QString& selectedCodecName); - void flushEncoder(); + void encodeFrameOfZeros(QByteArray& encodedZeros); std::unique_ptr _scriptEngine; EntityEditPacketSender _entityEditSender; diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 63f4106f0a..bc356b8ce1 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -810,7 +810,8 @@ void AudioMixer::broadcastMixes() { std::unique_ptr mixPacket; - if (mixHasAudio) { + if (mixHasAudio || nodeData->shouldFlushEncoder()) { + int mixPacketBytes = sizeof(quint16) + AudioConstants::MAX_CODEC_NAME_LENGTH_ON_WIRE + AudioConstants::NETWORK_FRAME_BYTES_STEREO; mixPacket = NLPacket::create(PacketType::MixedAudio, mixPacketBytes); @@ -823,12 +824,17 @@ void AudioMixer::broadcastMixes() { QString codecInPacket = nodeData->getCodecName(); mixPacket->writeString(codecInPacket); - QByteArray decodedBuffer(reinterpret_cast(_clampedSamples), AudioConstants::NETWORK_FRAME_BYTES_STEREO); QByteArray encodedBuffer; - nodeData->encode(decodedBuffer, encodedBuffer); - + if (mixHasAudio) { + QByteArray decodedBuffer(reinterpret_cast(_clampedSamples), AudioConstants::NETWORK_FRAME_BYTES_STEREO); + nodeData->encode(decodedBuffer, encodedBuffer); + } else { + // time to flush, which resets the shouldFlush until next time we encode something + nodeData->encodeFrameOfZeros(encodedBuffer); + } // pack mixed audio samples mixPacket->write(encodedBuffer.constData(), encodedBuffer.size()); + } else { int silentPacketBytes = sizeof(quint16) + sizeof(quint16) + AudioConstants::MAX_CODEC_NAME_LENGTH_ON_WIRE; mixPacket = NLPacket::create(PacketType::SilentAudioFrame, silentPacketBytes); diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index dba7b26dbf..58d89697af 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -371,6 +371,17 @@ void AudioMixerClientData::sendSelectAudioFormat(SharedNodePointer node, const Q nodeList->sendPacket(std::move(replyPacket), *node); } +void AudioMixerClientData::encodeFrameOfZeros(QByteArray& encodedZeros) { + static QByteArray zeros(AudioConstants::NETWORK_FRAME_BYTES_STEREO, 0); + if (_shouldFlushEncoder) { + if (_encoder) { + _encoder->encode(zeros, encodedZeros); + } else { + encodedZeros = zeros; + } + } + _shouldFlushEncoder = false; +} void AudioMixerClientData::setupCodec(CodecPluginPointer codec, const QString& codecName) { cleanupCodec(); // cleanup any previously allocated coders first diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index f12df5bd82..34263f9cbe 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -77,7 +77,11 @@ public: } else { encodedBuffer = decodedBuffer; } + // once you have encoded, you need to flush eventually. + _shouldFlushEncoder = true; } + void encodeFrameOfZeros(QByteArray& encodedZeros); + bool shouldFlushEncoder() { return _shouldFlushEncoder; } QString getCodecName() { return _selectedCodecName; } @@ -106,6 +110,8 @@ private: QString _selectedCodecName; Encoder* _encoder{ nullptr }; // for outbound mixed stream Decoder* _decoder{ nullptr }; // for mic stream + + bool _shouldFlushEncoder { false }; }; #endif // hifi_AudioMixerClientData_h