diff --git a/app/audio/audiomanager.cpp b/app/audio/audiomanager.cpp index 5873b57b2..86d64b692 100644 --- a/app/audio/audiomanager.cpp +++ b/app/audio/audiomanager.cpp @@ -20,6 +20,10 @@ #include "audiomanager.h" +#ifdef Q_OS_LINUX +#include +#endif + #include #include "config/config.h" @@ -46,20 +50,6 @@ AudioManager *AudioManager::instance() return instance_; } -void AudioManager::RefreshDevices() -{ -} - -bool AudioManager::IsRefreshingOutputs() -{ - return is_refreshing_outputs_; -} - -bool AudioManager::IsRefreshingInputs() -{ - return is_refreshing_inputs_; -} - void AudioManager::SetOutputNotifyInterval(int n) { output_buffer_->set_notify_interval(n); @@ -166,33 +156,6 @@ void AudioManager::SetOutputDevice(PaDeviceIndex device) output_device_ = device; CloseOutputStream(); - - /*qInfo() << "Setting output audio device to" << info.deviceName(); - - StopOutput(); - - output_device_info_ = info; - - if (output_params_.is_valid()) { - QAudioFormat format; - format.setSampleRate(output_params_.sample_rate()); - format.setChannelCount(output_params_.channel_count()); - format.setCodec("audio/pcm"); - format.setByteOrder(QAudioFormat::LittleEndian); - format.setSampleSize(output_params_.bits_per_sample()); - format.setSampleType(AudioParams::GetQtSampleType(output_params_.format())); - - if (info.isFormatSupported(format)) { - QMetaObject::invokeMethod(output_manager_, - "SetOutputDevice", - Qt::QueuedConnection, - Q_ARG(const QAudioDeviceInfo&, info), - Q_ARG(const QAudioFormat&, format)); - output_is_set_ = true; - } else { - qWarning() << "Output format not supported by device"; - } - }*/ } void AudioManager::SetInputDevice(PaDeviceIndex device) @@ -206,17 +169,53 @@ void AudioManager::SetInputDevice(PaDeviceIndex device) input_device_ = device; } +void AudioManager::HardReset() +{ + CloseOutputStream(); + Pa_Terminate(); + Pa_Initialize(); +} + +PaDeviceIndex AudioManager::FindConfigDeviceByName(bool is_output_device) +{ + QString entry = is_output_device ? QStringLiteral("AudioOutput") : QStringLiteral("AudioInput"); + + return FindDeviceByName(Config::Current()[entry].toString(), is_output_device); +} + +PaDeviceIndex AudioManager::FindDeviceByName(const QString &s, bool is_output_device) +{ + if (!s.isEmpty()) { + for (PaDeviceIndex i=0, end=Pa_GetDeviceCount(); imaxOutputChannels) || (!is_output_device && device->maxInputChannels)) + && !s.compare(device->name)) { + return i; + } + } + } + + return is_output_device ? Pa_GetDefaultOutputDevice() : Pa_GetDefaultInputDevice(); +} + AudioManager::AudioManager() : - is_refreshing_inputs_(false), - is_refreshing_outputs_(false), output_stream_(nullptr) { - //RefreshDevices(); - Pa_Initialize(); - SetOutputDevice(Pa_GetDefaultOutputDevice()); - SetInputDevice(Pa_GetDefaultInputDevice()); +#ifdef Q_OS_LINUX + // PortAudio doesn't do a strcpy, so we need a const char that's readily accessible (i.e. not + // a QString converted to UTF-8) + PaJack_SetClientName("Olive"); +#endif + + // Get device from config + PaDeviceIndex output_device = FindConfigDeviceByName(true); + PaDeviceIndex input_device = FindConfigDeviceByName(false); + + SetOutputDevice(output_device); + SetInputDevice(input_device); output_buffer_ = new PreviewAudioDevice(this); output_buffer_->open(PreviewAudioDevice::ReadWrite); @@ -230,58 +229,4 @@ AudioManager::~AudioManager() Pa_Terminate(); } -void AudioManager::OutputDevicesRefreshed() -{ - /*QFutureWatcher< QList >* watcher = static_cast >*>(sender()); - - output_devices_ = watcher->result(); - watcher->deleteLater(); - is_refreshing_outputs_ = false; - - QString preferred_audio_output = Config::Current()["AudioOutput"].toString(); - - if (output_ == paNoDevice - || (!preferred_audio_output.isEmpty() && output_device_info_.deviceName() != preferred_audio_output)) { - if (preferred_audio_output.isEmpty()) { - SetOutputDevice(QAudioDeviceInfo::defaultOutputDevice()); - } else { - foreach (const QAudioDeviceInfo& info, output_devices_) { - if (info.deviceName() == preferred_audio_output) { - SetOutputDevice(info); - break; - } - } - } - } - - emit OutputListReady();*/ -} - -void AudioManager::InputDevicesRefreshed() -{ - /*QFutureWatcher< QList >* watcher = static_cast >*>(sender()); - - input_devices_ = watcher->result(); - watcher->deleteLater(); - is_refreshing_inputs_ = false; - - QString preferred_audio_input = Config::Current()["AudioInput"].toString(); - - if (input_ == nullptr - || (!preferred_audio_input.isEmpty() && input_device_info_.deviceName() != preferred_audio_input)) { - if (preferred_audio_input.isEmpty()) { - SetInputDevice(QAudioDeviceInfo::defaultInputDevice()); - } else { - foreach (const QAudioDeviceInfo& info, input_devices_) { - if (info.deviceName() == preferred_audio_input) { - SetInputDevice(info); - break; - } - } - } - } - - emit InputListReady();*/ -} - } diff --git a/app/audio/audiomanager.h b/app/audio/audiomanager.h index d5f224f03..0d0329bd6 100644 --- a/app/audio/audiomanager.h +++ b/app/audio/audiomanager.h @@ -49,12 +49,6 @@ public: static AudioManager* instance(); - void RefreshDevices(); - - bool IsRefreshingOutputs(); - - bool IsRefreshingInputs(); - void SetOutputNotifyInterval(int n); void PushToOutput(const AudioParams ¶ms, const QByteArray& samples); @@ -63,17 +57,28 @@ public: void StopOutput(); + PaDeviceIndex GetOutputDevice() const + { + return output_device_; + } + + PaDeviceIndex GetInputDevice() const + { + return input_device_; + } + void SetOutputDevice(PaDeviceIndex device); void SetInputDevice(PaDeviceIndex device); + void HardReset(); + + static PaDeviceIndex FindConfigDeviceByName(bool is_output_device); + static PaDeviceIndex FindDeviceByName(const QString &s, bool is_output_device); + signals: - void OutputListReady(); - void OutputNotify(); - void InputListReady(); - private: AudioManager(); @@ -83,9 +88,6 @@ private: void CloseOutputStream(); - bool is_refreshing_inputs_; - bool is_refreshing_outputs_; - static AudioManager* instance_; PaDeviceIndex output_device_; @@ -95,11 +97,6 @@ private: PaDeviceIndex input_device_; -private slots: - void OutputDevicesRefreshed(); - - void InputDevicesRefreshed(); - }; } diff --git a/app/dialog/preferences/tabs/preferencesaudiotab.cpp b/app/dialog/preferences/tabs/preferencesaudiotab.cpp index 4c0d4536b..b13f8af59 100644 --- a/app/dialog/preferences/tabs/preferencesaudiotab.cpp +++ b/app/dialog/preferences/tabs/preferencesaudiotab.cpp @@ -33,12 +33,7 @@ PreferencesAudioTab::PreferencesAudioTab() { QVBoxLayout* audio_tab_layout = new QVBoxLayout(this); - QLabel *wip_lbl = new QLabel(tr("We just ported our audio backend to PortAudio so this section will need to be redone. Come back later...")); - wip_lbl->setWordWrap(true); - wip_lbl->setAlignment(Qt::AlignCenter); - audio_tab_layout->addWidget(wip_lbl); - - /*{ + { // Backend Layout QGridLayout* main_layout = new QGridLayout(); main_layout->setMargin(0); @@ -48,195 +43,166 @@ PreferencesAudioTab::PreferencesAudioTab() main_layout->addWidget(new QLabel(tr("Backend:")), row, 0); audio_backend_combobox_ = new QComboBox(); - for (int i=0; iaddItem(AudioManager::GetAudioBackendName(static_cast(i))); - } + connect(audio_backend_combobox_, static_cast(&QComboBox::currentIndexChanged), this, &PreferencesAudioTab::RefreshDevices); main_layout->addWidget(audio_backend_combobox_, row, 1); audio_tab_layout->addLayout(main_layout); } { - // Qt-Backend Layout - QGroupBox* qt_groupbox = new QGroupBox(); - audio_tab_layout->addWidget(qt_groupbox); + QGroupBox* groupbox = new QGroupBox(); + audio_tab_layout->addWidget(groupbox); - QVBoxLayout* qt_layout = new QVBoxLayout(qt_groupbox); + QVBoxLayout* layout = new QVBoxLayout(groupbox); int row = 0; { // Output Group - QGroupBox* qt_output_group = new QGroupBox(); - qt_output_group->setTitle(tr("Output")); - qt_layout->addWidget(qt_output_group); + QGroupBox* output_group = new QGroupBox(); + output_group->setTitle(tr("Output")); + layout->addWidget(output_group); - QGridLayout* qt_output_layout = new QGridLayout(qt_output_group); + QGridLayout* output_layout = new QGridLayout(output_group); - qt_output_layout->addWidget(new QLabel(tr("Device:")), row, 0); + output_layout->addWidget(new QLabel(tr("Device:")), row, 0); audio_output_devices_ = new QComboBox(); - qt_output_layout->addWidget(audio_output_devices_, row, 1); + output_layout->addWidget(audio_output_devices_, row, 1); } row = 0; { - QGroupBox* qt_input_group = new QGroupBox(); - qt_input_group->setTitle(tr("Input")); - qt_layout->addWidget(qt_input_group); + QGroupBox* input_group = new QGroupBox(); + input_group->setTitle(tr("Input")); + layout->addWidget(input_group); - QGridLayout* qt_input_layout = new QGridLayout(qt_input_group); + QGridLayout* input_layout = new QGridLayout(input_group); - qt_input_layout->addWidget(new QLabel(tr("Device:")), row, 0); + input_layout->addWidget(new QLabel(tr("Device:")), row, 0); audio_input_devices_ = new QComboBox(); - qt_input_layout->addWidget(audio_input_devices_, row, 1); + input_layout->addWidget(audio_input_devices_, row, 1); row++; - qt_input_layout->addWidget(new QLabel(tr("Recording Mode:"), this), row, 0); + input_layout->addWidget(new QLabel(tr("Recording Mode:"), this), row, 0); recording_combobox_ = new QComboBox(); recording_combobox_->addItem(tr("Mono")); recording_combobox_->addItem(tr("Stereo")); - qt_input_layout->addWidget(recording_combobox_, row, 1); + input_layout->addWidget(recording_combobox_, row, 1); } - QHBoxLayout* qt_refresh_layout = new QHBoxLayout(); - qt_layout->addLayout(qt_refresh_layout); - qt_refresh_layout->addStretch(); + QHBoxLayout* refresh_layout = new QHBoxLayout(); + layout->addLayout(refresh_layout); + refresh_layout->addStretch(); refresh_devices_btn_ = new QPushButton(tr("Refresh Devices")); - qt_refresh_layout->addWidget(refresh_devices_btn_); + refresh_layout->addWidget(refresh_devices_btn_); - RetrieveDeviceLists(); - - connect(refresh_devices_btn_, &QPushButton::clicked, this, &PreferencesAudioTab::RefreshDevices); - connect(AudioManager::instance(), &AudioManager::OutputListReady, this, &PreferencesAudioTab::RetrieveOutputList); - connect(AudioManager::instance(), &AudioManager::InputListReady, this, &PreferencesAudioTab::RetrieveInputList); + connect(refresh_devices_btn_, &QPushButton::clicked, this, &PreferencesAudioTab::HardRefreshBackends); } - audio_tab_layout->addStretch();*/ + audio_tab_layout->addStretch(); + + // Populate lists + RefreshBackends(); } void PreferencesAudioTab::Accept(MultiUndoCommand *command) { - /* Q_UNUSED(command) - // FIXME: Qt documentation states that QAudioDeviceInfo::deviceName() is a "unique identifiers", which would make them - // ideal for saving in preferences, but in practice they don't actually appear to be unique. - // See: https://bugreports.qt.io/browse/QTBUG-16841 + // Get device indexes + PaDeviceIndex output_device = audio_output_devices_->currentData().value(); + PaDeviceIndex input_device = audio_input_devices_->currentData().value(); - // If we don't have the device list, we can't set it - if (audio_output_devices_->isEnabled()) { - // Get device info - QAudioDeviceInfo selected_output; - QString selected_output_name; + // Get device names, which seem to be the closest thing we have to a "unique identifier" for them + Config::Current()[QStringLiteral("AudioOutput")] = audio_output_devices_->currentText(); + Config::Current()[QStringLiteral("AudioInput")] = audio_input_devices_->currentText(); - // Index 0 is always the default device - if (audio_output_devices_->currentIndex() == 0) { - selected_output = QAudioDeviceInfo::defaultOutputDevice(); - } else { - selected_output = AudioManager::instance()->ListOutputDevices().at(audio_output_devices_->currentData().toInt()); - selected_output_name = selected_output.deviceName(); - } + // Set devices to be used from now on + AudioManager::instance()->SetOutputDevice(output_device); + AudioManager::instance()->SetInputDevice(input_device); +} - // Save it in the global application preferences - if (Config::Current()["AudioOutput"] != selected_output_name) { - Config::Current()["AudioOutput"] = selected_output_name; - AudioManager::instance()->SetOutputDevice(selected_output); - } +void PreferencesAudioTab::RefreshBackends() +{ + audio_backend_combobox_->clear(); + for (PaHostApiIndex i=0, end=Pa_GetHostApiCount(); iaddItem(info->name); } - if (audio_input_devices_->isEnabled()) { - QAudioDeviceInfo selected_input; - QString selected_input_name; - - // Index 0 is always the default device - if (audio_input_devices_->currentIndex() == 0) { - selected_input = QAudioDeviceInfo::defaultInputDevice(); - } else { - selected_input = AudioManager::instance()->ListInputDevices().at(audio_input_devices_->currentData().toInt()); - selected_input_name = selected_input.deviceName(); - } - - if (Config::Current()["AudioInput"] != selected_input_name) { - Config::Current()["AudioInput"] = selected_input_name; - AudioManager::instance()->SetInputDevice(selected_input); - } - } - */ + RefreshDevices(); } void PreferencesAudioTab::RefreshDevices() { - AudioManager::instance()->RefreshDevices(); + if (audio_backend_combobox_->count() == 0) { + return; + } - RetrieveDeviceLists(); -} + PaHostApiIndex host_index = audio_backend_combobox_->currentIndex(); + const PaHostApiInfo *host = Pa_GetHostApiInfo(host_index); -void PreferencesAudioTab::RetrieveOutputList() -{ - /*PopulateComboBox(audio_output_devices_, - AudioManager::instance()->IsRefreshingOutputs(), - AudioManager::instance()->ListOutputDevices(), - Config::Current()["AudioOutput"].toString());*/ + audio_output_devices_->clear(); + audio_input_devices_->clear(); - UpdateRefreshButtonEnabled(); -} - -void PreferencesAudioTab::RetrieveInputList() -{ - /*PopulateComboBox(audio_input_devices_, - AudioManager::instance()->IsRefreshingInputs(), - AudioManager::instance()->ListInputDevices(), - Config::Current()["AudioInput"].toString());*/ - - UpdateRefreshButtonEnabled(); -} - -void PreferencesAudioTab::RetrieveDeviceLists() -{ - RetrieveOutputList(); - RetrieveInputList(); -} - -void PreferencesAudioTab::UpdateRefreshButtonEnabled() -{ - refresh_devices_btn_->setEnabled(audio_output_devices_->isEnabled() - && audio_input_devices_->isEnabled()); -} - -/*void PreferencesAudioTab::PopulateComboBox(QComboBox *cb, bool still_refreshing, const QList &list, const QString& preferred) -{ - cb->clear(); - - cb->setEnabled(!still_refreshing); - - if (still_refreshing) { - cb->addItem(tr("Please wait...")); - } else { - bool found_preferred_device = false; - - // Add null default item - cb->addItem(tr("Default"), QVariant()); - - // For each entry, add it to the combobox - for (int i=0;iaddItem(list.at(i).deviceName(), i); - - if (!found_preferred_device - && list.at(i).deviceName() == preferred) { - cb->setCurrentIndex(cb->count()-1); - found_preferred_device = true; - } + for (int i=0; ideviceCount; i++) { + PaDeviceIndex device_index = Pa_HostApiDeviceIndexToDeviceIndex(host_index, i); + const PaDeviceInfo *device = Pa_GetDeviceInfo(device_index); + if (device->maxOutputChannels) { + audio_output_devices_->addItem(device->name, device_index); } + if (device->maxInputChannels) { + audio_input_devices_->addItem(device->name, device_index); + } } -}*/ + + AttemptToSetDevicesFromConfig(); +} + +void PreferencesAudioTab::HardRefreshBackends() +{ + AudioManager::instance()->HardReset(); + RefreshBackends(); +} + +void PreferencesAudioTab::AttemptToSetDevicesFromConfig() +{ + // Load with currently active devices + PaDeviceIndex current_output_index = AudioManager::instance()->GetOutputDevice(); + PaDeviceIndex current_input_index = AudioManager::instance()->GetInputDevice(); + + const PaDeviceInfo *current_output = nullptr, *current_input = nullptr; + if (current_output_index != paNoDevice) { + current_output = Pa_GetDeviceInfo(current_output_index); + } + if (current_input_index != paNoDevice) { + current_input = Pa_GetDeviceInfo(current_input_index); + } + + if (current_output || current_input) { + PaHostApiIndex host = current_output ? current_output->hostApi : current_input->hostApi; + + // Set backend accordingly + audio_backend_combobox_->setCurrentIndex(host); + + // Device comboboxes should be populated correctly now + if (current_output) { + audio_output_devices_->setCurrentText(current_output->name); + } + + if (current_input) { + audio_input_devices_->setCurrentText(current_input->name); + } + } +} } diff --git a/app/dialog/preferences/tabs/preferencesaudiotab.h b/app/dialog/preferences/tabs/preferencesaudiotab.h index b2cbcbd34..38b6138e3 100644 --- a/app/dialog/preferences/tabs/preferencesaudiotab.h +++ b/app/dialog/preferences/tabs/preferencesaudiotab.h @@ -60,18 +60,13 @@ private: QPushButton* refresh_devices_btn_; private slots: + void RefreshBackends(); + void RefreshDevices(); - void RetrieveOutputList(); + void HardRefreshBackends(); - void RetrieveInputList(); - -private: - void RetrieveDeviceLists(); - - void UpdateRefreshButtonEnabled(); - - //static void PopulateComboBox(QComboBox* cb, bool still_refreshing, const QList& list, const QString &preferred); + void AttemptToSetDevicesFromConfig(); };