diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index 1fc0c766b..48d7c6438 100644
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -21,6 +21,7 @@ set(OLIVE_SOURCES
main.cpp
)
+add_subdirectory(audio)
add_subdirectory(common)
add_subdirectory(config)
add_subdirectory(decoder)
diff --git a/app/audio/CMakeLists.txt b/app/audio/CMakeLists.txt
new file mode 100644
index 000000000..72ceaba7c
--- /dev/null
+++ b/app/audio/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Olive - Non-Linear Video Editor
+# Copyright (C) 2019 Olive Team
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+set(OLIVE_SOURCES
+ ${OLIVE_SOURCES}
+ audio/audiomanager.h
+ audio/audiomanager.cpp
+ PARENT_SCOPE
+)
diff --git a/app/audio/audiomanager.cpp b/app/audio/audiomanager.cpp
new file mode 100644
index 000000000..a03faf166
--- /dev/null
+++ b/app/audio/audiomanager.cpp
@@ -0,0 +1,111 @@
+/***
+
+ Olive - Non-Linear Video Editor
+ Copyright (C) 2019 Olive Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+***/
+
+#include "audiomanager.h"
+
+AudioManager* AudioManager::audio_ = nullptr;
+
+void AudioManager::CreateInstance()
+{
+ if (audio_ == nullptr) {
+ audio_ = new AudioManager();
+ }
+}
+
+void AudioManager::DestroyInstance()
+{
+ delete audio_;
+ audio_ = nullptr;
+}
+
+AudioManager *AudioManager::instance()
+{
+ return audio_;
+}
+
+void AudioManager::RefreshDevices()
+{
+ if (refreshing_devices_) {
+ return;
+ }
+
+ input_devices_.clear();
+ output_devices_.clear();
+
+ refreshing_devices_ = true;
+
+ refresh_thread_.start(QThread::LowPriority);
+}
+
+bool AudioManager::IsRefreshing()
+{
+ return refreshing_devices_;
+}
+
+const QList &AudioManager::ListInputDevices()
+{
+ return input_devices_;
+}
+
+const QList &AudioManager::ListOutputDevices()
+{
+ return output_devices_;
+}
+
+AudioManager::AudioManager() :
+ output_(nullptr),
+ refreshing_devices_(false)
+{
+ RefreshDevices();
+
+ connect(&refresh_thread_, SIGNAL(ListsReady()), this, SLOT(RefreshThreadDone()));
+}
+
+void AudioManager::RefreshThreadDone()
+{
+ output_devices_ = refresh_thread_.output_devices();
+ input_devices_ = refresh_thread_.input_devices();
+
+ refreshing_devices_ = false;
+
+ emit DeviceListReady();
+}
+
+AudioRefreshDevicesThread::AudioRefreshDevicesThread()
+{
+}
+
+void AudioRefreshDevicesThread::run()
+{
+ output_devices_ = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
+ input_devices_ = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
+
+ emit ListsReady();
+}
+
+const QList& AudioRefreshDevicesThread::input_devices()
+{
+ return input_devices_;
+}
+
+const QList& AudioRefreshDevicesThread::output_devices()
+{
+ return output_devices_;
+}
diff --git a/app/audio/audiomanager.h b/app/audio/audiomanager.h
new file mode 100644
index 000000000..75778ee61
--- /dev/null
+++ b/app/audio/audiomanager.h
@@ -0,0 +1,90 @@
+/***
+
+ Olive - Non-Linear Video Editor
+ Copyright (C) 2019 Olive Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+***/
+
+#ifndef AUDIOMANAGER_H
+#define AUDIOMANAGER_H
+
+#include
+#include
+#include
+
+/**
+ * @brief A thread for refreshing the total list of devices on the system
+ *
+ * Refreshing devices causes a noticeable pause in execution. Doing it another thread is intended to avoid this.
+ */
+class AudioRefreshDevicesThread : public QThread {
+ Q_OBJECT
+public:
+ AudioRefreshDevicesThread();
+
+ virtual void run() override;
+
+ const QList& input_devices();
+ const QList& output_devices();
+
+signals:
+ void ListsReady();
+
+private:
+ QList input_devices_;
+ QList output_devices_;
+};
+
+class AudioManager : public QObject
+{
+ Q_OBJECT
+public:
+ static void CreateInstance();
+ static void DestroyInstance();
+
+ static AudioManager* instance();
+
+ void RefreshDevices();
+
+ bool IsRefreshing();
+
+ const QList& ListInputDevices();
+ const QList& ListOutputDevices();
+
+signals:
+ void DeviceListReady();
+
+private:
+ AudioManager();
+
+ QList input_devices_;
+
+ QList output_devices_;
+
+ static AudioManager* audio_;
+
+ std::unique_ptr output_;
+
+ bool refreshing_devices_;
+
+ AudioRefreshDevicesThread refresh_thread_;
+
+private slots:
+ void RefreshThreadDone();
+
+};
+
+#endif // AUDIOMANAGER_H
diff --git a/app/core.cpp b/app/core.cpp
index d4f735110..6f7f1c9a0 100644
--- a/app/core.cpp
+++ b/app/core.cpp
@@ -29,6 +29,7 @@
#include
#include
+#include "audio/audiomanager.h"
#include "config/config.h"
#include "dialog/about/about.h"
#include "dialog/sequence/sequence.h"
@@ -384,6 +385,10 @@ void Core::StartGUI(bool full_screen)
// Initialize color service
ColorService::Init();
+
+ // Initialize audio service
+ AudioManager::CreateInstance();
+
}
Project *Core::GetActiveProject()
diff --git a/app/dialog/preferences/tabs/preferencesaudiotab.cpp b/app/dialog/preferences/tabs/preferencesaudiotab.cpp
index f5ddfacff..4723ce284 100644
--- a/app/dialog/preferences/tabs/preferencesaudiotab.cpp
+++ b/app/dialog/preferences/tabs/preferencesaudiotab.cpp
@@ -3,10 +3,13 @@
#include
#include
#include
+#include
+#include "audio/audiomanager.h"
#include "config/config.h"
-PreferencesAudioTab::PreferencesAudioTab()
+PreferencesAudioTab::PreferencesAudioTab() :
+ has_devices_(false)
{
QGridLayout* audio_tab_layout = new QGridLayout(this);
audio_tab_layout->setMargin(0);
@@ -14,47 +17,17 @@ PreferencesAudioTab::PreferencesAudioTab()
int row = 0;
// Audio -> Output Device
-
audio_tab_layout->addWidget(new QLabel(tr("Output Device:")), row, 0);
audio_output_devices = new QComboBox();
- audio_output_devices->addItem(tr("Default"), "");
-
- // list all available audio output devices
- QList devs = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
- bool found_preferred_device = false;
- for (int i=0;iaddItem(devs.at(i).deviceName(), devs.at(i).deviceName());
- if (!found_preferred_device
- && devs.at(i).deviceName() == Config::Current()["AudioOutput"]) {
- audio_output_devices->setCurrentIndex(audio_output_devices->count()-1);
- found_preferred_device = true;
- }
- }
-
audio_tab_layout->addWidget(audio_output_devices, row, 1);
row++;
// Audio -> Input Device
-
audio_tab_layout->addWidget(new QLabel(tr("Input Device:")), row, 0);
audio_input_devices = new QComboBox();
- audio_input_devices->addItem(tr("Default"), "");
-
- // list all available audio input devices
- devs = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
- found_preferred_device = false;
- for (int i=0;iaddItem(devs.at(i).deviceName(), devs.at(i).deviceName());
- if (!found_preferred_device
- && devs.at(i).deviceName() == Config::Current()["AudioInput"]) {
- audio_input_devices->setCurrentIndex(audio_input_devices->count()-1);
- found_preferred_device = true;
- }
- }
-
audio_tab_layout->addWidget(audio_input_devices, row, 1);
row++;
@@ -86,9 +59,76 @@ PreferencesAudioTab::PreferencesAudioTab()
audio_tab_layout->addWidget(recordingComboBox, row, 1);
row++;
+
+ QPushButton* refresh_devices = new QPushButton(tr("Refresh Devices"));
+ audio_tab_layout->addWidget(refresh_devices, row, 1);
+
+ row++;
+
+ RetrieveDeviceLists();
+
+ connect(refresh_devices, SIGNAL(clicked(bool)), this, SLOT(RefreshDevices()));
+ connect(AudioManager::instance(), SIGNAL(DeviceListReady()), this, SLOT(RetrieveDeviceLists()));
}
void PreferencesAudioTab::Accept()
{
+ // If we don't have the device list, we can't set it
+ if (!has_devices_) {
+ return;
+ }
+}
+void PreferencesAudioTab::RefreshDevices()
+{
+ AudioManager::instance()->RefreshDevices();
+
+ RetrieveDeviceLists();
+}
+
+void PreferencesAudioTab::RetrieveDeviceLists()
+{
+ has_devices_ = false;
+
+ audio_input_devices->clear();
+ audio_output_devices->clear();
+
+ if (AudioManager::instance()->IsRefreshing()) {
+ audio_output_devices->addItem(tr("Please wait..."));
+ audio_input_devices->addItem(tr("Please wait..."));
+ audio_output_devices->setEnabled(false);
+ audio_input_devices->setEnabled(false);
+ return;
+ }
+
+ audio_output_devices->setEnabled(true);
+ audio_input_devices->setEnabled(true);
+
+ // list all available audio output devices
+ bool found_preferred_device = false;
+ audio_output_devices->addItem(tr("Default"), "");
+ for (int i=0;iListOutputDevices().size();i++) {
+ audio_output_devices->addItem(AudioManager::instance()->ListOutputDevices().at(i).deviceName(),
+ AudioManager::instance()->ListOutputDevices().at(i).deviceName());
+ if (!found_preferred_device
+ && AudioManager::instance()->ListOutputDevices().at(i).deviceName() == Config::Current()["AudioOutput"]) {
+ audio_output_devices->setCurrentIndex(audio_output_devices->count()-1);
+ found_preferred_device = true;
+ }
+ }
+
+ // list all available audio input devices
+ found_preferred_device = false;
+ audio_input_devices->addItem(tr("Default"), "");
+ for (int i=0;iListInputDevices().size();i++) {
+ audio_input_devices->addItem(AudioManager::instance()->ListInputDevices().at(i).deviceName(),
+ AudioManager::instance()->ListInputDevices().at(i).deviceName());
+ if (!found_preferred_device
+ && AudioManager::instance()->ListInputDevices().at(i).deviceName() == Config::Current()["AudioInput"]) {
+ audio_input_devices->setCurrentIndex(audio_input_devices->count()-1);
+ found_preferred_device = true;
+ }
+ }
+
+ has_devices_ = true;
}
diff --git a/app/dialog/preferences/tabs/preferencesaudiotab.h b/app/dialog/preferences/tabs/preferencesaudiotab.h
index a7b4fde6b..8b3bcde32 100644
--- a/app/dialog/preferences/tabs/preferencesaudiotab.h
+++ b/app/dialog/preferences/tabs/preferencesaudiotab.h
@@ -34,6 +34,14 @@ private:
*/
QComboBox* recordingComboBox;
+private slots:
+ void RefreshDevices();
+
+ void RetrieveDeviceLists();
+
+private:
+ bool has_devices_;
+
};
#endif // PREFERENCESAUDIOTAB_H