Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions include/dpp/discordvoiceclient.h
Original file line number Diff line number Diff line change
Expand Up @@ -561,9 +561,9 @@ class DPP_EXPORT discord_voice_client : public websocket_client
std::chrono::high_resolution_clock::time_point last_timestamp;

/**
* @brief Fraction of the sleep that was not executed after the last audio packet was sent
* @brief Last sent packet duration
*/
std::chrono::nanoseconds last_sleep_remainder{};
uint64_t last_duration;

/**
* @brief Maps receiving ssrc to user id
Expand Down Expand Up @@ -799,12 +799,11 @@ class DPP_EXPORT discord_voice_client : public websocket_client
* audio data because Discord does not expect to receive, say, 3 minutes'
* worth of audio data in 1 second.
*
* There are some inaccuracies in the throttling method used by the recorded
* There was some inaccuracies in the throttling method used by the recorded
* audio mode on some systems (mainly Windows) which causes gaps and stutters
* in the resulting audio stream. The overlap audio mode provides a different
* implementation that fixes the issue. This method is slightly more CPU
* intensive, and should only be used if you encounter issues with recorded audio
* on your system.
* implementation that fixes the issue in the past. This method is not used
* anymore and behave the same as the recorded audio mode.
*
* Use discord_voice_client::set_send_audio_type to change this value as
* it ensures thread safety.
Expand Down
1 change: 1 addition & 0 deletions src/dpp/voice/enabled/constructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ discord_voice_client::discord_voice_client(dpp::cluster* _cluster, full_reconnec
timestamp(0),
packet_nonce(1),
last_timestamp(std::chrono::high_resolution_clock::now()),
last_duration(0),
sending(false),
tracks(0),
dave_version(enable_dave ? dave_version_1 : dave_version_none),
Expand Down
64 changes: 21 additions & 43 deletions src/dpp/voice/enabled/write_ready.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,27 @@
namespace dpp {

void discord_voice_client::write_ready() {
bool needs_write = false;
{
std::lock_guard<std::mutex> lock(this->stream_mutex);
const bool needs_stop_frames = this->paused && !this->sent_stop_frames;
const bool needs_send_audio = !this->paused && !outbuf.empty();
needs_write = needs_stop_frames || needs_send_audio;
}
std::chrono::nanoseconds latency{0};
if (send_audio_type != satype_live_audio) {
const auto now = std::chrono::high_resolution_clock::now();

const auto minimum = std::chrono::nanoseconds(last_duration);
const auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(now - last_timestamp);

if (needs_write) {
udp_events.flags = WANT_READ | WANT_WRITE | WANT_ERROR;
owner->socketengine->update_socket(udp_events);
if (elapsed < minimum) {
std::this_thread::sleep_for(minimum - elapsed);
udp_events.flags = WANT_READ | WANT_WRITE | WANT_ERROR;
owner->socketengine->update_socket(udp_events);
return;
}

latency = elapsed - minimum;
last_timestamp = now;
}

uint64_t duration = 0;
bool track_marker_found = false;
uint64_t bufsize = 0;
send_audio_type_t type = satype_recorded_audio;
{
std::lock_guard<std::mutex> lock(this->stream_mutex);
if (this->paused) {
Expand All @@ -58,7 +62,6 @@ void discord_voice_client::write_ready() {

/* Fallthrough if paused */
} else if (!outbuf.empty()) {
type = send_audio_type;
if (outbuf[0].packet.size() == sizeof(uint16_t) && (*(reinterpret_cast<uint16_t*>(outbuf[0].packet.data()))) == AUDIO_TRACK_MARKER) {
outbuf.erase(outbuf.begin());
track_marker_found = true;
Expand All @@ -74,40 +77,15 @@ void discord_voice_client::write_ready() {
outbuf.erase(outbuf.begin());
}
}
if (!outbuf.empty()) {
udp_events.flags = WANT_READ | WANT_WRITE | WANT_ERROR;
owner->socketengine->update_socket(udp_events);
}
}
}
if (duration) {
if (type == satype_recorded_audio) {
std::chrono::nanoseconds latency = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - last_timestamp);
std::chrono::nanoseconds sleep_time = std::chrono::nanoseconds(duration) - latency;
if (sleep_time.count() > 0) {
std::this_thread::sleep_for(sleep_time);
}
}
else if (type == satype_overlap_audio) {
std::chrono::nanoseconds latency = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - last_timestamp);
std::chrono::nanoseconds sleep_time = std::chrono::nanoseconds(duration) + last_sleep_remainder - latency;
std::chrono::nanoseconds sleep_increment = (std::chrono::nanoseconds(duration) - latency) / AUDIO_OVERLAP_SLEEP_SAMPLES;
if (sleep_time.count() > 0) {
uint16_t samples_count = 0;
std::chrono::nanoseconds overshoot_accumulator{};

do {
std::chrono::high_resolution_clock::time_point start_sleep = std::chrono::high_resolution_clock::now();
std::this_thread::sleep_for(sleep_increment);
std::chrono::high_resolution_clock::time_point end_sleep = std::chrono::high_resolution_clock::now();

samples_count++;
overshoot_accumulator += std::chrono::duration_cast<std::chrono::nanoseconds>(end_sleep - start_sleep) - sleep_increment;
sleep_time -= std::chrono::duration_cast<std::chrono::nanoseconds>(end_sleep - start_sleep);
} while (std::chrono::nanoseconds(overshoot_accumulator.count() / samples_count) + sleep_increment < sleep_time);
last_sleep_remainder = sleep_time;
} else {
last_sleep_remainder = std::chrono::nanoseconds(0);
}
}

last_timestamp = std::chrono::high_resolution_clock::now();
const auto latcount = latency.count();
last_duration = duration > latcount ? duration - latcount : duration;
if (!creator->on_voice_buffer_send.empty()) {
voice_buffer_send_t snd(owner, 0, "");
snd.buffer_size = bufsize;
Expand Down
Loading