13#if QT_VERSION >= QT_VERSION_CHECK(6,5,0)
14#include <QtSystemDetection>
16#include <QCoreApplication>
24#include "libmythbase/mythconfig.h"
28#ifndef __cpp_size_t_suffix
38#include "libavformat/avformat.h"
46 QString dflt =
"OpenSLES:";
47#elif CONFIG_AUDIO_ALSA
48 QString dflt =
"ALSA:default";
49#elif CONFIG_AUDIO_PULSEOUTPUT
50 QString dflt =
"PulseAudio:default";
51#elif defined(Q_OS_DARWIN)
52 QString dflt =
"CoreAudio:";
53#elif defined(Q_OS_WINDOWS)
54 QString dflt =
"Windows:";
56 QString dflt =
"NULL";
84 for (
const auto & it : std::as_const(vect))
86 if (value != it.m_name)
114 if (settings ==
nullptr)
116 settings->CheckConfiguration();
121 m_passThroughOverride(PassThroughOverride()),
122 m_passThroughDeviceOverride(PassThroughOutputDevice())
130 rescan->setLabel(tr(
"Rescan"));
131 rescan->setHelpText(tr(
"Rescan for available audio devices. "
132 "Current entry will be checked and "
133 "capability entries populated."));
153 advancedSettings->setLabel(tr(
"Advanced Audio Settings"));
154 advancedSettings->setHelpText(tr(
"Enable extra audio settings. Under most "
155 "usage all options should be left alone"));
211 QString msg = tr(
"%1 is invalid or not useable.").arg(name);
215 LOG(VB_GENERAL, LOG_ERR, QString(
"Audio device %1 isn't usable")
224 QString pt_msg = tr(
"Passthrough device is invalid or not useable. Check "
225 "configuration in Advanced Settings:") +
230 LOG(VB_GENERAL, LOG_ERR, QString(
"Audio device %1 isn't usable")
253 for (
const auto & dev : std::as_const(*list))
285 bool restore,
bool AC3)
287 int max_speakers = 8;
288 int realmax_speakers = 8;
290 bool invalid =
false;
323 LOG(VB_AUDIO, LOG_ERR, QString(
"Update not found (%1)").arg(out));
331 settingsdigital = bForceDigital ?
333 .m_settings : settings;
351 if (max_speakers > 2 && !bLPCM)
353 if (max_speakers == 2 && bAC3)
380 if (cur_speakers > max_speakers)
382 LOG(VB_AUDIO, LOG_INFO, QString(
"Reset device %1").arg(out));
383 cur_speakers = max_speakers;
389 for (
int i = 1; i <= max_speakers; i++)
399 txt = QCoreApplication::translate(
"(Common)",
"Stereo");
402 txt = QCoreApplication::translate(
"(Common)",
"5.1");
405 txt = QCoreApplication::translate(
"(Common)",
"7.1");
446 QString name =
"MaxChannels";
450 gc->setLabel(tr(
"Speaker configuration"));
452 gc->addSelection(QCoreApplication::translate(
"(Common)",
"Stereo"),
455 gc->setHelpText(tr(
"Select the maximum number of audio "
456 "channels supported by your receiver "
465 gc->setLabel(tr(
"Upconvert stereo to 5.1 surround"));
469 gc->setHelpText(tr(
"If enabled, MythTV will upconvert stereo "
470 "to 5.1 audio. You can enable or disable "
471 "the upconversion during playback at any time."));
479 gc->setLabel(tr(
"Upmix Quality"));
481 gc->addSelection(tr(
"Passive"),
"0");
482 gc->addSelection(tr(
"Hall",
"Upmix Quality"),
"3");
483 gc->addSelection(tr(
"Good",
"Upmix Quality"),
"1");
484 gc->addSelection(tr(
"Best",
"Upmix Quality"),
"2",
true);
486 gc->setHelpText(tr(
"Set the audio surround-upconversion quality."));
495 gc->setLabel(tr(
"Dolby Digital"));
499 gc->setHelpText(tr(
"Enable if your amplifier or sound decoder "
500 "supports AC-3/Dolby Digital. You must use a digital "
501 "connection. Uncheck if using an analog connection."));
509 gc->setLabel(tr(
"DTS"));
513 gc->setHelpText(tr(
"Enable if your amplifier or sound decoder supports "
514 "DTS. You must use a digital connection. Uncheck "
515 "if using an analog connection"));
523 gc->setLabel(tr(
"E-AC-3"));
527 gc->setHelpText(tr(
"Enable if your amplifier or sound decoder supports "
528 "E-AC-3 (DD+). You must use a HDMI connection."));
536 gc->setLabel(tr(
"TrueHD"));
540 gc->setHelpText(tr(
"Enable if your amplifier or sound decoder supports "
541 "Dolby TrueHD. You must use a HDMI connection."));
549 gc->setLabel(tr(
"DTS-HD"));
553 gc->setHelpText(tr(
"Enable if your amplifier or sound decoder supports "
554 "DTS-HD. You must use a HDMI connection."));
569 LOG(VB_GENERAL, LOG_ERR,
570 QString(
"Passthru device %1 isn't usable "
571 "Check audio configuration").arg(name));
584 const QDir& dir,
bool absPath =
true)
587 QFileInfoList entries = dir.entryInfoList();
588 for (
const auto & fi : std::as_const(entries))
602 QString passthrough =
611 : QEvent(kEventType),
612 m_channel(std::move(channame)),
618 QString
main, QString passthrough,
623 m_parent(parent), m_channels(channels), m_device(std::move(
main)),
624 m_passthrough(std::move(passthrough)), m_hd(hd),
625 m_samplerate(hd ? settings.BestSupportedRate() : 48000),
626 m_format(hd ? settings.BestSupportedFormat() :
FORMAT_S16)
632 true,
false, 0, &settings);
640 static_cast<QEvent::Type
>(QEvent::registerEventType());
663 std::array<std::array<int,8>,7> smptelayout {{
668 { 0, 2, 1, 5, 4, 3 },
669 { 0, 2, 1, 6, 4, 5, 3 },
670 { 0, 2, 1, 7, 5, 4, 6, 3 },
675#ifdef __cpp_size_t_suffix
676 char *frames =
new (std::align_val_t(16))
char[
m_channels * 1024UZ *
sizeof(int32_t)];
678 char *frames =
new (std::align_val_t(16))
char[
m_channels * 1024_UZ *
sizeof(int32_t)];
703 channel =
"frontleft";
706 channel =
"frontright";
716 channel =
"surroundleft";
718 channel =
"rearright";
720 channel =
"rearleft";
724 channel =
"surroundright";
726 channel =
"surroundleft";
728 channel =
"rearright";
732 channel =
"surroundright";
734 channel =
"surroundleft";
737 channel =
"surroundright";
740 QCoreApplication::postEvent(
743 LOG(VB_AUDIO, LOG_INFO, QString(
"AudioTest: %1 (%2->%3)")
744 .arg(channel).arg(i).arg(
current));
755 LOG(VB_AUDIO, LOG_ERR,
"AddData() Audio buffer "
756 "overflow, audio data lost!");
762 std::this_thread::sleep_for(500ms);
770 ::operator
delete[] (frames, std::align_val_t(16));
780 setLabel(tr(
"Audio Configuration Testing"));
781 setHelpText(tr(
"Will play a test pattern on all configured "
813 QString surroundleft;
867 "supported by your audio card. This will be "
868 "a good place to start troubleshooting "
869 "potential errors"));
887 const QString &passthrough,
947 else if (this->sender() ==
m_lfe)
969 else if (this->sender() ==
m_center)
1008 QString msg = tr(
"Audio device is invalid or not useable.");
1024 return QObject::event(
event);
1028 return GroupSetting::event(
event);
1030 QString channel = cce->m_channel;
1032 if (!cce->m_fulltest)
1033 return GroupSetting::event(
event);
1044 if (channel ==
"frontleft")
1048 else if (channel ==
"frontright")
1052 else if (channel ==
"center")
1056 else if (channel ==
"lfe")
1060 else if (channel ==
"surroundleft")
1064 else if (channel ==
"surroundright")
1068 else if (channel ==
"rearleft")
1072 else if (channel ==
"rearright")
1092 return GroupSetting::event(
event);
1100 gc->setLabel(tr(
"Use internal volume controls"));
1104 gc->setHelpText(tr(
"If enabled, MythTV will control the PCM and "
1105 "master mixer volume. Disable this option if you "
1106 "prefer to control the volume externally (for "
1107 "example, using your amplifier) or if you use an "
1108 "external mixer program."));
1120 gc->setLabel(tr(
"Mixer device"));
1123 QDir dev(
"/dev",
"mixer*", QDir::Name, QDir::System);
1126 dev.setPath(
"/dev/sound");
1132#if CONFIG_AUDIO_ALSA
1133 gc->addSelection(
"ALSA:default",
"ALSA:default");
1136 gc->addSelection(
"DirectX:",
"DirectX:");
1137 gc->addSelection(
"Windows:",
"Windows:");
1140 gc->addSelection(
"OpenSLES:",
"OpenSLES:");
1143 gc->addSelection(tr(
"software"),
"software");
1146 gc->setHelpText(tr(
"Setting the mixer device to \"%1\" lets MythTV control "
1147 "the volume of all audio at the expense of a slight "
1149 .arg(tr(
"software")));
1156 QT_TR_NOOP(
"Master")};
1162 gc->setLabel(tr(
"Mixer controls"));
1165 gc->addSelection(tr(control), control);
1167 gc->setHelpText(tr(
"Changing the volume adjusts the selected mixer."));
1176 gs->setLabel(tr(
"Master mixer volume"));
1180 gs->setHelpText(tr(
"Initial volume for the Master mixer. This affects "
1181 "all sound created by the audio device. Note: Do not "
1182 "set this too low."));
1190 gs->setLabel(tr(
"PCM mixer volume"));
1194 gs->setHelpText(tr(
"Initial volume for PCM output. Using the volume "
1195 "keys in MythTV will adjust this parameter."));
1203 gc->setLabel(tr(
"Stereo PCM Only"));
1205 gc->setValue(
false);
1207 gc->setHelpText(tr(
"Enable if your amplifier or sound decoder only "
1208 "supports 2 channel PCM (typically an old HDMI 1.0 "
1209 "device). Multichannel audio will be re-encoded to "
1210 "AC-3 when required"));
1218 gc->setLabel(tr(
"Override SRC quality"));
1220 gc->setValue(
false);
1222 gc->setHelpText(tr(
"Enable to override audio sample rate "
1223 "conversion quality."));
1231 gc->setLabel(tr(
"Sample rate conversion"));
1233 gc->addSelection(tr(
"Disabled",
"Sample rate conversion"),
"-1");
1234 gc->addSelection(tr(
"Fastest",
"Sample rate conversion"),
"0");
1235 gc->addSelection(tr(
"Good",
"Sample rate conversion"),
"1",
true);
1236 gc->addSelection(tr(
"Best",
"Sample rate conversion"),
"2");
1238 gc->setHelpText(tr(
"Set the quality of audio sample-rate "
1239 "conversion. \"%1\" (default) provides the best "
1240 "compromise between CPU usage and quality. \"%2\" "
1241 "lets the audio device handle sample-rate conversion.")
1242 .arg(tr(
"Good",
"Sample rate conversion"),
1243 tr(
"Disabled",
"Sample rate conversion")));
1252 gc->setLabel(tr(
"Force audio device output to 48kHz"));
1253 gc->setValue(
false);
1255 gc->setHelpText(tr(
"Force audio sample rate to 48kHz. Some audio devices "
1256 "will report various rates, but they ultimately "
1265 gc->setLabel(tr(
"Separate digital output device"));
1267 gc->setValue(
false);
1269 gc->setHelpText(tr(
"Use a distinct digital output device from default. "
1270 "(default is not checked)"));
1279 gc->setLabel(tr(
"Digital output device"));
1282 gc->addSelection(QCoreApplication::translate(
"(Common)",
"Default"),
1285 gc->addSelection(
"DirectX:Primary Sound Driver");
1287 gc->addSelection(
"ALSA:iec958:{ AES0 0x02 }",
1288 "ALSA:iec958:{ AES0 0x02 }");
1289 gc->addSelection(
"ALSA:hdmi",
"ALSA:hdmi");
1290 gc->addSelection(
"ALSA:plughw:0,3",
"ALSA:plughw:0,3");
1293 gc->setHelpText(tr(
"Audio output device to use for digital audio. This "
1294 "value is currently only used with ALSA and DirectX "
1303 gc->setLabel(tr(
"SPDIF 48kHz rate override"));
1305 gc->setValue(
false);
1307 gc->setHelpText(tr(
"ALSA only. By default, let ALSA determine the "
1308 "passthrough sampling rate. If checked set the sampling "
1309 "rate to 48kHz for passthrough. (default is not "
1318 gc->setLabel(tr(
"HBR passthrough support"));
1322 gc->setHelpText(tr(
"HBR support is required for TrueHD and DTS-HD "
1323 "passthrough. If unchecked, Myth will limit the "
1324 "passthrough bitrate to 6.144Mbit/s. This will "
1325 "disable True-HD passthrough, however will allow "
1326 "DTS-HD content to be sent as DTS-HD Hi-Res. (default "
void Load(void) override
Load data which will ultimately be displayed on-screen or used to determine what appears on-screen (S...
AudioConfigScreen(MythScreenStack *parent, const char *name, GroupSetting *groupSetting)
void Init(void) override
Used after calling Load() to assign data to widgets and other UI initilisation which is prohibited in...
void UpdateVisibility(StandardSetting *)
AudioDeviceComboBox * m_outputDevice
HostCheckBoxSetting * m_passThroughOverride
ADCMap & AudioDeviceMap(void)
AudioOutputSettings UpdateCapabilitiesAC3(void)
HostComboBoxSetting * m_audioUpmixType
static const std::array< const char *, 2 > kMixerControlControls
static HostComboBoxSetting * PassThroughOutputDevice()
HostCheckBoxSetting * m_trueHDPassThrough
static HostComboBoxSetting * MixerDevice()
static HostCheckBoxSetting * AudioUpmix()
static HostCheckBoxSetting * DTSPassThrough()
static HostCheckBoxSetting * SRCQualityOverride()
static HostCheckBoxSetting * TrueHDPassThrough()
HostCheckBoxSetting * m_dtsPassThrough
void CheckConfiguration(void)
static HostCheckBoxSetting * EAC3PassThrough()
static HostComboBoxSetting * AudioUpmixType()
static HostCheckBoxSetting * AC3PassThrough()
static HostCheckBoxSetting * HBRPassthrough()
HostComboBoxSetting * m_passThroughDeviceOverride
HostCheckBoxSetting * m_dtsHDPassThrough
static HostComboBoxSetting * MixerControl()
static HostCheckBoxSetting * Audio48kOverride()
HostCheckBoxSetting * m_ac3PassThrough
static HostComboBoxSetting * MaxAudioChannels()
QString m_lastAudioDevice
static HostCheckBoxSetting * MPCM()
HostCheckBoxSetting * m_mpcm
GroupSetting * m_triggerDigital
HostCheckBoxSetting * m_eac3PassThrough
static HostCheckBoxSetting * DTSHDPassThrough()
HostComboBoxSetting * m_maxAudioChannels
static HostCheckBoxSetting * MythControlsVolume()
AudioOutput::ADCVect m_devices
AudioOutputSettings UpdateCapabilities(bool restore=true, bool AC3=false)
static HostCheckBoxSetting * SPDIFRateOverride()
static HostSpinBoxSetting * PCMVolume()
void setMPCMEnabled(bool flag)
AudioOutput::ADCVect & AudioDeviceVect(void)
static HostComboBoxSetting * SRCQuality()
static HostSpinBoxSetting * MixerVolume()
HostCheckBoxSetting * m_audioUpmix
static HostCheckBoxSetting * PassThroughOverride()
void AudioDescriptionHelp(StandardSetting *setting)
void edit(MythScreenType *screen) override
AudioConfigSettings * m_parent
AudioDeviceComboBox(AudioConfigSettings *parent)
bool IsSupportedChannels(int channels)
int BestSupportedChannels()
bool canFeature(DigitalFeature arg) const
return DigitalFeature mask.
void SetBestSupportedChannels(int channels)
Force set the greatest number of channels supported by the audio device.
void setFeature(DigitalFeature arg)
set the provided digital feature possible values are:
int canPassthrough() const
bool IsInvalid() const
return true if class instance is marked invalid.
AudioOutputSettings m_settings
virtual void Drain(void)=0
static AudioOutput * OpenAudio(const QString &main_device, const QString &passthru_device, AudioFormat format, int channels, AVCodecID codec, int samplerate, AudioOutputSource source, bool set_initial_vol, bool passthru, int upmixer_startup=0, AudioOutputSettings *custom=nullptr)
virtual std::chrono::milliseconds LengthLastData(void) const
static ADCVect * GetOutputList(void)
QVector< AudioDeviceConfig > ADCVect
static AudioDeviceConfig * GetAudioDeviceConfig(QString &name, const QString &desc, bool willsuspendpa=false)
virtual void Pause(bool paused)=0
bool playPinkNoise(char *frames, int channels, int channel, int count, int bits)
Generates and plays pink noise from a speaker for testing.
void setChannel(int channel)
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
AudioTestThread(QObject *parent, QString main, QString passthrough, int channels, AudioOutputSettings &settings, bool hd)
AudioOutput * m_audioOutput
~AudioTestThread() override
ButtonStandardSetting * m_startButton
ButtonStandardSetting * m_frontright
ButtonStandardSetting * m_lfe
ButtonStandardSetting * m_surroundleft
ButtonStandardSetting * m_frontleft
TransMythUICheckBoxSetting * m_hd
ButtonStandardSetting * m_center
ButtonStandardSetting * m_surroundright
void togglequality(const QString &)
ButtonStandardSetting * m_rearright
bool event(QEvent *event) override
ButtonStandardSetting * m_rearleft
AudioOutputSettings m_settings
void UpdateCapabilities(const QString &main, const QString &passthrough, int channels, const AudioOutputSettings &settings)
ChannelChangedEvent(QString channame, bool fulltest)
static const Type kEventType
This is a wrapper around QThread that does several additional things.
bool isRunning(void) const
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Dialog asking for user confirmation.
QString GetSetting(const QString &key, const QString &defaultval="")
int GetNumSetting(const QString &key, int defaultval=0)
bool GetBoolSetting(const QString &key, bool defaultval=false)
MythScreenStack * GetMainStack()
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Screen in which all other widgets are contained and rendered.
void SetBusyPopupMessage(const QString &message)
virtual void addSelection(const QString &label, QString value=QString(), bool select=false)
void edit(MythScreenType *screen) override
void Init(void) override
Used after calling Load() to assign data to widgets and other UI initilisation which is prohibited in...
void Load(void) override
Load data which will ultimately be displayed on-screen or used to determine what appears on-screen (S...
GroupSetting * GetGroupSettings(void) const
virtual void addChild(StandardSetting *child)
void addTargetedChild(const QString &value, StandardSetting *setting)
virtual void setHelpText(const QString &str)
bool haveChanged()
Return true if the setting have changed or any of its children.
void valueChanged(const QString &newValue)
virtual QString getValue(void) const
virtual void setEnabled(bool enabled)
virtual void setLabel(QString str)
void setChanged(bool changed)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
MythMainWindow * GetMythMainWindow(void)
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
uint fillSelectionsFromDir(const QDir &dir, uint minor_min, uint minor_max, const QString &card, const QRegularExpression &driver, bool allow_duplicates, V2CaptureDeviceList *pList, const QString &cardType)
VERBOSE_PREAMBLE Most true