MythTV master
setupwizard_audio.cpp
Go to the documentation of this file.
1// C++
2#include <algorithm>
3
4// Qt
5#include <QString>
6#include <QVariant>
7
8// MythTV
15
16// MythFrontend
18#include "setupwizard_audio.h"
19#include "setupwizard_general.h"
20#include "setupwizard_video.h"
21
23{
24 // Load the theme for this screen
25 bool foundtheme = LoadWindowFromXML("config-ui.xml", "audiowizard", this);
26 if (!foundtheme)
27 return false;
28
30 dynamic_cast<MythUIButtonList *> (GetChild("audiodevices"));
32 dynamic_cast<MythUIButtonList *> (GetChild("speakers"));
33
34 m_dtsCheck = dynamic_cast<MythUICheckBox *> (GetChild("dtscheck"));
35 m_ac3Check = dynamic_cast<MythUICheckBox *> (GetChild("ac3check"));
36 m_eac3Check = dynamic_cast<MythUICheckBox *> (GetChild("eac3check"));
37 m_truehdCheck = dynamic_cast<MythUICheckBox *> (GetChild("truehdcheck"));
38 m_dtshdCheck = dynamic_cast<MythUICheckBox *> (GetChild("dtshdcheck"));
39
41 dynamic_cast<MythUIButton *> (GetChild("testspeakers"));
42
43 m_nextButton = dynamic_cast<MythUIButton *> (GetChild("next"));
44 m_prevButton = dynamic_cast<MythUIButton *> (GetChild("previous"));
45
49 {
50 LOG(VB_GENERAL, LOG_ERR, "Theme is missing critical theme elements.");
51 return false;
52 }
53
54 // Pre-set the widgets to their database values
55 // Buttonlists are set in load()
56
57 int dtsSetting = gCoreContext->GetNumSetting("DTSPassThru", 0);
58 if (dtsSetting == 1)
60
61 int ac3Setting = gCoreContext->GetNumSetting("AC3PassThru", 0);
62 if (ac3Setting == 1)
64
65 int eac3Setting = gCoreContext->GetNumSetting("EAC3PassThru", 0);
66 if (eac3Setting == 1)
68
69 int truehdSetting = gCoreContext->GetNumSetting("TrueHDPassThru", 0);
70 if (truehdSetting == 1)
72
73 int dtshdSetting = gCoreContext->GetNumSetting("DTSHDPassThru", 0);
74 if (dtshdSetting == 1)
76
77 // Help Text
78
79 // Buttonlists
80 m_audioDeviceButtonList->SetHelpText( tr("Select from one of the "
81 "audio devices detected on your system. When "
82 "satisfied, you can test audio before moving "
83 "on. If you fail to configure audio, video "
84 "playback may fail as well.") );
85 m_speakerNumberButtonList->SetHelpText( tr("Select the number of speakers you "
86 "have.") );
87
88 // Checkboxes
89 m_dtsCheck->SetHelpText( tr("Select this checkbox if your receiver "
90 "is capable of playing DTS.") );
91 m_ac3Check->SetHelpText( tr("Select this checkbox if your receiver "
92 "is capable of playing AC-3 (Dolby Digital).") );
93 m_eac3Check->SetHelpText( tr("Select this checkbox if your receiver "
94 "is capable of playing E-AC-3 (Dolby Digital Plus).") );
95 m_truehdCheck->SetHelpText( tr("Select this checkbox if your receiver "
96 "is capable of playing TrueHD.") );
97 m_dtshdCheck->SetHelpText( tr("Select this checkbox if your receiver "
98 "is capable of playing DTS-HD.") );
99
100 // Buttons
101 m_testSpeakerButton->SetHelpText( tr("Test your audio settings by playing "
102 "noise through each speaker.") );
103 m_nextButton->SetHelpText( tr("Save these changes and move on to the next "
104 "configuration step.") );
105 m_prevButton->SetHelpText( tr("Return to the previous configuration step.") );
106
107 // I hate to SetText but it's the only way to make it reliably bi-modal
108 m_testSpeakerButton->SetText(tr("Test Speakers"));
109
113
114 QString message = tr("Discovering audio devices...");
115 LoadInBackground(message);
116
118
119 return true;
120}
121
123{
124 if (m_testThread)
125 {
128 delete m_testThread;
129 }
130 delete m_outputlist;
131}
132
134{
136}
137
139{
140 QString current = gCoreContext->GetSetting(QString("AudioOutputDevice"));
141 bool found = false;
142
143 if (!current.isEmpty())
144 {
145 auto samename = [current](const auto & ao){ return ao.m_name == current; };
146 found = std::any_of(m_outputlist->cbegin(), m_outputlist->cend(), samename);
147 if (!found)
148 {
151 if (adc->m_settings.IsInvalid())
152 {
153 LOG(VB_GENERAL, LOG_ERR, QString("Audio device %1 isn't usable")
154 .arg(current));
155 }
156 else
157 {
158 // only insert the device if it is valid
159 m_outputlist->insert(0, *adc);
160 }
161 delete adc;
162 }
163 }
164 for (const auto & ao : std::as_const(*m_outputlist))
165 {
166 QString name = ao.m_name;
168 output->SetData(name);
169 }
170 if (found)
171 {
172 m_audioDeviceButtonList->SetValueByData(QVariant::fromValue(current));
173 }
174
175 m_maxspeakers = gCoreContext->GetNumSetting("MaxChannels", 2);
177
178 // Update list for default audio device
180
184 this, qOverload<MythUIButtonListItem*>(&AudioSetupWizard::UpdateCapabilities));
185}
186
188{
190 int max_speakers = 8;
191 int realmax_speakers = 8;
192
193 AudioOutputSettings settings;
194
195 auto samename = [out](const auto & ao){ return ao.m_name == out; };
196 // NOLINTNEXTLINE(readability-qualified-auto) // qt6
197 const auto ao = std::find_if(m_outputlist->cbegin(), m_outputlist->cend(), samename);
198 if (ao != m_outputlist->cend())
199 settings = ao->m_settings;
200
201 realmax_speakers = max_speakers = settings.BestSupportedChannels();
202
203 bool bAC3 = settings.canFeature(FEATURE_AC3);
204 bool bDTS = settings.canFeature(FEATURE_DTS);
205 bool bLPCM = settings.canFeature(FEATURE_LPCM);
206 bool bEAC3 = settings.canFeature(FEATURE_EAC3);
207 bool bTRUEHD = settings.canFeature(FEATURE_TRUEHD);
208 bool bDTSHD = settings.canFeature(FEATURE_DTSHD);
209
210 bAC3 ? m_ac3Check->Show() : m_ac3Check->Hide();
211 bDTS ? m_dtsCheck->Show() : m_dtsCheck->Hide();
212 bEAC3 ? m_eac3Check->Show() : m_eac3Check->Hide();
213 bTRUEHD ? m_truehdCheck->Show() : m_truehdCheck->Hide();
214 bDTSHD ? m_dtshdCheck->Show() : m_dtshdCheck->Hide();
215
218
219 if (max_speakers > 2 && !bLPCM)
220 max_speakers = 2;
221 if (max_speakers == 2 && bAC3)
222 {
223 max_speakers = 6;
224 if (AC3)
225 {
226 restore = true;
227 }
228 }
229
230 int cur_speakers = m_maxspeakers;
231
233 {
235 .value<int>();
236 }
237 m_maxspeakers = std::max(cur_speakers, m_maxspeakers);
238 if (restore)
239 {
240 cur_speakers = m_maxspeakers;
241 }
242
243 if (cur_speakers > max_speakers)
244 {
245 LOG(VB_AUDIO, LOG_INFO, QString("Reset device %1").arg(out));
246 cur_speakers = max_speakers;
247 }
248
249 // Remove everything and re-add available channels
251 for (int i = 1; i <= max_speakers; i++)
252 {
253 if (settings.IsSupportedChannels(i))
254 {
255 switch (i)
256 {
257 case 2:
258 {
259 auto *stereo =
261 QObject::tr("Stereo"));
262 stereo->SetData(2);
263 break;
264 }
265 case 6:
266 {
267 auto *sixchan =
269 QObject::tr("5.1 Channel Audio"));
270 sixchan->SetData(6);
271 break;
272 }
273 case 8:
274 {
275 auto *eightchan =
277 QObject::tr("7.1 Channel Audio"));
278 eightchan->SetData(8);
279 break;
280 }
281 default:
282 continue;
283 }
284 }
285 }
286 m_speakerNumberButtonList->SetValueByData(QVariant::fromValue(cur_speakers));
287
288 // Return values is used by audio test
289 // where we mainly are interested by the number of channels
290 // if we support AC3 and/or LPCM
291 settings.SetBestSupportedChannels(cur_speakers);
292 settings.setFeature(bAC3, FEATURE_AC3);
293 settings.setFeature(bDTS, FEATURE_DTS);
294 settings.setFeature(bLPCM && realmax_speakers > 2, FEATURE_LPCM);
295
296 return settings;
297}
298
301{
302 bool restore = false;
303 if (item)
304 {
305 restore = item->GetText() != m_lastAudioDevice;
306 m_lastAudioDevice = item->GetText();
307 }
308 return UpdateCapabilities(restore);
309}
310
312{
313 return UpdateCapabilities(false, true);
314}
315
317{
318 if (m_testThread)
319 {
321 }
322
323 save();
324
326 auto *sw = new VideoSetupWizard(mainStack, m_generalScreen,
327 this, "videosetupwizard");
328
329 if (sw->Create())
330 {
331 mainStack->AddScreen(sw);
332 }
333 else
334 {
335 delete sw;
336 }
337}
338
340{
341 // reset advanced audio config to default values
342 gCoreContext->SaveBoolSetting("StereoPCM", false);
343 gCoreContext->SaveBoolSetting("Audio48kOverride", false);
344 gCoreContext->SaveBoolSetting("HBRPassthru", true);
345 gCoreContext->SaveBoolSetting("PassThruDeviceOverride", false);
346 gCoreContext->SaveSetting("PassThruOutputDevice", QString());
347
349 .value<int>();
350 gCoreContext->SaveSetting("MaxChannels", channels);
351
352 QString device =
354 gCoreContext->SaveSetting("AudioOutputDevice", device);
355
356 bool ac3State = (m_ac3Check->GetCheckState() == MythUIStateType::Full);
357 gCoreContext->SaveBoolSetting("AC3PassThru", ac3State);
358
359 bool dtsState = (m_dtsCheck->GetCheckState() == MythUIStateType::Full);
360 gCoreContext->SaveBoolSetting("DTSPassThru", dtsState);
361
362 bool eac3State = (m_eac3Check->GetCheckState() == MythUIStateType::Full);
363 gCoreContext->SaveBoolSetting("EAC3PassThru", eac3State);
364
365 bool truehdState = (m_truehdCheck->GetCheckState() == MythUIStateType::Full);
366 gCoreContext->SaveBoolSetting("TrueHDPassThru", truehdState);
367
368 bool dtshdState = (m_dtshdCheck->GetCheckState() == MythUIStateType::Full);
369 gCoreContext->SaveBoolSetting("DTSHDPassThru", dtshdState);
370}
371
373{
374 Close();
375}
376
378{
379 if (GetFocusWidget()->keyPressEvent(event))
380 return true;
381
382 bool handled = false;
383
385 handled = true;
386
387 return handled;
388}
389
391{
392 if (m_testThread)
393 {
396 delete m_testThread;
397 m_testThread = nullptr;
398 m_testSpeakerButton->SetText(tr("Test Speakers"));
399 return;
400 }
401
402 AudioOutputSettings settings = UpdateCapabilities(false);
405 .value<int> ();
406
408 new AudioTestThread(this, out, out, channels, settings, false);
409 if (!m_testThread->result().isEmpty())
410 {
411 QString msg = QObject::tr("Audio device is invalid or not useable.");
412 ShowOkPopup(msg);
413 delete m_testThread;
414 m_testThread = nullptr;
415 }
416 else
417 {
419 m_testSpeakerButton->SetText(tr("Stop Speaker Test"));
420 }
421}
@ FEATURE_DTS
@ FEATURE_AC3
@ FEATURE_DTSHD
@ FEATURE_EAC3
@ FEATURE_LPCM
@ FEATURE_TRUEHD
bool IsSupportedChannels(int channels)
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:
bool IsInvalid() const
return true if class instance is marked invalid.
AudioOutputSettings m_settings
Definition: audiooutput.h:34
static ADCVect * GetOutputList(void)
static AudioDeviceConfig * GetAudioDeviceConfig(QString &name, const QString &desc, bool willsuspendpa=false)
AudioTestThread * m_testThread
AudioOutputSettings UpdateCapabilitiesAC3(void)
AudioOutputSettings UpdateCapabilities(bool restore=true, bool AC3=false)
MythUICheckBox * m_dtsCheck
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
bool Create(void) override
MythUIButton * m_testSpeakerButton
MythUICheckBox * m_eac3Check
MythUICheckBox * m_ac3Check
MythUIButtonList * m_speakerNumberButtonList
MythUICheckBox * m_dtshdCheck
~AudioSetupWizard() override
void Load(void) override
Load data which will ultimately be displayed on-screen or used to determine what appears on-screen (S...
MythUIButtonList * m_audioDeviceButtonList
MythUICheckBox * m_truehdCheck
MythUIButton * m_nextButton
QVector< AudioOutput::AudioDeviceConfig > * m_outputlist
MythScreenType * m_generalScreen
void Init(void) override
Used after calling Load() to assign data to widgets and other UI initilisation which is prohibited in...
MythUIButton * m_prevButton
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
void SaveBoolSetting(const QString &key, bool newValue)
void SaveSetting(const QString &key, int newValue)
QString GetSetting(const QString &key, const QString &defaultval="")
int GetNumSetting(const QString &key, int defaultval=0)
MythScreenStack * GetMainStack()
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
void LoadInBackground(const QString &message="")
void BuildFocusList(void)
MythUIType * GetFocusWidget(void) const
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
virtual void Close()
QString GetText(const QString &name="") const
List widget, displays list items in a variety of themeable arrangements and can trigger signals when ...
MythUIButtonListItem * GetItemCurrent() const
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
void SetValueByData(const QVariant &data)
void itemSelected(MythUIButtonListItem *item)
A single button widget.
Definition: mythuibutton.h:22
void SetText(const QString &msg)
void Clicked()
A checkbox widget supporting three check states - on,off,half and two conditions - selected and unsel...
void SetCheckState(MythUIStateType::StateType state)
MythUIStateType::StateType GetCheckState() const
void valueChanged()
void SetHelpText(const QString &text)
Definition: mythuitype.h:177
void Hide(void)
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:138
void Show(void)
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
@ AC3
Definition: element.h:84
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_)
Definition: mythlogging.h:39
MythMainWindow * GetMythMainWindow(void)
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
#define output