SDL driver's input and output device configuration via combo box (#7421)

* Enable configuration of input device for SDL

Up to now the SDL audio driver attempted to use the default recording
device. This might not be what users want or expect, especially since the
actually used device is not visible anywhere. So if recording does not
work for the users they have no way to find out what's wrong.

Extend the settings screen of the SDL driver with a combo box that allows
to select the input device to be used. Store the selected device name in
a new attribute called "inputdevice" in the "audiosdl" section of the
configuration file.

Use the information from the configuration when attempting to inialize
the input device. Fall back to the default device if that does not work.

(cherry picked from commit 33139b9f4c)

* Provide a setting for system default input

Provide the setting "[System Default]" which instructs the SDL driver to
use the default device of the system as the input device. In the
configuration file this option is represented as an empty string. This
should play well with the current existing configuration of the users.

(cherry picked from commit 29c43c2bb6)

* Configuration of output device for SDL

Let users configure the output device that's used by the SDL driver.
Code-wise the implementation is very similar to the input device
configuration.

Use a `QComboBox` instead of a `QLineEdit` for `m_device` and rename it
to `m_playbackDeviceComboBox`.

Rename `s_defaultInputDevice` to `s_systemDefaultDevice` because it is
used in the context of playback and input devices.

(cherry picked from commit 1ab45e4994)

* Ensure label visibility

Make sure that labels are always shown by setting the row wrap policy of
the form layout to wrap long rows.

(cherry picked from commit a123d0e3cb)

* Rename "Device"

Rename "Device" to "Playback device" to make clear what the setting
refers to.

(cherry picked from commit 1f0cda4983)

* Remove repeated strings

Introduce const expressions to get rid of repeated strings with a risk
of typos.

(cherry picked from commit f9ea9705b8)

* Apply some more changes

Apply some more changes that have been made to `AudioSdl` in the
recording branch.

* Conditional ternary operator

Also use a conditional ternary operator for the input device setup.

* Methods for population of combo boxes

Move the population of the input and playback device combo boxes into
the methods `populatePlaybackDeviceComboBox` and
`populateInputDeviceComboBox`.

* Sort devices in combo box

Sort the devices names alphabetically in the input and playback combo
boxes. The default devices is always shown as the first entry.

* Code review fixes

Use `AudioDeviceSetupWidget` instead of `QObject` to translate "[System
Default]".

Fix copy/paste error in comment.

* Simplify some constexpr statements
This commit is contained in:
Michael Gregorius
2024-08-10 22:33:52 +02:00
committed by GitHub
parent 44a8b038f5
commit 74c73e5848
2 changed files with 118 additions and 17 deletions

View File

@@ -39,7 +39,7 @@
#include "AudioDevice.h"
#include "AudioDeviceSetupWidget.h"
class QLineEdit;
class QComboBox;
namespace lmms
{
@@ -64,10 +64,16 @@ public:
~setupWidget() override = default;
void saveSettings() override;
private:
void populatePlaybackDeviceComboBox();
void populateInputDeviceComboBox();
private:
QLineEdit * m_device;
QComboBox* m_playbackDeviceComboBox = nullptr;
QComboBox* m_inputDeviceComboBox = nullptr;
static QString s_systemDefaultDevice;
} ;

View File

