From ddac6acaf2781ea9368dc5a59fdb009a6e2736a8 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Thu, 11 Apr 2024 18:46:34 +0200 Subject: Fix messed up audio on some distros (those using pulseaudio?) --- include/sound.hpp | 3 +- src/main.cpp | 3 -- src/sound.cpp | 82 +++++++++++++++++++++++++++++++++++++------------------ 3 files changed, 57 insertions(+), 31 deletions(-) diff --git a/include/sound.hpp b/include/sound.hpp index 32821bc..731e787 100644 --- a/include/sound.hpp +++ b/include/sound.hpp @@ -24,7 +24,6 @@ typedef struct { void *handle; unsigned int frames; - double latency_seconds; } SoundDevice; struct AudioInput { @@ -54,7 +53,7 @@ void sound_device_close(SoundDevice *device); /* Returns the next chunk of audio into @buffer. - Returns the number of bytes read, or a negative value on failure. + Returns the number of frames read, or a negative value on failure. */ int sound_device_read_next_chunk(SoundDevice *device, void **buffer, double timeout_sec); diff --git a/src/main.cpp b/src/main.cpp index 2d0c719..98da891 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2435,7 +2435,6 @@ int main(int argc, char **argv) { if(new_pts == audio_device.frame->pts) continue; audio_device.frame->pts = new_pts; - //audio_device.frame->linesize[0] = sound_buffer_size / 2; if(audio_track.graph) { std::lock_guard lock(audio_filter_mutex); @@ -2468,7 +2467,6 @@ int main(int argc, char **argv) { if(new_pts == audio_device.frame->pts) continue; audio_device.frame->pts = new_pts; - //audio_device.frame->linesize[0] = sound_buffer_size / 2; if(audio_track.graph) { std::lock_guard lock(audio_filter_mutex); @@ -2526,7 +2524,6 @@ int main(int argc, char **argv) { if(new_pts == aframe->pts) continue; aframe->pts = new_pts; - //aframe->linesize[0] = sound_buffer_size / 2; err = avcodec_send_frame(audio_track.codec_context, aframe); if(err >= 0){ // TODO: Move to separate thread because this could write to network (for example when livestreaming) diff --git a/src/sound.cpp b/src/sound.cpp index 99342f2..485548b 100644 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -41,7 +41,6 @@ struct pa_handle { size_t output_index, output_length; int operation_success; - double latency_seconds; }; static void pa_sound_device_free(pa_handle *s) { @@ -80,7 +79,6 @@ static pa_handle* pa_sound_device_new(const char *server, p->read_data = NULL; p->read_length = 0; p->read_index = 0; - p->latency_seconds = 0; const int buffer_size = attr->maxlength; void *buffer = malloc(buffer_size); @@ -160,36 +158,71 @@ static int pa_sound_device_read(pa_handle *p, double timeout_seconds) { const double start_time = clock_get_monotonic_seconds(); + bool success = false; int r = 0; - //pa_usec_t latency = 0; - //int negative = 0; int *rerror = &r; CHECK_DEAD_GOTO(p, rerror, fail); - while(clock_get_monotonic_seconds() - start_time < timeout_seconds) { - pa_mainloop_prepare(p->mainloop, 1 * 1000); - pa_mainloop_poll(p->mainloop); - pa_mainloop_dispatch(p->mainloop); + while (p->output_index < p->output_length) { + if(clock_get_monotonic_seconds() - start_time >= timeout_seconds) + return -1; - if(pa_stream_peek(p->stream, &p->read_data, &p->read_length) < 0) - goto fail; + if(!p->read_data) { + pa_mainloop_prepare(p->mainloop, 1 * 1000); // 1 ms + pa_mainloop_poll(p->mainloop); + pa_mainloop_dispatch(p->mainloop); - if(!p->read_data && p->read_length == 0) - continue; + if(pa_stream_peek(p->stream, &p->read_data, &p->read_length) < 0) + goto fail; - // pa_operation_unref(pa_stream_update_timing_info(p->stream, NULL, NULL)); - // if (pa_stream_get_latency(p->stream, &latency, &negative) >= 0) { - // fprintf(stderr, "latency: %lu ms, negative: %d, extra delay: %f ms\n", latency / 1000, negative, (clock_get_monotonic_seconds() - start_time) * 1000.0); - // } + if(!p->read_data && p->read_length == 0) + continue; + + if(!p->read_data && p->read_length > 0) { + // There is a hole in the stream :( drop it. Maybe we should generate silence instead? TODO + if(pa_stream_drop(p->stream) != 0) + goto fail; + continue; + } - memcpy(p->output_data, p->read_data, p->read_length); - pa_stream_drop(p->stream); - p->latency_seconds = clock_get_monotonic_seconds() - start_time; - return p->read_length; + if(p->read_length <= 0) { + p->read_data = NULL; + if(pa_stream_drop(p->stream) != 0) + goto fail; + + CHECK_DEAD_GOTO(p, rerror, fail); + continue; + } + } + + const size_t space_free_in_output_buffer = p->output_length - p->output_index; + if(space_free_in_output_buffer < p->read_length) { + memcpy(p->output_data + p->output_index, (const uint8_t*)p->read_data + p->read_index, space_free_in_output_buffer); + p->output_index = 0; + p->read_index += space_free_in_output_buffer; + p->read_length -= space_free_in_output_buffer; + break; + } else { + memcpy(p->output_data + p->output_index, (const uint8_t*)p->read_data + p->read_index, p->read_length); + p->output_index += p->read_length; + p->read_data = NULL; + p->read_length = 0; + p->read_index = 0; + + if(pa_stream_drop(p->stream) != 0) + goto fail; + + if(p->output_index == p->output_length) { + p->output_index = 0; + break; + } + } } + success = true; + fail: - return -1; + return success ? 0 : -1; } static pa_sample_format_t audio_format_to_pulse_audio_format(AudioFormat audio_format) { @@ -234,7 +267,6 @@ int sound_device_get_by_name(SoundDevice *device, const char *device_name, const device->handle = handle; device->frames = period_frame_size; - device->latency_seconds = 0.0; return 0; } @@ -246,14 +278,12 @@ void sound_device_close(SoundDevice *device) { int sound_device_read_next_chunk(SoundDevice *device, void **buffer, double timeout_sec) { pa_handle *pa = (pa_handle*)device->handle; - int size = pa_sound_device_read(pa, timeout_sec); - if(size < 0) { + if(pa_sound_device_read(pa, timeout_sec) < 0) { //fprintf(stderr, "pa_simple_read() failed: %s\n", pa_strerror(error)); return -1; } *buffer = pa->output_data; - device->latency_seconds = pa->latency_seconds; - return size; + return device->frames; } static void pa_state_cb(pa_context *c, void *userdata) { -- cgit v1.2.3