Some changes
This commit is contained in:
parent
9e5371fa88
commit
4925e33802
2
github
2
github
@ -1 +1 @@
|
|||||||
Subproject commit 06391c6cdd772c2f83c1387960f7224f7cd9f514
|
Subproject commit 2dd1f60e8d034a68bbca9afe294070c8a83caa9e
|
@ -61,11 +61,30 @@ function spawn_main_window(entry_point: string) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
main_window.webContents.on('new-window', (event, url, frameName, disposition, options, additionalFeatures) => {
|
main_window.webContents.on('new-window', (event, url_str, frameName, disposition, options, additionalFeatures) => {
|
||||||
console.log("Got new window " + frameName);
|
|
||||||
const url_preview = require("./url-preview");
|
|
||||||
url_preview.open_preview(url);
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
try {
|
||||||
|
let url: URL;
|
||||||
|
try {
|
||||||
|
url = new URL(url_str);
|
||||||
|
} catch(error) {
|
||||||
|
throw "failed to parse URL";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let protocol = url.protocol.endsWith(":") ? url.protocol.substring(0, url.protocol.length - 1) : url.protocol;
|
||||||
|
if(protocol !== "https" && protocol !== "http") {
|
||||||
|
throw "invalid protocol (" + protocol + "). HTTP(S) are only supported!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Got new window " + frameName);
|
||||||
|
const url_preview = require("./url-preview");
|
||||||
|
url_preview.open_preview(url_str);
|
||||||
|
} catch(error) {
|
||||||
|
console.error("Failed to open preview window for URL %s: %o", url_str, error);
|
||||||
|
dialog.showErrorBox("Failed to open preview", "Failed to open preview URL: " + url_str + "\nError: " + error);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
main_window.webContents.on('crashed', event => {
|
main_window.webContents.on('crashed', event => {
|
||||||
|
@ -77,6 +77,7 @@ export async function open_preview(url: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("Opening URL '%s' as preview.", url);
|
||||||
global_window.webContents.send('preview', url);
|
global_window.webContents.send('preview', url);
|
||||||
if(!global_window.isFocused())
|
if(!global_window.isFocused())
|
||||||
global_window.focus();
|
global_window.focus();
|
||||||
|
@ -135,8 +135,18 @@ void EventExecutor::_executor(tc::event::EventExecutor *loop) {
|
|||||||
event_handler->_event_ptr = nullptr;
|
event_handler->_event_ptr = nullptr;
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
if(event_handler)
|
if(event_handler) {
|
||||||
event_handler->event_execute(linked_entry->scheduled);
|
if(event_handler->single_thread_executed()) {
|
||||||
|
auto execute_lock = event_handler->execute_lock(false);
|
||||||
|
if(!execute_lock) {
|
||||||
|
event_handler->event_execute_dropped(linked_entry->scheduled);
|
||||||
|
} else {
|
||||||
|
event_handler->event_execute(linked_entry->scheduled);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
event_handler->event_execute(linked_entry->scheduled);
|
||||||
|
}
|
||||||
|
}
|
||||||
delete linked_entry;
|
delete linked_entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -14,9 +14,21 @@ namespace tc {
|
|||||||
friend class EventExecutor;
|
friend class EventExecutor;
|
||||||
public:
|
public:
|
||||||
virtual void event_execute(const std::chrono::system_clock::time_point& /* scheduled timestamp */) = 0;
|
virtual void event_execute(const std::chrono::system_clock::time_point& /* scheduled timestamp */) = 0;
|
||||||
|
virtual void event_execute_dropped(const std::chrono::system_clock::time_point& /* scheduled timestamp */) {}
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> execute_lock(bool force) {
|
||||||
|
if(force)
|
||||||
|
return std::unique_lock<std::mutex>(this->_execute_mutex);
|
||||||
|
else
|
||||||
|
return std::unique_lock<std::mutex>(this->_execute_mutex, std::try_to_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool single_thread_executed() const { return this->_single_thread; }
|
||||||
|
inline void single_thread_executed(bool value) { this->_single_thread = value; }
|
||||||
private:
|
private:
|
||||||
void* _event_ptr = nullptr;
|
void* _event_ptr = nullptr;
|
||||||
|
bool _single_thread = true; /* if its set to true there might are some dropped executes! */
|
||||||
|
std::mutex _execute_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EventExecutor {
|
class EventExecutor {
|
||||||
|
@ -28,7 +28,7 @@ ssize_t AudioOutputSource::pop_samples(void *buffer, size_t samples) {
|
|||||||
memcpy(buffer, (char *) buf->sample_data + this->channel_count * buf->sample_index * 4, sc * this->channel_count * 4);
|
memcpy(buffer, (char *) buf->sample_data + this->channel_count * buf->sample_index * 4, sc * this->channel_count * 4);
|
||||||
} else {
|
} else {
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
/* fot my debugger */
|
/* for my debugger */
|
||||||
__asm__("nop");
|
__asm__("nop");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,10 @@
|
|||||||
#include "audio/js/AudioFilter.h"
|
#include "audio/js/AudioFilter.h"
|
||||||
#include "connection/audio/AudioEventLoop.h"
|
#include "connection/audio/AudioEventLoop.h"
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <tomcrypt_misc.h>
|
#include <tomcrypt_misc.h>
|
||||||
#include <tomcrypt.h>
|
#include <tomcrypt.h>
|
||||||
@ -69,7 +73,11 @@ tc::audio::AudioOutput* global_audio_output;
|
|||||||
|
|
||||||
NAN_MODULE_INIT(init) {
|
NAN_MODULE_INIT(init) {
|
||||||
logger::initialize_node();
|
logger::initialize_node();
|
||||||
logger::info(category::general, "Hello World from C");
|
#ifndef WIN32
|
||||||
|
logger::info(category::general, tr("Hello World from C. PPID: {}, PID: {}"), getppid(), getpid());
|
||||||
|
#else
|
||||||
|
logger::info(category::general, tr("Hello World from C."), getppid(), getpid());
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "audio/VoiceConnection.h"
|
#include "audio/VoiceConnection.h"
|
||||||
#include "audio/AudioSender.h"
|
#include "audio/AudioSender.h"
|
||||||
#include "../logger.h"
|
#include "../logger.h"
|
||||||
|
#include "../hwuid.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
@ -11,8 +12,12 @@
|
|||||||
#include <misc/net.h>
|
#include <misc/net.h>
|
||||||
#include <misc/base64.h>
|
#include <misc/base64.h>
|
||||||
#include <misc/endianness.h>
|
#include <misc/endianness.h>
|
||||||
|
#include <misc/strobf.h>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
|
//#define FUZZ_VOICE
|
||||||
|
//#define SHUFFLE_VOICE
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
using namespace tc::connection;
|
using namespace tc::connection;
|
||||||
@ -195,6 +200,10 @@ void ServerConnection::schedule_resend(const std::chrono::system_clock::time_poi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
NAN_METHOD(ServerConnection::connect) {
|
NAN_METHOD(ServerConnection::connect) {
|
||||||
|
if(!this->protocol_handler) {
|
||||||
|
Nan::ThrowError("ServerConnection not initialized");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(info.Length() != 1) {
|
if(info.Length() != 1) {
|
||||||
Nan::ThrowError(tr("Invalid argument count"));
|
Nan::ThrowError(tr("Invalid argument count"));
|
||||||
return;
|
return;
|
||||||
@ -231,8 +240,8 @@ NAN_METHOD(ServerConnection::connect) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_lock disconnect_lock(this->disconnect_lock, defer_lock);
|
unique_lock _disconnect_lock(this->disconnect_lock, defer_lock);
|
||||||
if(!disconnect_lock.try_lock_for(chrono::milliseconds(500))) {
|
if(!_disconnect_lock.try_lock_for(chrono::milliseconds(500))) {
|
||||||
Nan::ThrowError(tr("failed to acquire disconnect lock"));
|
Nan::ThrowError(tr("failed to acquire disconnect lock"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -294,7 +303,6 @@ NAN_METHOD(ServerConnection::connect) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this->socket->on_data = [&](const pipes::buffer_view& buffer) { this->protocol_handler->progress_packet(buffer); };
|
this->socket->on_data = [&](const pipes::buffer_view& buffer) { this->protocol_handler->progress_packet(buffer); };
|
||||||
|
|
||||||
if(teamspeak->IsBoolean() && teamspeak->BooleanValue(info.GetIsolate()))
|
if(teamspeak->IsBoolean() && teamspeak->BooleanValue(info.GetIsolate()))
|
||||||
this->protocol_handler->server_type = server_type::TEAMSPEAK;
|
this->protocol_handler->server_type = server_type::TEAMSPEAK;
|
||||||
this->protocol_handler->connect();
|
this->protocol_handler->connect();
|
||||||
@ -333,7 +341,9 @@ NAN_METHOD(ServerConnection::disconnect) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->protocol_handler->disconnect(*Nan::Utf8String(info[0]));
|
if(this->protocol_handler) {
|
||||||
|
this->protocol_handler->disconnect(*Nan::Utf8String(info[0]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NAN_METHOD(ServerConnection::_error_message) {
|
NAN_METHOD(ServerConnection::_error_message) {
|
||||||
@ -365,6 +375,11 @@ NAN_METHOD(ServerConnection::_send_command) {
|
|||||||
return ObjectWrap::Unwrap<ServerConnection>(info.Holder())->send_command(info);
|
return ObjectWrap::Unwrap<ServerConnection>(info.Holder())->send_command(info);
|
||||||
}
|
}
|
||||||
NAN_METHOD(ServerConnection::send_command) {
|
NAN_METHOD(ServerConnection::send_command) {
|
||||||
|
if(!this->protocol_handler) {
|
||||||
|
Nan::ThrowError("ServerConnection not initialized");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(info.Length() != 3) {
|
if(info.Length() != 3) {
|
||||||
Nan::ThrowError("invalid argument count");
|
Nan::ThrowError("invalid argument count");
|
||||||
return;
|
return;
|
||||||
@ -432,6 +447,7 @@ NAN_METHOD(ServerConnection::send_command) {
|
|||||||
cmd["client_version"] = "0.0.1 [Build: 1549713549]";
|
cmd["client_version"] = "0.0.1 [Build: 1549713549]";
|
||||||
cmd["client_platform"] = "Linux";
|
cmd["client_platform"] = "Linux";
|
||||||
cmd["client_version_sign"] = "7XvKmrk7uid2ixHFeERGqcC8vupeQqDypLtw2lY9slDNPojEv//F47UaDLG+TmVk4r6S0TseIKefzBpiRtLDAQ==";
|
cmd["client_version_sign"] = "7XvKmrk7uid2ixHFeERGqcC8vupeQqDypLtw2lY9slDNPojEv//F47UaDLG+TmVk4r6S0TseIKefzBpiRtLDAQ==";
|
||||||
|
cmd[strobf("hwid").string()] = system_uuid(); /* we dont want anybody to patch this out */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->protocol_handler->send_command(cmd);
|
this->protocol_handler->send_command(cmd);
|
||||||
@ -442,6 +458,11 @@ NAN_METHOD(ServerConnection::_send_voice_data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NAN_METHOD(ServerConnection::send_voice_data) {
|
NAN_METHOD(ServerConnection::send_voice_data) {
|
||||||
|
if(!this->protocol_handler) {
|
||||||
|
Nan::ThrowError("ServerConnection not initialized");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(info.Length() != 3) {
|
if(info.Length() != 3) {
|
||||||
Nan::ThrowError("invalid argument count");
|
Nan::ThrowError("invalid argument count");
|
||||||
return;
|
return;
|
||||||
@ -480,11 +501,13 @@ NAN_METHOD(ServerConnection::send_voice_data_raw) {
|
|||||||
auto flag_head = info[2]->BooleanValue(info.GetIsolate());
|
auto flag_head = info[2]->BooleanValue(info.GetIsolate());
|
||||||
|
|
||||||
auto voice_data = info[0].As<v8::Float32Array>()->Buffer();
|
auto voice_data = info[0].As<v8::Float32Array>()->Buffer();
|
||||||
auto vs = this->voice_connection->voice_sender();
|
auto vs = this->voice_connection ? this->voice_connection->voice_sender() : nullptr;
|
||||||
|
if(vs) vs->send_data(voice_data->GetContents().Data(), voice_data->GetContents().ByteLength() / (4 * channels), sample_rate, channels);
|
||||||
vs->send_data(voice_data->GetContents().Data(), voice_data->GetContents().ByteLength() / (4 * channels), sample_rate, channels);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SHUFFLE_VOICE
|
||||||
|
static shared_ptr<ts::protocol::ClientPacket> shuffle_cached_packet;
|
||||||
|
#endif
|
||||||
void ServerConnection::send_voice_data(const void *buffer, size_t buffer_length, uint8_t codec, bool head) {
|
void ServerConnection::send_voice_data(const void *buffer, size_t buffer_length, uint8_t codec, bool head) {
|
||||||
auto _buffer = pipes::buffer{ts::protocol::ClientPacket::META_SIZE + buffer_length + 3};
|
auto _buffer = pipes::buffer{ts::protocol::ClientPacket::META_SIZE + buffer_length + 3};
|
||||||
auto packet = make_shared<ts::protocol::ClientPacket>(_buffer);
|
auto packet = make_shared<ts::protocol::ClientPacket>(_buffer);
|
||||||
@ -501,13 +524,19 @@ void ServerConnection::send_voice_data(const void *buffer, size_t buffer_length,
|
|||||||
packet->enable_flag(ts::protocol::PacketFlag::Compressed);
|
packet->enable_flag(ts::protocol::PacketFlag::Compressed);
|
||||||
packet->enable_flag(ts::protocol::PacketFlag::Unencrypted);
|
packet->enable_flag(ts::protocol::PacketFlag::Unencrypted);
|
||||||
|
|
||||||
//#define FUZZ_VOICE
|
|
||||||
#ifdef FUZZ_VOICE
|
#ifdef FUZZ_VOICE
|
||||||
if((rand() % 10) < 2) {
|
if((rand() % 10) < 2) {
|
||||||
log_info(category::connection, tr("Dropping voice packet"));
|
log_info(category::connection, tr("Dropping voice packet"));
|
||||||
} else {
|
} else {
|
||||||
this->protocol_handler->send_packet(packet);
|
this->protocol_handler->send_packet(packet);
|
||||||
}
|
}
|
||||||
|
#elif defined(SHUFFLE_VOICE)
|
||||||
|
if(shuffle_cached_packet) {
|
||||||
|
this->protocol_handler->send_packet(packet);
|
||||||
|
this->protocol_handler->send_packet(std::exchange(shuffle_cached_packet, nullptr));
|
||||||
|
} else {
|
||||||
|
shuffle_cached_packet = packet;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
this->protocol_handler->send_packet(packet);
|
this->protocol_handler->send_packet(packet);
|
||||||
#endif
|
#endif
|
||||||
@ -525,10 +554,10 @@ void ServerConnection::close_connection() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this->event_loop_execute_connection_close = false;
|
this->event_loop_execute_connection_close = false;
|
||||||
if(this->socket) {
|
if(this->socket)
|
||||||
this->socket->finalize();
|
this->socket->finalize();
|
||||||
}
|
if(this->protocol_handler)
|
||||||
this->protocol_handler->do_close_connection();
|
this->protocol_handler->do_close_connection();
|
||||||
this->socket = nullptr;
|
this->socket = nullptr;
|
||||||
this->call_disconnect_result.call(0, true);
|
this->call_disconnect_result.call(0, true);
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ using namespace tc::connection;
|
|||||||
|
|
||||||
extern tc::audio::AudioOutput* global_audio_output;
|
extern tc::audio::AudioOutput* global_audio_output;
|
||||||
|
|
||||||
|
#define DEBUG_PREMATURE_PACKETS
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#define _field_(name, value) value
|
#define _field_(name, value) value
|
||||||
#else
|
#else
|
||||||
@ -210,7 +212,7 @@ VoiceClient::VoiceClient(const std::shared_ptr<VoiceConnection>&, uint16_t clien
|
|||||||
this->output_source = global_audio_output->create_source();
|
this->output_source = global_audio_output->create_source();
|
||||||
this->output_source->overflow_strategy = audio::overflow_strategy::ignore;
|
this->output_source->overflow_strategy = audio::overflow_strategy::ignore;
|
||||||
this->output_source->max_latency = (size_t) ceil(this->output_source->sample_rate * 1);
|
this->output_source->max_latency = (size_t) ceil(this->output_source->sample_rate * 1);
|
||||||
this->output_source->min_buffer = (size_t) ceil(this->output_source->sample_rate * 0.025);
|
this->output_source->min_buffer = (size_t) ceil(this->output_source->sample_rate * 0.04);
|
||||||
|
|
||||||
this->output_source->on_underflow = [&]{
|
this->output_source->on_underflow = [&]{
|
||||||
if(this->_state == state::stopping)
|
if(this->_state == state::stopping)
|
||||||
@ -221,14 +223,15 @@ VoiceClient::VoiceClient(const std::shared_ptr<VoiceConnection>&, uint16_t clien
|
|||||||
log_warn(category::audio, tr("Client {} has a audio buffer underflow and not received any data for one second. Stopping replay."), this->_client_id);
|
log_warn(category::audio, tr("Client {} has a audio buffer underflow and not received any data for one second. Stopping replay."), this->_client_id);
|
||||||
} else {
|
} else {
|
||||||
if(this->_state != state::buffering) {
|
if(this->_state != state::buffering) {
|
||||||
log_warn(category::audio, tr("Client {} has a audio buffer underflow. Buffer again."), this->_client_id);
|
log_warn(category::audio, tr("Client {} has a audio buffer underflow. Buffer again and try to replay prematured packets."), this->_client_id);
|
||||||
this->set_state(state::buffering);
|
this->set_state(state::buffering);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
play_premature_packets = true; /* try to replay any premature packets because we assume that the other packets got lost */
|
||||||
|
audio::decode_event_loop->schedule(static_pointer_cast<event::EventEntry>(this->ref()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
play_premature_packets = true; /* try to replay any premature packets because we assume that the other packets got lost */
|
|
||||||
audio::decode_event_loop->schedule(static_pointer_cast<event::EventEntry>(this->ref()));
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
this->output_source->on_overflow = [&](size_t count){
|
this->output_source->on_overflow = [&](size_t count){
|
||||||
@ -327,8 +330,10 @@ void VoiceClient::event_execute(const std::chrono::system_clock::time_point &sch
|
|||||||
play_count++;
|
play_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_PREMATURE_PACKETS
|
||||||
if(play_count > 0)
|
if(play_count > 0)
|
||||||
log_debug(category::audio, tr("Replayed {} premature packets for client {}"), play_count, this->_client_id);
|
log_debug(category::audio, tr("Replayed (buffer underflow) {} premature packets for client {}"), play_count, this->_client_id);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -350,14 +355,19 @@ void VoiceClient::event_execute(const std::chrono::system_clock::time_point &sch
|
|||||||
this->process_encoded_buffer(entry);
|
this->process_encoded_buffer(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(audio_decode_event_dropped.exchange(false) && !reschedule) {
|
||||||
|
//Is not really a warning, it happens all the time and isn't really an issue
|
||||||
|
//log_warn(category::voice_connection, tr("Dropped auto enqueue event execution for client {}. No reschedulling planned, hopefully we processed all buffers."), this->_client_id);
|
||||||
|
}
|
||||||
|
|
||||||
if(reschedule) {
|
if(reschedule) {
|
||||||
log_warn(category::voice_connection, tr("Audio data decode will take longer than {} us. Enqueueing for later"), chrono::duration_cast<chrono::microseconds>(max_time).count());
|
log_warn(category::voice_connection, tr("Audio data decode will take longer than {} us. Enqueueing for later"), chrono::duration_cast<chrono::microseconds>(max_time).count());
|
||||||
audio::decode_event_loop->schedule(static_pointer_cast<event::EventEntry>(this->ref()));
|
audio::decode_event_loop->schedule(static_pointer_cast<event::EventEntry>(this->ref()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//FIXME premature packets dont work
|
|
||||||
#define MAX_LOST_PACKETS (6)
|
#define MAX_LOST_PACKETS (6)
|
||||||
|
//Note: This function must be executed single threaded
|
||||||
void VoiceClient::process_encoded_buffer(const std::unique_ptr<EncodedBuffer> &buffer) {
|
void VoiceClient::process_encoded_buffer(const std::unique_ptr<EncodedBuffer> &buffer) {
|
||||||
string error;
|
string error;
|
||||||
|
|
||||||
@ -425,9 +435,12 @@ void VoiceClient::process_encoded_buffer(const std::unique_ptr<EncodedBuffer> &b
|
|||||||
this->set_state(state::stopping);
|
this->set_state(state::stopping);
|
||||||
|
|
||||||
/* enqueue all premature packets (list should be already ordered!) */
|
/* enqueue all premature packets (list should be already ordered!) */
|
||||||
for(const auto& packet : codec_data->premature_packets)
|
{
|
||||||
this->output_source->enqueue_samples(packet.buffer);
|
unique_lock buffer_lock(this->audio_decode_queue_lock);
|
||||||
codec_data->premature_packets.clear();
|
for(const auto& packet : codec_data->premature_packets)
|
||||||
|
this->output_source->enqueue_samples(packet.buffer);
|
||||||
|
codec_data->premature_packets.clear();
|
||||||
|
}
|
||||||
|
|
||||||
log_trace(category::voice_connection, tr("Stopping replay for client {}. Empty buffer!"), this->_client_id);
|
log_trace(category::voice_connection, tr("Stopping replay for client {}. Empty buffer!"), this->_client_id);
|
||||||
return;
|
return;
|
||||||
@ -442,14 +455,15 @@ void VoiceClient::process_encoded_buffer(const std::unique_ptr<EncodedBuffer> &b
|
|||||||
|
|
||||||
if(diff <= MAX_LOST_PACKETS) {
|
if(diff <= MAX_LOST_PACKETS) {
|
||||||
if(diff > 0) {
|
if(diff > 0) {
|
||||||
log_debug(category::voice_connection,
|
|
||||||
tr("Client {} dropped one or more audio packets. Old packet id: {}, New packet id: {}, Diff: {}"),
|
|
||||||
this->_client_id, old_packet_id, buffer->packet_id, diff);
|
|
||||||
/* lets first handle packet as "lost", even thou we're enqueueing it as premature */
|
/* lets first handle packet as "lost", even thou we're enqueueing it as premature */
|
||||||
//auto status = codec_data->converter->decode_lost(error, diff);
|
//auto status = codec_data->converter->decode_lost(error, diff);
|
||||||
//if(status < 0)
|
//if(status < 0)
|
||||||
// log_warn(category::voice_connection, tr("Failed to decode (skip) dropped packets. Return code {} => {}"), status, error);
|
// log_warn(category::voice_connection, tr("Failed to decode (skip) dropped packets. Return code {} => {}"), status, error);
|
||||||
premature = this->state() != state::stopped;
|
premature = !buffer->head && this->state() != state::stopped;
|
||||||
|
|
||||||
|
log_debug(category::voice_connection,
|
||||||
|
tr("Client {} dropped one or more audio packets. Old packet id: {}, New packet id: {}, Diff: {}. Head: {}. Flagging chunk as premature: {}"),
|
||||||
|
this->_client_id, old_packet_id, buffer->packet_id, diff, buffer->head, premature);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log_debug(category::voice_connection, tr("Client {} resetted decoder. Old packet id: {}, New packet id: {}, diff: {}"), this->_client_id, old_packet_id, buffer->packet_id, diff);
|
log_debug(category::voice_connection, tr("Client {} resetted decoder. Old packet id: {}, New packet id: {}, diff: {}"), this->_client_id, old_packet_id, buffer->packet_id, diff);
|
||||||
@ -459,31 +473,9 @@ void VoiceClient::process_encoded_buffer(const std::unique_ptr<EncodedBuffer> &b
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(!premature)
|
||||||
if(!premature) {
|
|
||||||
codec_data->last_packet_id = buffer->packet_id;
|
codec_data->last_packet_id = buffer->packet_id;
|
||||||
|
|
||||||
/* test if any premature got its original place */
|
|
||||||
{
|
|
||||||
size_t play_count = 0;
|
|
||||||
while(!codec_data->premature_packets.empty()) {
|
|
||||||
auto& packet = codec_data->premature_packets.front();
|
|
||||||
|
|
||||||
//Test if we're able to replay stuff again
|
|
||||||
if((uint16_t) (codec_data->last_packet_id + 1) < packet.packet_id)
|
|
||||||
break; //Nothing new
|
|
||||||
|
|
||||||
this->output_source->enqueue_samples(packet.buffer);
|
|
||||||
codec_data->last_packet_id = packet.packet_id;
|
|
||||||
codec_data->premature_packets.pop_front();
|
|
||||||
play_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(play_count > 0)
|
|
||||||
log_debug(category::audio, tr("Replayed {} premature packets for client {}"), play_count, this->_client_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char target_buffer[target_buffer_length];
|
char target_buffer[target_buffer_length];
|
||||||
if(target_buffer_length < codec_data->converter->expected_decoded_length(buffer->buffer.data_ptr(), buffer->buffer.length())) {
|
if(target_buffer_length < codec_data->converter->expected_decoded_length(buffer->buffer.data_ptr(), buffer->buffer.length())) {
|
||||||
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->buffer.data_ptr(), buffer->buffer.length()));
|
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->buffer.data_ptr(), buffer->buffer.length()));
|
||||||
@ -523,23 +515,55 @@ void VoiceClient::process_encoded_buffer(const std::unique_ptr<EncodedBuffer> &b
|
|||||||
audio_buffer->sample_index = 0;
|
audio_buffer->sample_index = 0;
|
||||||
memcpy(audio_buffer->sample_data, target_buffer, this->output_source->channel_count * resampled_samples * 4);
|
memcpy(audio_buffer->sample_data, target_buffer, this->output_source->channel_count * resampled_samples * 4);
|
||||||
|
|
||||||
auto it = codec_data->premature_packets.begin();
|
{
|
||||||
for(; it != codec_data->premature_packets.end(); it++) {
|
unique_lock buffer_lock(this->audio_decode_queue_lock);
|
||||||
if(it->packet_id > buffer->packet_id) {
|
auto it = codec_data->premature_packets.begin();
|
||||||
break; /* it is set to the right position */
|
for(; it != codec_data->premature_packets.end(); it++) {
|
||||||
|
if(it->packet_id > buffer->packet_id) {
|
||||||
|
break; /* it is set to the right position */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
codec_data->premature_packets.insert(it, {
|
||||||
|
buffer->packet_id,
|
||||||
|
move(audio_buffer)
|
||||||
|
});
|
||||||
|
std::stable_sort(codec_data->premature_packets.begin(), codec_data->premature_packets.end(), [](const PrematureAudioPacket& a, const PrematureAudioPacket& b) {
|
||||||
|
return a.packet_id < b.packet_id;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
codec_data->premature_packets.insert(it, {
|
|
||||||
buffer->packet_id,
|
|
||||||
audio_buffer
|
|
||||||
});
|
|
||||||
std::stable_sort(codec_data->premature_packets.begin(), codec_data->premature_packets.end(), [](const PrematureAudioPacket& a, const PrematureAudioPacket& b) {
|
|
||||||
return a.packet_id < b.packet_id;
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
auto enqueued = this->output_source->enqueue_samples(target_buffer, resampled_samples);
|
auto enqueued = this->output_source->enqueue_samples(target_buffer, resampled_samples);
|
||||||
if(enqueued != resampled_samples)
|
if(enqueued != resampled_samples)
|
||||||
log_warn(category::voice_connection, tr("Failed to enqueue all samples for client {}. Enqueued {} of {}"), this->_client_id, enqueued, resampled_samples);
|
log_warn(category::voice_connection, tr("Failed to enqueue all samples for client {}. Enqueued {} of {}"), this->_client_id, enqueued, resampled_samples);
|
||||||
this->set_state(state::playing);
|
this->set_state(state::playing);
|
||||||
|
|
||||||
|
/* test if any premature got its original place */
|
||||||
|
{
|
||||||
|
unique_lock buffer_lock(this->audio_decode_queue_lock);
|
||||||
|
|
||||||
|
size_t play_count = 0;
|
||||||
|
while(!codec_data->premature_packets.empty()) {
|
||||||
|
auto& packet = codec_data->premature_packets[0];
|
||||||
|
|
||||||
|
//Test if we're able to replay stuff again
|
||||||
|
if((uint16_t) (codec_data->last_packet_id + 1) < packet.packet_id)
|
||||||
|
break; //Nothing new
|
||||||
|
|
||||||
|
this->output_source->enqueue_samples(packet.buffer);
|
||||||
|
codec_data->last_packet_id = packet.packet_id;
|
||||||
|
codec_data->premature_packets.pop_front();
|
||||||
|
play_count++;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG_PREMATURE_PACKETS
|
||||||
|
if(play_count > 0)
|
||||||
|
log_debug(category::audio, tr("Replayed (id match) {} premature packets for client {}"), play_count, this->_client_id);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VoiceClient::event_execute_dropped(const std::chrono::system_clock::time_point &point) {
|
||||||
|
if(audio_decode_event_dropped.exchange(true))
|
||||||
|
//Is not really a warning, it happens all the time and isn't really an issue
|
||||||
|
;//log_warn(category::voice_connection, tr("Dropped auto enqueue event execution two or more times in a row for client {}"), this->_client_id);
|
||||||
|
}
|
||||||
|
@ -90,7 +90,7 @@ namespace tc {
|
|||||||
private:
|
private:
|
||||||
struct PrematureAudioPacket {
|
struct PrematureAudioPacket {
|
||||||
uint16_t packet_id = 0;
|
uint16_t packet_id = 0;
|
||||||
std::shared_ptr<tc::audio::SampleBuffer> buffer;
|
std::shared_ptr<tc::audio::SampleBuffer> buffer{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AudioCodec {
|
struct AudioCodec {
|
||||||
@ -138,9 +138,12 @@ namespace tc {
|
|||||||
codec::value codec;
|
codec::value codec;
|
||||||
std::chrono::system_clock::time_point receive_timestamp;
|
std::chrono::system_clock::time_point receive_timestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::atomic_bool audio_decode_event_dropped{false};
|
||||||
std::mutex audio_decode_queue_lock;
|
std::mutex audio_decode_queue_lock;
|
||||||
std::deque<std::unique_ptr<EncodedBuffer>> audio_decode_queue;
|
std::deque<std::unique_ptr<EncodedBuffer>> audio_decode_queue;
|
||||||
void event_execute(const std::chrono::system_clock::time_point &point) override;
|
void event_execute(const std::chrono::system_clock::time_point &point) override;
|
||||||
|
void event_execute_dropped(const std::chrono::system_clock::time_point &point) override;
|
||||||
void process_encoded_buffer(const std::unique_ptr<EncodedBuffer>& /* buffer */);
|
void process_encoded_buffer(const std::unique_ptr<EncodedBuffer>& /* buffer */);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -121,9 +121,49 @@ std::string system_uuid() {
|
|||||||
return _cached_system_uuid;
|
return _cached_system_uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
"Hello World": Avg raw: 18ms Avg obf: 20ms
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
using namespace std::chrono;
|
||||||
int main() {
|
int main() {
|
||||||
std::cout << "UUID: " << system_uuid() << "\n";
|
#define TEST_MESSAGE ("Hello World I'm a bit longer that 50 character string! Hello World I'm a bit longer that 50 character string! Hello World I'm a bit longer that 50 character string! Hello World I'm a bit longer that 50 character string! Hello World I'm a bit longer that 50 character string! Hello World I'm a bit longer that 50 character string!")
|
||||||
|
|
||||||
|
system_clock::time_point begin, end;
|
||||||
|
size_t sum_raw = 0, sum_obf = 0, runs = 50;
|
||||||
|
|
||||||
|
std::cerr << "Testing raw\n";
|
||||||
|
for(int i = 0; i < runs; i++) {
|
||||||
|
begin = system_clock::now();
|
||||||
|
for(size_t index = 0; index < 1e6; index++) {
|
||||||
|
puts(TEST_MESSAGE);
|
||||||
|
}
|
||||||
|
end = system_clock::now();
|
||||||
|
|
||||||
|
auto ms = floor<milliseconds>(end - begin).count();
|
||||||
|
sum_raw += ms;
|
||||||
|
//std::cerr << "Raw test took " << ms << "ms\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "Testing obf\n";
|
||||||
|
for(int i = 0; i < runs; i++) {
|
||||||
|
begin = system_clock::now();
|
||||||
|
for(size_t index = 0; index < 1e6; index++) {
|
||||||
|
puts(strobf(TEST_MESSAGE).c_str());
|
||||||
|
}
|
||||||
|
end = system_clock::now();
|
||||||
|
|
||||||
|
auto ms = floor<milliseconds>(end - begin).count();
|
||||||
|
sum_obf += ms;
|
||||||
|
//std::cerr << "Obf test took " << ms << "ms\n";
|
||||||
|
}
|
||||||
|
std::cerr << "Avg raw: " << (sum_raw / runs) << "ms Avg obf: " << (sum_obf / runs) << "ms\n";
|
||||||
|
|
||||||
|
//std::cout << "UUID: " << system_uuid() << "\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//ADaX2mIRrC1uv83h
|
//ADaX2mIRrC1uv83h
|
||||||
|
|
||||||
|
*/
|
Loading…
Reference in New Issue
Block a user