Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
12 changes: 8 additions & 4 deletions include/dpp/discordvoiceclient.h
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,11 @@ class DPP_EXPORT discord_voice_client : public websocket_client
*/
std::chrono::high_resolution_clock::time_point last_timestamp;

/**
* @brief Last sent packet duration
*/
uint64_t last_duration;

/**
* @brief Fraction of the sleep that was not executed after the last audio packet was sent
*/
Expand Down Expand Up @@ -799,12 +804,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
65 changes: 22 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,28 @@
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) {
auto now = std::chrono::high_resolution_clock::now();

auto minimum = std::chrono::nanoseconds(last_duration);
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);
bool should_send_now = elapsed >= minimum;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we're not reusing this i'd probs just change this to be in the if below

or, const it (you could also add const to the stuff above)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

if (!should_send_now) {
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 +63,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 +78,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();
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