From 0cdd1ad2c85756be1f9bacb445543b82abffdbef Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Sun, 9 Feb 2020 23:49:02 +0100 Subject: [PATCH] Fixed input stuff --- .../src/audio/driver/AudioDriver.cpp | 19 +++---- .../src/audio/driver/AudioDriver.h | 1 + .../src/audio/driver/SoundIO.h | 7 ++- .../src/audio/driver/SoundIORecord.cpp | 54 ++++++++++++++++--- .../src/audio/filter/FilterThreshold.cpp | 1 - 5 files changed, 65 insertions(+), 17 deletions(-) diff --git a/native/serverconnection/src/audio/driver/AudioDriver.cpp b/native/serverconnection/src/audio/driver/AudioDriver.cpp index 8430edf..903fe4e 100644 --- a/native/serverconnection/src/audio/driver/AudioDriver.cpp +++ b/native/serverconnection/src/audio/driver/AudioDriver.cpp @@ -27,13 +27,7 @@ namespace tc::audio { result.insert(result.end(), input_devices.begin(), input_devices.end()); result.insert(result.end(), output_devices.begin(), output_devices.end()); } -#if defined(WIN32) && false - //Remove all not raw devices. We do not support shared mode yet - result.erase(std::remove_if(result.begin(), result.end(), [](const std::shared_ptr& device) { - if(device->driver() != "WASAPI") return false; - return !ends_with(device->id(), "_raw"); - }), result.end()); -#endif + return result; } @@ -193,7 +187,12 @@ namespace tc::audio { bool AudioDeviceRecord::start(std::string &error) { std::lock_guard lock{this->state_lock}; - if(this->running) return true; + if(this->running && !this->stream_invalid) return true; + if(this->stream_invalid) { + this->impl_stop(); + this->running = false; + this->stream_invalid = false; + } if(!this->impl_start(error)) { log_error(category::audio, tr("Failed to start record: {}"), error); @@ -212,14 +211,16 @@ namespace tc::audio { this->impl_stop(); this->running = false; + this->stream_invalid = false; } void AudioDeviceRecord::stop() { std::lock_guard lock{this->state_lock}; - if(this->running) return; + if(!this->running) return; this->impl_stop(); this->running = false; + this->stream_invalid = false; } void AudioDeviceRecord::register_consumer(Consumer* source) { diff --git a/native/serverconnection/src/audio/driver/AudioDriver.h b/native/serverconnection/src/audio/driver/AudioDriver.h index bd6d392..b0544f1 100644 --- a/native/serverconnection/src/audio/driver/AudioDriver.h +++ b/native/serverconnection/src/audio/driver/AudioDriver.h @@ -33,6 +33,7 @@ namespace tc::audio { std::mutex state_lock{}; bool running{false}; + bool stream_invalid{false}; std::mutex consumer_lock{}; std::vector _consumers{}; diff --git a/native/serverconnection/src/audio/driver/SoundIO.h b/native/serverconnection/src/audio/driver/SoundIO.h index 432d3af..9176066 100644 --- a/native/serverconnection/src/audio/driver/SoundIO.h +++ b/native/serverconnection/src/audio/driver/SoundIO.h @@ -80,12 +80,17 @@ namespace tc::audio { private: size_t _sample_rate; - bool stream_invalid{false}; struct ::SoundIoDevice* device_handle{nullptr}; struct ::SoundIoInStream* stream{nullptr}; + size_t failed_count{0}; + std::thread fail_recover_thread{}; + std::mutex fail_cv_mutex{}; + std::condition_variable fail_cv{}; + struct ::SoundIoRingBuffer* buffer{nullptr}; + void execute_recovery(); void read_callback(int frame_count_min, int frame_count_max); }; diff --git a/native/serverconnection/src/audio/driver/SoundIORecord.cpp b/native/serverconnection/src/audio/driver/SoundIORecord.cpp index 98d147e..8343dbc 100644 --- a/native/serverconnection/src/audio/driver/SoundIORecord.cpp +++ b/native/serverconnection/src/audio/driver/SoundIORecord.cpp @@ -30,6 +30,10 @@ SoundIORecord::SoundIORecord(struct ::SoundIoDevice *device) : device_handle{dev } SoundIORecord::~SoundIORecord() { + { + std::lock_guard slock{this->state_lock}; + if(this->running) this->impl_stop(); + } soundio_device_unref(this->device_handle); } @@ -37,9 +41,34 @@ size_t SoundIORecord::sample_rate() const { return this->_sample_rate; } +void SoundIORecord::execute_recovery() { + if(this->fail_recover_thread.joinable()) return; + + this->fail_recover_thread = std::thread([&]{ + _fail_begin: + { + std::unique_lock cv_lock{this->fail_cv_mutex}; + auto fc = this->failed_count; + if(fc == 0) fc = 1; + else if(fc > 10) return; + this->fail_cv.wait_for(cv_lock, std::chrono::seconds{(fc - 1) * 10}); + } + + std::lock_guard slock{this->state_lock}; + if(!this->running) return; + + std::string error{}; + this->impl_stop(); + if(!this->impl_start(error)) { + log_info(category::audio, tr("Failed to recover from device fail: {}. Trying again later."), error); + this->failed_count++; + goto _fail_begin; + } + }); +} + bool SoundIORecord::impl_start(std::string &error) { assert(this->device_handle); - this->buffer = soundio_ring_buffer_create(nullptr, kChunkSize * sizeof(float) * 2); //2 Channels if(!buffer) { error = "failed to allocate the buffer"; @@ -61,12 +90,18 @@ bool SoundIORecord::impl_start(std::string &error) { this->stream->overflow_callback = [](auto str) { auto handle = reinterpret_cast(str->userdata); log_info(category::audio, tr("Having an overflow on {}"), handle->device_handle->id); + + handle->failed_count++; }; this->stream->error_callback = [](auto str, int err) { auto handle = reinterpret_cast(str->userdata); - log_info(category::audio, tr("Having an error on {}: {}. Aborting recording."), handle->device_handle->id, soundio_strerror(err)); + log_info(category::audio, tr("Having an error on {}: {}. Aborting recording and trying again later."), handle->device_handle->id, soundio_strerror(err)); + std::lock_guard slock{handle->state_lock}; + if(!handle->running) return; + handle->stream_invalid = true; + handle->execute_recovery(); }; this->stream->read_callback = [](struct SoundIoInStream *str, int frame_count_min, int frame_count_max) { @@ -111,6 +146,11 @@ bool SoundIORecord::impl_start(std::string &error) { void SoundIORecord::impl_stop() { if(!this->stream) return; + if(this->fail_recover_thread.joinable() && std::this_thread::get_id() != this->fail_recover_thread.get_id()) { + this->fail_cv.notify_all(); + this->fail_recover_thread.join(); + } + soundio_instream_destroy(this->stream); this->stream = nullptr; @@ -124,7 +164,7 @@ void SoundIORecord::read_callback(int frame_count_min, int frame_count_max) { struct SoundIoChannelArea *areas; int frames_left{frame_count_max}; - int buffer_samples = soundio_ring_buffer_free_count(this->buffer) / (sizeof(float) * layout->channel_count); + int buffer_samples = kChunkSize - soundio_ring_buffer_fill_count(this->buffer) / (sizeof(float) * layout->channel_count); while(frames_left > 0) { int frame_count{frames_left}; @@ -165,11 +205,13 @@ void SoundIORecord::read_callback(int frame_count_min, int frame_count_max) { if(buffer_samples == 0) { std::lock_guard consumer{this->consumer_lock}; const auto byte_count = soundio_ring_buffer_fill_count(this->buffer); - const auto frame_count = byte_count / (sizeof(float) * layout->channel_count); + const auto buffer_frame_count = byte_count / (sizeof(float) * layout->channel_count); + for(auto& consumer : this->_consumers) - consumer->consume(soundio_ring_buffer_read_ptr(this->buffer), frame_count, layout->channel_count); + consumer->consume(soundio_ring_buffer_read_ptr(this->buffer), buffer_frame_count, layout->channel_count); + soundio_ring_buffer_advance_read_ptr(this->buffer, byte_count); - buffer_samples = frame_count; + buffer_samples = kChunkSize; } if(auto err = soundio_instream_end_read(this->stream); err) { diff --git a/native/serverconnection/src/audio/filter/FilterThreshold.cpp b/native/serverconnection/src/audio/filter/FilterThreshold.cpp index 3919188..71e55ba 100644 --- a/native/serverconnection/src/audio/filter/FilterThreshold.cpp +++ b/native/serverconnection/src/audio/filter/FilterThreshold.cpp @@ -77,7 +77,6 @@ long double ThresholdFilter::analyze(const void *_buffer, size_t channel) { /* equation taken from the web client */ auto buffer = (float*) _buffer; - buffer += channel; long double value = 0; auto sample = this->_frame_size;