@@ -29,6 +29,7 @@
#include <QFormLayout>
#include <QLineEdit>
#include <QComboBox>
#include <SDL.h>
#include "AudioEngine.h"
@@ -37,6 +38,10 @@
namespace lmms
{
constexpr auto SectionSDL = "audiosdl";
constexpr auto PlaybackDeviceSDL = "device";
constexpr auto InputDeviceSDL = "inputdevice";
AudioSdl::AudioSdl( bool & _success_ful, AudioEngine* _audioEngine ) :
AudioDevice( DEFAULT_CHANNELS, _audioEngine ),
m_outBuf(new SampleFrame[audioEngine()->framesPerPeriod()])
@@ -78,11 +83,19 @@ AudioSdl::AudioSdl( bool & _success_ful, AudioEngine* _audioEngine ) :
SDL_AudioSpec actual;
#ifdef LMMS_HAVE_SDL2
m_outputDevice = SDL_OpenAudioDevice (nullptr,
0,
&m_audioHandle,
&actual,
0);
const auto playbackDevice = ConfigManager::inst()->value(SectionSDL, PlaybackDeviceSDL).toStdString();
const bool isDefaultPlayback = playbackDevice.empty();
// Try with the configured device
const auto playbackDeviceCStr = isDefaultPlayback ? nullptr : playbackDevice.c_str();
m_outputDevice = SDL_OpenAudioDevice(playbackDeviceCStr, 0, &m_audioHandle, &actual, 0);
// If we did not get a device ID try again with the default device if we did not try that before
if (m_outputDevice == 0 && !isDefaultPlayback)
{
m_outputDevice = SDL_OpenAudioDevice(nullptr, 0, &m_audioHandle, &actual, 0);
}
if (m_outputDevice == 0) {
qCritical( "Couldn't open SDL-audio: %s\n", SDL_GetError() );
return;
@@ -108,11 +121,19 @@ AudioSdl::AudioSdl( bool & _success_ful, AudioEngine* _audioEngine ) :
m_inputAudioHandle = m_audioHandle;
m_inputAudioHandle.callback = sdlInputAudioCallback;
m_inputDevice = SDL_OpenAudioDevice (nullptr,
1,
&m_inputAudioHandle,
&actual,
0);
const auto inputDevice = ConfigManager::inst()->value(SectionSDL, InputDeviceSDL).toStdString();
const bool isDefaultInput = inputDevice.empty();
// Try with the configured device
const auto inputDeviceCStr = isDefaultInput ? nullptr : inputDevice.c_str();
m_inputDevice = SDL_OpenAudioDevice (inputDeviceCStr, 1, &m_inputAudioHandle, &actual, 0);
// If we did not get a device ID try again with the default device if we did not try that before
if (m_inputDevice == 0 && !isDefaultInput)
{
m_inputDevice = SDL_OpenAudioDevice(nullptr, 1, &m_inputAudioHandle, &actual, 0);
}
if (m_inputDevice != 0) {
m_supportsCapture = true;
} else {
@@ -283,15 +304,25 @@ void AudioSdl::sdlInputAudioCallback(Uint8 *_buf, int _len) {
#endif
QString AudioSdl::setupWidget::s_systemDefaultDevice = AudioDeviceSetupWidget::tr("[System Default]");
AudioSdl::setupWidget::setupWidget( QWidget * _parent ) :
AudioDeviceSetupWidget( AudioSdl::name(), _parent )
{
QFormLayout * form = new QFormLayout(this);
form->setRowWrapPolicy(QFormLayout::WrapLongRows);
QString dev = ConfigManager::inst()->value( "audiosdl", "device" );
m_device = new QLineEdit( dev, this );
m_playbackDeviceComboBox = new QComboBox(this);
form->addRow(tr("Device"), m_device);
populatePlaybackDeviceComboBox();
form->addRow(tr("Playback device"), m_playbackDeviceComboBox);
m_inputDeviceComboBox = new QComboBox(this);
populateInputDeviceComboBox();
form->addRow(tr("Input device"), m_inputDeviceComboBox);
}
@@ -299,8 +330,72 @@ AudioSdl::setupWidget::setupWidget( QWidget * _parent ) :
void AudioSdl::setupWidget::saveSettings()
{
ConfigManager::inst()->setValue( "audiosdl", "device",
m_device->text() );
const auto currentPlaybackDevice = m_playbackDeviceComboBox->currentText();
if (currentPlaybackDevice == s_systemDefaultDevice)
{
// Represent the default playback device with an empty string
ConfigManager::inst()->setValue(SectionSDL, PlaybackDeviceSDL, "");
}
else if (!currentPlaybackDevice.isEmpty())
{
ConfigManager::inst()->setValue(SectionSDL, PlaybackDeviceSDL, currentPlaybackDevice);
}
const auto currentInputDevice = m_inputDeviceComboBox->currentText();
if (currentInputDevice == s_systemDefaultDevice)
{
// Represent the default input device with an empty string
ConfigManager::inst()->setValue(SectionSDL, InputDeviceSDL, "");
}
else if (!currentInputDevice.isEmpty())
{
ConfigManager::inst()->setValue(SectionSDL, InputDeviceSDL, currentInputDevice);
}
}
void AudioSdl::setupWidget::populatePlaybackDeviceComboBox()
{
#ifdef LMMS_HAVE_SDL2
m_playbackDeviceComboBox->addItem(s_systemDefaultDevice);
QStringList playbackDevices;
const int numberOfPlaybackDevices = SDL_GetNumAudioDevices(0);
for (int i = 0; i < numberOfPlaybackDevices; ++i)
{
const QString deviceName = SDL_GetAudioDeviceName(i, 0);
playbackDevices.append(deviceName);
}
playbackDevices.sort();
m_playbackDeviceComboBox->addItems(playbackDevices);
const auto playbackDevice = ConfigManager::inst()->value(SectionSDL, PlaybackDeviceSDL);
m_playbackDeviceComboBox->setCurrentText(playbackDevice.isEmpty() ? s_systemDefaultDevice : playbackDevice);
#endif
}
void AudioSdl::setupWidget::populateInputDeviceComboBox()
{
#ifdef LMMS_HAVE_SDL2
m_inputDeviceComboBox->addItem(s_systemDefaultDevice);
QStringList inputDevices;
const int numberOfInputDevices = SDL_GetNumAudioDevices(1);
for (int i = 0; i < numberOfInputDevices; ++i)
{
const QString deviceName = SDL_GetAudioDeviceName(i, 1);
inputDevices.append(deviceName);
}
inputDevices.sort();
m_inputDeviceComboBox->addItems(inputDevices);
// Set the current device to the one in the configuration
const auto inputDevice = ConfigManager::inst()->value(SectionSDL, InputDeviceSDL);
m_inputDeviceComboBox->setCurrentText(inputDevice.isEmpty() ? s_systemDefaultDevice : inputDevice);
#endif
}