From d60eecd9a9d94366c2f0a319d85bc99d7e0ad50b Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Fri, 1 May 2020 20:03:55 +0200 Subject: [PATCH] Fixes for 1.4.6 --- github | 2 +- .../renderer/connection/VoiceConnection.ts | 2 +- .../src/audio/AudioOutput.cpp | 122 +++++++++++++++++- .../serverconnection/src/audio/AudioOutput.h | 11 +- .../src/audio/codec/Converter.h | 4 +- .../src/audio/codec/OpusConverter.cpp | 25 +++- .../src/audio/codec/OpusConverter.h | 5 +- .../src/audio/sounds/SoundPlayer.cpp | 2 +- .../src/connection/audio/AudioSender.cpp | 11 +- .../src/connection/audio/VoiceClient.cpp | 78 ++++++++--- .../src/connection/audio/VoiceClient.h | 2 +- native/serverconnection/src/ring_buffer.cpp | 5 + native/serverconnection/src/ring_buffer.h | 2 + native/updater/test/update.log | 11 ++ package.json | 2 +- 15 files changed, 242 insertions(+), 42 deletions(-) diff --git a/github b/github index cca8985..30322f6 160000 --- a/github +++ b/github @@ -1 +1 @@ -Subproject commit cca898581e4b4138a2b4f99429d0bbd70a344bc4 +Subproject commit 30322f64162fd4805bc01542cc5cefbb9fe842a3 diff --git a/modules/renderer/connection/VoiceConnection.ts b/modules/renderer/connection/VoiceConnection.ts index 829d197..b490f31 100644 --- a/modules/renderer/connection/VoiceConnection.ts +++ b/modules/renderer/connection/VoiceConnection.ts @@ -119,7 +119,7 @@ export class VoiceConnection extends AbstractVoiceConnection { support_latency_settings() { return true; }, reset_latency_settings: function() { const stream = this.get_stream(); - stream.set_buffer_latency(0.02); + stream.set_buffer_latency(0.040); stream.set_buffer_max_latency(0.2); return this.latency_settings(); }, diff --git a/native/serverconnection/src/audio/AudioOutput.cpp b/native/serverconnection/src/audio/AudioOutput.cpp index c80dcc5..43cac42 100644 --- a/native/serverconnection/src/audio/AudioOutput.cpp +++ b/native/serverconnection/src/audio/AudioOutput.cpp @@ -13,6 +13,56 @@ using namespace tc::audio; void AudioOutputSource::clear() { this->buffer.clear(); this->buffering = true; + this->fade_in_start = this->buffer.write_ptr(); +} + +void AudioOutputSource::do_fade_out(size_t pop_count) { + if(this->will_buffer_in != -1) return; + + _test_for_fade: + const auto samples_left = this->current_latency(); + if(samples_left < this->fadeout_sample_length + pop_count) { + if(auto fn = this->on_underflow; fn && fn(0)) + goto _test_for_fade; + + auto wptr = (float*) this->buffer.write_ptr(); + auto total_samples = std::min(samples_left, this->fadeout_sample_length); + if(total_samples == 0) return; //TODO Test against min_buffered_samples + + for(size_t index{0}; index < total_samples; index++) { + const auto offset = (float) ((float) index / (float) total_samples); + const auto volume = log10f(1 - offset) / -2.71828182845904f; + for(int channel{0}; channel < this->channel_count; channel++) + *wptr-- *= volume; + } + + log_trace(category::audio, tr("Will buffer due to fade out ({} | {})"), total_samples, *(float*) this->buffer.write_ptr()); + this->will_buffer_in = total_samples; + } +} + +void AudioOutputSource::do_fade_in() { + if(!this->fade_in_start) + return; + + const auto samples_available = this->current_latency(); + auto wptr = (float*) this->fade_in_start; + auto total_samples = std::min(samples_available, this->fadeout_sample_length); + if(total_samples == 0) { + log_trace(category::audio, tr("Ignoring fade in 0: {} {}"), samples_available, this->fadeout_sample_length); + return; + } + + for(size_t index{0}; index < total_samples; index++) { + const auto offset = (float) ((float) index / (float) total_samples); + const auto volume = log10f(1 - offset) / -2.71828182845904f; + for(int channel{0}; channel < this->channel_count; channel++) + *wptr++ *= volume; + } + + log_trace(category::audio, tr("Fade in to new buffer ({})"), total_samples); + + this->fade_in_start = nullptr; } ssize_t AudioOutputSource::pop_samples(void *buffer, size_t samples) { @@ -21,12 +71,27 @@ ssize_t AudioOutputSource::pop_samples(void *buffer, size_t samples) { load_buffer: auto available_bytes = this->buffer.fill_count(); if(available_bytes < sizeof(float) * this->channel_count) return written; - auto available_samples = available_bytes / sizeof(float) / this->channel_count; - //log_trace(category::audio, tr("Min: {}, Max: {}, Current: {}, Buffering: {}"), this->min_buffered_samples, this->max_buffered_samples, available_samples, this->buffering); - if(this->buffering && available_samples < this->min_buffered_samples) return -2; - this->buffering = false; + if(this->buffering && available_samples < this->min_buffered_samples) return -2; + this->do_fade_in(); + this->do_fade_out(samples); /* will also call for underflow */ + //log_trace(category::audio, tr("Min: {}, Max: {}, Current: {}, Buffering: {} Required: {}, left: {}, will buffer in {}"), this->min_buffered_samples, this->max_buffered_samples, available_samples, this->buffering, samples, (int) available_samples - samples, this->will_buffer_in); + + if(this->will_buffer_in > 0) { + if(samples > this->will_buffer_in) { + samples = this->will_buffer_in; + this->buffering = true; + this->fade_in_start = this->buffer.calculate_advanced_write_ptr(samples * sizeof(float) * this->channel_count); + this->will_buffer_in = -1; + log_trace(category::audio, tr("Start buffering due to fade out. Fade in ptr {}"), (void*) this->fade_in_start); + } else { + this->will_buffer_in -= samples; + } + } else { + this->buffering = false; + } + if(available_samples >= samples - written) { const auto byte_length = (samples - written) * sizeof(float) * this->channel_count; if(buffer)memcpy((char*) buffer + written_bytes, this->buffer.read_ptr(), byte_length); @@ -34,10 +99,11 @@ ssize_t AudioOutputSource::pop_samples(void *buffer, size_t samples) { if(this->on_read) this->on_read(); + return samples; } else { const auto byte_length = available_samples * sizeof(float) * this->channel_count; - if(buffer)memcpy((char*) buffer + written_bytes, this->buffer.read_ptr(), byte_length); + if(buffer) memcpy((char*) buffer + written_bytes, this->buffer.read_ptr(), byte_length); this->buffer.advance_read_ptr(byte_length); written += available_samples; written_bytes += byte_length; @@ -48,14 +114,58 @@ ssize_t AudioOutputSource::pop_samples(void *buffer, size_t samples) { if(fn(samples - written)) goto load_buffer; - if(buffer)memset(buffer, 0, (samples - written) * sizeof(float) * this->channel_count); + if(buffer) + memset((char*) buffer + written_bytes, 0, (samples - written) * sizeof(float) * this->channel_count); + this->buffering = true; + this->fade_in_start = this->buffer.write_ptr(); + log_trace(category::audio, tr("Start buffering due to underflow."), (void*) this->fade_in_start); + this->will_buffer_in = -1; if(this->on_read) this->on_read(); return written; /* return the written samples */ } +ssize_t AudioOutputSource::enqueue_silence(size_t samples) { + size_t enqueued{0}; + + auto free_bytes = this->buffer.free_count(); + auto free_samples = free_bytes / sizeof(float) / this->channel_count; + if(this->max_buffered_samples && free_samples > this->max_buffered_samples) free_samples = this->max_buffered_samples; + + if(free_samples >= samples) { + const auto byte_length = samples * sizeof(float) * this->channel_count; + memset(this->buffer.write_ptr(), 0, byte_length); + this->buffer.advance_write_ptr(byte_length); + return samples; + } else { + const auto byte_length = free_samples * sizeof(float) * this->channel_count; + memset(this->buffer.write_ptr(), 0, byte_length); + this->buffer.advance_write_ptr(byte_length); + enqueued += free_samples; + } + + if(auto fn = this->on_overflow; fn) + fn(samples - enqueued); + + switch (this->overflow_strategy) { + case overflow_strategy::discard_input: + return -2; + case overflow_strategy::discard_buffer_all: + this->buffer.clear(); + break; + case overflow_strategy::discard_buffer_half: + this->buffer.advance_read_ptr(this->buffer.fill_count() / 2); + break; + case overflow_strategy::ignore: + break; + } + + this->fade_in_start = this->buffer.write_ptr(); /* so we fade in from silence */ + return enqueued; +} + ssize_t AudioOutputSource::enqueue_samples(const void *buffer, size_t samples) { size_t enqueued{0}; diff --git a/native/serverconnection/src/audio/AudioOutput.h b/native/serverconnection/src/audio/AudioOutput.h index 02cd03a..c51575e 100644 --- a/native/serverconnection/src/audio/AudioOutput.h +++ b/native/serverconnection/src/audio/AudioOutput.h @@ -50,8 +50,12 @@ namespace tc::audio { } bool buffering{true}; + char* fade_in_start{nullptr}; + ssize_t will_buffer_in{-1}; size_t min_buffered_samples{0}; - size_t max_buffered_samples{0}; + size_t max_buffered_samples{0}; + + size_t fadeout_sample_length{360}; overflow_strategy::value overflow_strategy = overflow_strategy::discard_buffer_half; @@ -62,14 +66,19 @@ namespace tc::audio { void clear(); ssize_t pop_samples(void* /* output buffer */, size_t /* sample count */); + ssize_t enqueue_silence(size_t /* sample count */); ssize_t enqueue_samples(const void * /* input buffer */, size_t /* sample count */); ssize_t enqueue_samples_no_interleave(const void * /* input buffer */, size_t /* sample count */); private: AudioOutputSource(AudioOutput* handle, size_t channel_count, size_t sample_rate, ssize_t max_buffer_sample_count = -1) : handle(handle), channel_count(channel_count), sample_rate(sample_rate), buffer{max_buffer_sample_count == -1 ? channel_count * sample_rate * sizeof(float) : max_buffer_sample_count * channel_count * sizeof(float)} { + this->clear(); } + void do_fade_out(size_t /* pop count */); + void do_fade_in(); + tc::ring_buffer buffer; }; diff --git a/native/serverconnection/src/audio/codec/Converter.h b/native/serverconnection/src/audio/codec/Converter.h index fcea8f0..5527dd2 100644 --- a/native/serverconnection/src/audio/codec/Converter.h +++ b/native/serverconnection/src/audio/codec/Converter.h @@ -40,12 +40,12 @@ namespace tc { /** * @return number of bytes written on success */ - virtual ssize_t encode(std::string& /* error */, const void* /* source */, void* /* destination */, size_t /* destination byte length */) = 0; + virtual ssize_t encode(std::string& /* error */, const void* /* source */, void* /* destination */, size_t /* destination byte length */, bool /* head package */) = 0; /** * @return number of samples on success */ - virtual ssize_t decode(std::string& /* error */, const void* /* source */, size_t /* source byte length */, void* /* destination */) = 0; + virtual ssize_t decode(std::string& /* error */, const void* /* source */, size_t /* source byte length */, void* /* destination */, bool /* fec decoding */) = 0; virtual ssize_t decode_lost(std::string& /* error */, size_t /* packets */) = 0; virtual size_t expected_encoded_length(size_t /* sample count */) = 0; diff --git a/native/serverconnection/src/audio/codec/OpusConverter.cpp b/native/serverconnection/src/audio/codec/OpusConverter.cpp index 2a2ee96..411a675 100644 --- a/native/serverconnection/src/audio/codec/OpusConverter.cpp +++ b/native/serverconnection/src/audio/codec/OpusConverter.cpp @@ -29,7 +29,7 @@ bool OpusConverter::initialize(std::string &error, int application_type) { void OpusConverter::reset_encoder() { lock_guard lock(this->coder_lock); - + log_info(category::audio, tr("Resetting encoder")); auto result = opus_encoder_ctl(this->encoder, OPUS_RESET_STATE); if(result != OPUS_OK) log_warn(category::audio, tr("Failed to reset opus encoder. Opus result: {}"), result); @@ -38,9 +38,11 @@ void OpusConverter::reset_encoder() { void OpusConverter::reset_decoder() { lock_guard lock(this->coder_lock); + log_info(category::audio, tr("Resetting decoder")); auto result = opus_decoder_ctl(this->decoder, OPUS_RESET_STATE); if(result != OPUS_OK) log_warn(category::audio, tr("Failed to reset opus decoder. Opus result: {}"), result); + this->fec_decoder_ = true; } @@ -54,9 +56,10 @@ void OpusConverter::finalize() { this->decoder = nullptr; } -ssize_t OpusConverter::encode(std::string &error, const void *source, void *target, size_t target_length) { +ssize_t OpusConverter::encode(std::string &error, const void *source, void *target, size_t target_length, bool head_package) { lock_guard lock(this->coder_lock); + opus_encoder_ctl(encoder, OPUS_SET_PACKET_LOSS_PERC(head_package ? 100 : 15)); auto result = opus_encode_float(this->encoder, (float*) source, (int) this->_frame_size, (uint8_t*) target, (opus_int32) target_length); if(result < OPUS_OK) { error = to_string(result) + "|" + opus_strerror(result); @@ -65,10 +68,10 @@ ssize_t OpusConverter::encode(std::string &error, const void *source, void *targ return result; } -ssize_t OpusConverter::decode(std::string &error, const void *source, size_t source_length, void *target) { +ssize_t OpusConverter::decode(std::string &error, const void *source, size_t source_length, void *target, bool use_fec) { lock_guard lock(this->coder_lock); - auto result = opus_decode_float(this->decoder, (uint8_t*) source, (opus_int32) source_length, (float*) target, (int) this->_frame_size, 0); + auto result = opus_decode_float(this->decoder, (uint8_t*) source, (opus_int32) source_length, (float*) target, (int) this->_frame_size, use_fec ? 1 : 0); if(result < OPUS_OK) { error = to_string(result) + "|" + opus_strerror(result); return -1; @@ -85,6 +88,7 @@ ssize_t OpusConverter::decode_lost(std::string &error, size_t packets) { if(result < OPUS_OK) log_warn(category::audio, tr("Opus decode lost resulted in error: {}"), result); } + this->fec_decoder_ = true; free(buffer); return 0; } @@ -123,6 +127,19 @@ bool OpusConverter::_initialize_encoder(std::string &error) { error = "failed to set bitrate (" + to_string(error_id) + ")"; return false; } + + error_id = opus_encoder_ctl(encoder, OPUS_SET_INBAND_FEC(1)); + if(error_id) { + error = "failed to enable fec (" + to_string(error_id) + ")"; + return false; + } + + error_id = opus_encoder_ctl(encoder, OPUS_SET_PACKET_LOSS_PERC(15)); + if(error_id) { + error = "failed to assume a 15% packet loss (" + to_string(error_id) + ")"; + return false; + } + return true; } diff --git a/native/serverconnection/src/audio/codec/OpusConverter.h b/native/serverconnection/src/audio/codec/OpusConverter.h index 8a9f17c..1e3d17d 100644 --- a/native/serverconnection/src/audio/codec/OpusConverter.h +++ b/native/serverconnection/src/audio/codec/OpusConverter.h @@ -20,8 +20,8 @@ namespace tc { void reset_encoder() override; void reset_decoder() override; - ssize_t encode(std::string & /* error */, const void * /* source */, void * /* target */, size_t /* target size */) override; - ssize_t decode(std::string & /* error */, const void * /* source */, size_t /* source size */, void *pVoid1) override; + ssize_t encode(std::string & /* error */, const void * /* source */, void * /* target */, size_t /* target size */, bool /* head package */) override; + ssize_t decode(std::string & /* error */, const void * /* source */, size_t /* source size */, void *pVoid1, bool /* use fec */) override; ssize_t decode_lost(std::string &string, size_t /* packets */) override; @@ -31,6 +31,7 @@ namespace tc { OpusDecoder* decoder = nullptr; OpusEncoder* encoder = nullptr; + bool fec_decoder_{false}; int _application_type = 0; bool _finalize_encoder(std::string& /* error */); diff --git a/native/serverconnection/src/audio/sounds/SoundPlayer.cpp b/native/serverconnection/src/audio/sounds/SoundPlayer.cpp index 40d12fa..cf97a36 100644 --- a/native/serverconnection/src/audio/sounds/SoundPlayer.cpp +++ b/native/serverconnection/src/audio/sounds/SoundPlayer.cpp @@ -211,7 +211,7 @@ namespace tc::audio::sounds { if(current_size > max_size) return false; const auto size_left = max_size - current_size; - return size_left >= this->cache_buffer_sample_size(); + return size_left >= this->cache_buffer_sample_size() * 1.5; /* ensure we've a bit more space */ } }; diff --git a/native/serverconnection/src/connection/audio/AudioSender.cpp b/native/serverconnection/src/connection/audio/AudioSender.cpp index 8303871..c914bd7 100644 --- a/native/serverconnection/src/connection/audio/AudioSender.cpp +++ b/native/serverconnection/src/connection/audio/AudioSender.cpp @@ -164,8 +164,13 @@ void VoiceSender::encode_raw_frame(const std::unique_ptr &frame) { return; } - if(codec_data) - codec_data->packet_counter = 0; + if(codec_data) { + codec_data->packet_counter = 0; + if(auto converter = codec_data->converter; converter) { + log_trace(category::voice_connection, tr("Resetting encoder")); + converter->reset_encoder(); + } + } auto server = this->handle->handle(); server->send_voice_data(this->_buffer, 0, codec, flag_head); return; @@ -205,7 +210,7 @@ void VoiceSender::encode_raw_frame(const std::unique_ptr &frame) { } char _packet_buffer[512]; - auto encoded_bytes = codec_data->converter->encode(error, this->_buffer, _packet_buffer, 512); + auto encoded_bytes = codec_data->converter->encode(error, this->_buffer, _packet_buffer, 512, flag_head); if(encoded_bytes <= 0) { log_error(category::voice_connection, tr("Failed to encode voice: {}"), error); return; diff --git a/native/serverconnection/src/connection/audio/VoiceClient.cpp b/native/serverconnection/src/connection/audio/VoiceClient.cpp index afaafa9..08a28d7 100644 --- a/native/serverconnection/src/connection/audio/VoiceClient.cpp +++ b/native/serverconnection/src/connection/audio/VoiceClient.cpp @@ -321,6 +321,12 @@ inline constexpr uint16_t packet_id_diff(uint16_t lower, uint16_t upper) { #define MAX_LOST_PACKETS (6) #define target_buffer_length 16384 void VoiceClient::process_packet(uint16_t packet_id, const pipes::buffer_view& buffer, codec::value codec, bool is_head) { +#if 0 + if(rand() % 10 == 0) { + log_info(category::audio, tr("Dropping audio packet id {}"), packet_id); + return; + } +#endif if(codec < 0 || codec > this->codec.size()) { log_warn(category::voice_connection, tr("Received voice packet from client {} with unknown codec ({})"), this->_client_id, codec); return; @@ -488,7 +494,7 @@ void VoiceClient::event_execute(const std::chrono::system_clock::time_point &sch replay_head = audio_codec.pending_buffers; audio_codec.pending_buffers = skip_ptr[SKIP_SEQ_LENGTH]; skip_ptr[SKIP_SEQ_LENGTH - 1]->next = nullptr; - log_trace(category::voice_connection, tr("Skipping from {} to {} because of {} packets in a row"), audio_codec.last_packet_id, head->packet_id, SKIP_SEQ_LENGTH); + log_trace(category::voice_connection, tr("Skipping from {} to {} because of {} packets in a row"), audio_codec.last_packet_id, replay_head->packet_id, SKIP_SEQ_LENGTH); /* Do not set process_pending to false, because we're not done * We're just replaying all loose packets which are not within a sequence until we reach a sequence @@ -508,7 +514,7 @@ void VoiceClient::event_execute(const std::chrono::system_clock::time_point &sch audio_codec.pending_buffers = head->next; head->next = nullptr; log_trace(category::voice_connection, tr("Skipping from {} to {} because of over 6 packets between"), - audio_codec.last_packet_id, head->packet_id); + audio_codec.last_packet_id, replay_head->packet_id); /* do not negate process_pending here. Same reason as with the 3 sequence */ } else { /* no packets we're willing to replay */ @@ -542,27 +548,60 @@ void VoiceClient::event_execute(const std::chrono::system_clock::time_point &sch if(replay_head->buffer.empty()) { this->set_state(state::stopping); log_debug(category::voice_connection, tr("Client {} send a stop signal. Flushing stream and stopping"), this->_client_id); - } else if(local_last_pid > replay_head->packet_id) { - log_debug(category::voice_connection, tr("Client {} tried to replay too old voice chunk. Current id is {}, attempted chunk id is {}. Dropping buffer."), this->_client_id, local_last_pid, replay_head->packet_id); } else { auto lost_packets = packet_id_diff(local_last_pid, replay_head->packet_id) - 1; - if(lost_packets > 6) { + if(lost_packets > 10) { log_debug(category::voice_connection, tr("Client {} seems to be missing {} packets in stream ({} to {}). Resetting decoder."), this->_client_id, lost_packets, local_last_pid, replay_head->packet_id); replay_head->reset_decoder = true; } else if(lost_packets > 0) { - log_debug(category::voice_connection, tr("Client {} seems to be missing {} packets in stream. Skipping ahead."), this->_client_id, lost_packets); + log_debug(category::voice_connection, tr("Client {} seems to be missing {} packets in stream. FEC decoding it."), this->_client_id, lost_packets); + /* if(audio_codec.converter->decode_lost(error, lost_packets)) log_warn(category::audio, tr("Failed to decode lost packets for client {}: {}"), this->_client_id, error); + */ + auto decoded = this->decode_buffer(audio_codec.codec, replay_head->buffer, true); + if(decoded) + this->output_source->enqueue_samples(decoded->sample_data, decoded->sample_size); } - if(replay_head->reset_decoder) - audio_codec.converter->reset_decoder(); + const auto is_new_audio_stream = this->_state != state::buffering && this->_state != state::playing; + if(replay_head->reset_decoder || is_new_audio_stream) { + audio_codec.converter->reset_decoder(); + replay_head->reset_decoder = false; + +#if 1 /* Better approch */ + /* initialize with last packet */ + char target_buffer[target_buffer_length]; + if(target_buffer_length > audio_codec.converter->expected_decoded_length(replay_head->buffer.data_ptr(), replay_head->buffer.length())) { + audio_codec.converter->decode(error, replay_head->buffer.data_ptr(), replay_head->buffer.length(), target_buffer, 1); + } else { + //TODO: May a small warning here? + } +#endif + } + +#if 0 /* (maybe) TS3 approch */ + if(replay_head->head) { + /* initialize with last packet */ + char target_buffer[target_buffer_length]; + if(target_buffer_length > audio_codec.converter->expected_decoded_length(replay_head->buffer.data_ptr(), replay_head->buffer.length())) { + audio_codec.converter->decode(error, replay_head->buffer.data_ptr(), replay_head->buffer.length(), target_buffer, 1); + } else { + //TODO: May a small warning here? + } + } +#endif //TODO: Use statically allocated buffer? - auto decoded = this->decode_buffer(audio_codec.codec, replay_head->buffer); + auto decoded = this->decode_buffer(audio_codec.codec, replay_head->buffer, false); if(!decoded) { log_warn(category::audio, tr("Failed to decode buffer for client {} (nullptr). Dropping buffer."), this->_client_id, error); } else { + if(is_new_audio_stream) { + log_warn(category::audio, tr("New audio chunk for client {}"), this->_client_id); + + //this->output_source->enqueue_silence((size_t) ceil(0.0075f * (float) this->output_source->sample_rate)); /* enqueue 7.5ms silence so we give the next packet a chance to be send */ + } this->output_source->enqueue_samples(decoded->sample_data, decoded->sample_size); this->set_state(state::playing); } @@ -613,7 +652,7 @@ void VoiceClient::initialize_code(const codec::value &audio_codec) { return; } - codec_data.resampler = make_shared(codec_data.converter->sample_rate(), this->output_source->sample_rate, codec_data.converter->channels()); + codec_data.resampler = make_shared(codec_data.converter->sample_rate(), this->output_source->sample_rate, this->output_source->channel_count); if(!codec_data.resampler->valid()) { log_warn(category::voice_connection, tr("Failed to initialized codec {} for client {}. Failed to initialize resampler"), audio_codec, this->_client_id); return; @@ -623,7 +662,7 @@ void VoiceClient::initialize_code(const codec::value &audio_codec) { log_trace(category::voice_connection, tr("Successfully initialized codec {} for client {}."), audio_codec, this->_client_id); } -std::shared_ptr VoiceClient::decode_buffer(const codec::value &audio_codec, const pipes::buffer_view &buffer) { +std::shared_ptr VoiceClient::decode_buffer(const codec::value &audio_codec, const pipes::buffer_view &buffer, bool fec) { assert(this->output_source); auto& codec_data = this->codec[audio_codec]; @@ -638,13 +677,19 @@ std::shared_ptr VoiceClient::decode_buffer(const codec::val log_warn(category::voice_connection, tr("Failed to decode audio data. Target buffer is smaller then expected bytes ({} < {})"), target_buffer_length, codec_data.converter->expected_decoded_length(buffer.data_ptr(), buffer.length())); return nullptr; } - auto samples = codec_data.converter->decode(error, buffer.data_ptr(), buffer.length(), target_buffer); + auto samples = codec_data.converter->decode(error, buffer.data_ptr(), buffer.length(), target_buffer, fec); if(samples < 0) { log_warn(category::voice_connection, tr("Failed to decode audio data: {}"), error); return nullptr; } - if(target_buffer_length < codec_data.resampler->estimated_output_size(samples) * codec_data.resampler->channels() * 4) { - log_warn(category::voice_connection, tr("Failed to resample audio data. Target buffer is smaller then expected bytes ({} < {})"), target_buffer_length, (codec_data.resampler->estimated_output_size(samples) * codec_data.resampler->channels() * 4)); + + if(!audio::merge::merge_channels_interleaved(target_buffer, this->output_source->channel_count, target_buffer, codec_data.converter->channels(), samples)) { + log_warn(category::voice_connection, tr("Failed to merge channels to output stream channel count!")); + return nullptr; + } + + if(target_buffer_length < codec_data.resampler->estimated_output_size(samples) * this->output_source->channel_count * sizeof(float)) { + log_warn(category::voice_connection, tr("Failed to resample audio data. Target buffer is smaller then expected bytes ({} < {})"), target_buffer_length, (codec_data.resampler->estimated_output_size(samples) * this->output_source->channel_count * 4)); return nullptr; } @@ -654,11 +699,6 @@ std::shared_ptr VoiceClient::decode_buffer(const codec::val return nullptr; } - if(!audio::merge::merge_channels_interleaved(target_buffer, this->output_source->channel_count, target_buffer, codec_data.resampler->channels(), resampled_samples)) { - log_warn(category::voice_connection, tr("Failed to merge channels to output stream channel count!")); - return nullptr; - } - if(this->_volume != 1) { auto buf = (float*) target_buffer; auto count = this->output_source->channel_count * resampled_samples; diff --git a/native/serverconnection/src/connection/audio/VoiceClient.h b/native/serverconnection/src/connection/audio/VoiceClient.h index d0eec40..bec7f17 100644 --- a/native/serverconnection/src/connection/audio/VoiceClient.h +++ b/native/serverconnection/src/connection/audio/VoiceClient.h @@ -164,7 +164,7 @@ namespace tc::connection { void event_execute_dropped(const std::chrono::system_clock::time_point &point) override; /* its recommend to call this in correct packet oder */ - std::shared_ptr decode_buffer(const codec::value& /* codec */,const pipes::buffer_view& /* buffer */); + std::shared_ptr decode_buffer(const codec::value& /* codec */,const pipes::buffer_view& /* buffer */, bool /* fec */); }; diff --git a/native/serverconnection/src/ring_buffer.cpp b/native/serverconnection/src/ring_buffer.cpp index a55669d..f1a9cd0 100644 --- a/native/serverconnection/src/ring_buffer.cpp +++ b/native/serverconnection/src/ring_buffer.cpp @@ -238,6 +238,11 @@ namespace tc { assert(this->fill_count() >= 0); } + char* ring_buffer::calculate_advanced_write_ptr(size_t bytes) { + auto offset{this->write_offset.load() + bytes}; + return this->memory.address + (offset % this->memory.capacity); + } + const void* ring_buffer::read_ptr() const { auto offset{this->read_offset.load()}; return this->memory.address + (offset % this->memory.capacity); diff --git a/native/serverconnection/src/ring_buffer.h b/native/serverconnection/src/ring_buffer.h index ee67cf1..41dec2f 100644 --- a/native/serverconnection/src/ring_buffer.h +++ b/native/serverconnection/src/ring_buffer.h @@ -18,6 +18,8 @@ namespace tc { char* write_ptr(); void advance_write_ptr(size_t /* count */); + char* calculate_advanced_write_ptr(size_t /* count */bytes); + /* do not read more than the capacity! */ [[nodiscard]] const void* read_ptr() const; void advance_read_ptr(size_t /* count */); diff --git a/native/updater/test/update.log b/native/updater/test/update.log index 876e4b7..f1e7aef 100644 --- a/native/updater/test/update.log +++ b/native/updater/test/update.log @@ -620,3 +620,14 @@ [59B2][2] Rollback done [59B2][2] executing callback file C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe with fail command line C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -EncodedCommand "QQBkAGQALQBUAHkAcABlACAALQBBAHMAcwBlAG0AYgBsAHkATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVwBpAG4AZABvAHcAcwAuAEYAbwByAG0AcwA7ACAAWwBTAHkAcwB0AGUAbQAuAFcAaQBuAGQAbwB3AHMALgBGAG8AcgBtAHMALgBNAGUAcwBzAGEAZwBlAEIAbwB4AF0AOgA6AFMAaABvAHcAKAAiAFUAcABkAGEAdABlACAAZgBhAGkAbABlAGQAIgAsACIAVQBwAGQAYQB0AGUAcgAiACwAMAApAA=="bG9nX2ZpbGU6ZFhCa1lYUmxjbHgwWlhOMFhIVndaR0YwWlM1c2IyYz07ZXJyb3JfaWQ6TURBd01RPT07ZXJyb3JfbWVzc2FnZTpjMjkxY21ObElHWnBiR1VnWkc5bGN5QnViM1FnWlhocGMzUno= [59B2][2] ----------- log ended at 2020-04-22.20:01:11 ----------- +[5EA7][2] ----------- log started at 2020-04-22.20:01:37 ----------- +[5EA7][2] App executed as admin: no +[5EA7][2] loading config from file updater\test\dummy_config.json +[5EA7][1] Loaded 1 locking actions and 1 moving actions +[5EA7][2] Awaiting the unlocking of all files +[5EA7][5] Failed to lock file D:\Program Files\IDA 7.0\ida.exe. Timeout: 5000, Time tried: 70663 +[5EA7][2] Rollbacking 0 moved files +[5EA7][2] Rollbacking 0 deleted files +[5EA7][2] Rollback done +[5EA7][2] executing callback file C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe with fail command line C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -EncodedCommand "QQBkAGQALQBUAHkAcABlACAALQBBAHMAcwBlAG0AYgBsAHkATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVwBpAG4AZABvAHcAcwAuAEYAbwByAG0AcwA7ACAAWwBTAHkAcwB0AGUAbQAuAFcAaQBuAGQAbwB3AHMALgBGAG8AcgBtAHMALgBNAGUAcwBzAGEAZwBlAEIAbwB4AF0AOgA6AFMAaABvAHcAKAAiAFUAcABkAGEAdABlACAAZgBhAGkAbABlAGQAIgAsACIAVQBwAGQAYQB0AGUAcgAiACwAMAApAA=="bG9nX2ZpbGU6ZFhCa1lYUmxjbHgwWlhOMFhIVndaR0YwWlM1c2IyYz07ZXJyb3JfaWQ6U0dWc2JHOGdWMjl5YkdRZ1pYSnliM0k9O2Vycm9yX21lc3NhZ2U6Wm1GcGJHVmtJSFJ2SUd4dlkyc2dabWxzWlE9PQ== +[5EA7][2] ----------- log ended at 2020-04-22.20:02:48 ----------- diff --git a/package.json b/package.json index 9f589de..192a12c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "TeaClient", - "version": "1.4.5-3", + "version": "1.4.6", "description": "", "main": "main.js", "scripts": {