From a11341f448722cee6c90eae543ed9edb8710bd03 Mon Sep 17 00:00:00 2001 From: Blueroom VR Date: Fri, 20 Nov 2020 04:14:45 -0800 Subject: [PATCH] Add Audio Device Selection to GUI (Fix #376) (#377) --- gui/CMakeLists.txt | 4 ++-- gui/include/settings.h | 4 ++++ gui/include/settingsdialog.h | 2 ++ gui/include/streamsession.h | 2 ++ gui/src/settings.cpp | 10 ++++++++++ gui/src/settingsdialog.cpp | 37 ++++++++++++++++++++++++++++++++++++ gui/src/streamsession.cpp | 18 ++++++++++++++++-- 7 files changed, 73 insertions(+), 4 deletions(-) diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index 7072b83..23f1b97 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -2,7 +2,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) -find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Multimedia OpenGL Svg) +find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Concurrent Multimedia OpenGL Svg) if(APPLE) find_package(Qt5 REQUIRED COMPONENTS MacExtras) endif() @@ -74,7 +74,7 @@ if(CHIAKI_ENABLE_CLI) endif() target_link_libraries(chiaki FFMPEG::avcodec FFMPEG::avutil) -target_link_libraries(chiaki Qt5::Core Qt5::Widgets Qt5::Gui Qt5::Multimedia Qt5::OpenGL Qt5::Svg) +target_link_libraries(chiaki Qt5::Core Qt5::Widgets Qt5::Gui Qt5::Concurrent Qt5::Multimedia Qt5::OpenGL Qt5::Svg) if(APPLE) target_link_libraries(chiaki Qt5::MacExtras) target_compile_definitions(chiaki PRIVATE CHIAKI_GUI_ENABLE_QT_MACEXTRAS) diff --git a/gui/include/settings.h b/gui/include/settings.h index 0d5975a..6b00591 100644 --- a/gui/include/settings.h +++ b/gui/include/settings.h @@ -9,6 +9,7 @@ #include "videodecoder.h" #include +#include enum class ControllerButtonExt { @@ -93,6 +94,9 @@ class Settings : public QObject */ unsigned int GetAudioBufferSize() const; void SetAudioBufferSize(unsigned int size); + + QString GetAudioOutDevice() const; + void SetAudioOutDevice(QString device_name); ChiakiConnectVideoProfile GetVideoProfile(); diff --git a/gui/include/settingsdialog.h b/gui/include/settingsdialog.h index b0b529e..27b4ee8 100644 --- a/gui/include/settingsdialog.h +++ b/gui/include/settingsdialog.h @@ -25,6 +25,7 @@ class SettingsDialog : public QDialog QComboBox *fps_combo_box; QLineEdit *bitrate_edit; QLineEdit *audio_buffer_size_edit; + QComboBox *audio_device_combo_box; QCheckBox *pi_decoder_check_box; QComboBox *hardware_decode_combo_box; @@ -41,6 +42,7 @@ class SettingsDialog : public QDialog void FPSSelected(); void BitrateEdited(); void AudioBufferSizeEdited(); + void AudioOutputSelected(); void HardwareDecodeEngineSelected(); void UpdateHardwareDecodeEngineComboBox(); diff --git a/gui/include/streamsession.h b/gui/include/streamsession.h index 2d5cb32..01becf5 100644 --- a/gui/include/streamsession.h +++ b/gui/include/streamsession.h @@ -42,6 +42,7 @@ struct StreamSessionConnectInfo QMap key_map; Decoder decoder; HardwareDecodeEngine hw_decode_engine; + QString audio_out_device; uint32_t log_level_mask; QString log_file; QString host; @@ -81,6 +82,7 @@ class StreamSession : public QObject ChiakiPiDecoder *pi_decoder; #endif + QAudioDeviceInfo audio_out_device_info; unsigned int audio_buffer_size; QAudioOutput *audio_output; QIODevice *audio_io; diff --git a/gui/src/settings.cpp b/gui/src/settings.cpp index bedce8d..18867f1 100644 --- a/gui/src/settings.cpp +++ b/gui/src/settings.cpp @@ -130,6 +130,16 @@ unsigned int Settings::GetAudioBufferSize() const return v ? v : GetAudioBufferSizeDefault(); } +QString Settings::GetAudioOutDevice() const +{ + return settings.value("settings/audio_out_device").toString(); +} + +void Settings::SetAudioOutDevice(QString device_name) +{ + settings.setValue("settings/audio_out_device", device_name); +} + void Settings::SetAudioBufferSize(unsigned int size) { settings.setValue("settings/audio_buffer_size", size); diff --git a/gui/src/settingsdialog.cpp b/gui/src/settingsdialog.cpp index 2e96b83..2bae786 100644 --- a/gui/src/settingsdialog.cpp +++ b/gui/src/settingsdialog.cpp @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include @@ -151,6 +153,36 @@ SettingsDialog::SettingsDialog(Settings *settings, QWidget *parent) : QDialog(pa audio_buffer_size_edit->setPlaceholderText(tr("Default (%1)").arg(settings->GetAudioBufferSizeDefault())); connect(audio_buffer_size_edit, &QLineEdit::textEdited, this, &SettingsDialog::AudioBufferSizeEdited); + audio_device_combo_box = new QComboBox(this); + audio_device_combo_box->addItem(tr("Auto")); + auto current_audio_device = settings->GetAudioOutDevice(); + if(!current_audio_device.isEmpty()) + { + // temporarily add the selected device before async fetching is done + audio_device_combo_box->addItem(current_audio_device, current_audio_device); + audio_device_combo_box->setCurrentIndex(1); + } + connect(audio_device_combo_box, QOverload::of(&QComboBox::activated), this, [this](){ + this->settings->SetAudioOutDevice(audio_device_combo_box->currentData().toString()); + }); + + // do this async because it's slow, assuming availableDevices() is thread-safe + auto audio_devices_future = QtConcurrent::run([]() { + return QAudioDeviceInfo::availableDevices(QAudio::AudioOutput); + }); + auto audio_devices_future_watcher = new QFutureWatcher>(this); + connect(audio_devices_future_watcher, &QFutureWatcher>::finished, this, [this, audio_devices_future_watcher, settings]() { + auto available_devices = audio_devices_future_watcher->result(); + while(audio_device_combo_box->count() > 1) // remove all but "Auto" + audio_device_combo_box->removeItem(1); + for (QAudioDeviceInfo di : available_devices) + audio_device_combo_box->addItem(di.deviceName(), di.deviceName()); + int audio_out_device_index = audio_device_combo_box->findData(settings->GetAudioOutDevice()); + audio_device_combo_box->setCurrentIndex(audio_out_device_index < 0 ? 0 : audio_out_device_index); + }); + audio_devices_future_watcher->setFuture(audio_devices_future); + general_layout->addRow(tr("Audio Output Device:"), audio_device_combo_box); + // Decode Settings auto decode_settings = new QGroupBox(tr("Decode Settings")); @@ -291,6 +323,11 @@ void SettingsDialog::AudioBufferSizeEdited() settings->SetAudioBufferSize(audio_buffer_size_edit->text().toUInt()); } +void SettingsDialog::AudioOutputSelected() +{ + settings->SetAudioOutDevice(audio_device_combo_box->currentText()); +} + void SettingsDialog::HardwareDecodeEngineSelected() { settings->SetHardwareDecodeEngine((HardwareDecodeEngine)hardware_decode_combo_box->currentData().toInt()); diff --git a/gui/src/streamsession.cpp b/gui/src/streamsession.cpp index bb67f91..d8f5147 100644 --- a/gui/src/streamsession.cpp +++ b/gui/src/streamsession.cpp @@ -20,6 +20,7 @@ StreamSessionConnectInfo::StreamSessionConnectInfo(Settings *settings, QString h key_map = settings->GetControllerMappingForDecoding(); decoder = settings->GetDecoder(); hw_decode_engine = settings->GetHardwareDecodeEngine(); + audio_out_device = settings->GetAudioOutDevice(); log_level_mask = settings->GetLogLevelMask(); log_file = CreateLogFilename(); video_profile = settings->GetVideoProfile(); @@ -67,6 +68,19 @@ StreamSession::StreamSession(const StreamSessionConnectInfo &connect_info, QObje } #endif + audio_out_device_info = QAudioDeviceInfo::defaultOutputDevice(); + if(!connect_info.audio_out_device.isEmpty()) + { + for(QAudioDeviceInfo di : QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) + { + if(di.deviceName() == connect_info.audio_out_device) + { + audio_out_device_info = di; + break; + } + } + } + chiaki_opus_decoder_init(&opus_decoder, log.GetChiakiLog()); audio_buffer_size = connect_info.audio_buffer_size; @@ -296,7 +310,7 @@ void StreamSession::InitAudio(unsigned int channels, unsigned int rate) audio_format.setCodec("audio/pcm"); audio_format.setSampleType(QAudioFormat::SignedInt); - QAudioDeviceInfo audio_device_info(QAudioDeviceInfo::defaultOutputDevice()); + QAudioDeviceInfo audio_device_info = audio_out_device_info; if(!audio_device_info.isFormatSupported(audio_format)) { CHIAKI_LOGE(log.GetChiakiLog(), "Audio Format with %u channels @ %u Hz not supported by Audio Device %s", @@ -305,7 +319,7 @@ void StreamSession::InitAudio(unsigned int channels, unsigned int rate) return; } - audio_output = new QAudioOutput(audio_format, this); + audio_output = new QAudioOutput(audio_device_info, audio_format, this); audio_output->setBufferSize(audio_buffer_size); audio_io = audio_output->start();