MythTV  master
audiogeneralsettings.cpp
Go to the documentation of this file.
1 
2 // -*- Mode: c++ -*-
3 
4 // Standard UNIX C headers
5 #include <chrono> // for milliseconds
6 #include <thread> // for sleep_for
7 #include <fcntl.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 
11 // Qt headers
12 #include <QCoreApplication>
13 #include <QDir>
14 #include <QEvent>
15 #include <utility>
16 
17 // MythTV headers
18 #include "mythconfig.h"
19 #include "mythcorecontext.h"
20 #include "mythdbcon.h"
21 #include "audiooutpututil.h"
22 #include "audiogeneralsettings.h"
23 #include "mythdialogbox.h"
24 #include "mythlogging.h"
25 #include "mythmainwindow.h"
26 
27 extern "C" {
28 #include "libavformat/avformat.h"
29 }
30 
32  HostComboBoxSetting("AudioOutputDevice", true), m_parent(parent)
33 {
34  setLabel(tr("Audio output device"));
35 #ifdef USING_ALSA
36  QString dflt = "ALSA:default";
37 #elif USING_PULSEOUTPUT
38  QString dflt = "PulseAudio:default";
39 #elif CONFIG_DARWIN
40  QString dflt = "CoreAudio:";
41 #elif _WIN32
42  QString dflt = "Windows:";
43 #elif ANDROID
44  QString dflt = "OpenSLES:";
45 #else
46  QString dflt = "NULL";
47 #endif
48  QString current = gCoreContext->GetSetting(QString("AudioOutputDevice"),
49  dflt);
51 
52  connect(this, SIGNAL(valueChanged(StandardSetting *)),
53  this, SLOT(AudioDescriptionHelp(StandardSetting *)));
54 }
55 
57 {
58  AudioRescan();
60 }
61 
63 {
65  AudioOutput::ADCVect::const_iterator it;
66 
67  if (vect.empty())
68  return;
69 
70  QString value = getValue();
72 
73  // Adding the current value first avoids marking the setting as changed
74  addSelection(value, value, true);
75  for (it = vect.begin(); it != vect.end(); ++it)
76  {
77  if (value != it->m_name)
78  addSelection(it->m_name, it->m_name);
79  }
80 }
81 
83 {
84  QString desc = m_parent->AudioDeviceMap().value(setting->getValue()).m_desc;
85  setHelpText(desc);
86 }
87 
89  GroupSetting *groupSetting)
90  : StandardSettingDialog(parent, name, groupSetting)
91 {
92 }
93 
95 {
96  SetBusyPopupMessage(tr("Scanning for available audio devices"));
98 }
99 
101 {
103 
104  AudioConfigSettings *settings =
105  static_cast<AudioConfigSettings*>(GetGroupSettings());
106  settings->CheckConfiguration();
107 }
108 
110 {
111  setLabel(tr("Audio System"));
112 
114  // Rescan button
115 
116  ButtonStandardSetting *rescan = new ButtonStandardSetting("rescan");
117  rescan->setLabel(tr("Rescan"));
118  rescan->setHelpText(tr("Rescan for available audio devices. "
119  "Current entry will be checked and "
120  "capability entries populated."));
121  addChild(rescan);
122  connect(rescan, SIGNAL(clicked()), SLOT(AudioRescan()));
123 
124  // digital settings
126  m_triggerDigital->setLabel(tr("Digital Audio Capabilities"));
133 
138 
139  //Advanced Settings
140  GroupSetting * advancedSettings = new GroupSetting();
141  advancedSettings->setLabel(tr("Advanced Audio Settings"));
142  advancedSettings->setHelpText(tr("Enable extra audio settings. Under most "
143  "usage all options should be left alone"));
144  addChild(advancedSettings);
146  advancedSettings->addChild(m_PassThroughOverride);
148  advancedSettings->addChild(m_PassThroughDeviceOverride);
150  connect(m_PassThroughOverride, SIGNAL(valueChanged(bool)),
152 
153  StandardSetting *srcqualityoverride = SRCQualityOverride();
154  srcqualityoverride->addTargetedChild("1", SRCQuality());
155  addChild(srcqualityoverride);
156 
157  advancedSettings->addChild(Audio48kOverride());
158 #if USING_ALSA
159  advancedSettings->addChild(SPDIFRateOverride());
160 #endif
161 
162  advancedSettings->addChild(HBRPassthrough());
163 
164  advancedSettings->addChild(m_MPCM = MPCM());
165 
166  addChild(m_audioTest = new AudioTest());
167 
168  // Set slots
169  connect(m_MaxAudioChannels, SIGNAL(valueChanged(StandardSetting *)),
170  this, SLOT(UpdateVisibility(StandardSetting *)));
171  connect(m_OutputDevice, SIGNAL(valueChanged(StandardSetting *)),
172  this, SLOT(UpdateCapabilities()));
173  connect(m_AC3PassThrough, SIGNAL(valueChanged(StandardSetting *)),
174  this, SLOT(UpdateCapabilitiesAC3()));
175 
176  connect(m_DTSPassThrough, SIGNAL(valueChanged(StandardSetting *)),
177  this, SLOT(UpdateCapabilities()));
178  connect(m_EAC3PassThrough, SIGNAL(valueChanged(StandardSetting *)),
179  this, SLOT(UpdateCapabilities()));
181  this, SLOT(UpdateCapabilities()));
182  connect(m_DTSHDPassThrough, SIGNAL(valueChanged(StandardSetting *)),
183  this, SLOT(UpdateCapabilities()));
184  //Slot for audio test
185  connect(m_OutputDevice, SIGNAL(valueChanged(StandardSetting *)),
186  this, SLOT(UpdateAudioTest()));
187  connect(m_MaxAudioChannels, SIGNAL(valueChanged(StandardSetting *)),
188  this, SLOT(UpdateAudioTest()));
189 }
190 
192 {
193  QString name = m_OutputDevice->getValue();
196  if (adc)
197  {
198  if (adc->m_settings.IsInvalid())
199  {
200  QString msg = tr("%1 is invalid or not useable.").arg(name);
201 
202  ShowOkPopup(msg);
203 
204  LOG(VB_GENERAL, LOG_ERR, QString("Audio device %1 isn't usable")
205  .arg(name));
206  }
207  delete adc;
208  }
209 
210  if (!CheckPassthrough())
211  {
212  QString pt_name = m_PassThroughDeviceOverride->getValue();
213  QString pt_msg = tr("Passthrough device is invalid or not useable. Check "
214  "configuration in Advanced Settings:") +
215  pt_name;
216 
217  ShowOkPopup(pt_msg);
218 
219  LOG(VB_GENERAL, LOG_ERR, QString("Audio device %1 isn't usable")
220  .arg(pt_name));
221  }
222 }
223 
225 {
227  AudioRescan();
228  // If this is the initial setup where there was nothing on the DB,
229  // set changed so that user can save.
230  if (gCoreContext->GetSetting(QString("AudioOutputDevice"),"").isEmpty())
231  setChanged(true);
232 }
233 
235 {
236  if (!slotlock.tryLock())
237  return;
238 
240  AudioOutput::ADCVect::const_iterator it;
241 
242  audiodevs.clear();
243  for (it = list->begin(); it != list->end(); ++it)
244  audiodevs.insert(it->m_name, *it);
245 
246  devices = *list;
247  delete list;
248 
249  QString name = m_OutputDevice->getValue();
250  if (!audiodevs.contains(name))
251  {
252  // Scan for possible custom entry that isn't in the list
255  audiodevs.insert(name, *adc);
256  devices.append(*adc);
257  delete adc;
258  }
260  slotlock.unlock();
262 }
263 
265 {
267  return;
268 
269  int cur_speakers = m_MaxAudioChannels->getValue().toInt();
270  m_AudioUpmix->setEnabled(cur_speakers > 2);
271  m_AudioUpmixType->setEnabled(cur_speakers > 2);
272 }
273 
275  bool restore, bool AC3)
276 {
277  int max_speakers = 8;
278  int realmax_speakers = 8;
279 
280  bool invalid = false;
281  QString out;
282 
283  if (m_OutputDevice)
284  out = m_OutputDevice->getValue();
285 
286  if (!out.isEmpty())
287  {
288  restore = out != m_lastAudioDevice;
289  m_lastAudioDevice = out;
290  }
291 
292  AudioOutputSettings settings, settingsdigital;
293 
294  // Test if everything is set yet
298  return settings;
299 
300  if (!slotlock.tryLock()) // Doing a rescan of channels
301  return settings;
302 
303  bool bAC3 = true;
304  //bool bDTS = true;
305  bool bLPCM = true;
306  bool bEAC3 = true;
307  bool bTRUEHD = true;
308  bool bDTSHD = true;
309 
310  if (!audiodevs.contains(out))
311  {
312  LOG(VB_AUDIO, LOG_ERR, QString("Update not found (%1)").arg(out));
313  invalid = true;
314  }
315  else
316  {
317  bool bForceDigital = m_PassThroughOverride->boolValue();
318 
319  settings = audiodevs.value(out).m_settings;
320  settingsdigital = bForceDigital ?
322  .m_settings : settings;
323 
324  realmax_speakers = max_speakers = settings.BestSupportedChannels();
325 
326  bAC3 = settingsdigital.canFeature(FEATURE_AC3) &&
328  //bDTS = settingsdigital.canFeature(FEATURE_DTS) &&
329  // m_DTSPassThrough->boolValue();
330  bLPCM = settings.canFeature(FEATURE_LPCM) &&
331  !gCoreContext->GetBoolSetting("StereoPCM", false);
332  bEAC3 = settingsdigital.canFeature(FEATURE_EAC3) &&
333  !gCoreContext->GetBoolSetting("Audio48kOverride", false);
334  bTRUEHD = settingsdigital.canFeature(FEATURE_TRUEHD) &&
335  !gCoreContext->GetBoolSetting("Audio48kOverride", false) &&
336  gCoreContext->GetBoolSetting("HBRPassthru", true);
337  bDTSHD = settingsdigital.canFeature(FEATURE_DTSHD) &&
338  !gCoreContext->GetBoolSetting("Audio48kOverride", false);
339 
340  if (max_speakers > 2 && !bLPCM)
341  max_speakers = 2;
342  if (max_speakers == 2 && bAC3)
343  {
344  max_speakers = 6;
345  if (AC3)
346  {
347  restore = true;
348  }
349  }
350  }
351 
352  m_triggerDigital->setEnabled(invalid || settingsdigital.canFeature(
358 
359  int cur_speakers = m_MaxAudioChannels->getValue().toInt();
360  if (cur_speakers > m_maxspeakers)
361  {
363  }
364  if (restore)
365  {
366  cur_speakers = m_maxspeakers;
367  }
368 
369  if (cur_speakers > max_speakers)
370  {
371  LOG(VB_AUDIO, LOG_INFO, QString("Reset device %1").arg(out));
372  cur_speakers = max_speakers;
373  }
374 
375  // Remove everything and re-add available channels
376  bool chansChanged = m_MaxAudioChannels->haveChanged();
378  for (int i = 1; i <= max_speakers; i++)
379  {
380  if (invalid || settings.IsSupportedChannels(i) ||
381  settingsdigital.IsSupportedChannels(i))
382  {
383  QString txt;
384 
385  switch (i)
386  {
387  case 2:
388  txt = QCoreApplication::translate("(Common)", "Stereo");
389  break;
390  case 6:
391  txt = QCoreApplication::translate("(Common)", "5.1");
392  break;
393  case 8:
394  txt = QCoreApplication::translate("(Common)", "7.1");
395  break;
396  default:
397  continue;
398  }
399  m_MaxAudioChannels->addSelection(txt, QString::number(i),
400  i == cur_speakers);
401  }
402  }
403  m_MaxAudioChannels->setChanged(chansChanged);
404 
405  setMPCMEnabled(settings.canPassthrough() >= 0);
406 
407  // Return values is used by audio test
408  // where we mainly are interested by the number of channels
409  // if we support AC3 and/or LPCM
410  settings.SetBestSupportedChannels(cur_speakers);
411  settings.setFeature(bAC3, FEATURE_AC3);
412  settings.setFeature(bLPCM && realmax_speakers > 2, FEATURE_LPCM);
413 
414  slotlock.unlock();
415  return settings;
416 }
417 
419 {
420  return UpdateCapabilities(false, true);
421 }
422 
423 
425 {
426  QString name = "MaxChannels";
427 
428  HostComboBoxSetting *gc = new HostComboBoxSetting(name, false);
429 
430  gc->setLabel(tr("Speaker configuration"));
431 
432  gc->addSelection(QCoreApplication::translate("(Common)", "Stereo"),
433  "2", true); // default
434 
435  gc->setHelpText(tr("Select the maximum number of audio "
436  "channels supported by your receiver "
437  "and speakers."));
438  return gc;
439 }
440 
442 {
443  HostCheckBoxSetting *gc = new HostCheckBoxSetting("AudioDefaultUpmix");
444 
445  gc->setLabel(tr("Upconvert stereo to 5.1 surround"));
446 
447  gc->setValue(true);
448 
449  gc->setHelpText(tr("If enabled, MythTV will upconvert stereo "
450  "to 5.1 audio. You can enable or disable "
451  "the upconversion during playback at any time."));
452  return gc;
453 }
454 
456 {
457  HostComboBoxSetting *gc = new HostComboBoxSetting("AudioUpmixType", false);
458 
459  gc->setLabel(tr("Upmix Quality"));
460 
461  gc->addSelection(tr("Passive"), "0");
462  gc->addSelection(tr("Hall", "Upmix Quality"), "3");
463  gc->addSelection(tr("Good", "Upmix Quality"), "1");
464  gc->addSelection(tr("Best", "Upmix Quality"), "2", true); // default
465 
466  gc->setHelpText(tr("Set the audio surround-upconversion quality."));
467 
468  return gc;
469 }
470 
472 {
473  HostCheckBoxSetting *gc = new HostCheckBoxSetting("AC3PassThru");
474 
475  gc->setLabel(tr("Dolby Digital"));
476 
477  gc->setValue(false);
478 
479  gc->setHelpText(tr("Enable if your amplifier or sound decoder "
480  "supports AC-3/Dolby Digital. You must use a digital "
481  "connection. Uncheck if using an analog connection."));
482  return gc;
483 }
484 
486 {
487  HostCheckBoxSetting *gc = new HostCheckBoxSetting("DTSPassThru");
488 
489  gc->setLabel(tr("DTS"));
490 
491  gc->setValue(false);
492 
493  gc->setHelpText(tr("Enable if your amplifier or sound decoder supports "
494  "DTS. You must use a digital connection. Uncheck "
495  "if using an analog connection"));
496  return gc;
497 }
498 
500 {
501  HostCheckBoxSetting *gc = new HostCheckBoxSetting("EAC3PassThru");
502 
503  gc->setLabel(tr("E-AC-3"));
504 
505  gc->setValue(false);
506 
507  gc->setHelpText(tr("Enable if your amplifier or sound decoder supports "
508  "E-AC-3 (DD+). You must use a HDMI connection."));
509  return gc;
510 }
511 
513 {
514  HostCheckBoxSetting *gc = new HostCheckBoxSetting("TrueHDPassThru");
515 
516  gc->setLabel(tr("TrueHD"));
517 
518  gc->setValue(false);
519 
520  gc->setHelpText(tr("Enable if your amplifier or sound decoder supports "
521  "Dolby TrueHD. You must use a HDMI connection."));
522  return gc;
523 }
524 
526 {
527  HostCheckBoxSetting *gc = new HostCheckBoxSetting("DTSHDPassThru");
528 
529  gc->setLabel(tr("DTS-HD"));
530 
531  gc->setValue(false);
532 
533  gc->setHelpText(tr("Enable if your amplifier or sound decoder supports "
534  "DTS-HD. You must use a HDMI connection."));
535  return gc;
536 }
537 
539 {
540  bool ok = true;
541 
543  {
547  if (adc->m_settings.IsInvalid())
548  {
549  LOG(VB_GENERAL, LOG_ERR,
550  QString("Passthru device %1 isn't usable "
551  "Check audio configuration").arg(name));
552  ok = false;
553  }
554  // add it to list of known devices
555  audiodevs.insert(name, *adc);
556  devices.append(*adc);
557  delete adc;
558  }
559  return ok;
560 }
561 
562 #ifdef USING_OSS
564  const QDir& dir, bool absPath = true)
565 
566 {
567  QFileInfoList il = dir.entryInfoList();
568 
569  for (QFileInfoList::Iterator it = il.begin();
570  it != il.end();
571  ++it )
572  {
573  QFileInfo &fi = *it;
574 
575  if (absPath)
576  comboBox->addSelection( fi.absoluteFilePath() );
577  else
578  comboBox->addSelection( fi.fileName() );
579  }
580 }
581 #endif
582 
584 {
585  AudioOutputSettings settings = UpdateCapabilities(false);
586  QString out = m_OutputDevice->getValue();
587  QString passthrough =
590  int channels = m_MaxAudioChannels->getValue().toInt();
591 
592  m_audioTest->UpdateCapabilities(out, passthrough, channels, settings);
593 }
594 
596  QString main, QString passthrough,
597  int channels,
598  AudioOutputSettings &settings,
599  bool hd) :
600  MThread("AudioTest"),
601  m_parent(parent), m_channels(channels), m_device(std::move(main)),
602  m_passthrough(std::move(passthrough)), m_hd(hd)
603 {
604  m_format = hd ? settings.BestSupportedFormat() : FORMAT_S16;
605  m_samplerate = hd ? settings.BestSupportedRate() : 48000;
606 
609  AV_CODEC_ID_NONE, m_samplerate,
611  true, false, 0, &settings);
612  if (result().isEmpty())
613  {
614  m_audioOutput->Pause(true);
615  }
616 }
617 
618 QEvent::Type ChannelChangedEvent::kEventType =
619  (QEvent::Type) QEvent::registerEventType();
620 
622 {
623  cancel();
624  wait();
625  delete m_audioOutput;
626 }
627 
629 {
630  m_interrupted = true;
631 }
632 
634 {
635  QString errMsg;
636  if (!m_audioOutput)
637  errMsg = tr("Unable to create AudioOutput.");
638  else
639  errMsg = m_audioOutput->GetError();
640  return errMsg;
641 }
642 
644 {
645  m_channel = channel;
646 }
647 
649 {
650  RunProlog();
651  m_interrupted = false;
652  int smptelayout[7][8] = {
653  { 0, 1, 1 }, //stereo
654  { }, //not used
655  { }, //not used
656  { 0, 2, 1, 4, 3 }, //5.0
657  { 0, 2, 1, 5, 4, 3 }, //5.1
658  { 0, 2, 1, 6, 4, 5, 3 }, //6.1
659  { 0, 2, 1, 7, 5, 4, 6, 3 }, //7.1
660  };
661 
662  if (m_audioOutput)
663  {
664  char *frames_in = new char[m_channels * 1024 * sizeof(int32_t) + 15];
665  char *frames = (char *)(((long)frames_in + 15) & ~0xf);
666 
667  m_audioOutput->Pause(false);
668 
669  int begin = 0;
670  int end = m_channels;
671  if (m_channel >= 0)
672  {
673  begin = m_channel;
674  end = m_channel + 1;
675  }
676  while (!m_interrupted)
677  {
678  for (int i = begin; i < end && !m_interrupted; i++)
679  {
680  int current = smptelayout[m_channels - 2][i];
681 
682  if (m_parent)
683  {
684  QString channel;
685 
686  switch(current)
687  {
688  case 0:
689  channel = "frontleft";
690  break;
691  case 1:
692  channel = "frontright";
693  break;
694  case 2:
695  channel = "center";
696  break;
697  case 3:
698  channel = "lfe";
699  break;
700  case 4:
701  if (m_channels == 6)
702  channel = "surroundleft";
703  else if (m_channels == 7)
704  channel = "rearright";
705  else
706  channel = "rearleft";
707  break;
708  case 5:
709  if (m_channels == 6)
710  channel = "surroundright";
711  else if (m_channels == 7)
712  channel = "surroundleft";
713  else
714  channel = "rearright";
715  break;
716  case 6:
717  if (m_channels == 7)
718  channel = "surroundright";
719  else
720  channel = "surroundleft";
721  break;
722  case 7:
723  channel = "surroundright";
724  break;
725  }
726  QCoreApplication::postEvent(
727  m_parent, new ChannelChangedEvent(channel,
728  m_channel < 0));
729  LOG(VB_AUDIO, LOG_INFO, QString("AudioTest: %1 (%2->%3)")
730  .arg(channel).arg(i).arg(current));
731  }
732 
733  // play sample sound for about 3s
734  int top = m_samplerate / 1000 * 3;
735  for (int j = 0; j < top && !m_interrupted; j++)
736  {
738  current, 1000,
739  m_hd ? 32 : 16);
740  if (!m_audioOutput->AddFrames(frames, 1000 , -1))
741  {
742  LOG(VB_AUDIO, LOG_ERR, "AddData() Audio buffer "
743  "overflow, audio data lost!");
744  }
745  std::this_thread::sleep_for(std::chrono::milliseconds(m_audioOutput->LengthLastData()));
746  }
747  m_audioOutput->Drain();
748  m_audioOutput->Pause(true);
749  std::this_thread::sleep_for(std::chrono::milliseconds(500)); // .5s pause
750  m_audioOutput->Pause(false);
751  }
752  if (m_channel >= 0)
753  break;
754  }
755  m_audioOutput->Pause(true);
756 
757  delete[] frames_in;
758  }
759  RunEpilog();
760 }
761 
763 {
764  int channels = 2;
765 
766  m_channels = gCoreContext->GetNumSetting("TestingChannels", channels);
767  setLabel(tr("Audio Configuration Testing"));
768  setHelpText(tr("Will play a test pattern on all configured "
769  "speakers"));
770 
772  m_frontleft->setLabel(tr("Front Left"));
773  m_frontleft->setHelpText(tr("Start front left channel test"));
775  connect(m_frontleft,
776  SIGNAL(clicked()), this, SLOT(toggle()));
777 
778  m_frontright = new ButtonStandardSetting(m_channels == 2 ? "1" : "2");
779  m_frontright->setLabel(tr("Front Right"));
780  m_frontright->setHelpText(tr("Start front right channel test"));
782  connect(m_frontright,
783  SIGNAL(clicked()), this, SLOT(toggle()));
784 
786  m_rearleft->setLabel(tr("Rear Left"));
787  m_rearleft->setHelpText(tr("Start rear left channel test"));
789  connect(m_rearleft,
790  SIGNAL(clicked()), this, SLOT(toggle()));
791 
793  m_rearright->setLabel(tr("Rear Right"));
794  m_rearright->setHelpText(tr("Start rear right channel test"));
796  connect(m_rearright,
797  SIGNAL(clicked()), this, SLOT(toggle()));
798 
799  m_lfe = new ButtonStandardSetting(m_channels == 6 ? "5" :
800  m_channels == 7 ? "6" : "7");
801  m_lfe->setLabel(tr("LFE"));
802  m_lfe->setHelpText(tr("Start LFE channel test"));
803  addChild(m_lfe);
804  connect(m_lfe,
805  SIGNAL(clicked()), this, SLOT(toggle()));
806 
808  m_channels == 7 ? "5" : "6");
809  m_surroundleft->setLabel(tr("Surround Left"));
810  m_surroundleft->setHelpText(tr("Start surround left channel test"));
812  connect(m_surroundleft,
813  SIGNAL(clicked()), this, SLOT(toggle()));
814 
816  m_surroundright->setLabel(tr("Surround Right"));
817  m_surroundright->setHelpText(tr("Start surround right channel test"));
819  connect(m_surroundright,
820  SIGNAL(clicked()), this, SLOT(toggle()));
821 
822  m_center = new ButtonStandardSetting("1");
823  m_center->setLabel(tr("Center"));
824  m_center->setHelpText(tr("Start center channel test"));
826  connect(m_center,
827  SIGNAL(clicked()), this, SLOT(toggle()));
828 
829  m_startButton = new ButtonStandardSetting("start");
830  m_startButton->setLabel(tr("Test All"));
831  m_startButton->setHelpText(tr("Start all channels test"));
833  connect(m_startButton, SIGNAL(clicked()), this, SLOT(toggle()));
834 
836  m_hd->setLabel(tr("Use Highest Quality Mode"));
837  m_hd->setHelpText(tr("Use the highest audio quality settings "
838  "supported by your audio card. This will be "
839  "a good place to start troubleshooting "
840  "potential errors"));
841  addChild(m_hd);
842  connect(m_hd, SIGNAL(valueChanged(QString)), this, SLOT(togglequality()));
843 }
844 
846 {
847  if (m_at)
848  {
849  m_at->cancel();
850  m_at->wait();
851  delete m_at;
852  }
853 }
854 
855 
857  const QString &passthrough,
858  int channels,
859  const AudioOutputSettings &settings)
860 {
861  m_main = main;
862  m_passthrough = passthrough;
863  m_channels = channels;
864  m_settings = settings;
867  m_lfe->setEnabled(m_channels >= 6);
871 }
872 
874 {
875  if (this->sender() == m_startButton)
876  {
877  if (m_at && m_at->isRunning())
878  cancelTest();
879  else
880  {
881  prepareTest();
882  m_at->setChannel(-1);
883  m_at->start();
884  m_startButton->setLabel(QCoreApplication::translate("(Common)",
885  "Stop"));
886  }
887  return;
888  }
889  if (m_at && m_at->isRunning())
890  {
891  m_at->cancel();
892  m_at->wait();
893  }
894 
895  prepareTest();
896 
897  int channel = 1;
898 
899  if (this->sender() == m_frontleft)
900  channel = 0;
901  else if (this->sender() == m_frontright)
902  channel = (m_channels == 2) ? 1 : 2;
903  else if (this->sender() == m_rearleft)
904  channel = 5;
905  else if (this->sender() == m_rearright)
906  channel = 4;
907  else if (this->sender() == m_lfe)
908  channel = ((m_channels == 6) ? 5 :((m_channels == 7) ? 6 : 7));
909  else if (this->sender() == m_surroundleft)
910  channel = ((m_channels == 6) ? 4 : ((m_channels == 7) ? 5 : 6));
911  else if (this->sender() == m_surroundright)
912  channel = 3;
913  else if (this->sender() == m_center)
914  channel = 1;
915 
916  m_at->setChannel(channel);
917 
918  m_at->start();
919 }
920 
922 {
923  cancelTest();
924  m_quality = m_hd->boolValue();
925 }
926 
928 {
929  if (m_at && m_at->isRunning())
930  {
931  m_at->cancel();
932  m_startButton->setLabel(tr("Test All"));
933  }
934 }
935 
937 {
938  cancelTest();
939  if (m_at)
940  {
941  m_at->cancel();
942  m_at->wait();
943  delete m_at;
944  }
945 
948  if (!m_at->result().isEmpty())
949  {
950  QString msg = tr("Audio device is invalid or not useable.");
952 
953  MythConfirmationDialog *mcd = new MythConfirmationDialog(mainStack,
954  msg, false);
955 
956  if (mcd->Create())
957  mainStack->AddScreen(mcd);
958  else
959  delete mcd;
960  }
961 }
962 
963 bool AudioTest::event(QEvent *event)
964 {
965  if (event->type() != ChannelChangedEvent::kEventType)
966  return QObject::event(event); //not handled
967 
969  QString channel = cce->m_channel;
970 
971  if (!cce->m_fulltest)
972  return false;
973 
974  bool fl, fr, c, lfe, sl, sr, rl, rr;
975  fl = fr = c = lfe = sl = sr = rl = rr = false;
976 
977  if (channel == "frontleft")
978  {
979  fl = true;
980  }
981  else if (channel == "frontright")
982  {
983  fr = true;
984  }
985  else if (channel == "center")
986  {
987  c = true;
988  }
989  else if (channel == "lfe")
990  {
991  lfe = true;
992  }
993  else if (channel == "surroundleft")
994  {
995  sl = true;
996  }
997  else if (channel == "surroundright")
998  {
999  sr = true;
1000  }
1001  else if (channel == "rearleft")
1002  {
1003  rl = true;
1004  }
1005  else if (channel == "rearright")
1006  {
1007  rr = true;
1008  }
1009  if (m_frontleft)
1010  m_frontleft->setEnabled(fl);
1011  if (m_frontright)
1012  m_frontright->setEnabled(fr);
1013  if (m_center)
1014  m_center->setEnabled(c);
1015  if (m_surroundleft)
1017  if (m_surroundright)
1019  if (m_rearleft)
1020  m_rearleft->setEnabled(rl);
1021  if (m_rearright)
1022  m_rearright->setEnabled(rr);
1023  if (m_lfe)
1024  m_lfe->setEnabled(lfe);
1025  return false;
1026 }
1027 
1028 
1030 {
1031  HostCheckBoxSetting *gc = new HostCheckBoxSetting("MythControlsVolume");
1032 
1033  gc->setLabel(tr("Use internal volume controls"));
1034 
1035  gc->setValue(true);
1036 
1037  gc->setHelpText(tr("If enabled, MythTV will control the PCM and "
1038  "master mixer volume. Disable this option if you "
1039  "prefer to control the volume externally (for "
1040  "example, using your amplifier) or if you use an "
1041  "external mixer program."));
1042 
1043  gc->addTargetedChild("1", MixerDevice());
1044  gc->addTargetedChild("1", MixerControl());
1045  gc->addTargetedChild("1", MixerVolume());
1046  gc->addTargetedChild("1", PCMVolume());
1047  return gc;
1048 }
1049 
1051 {
1052  HostComboBoxSetting *gc = new HostComboBoxSetting("MixerDevice", true);
1053  gc->setLabel(tr("Mixer device"));
1054 
1055 #ifdef USING_OSS
1056  QDir dev("/dev", "mixer*", QDir::Name, QDir::System);
1057  fillSelectionsFromDir(gc, dev);
1058 
1059  dev.setPath("/dev/sound");
1060  if (dev.exists())
1061  {
1062  fillSelectionsFromDir(gc, dev);
1063  }
1064 #endif
1065 #ifdef USING_ALSA
1066  gc->addSelection("ALSA:default", "ALSA:default");
1067 #endif
1068 #ifdef _WIN32
1069  gc->addSelection("DirectX:", "DirectX:");
1070  gc->addSelection("Windows:", "Windows:");
1071 #endif
1072 #ifdef ANDROID
1073  gc->addSelection("OpenSLES:", "OpenSLES:");
1074 #endif
1075 #ifdef USING_OPENMAX
1076  gc->addSelection("OpenMAX:", "OpenMAX:");
1077 #endif
1078 #if !defined(_WIN32)
1079  gc->addSelection(tr("software"), "software");
1080 #endif
1081 
1082  gc->setHelpText(tr("Setting the mixer device to \"%1\" lets MythTV control "
1083  "the volume of all audio at the expense of a slight "
1084  "quality loss.")
1085  .arg(tr("software")));
1086 
1087  return gc;
1088 }
1089 
1091  {QT_TR_NOOP("PCM"),
1092  QT_TR_NOOP("Master")};
1093 
1095 {
1096  HostComboBoxSetting *gc = new HostComboBoxSetting("MixerControl", true);
1097 
1098  gc->setLabel(tr("Mixer controls"));
1099 
1100  for (size_t i = 0; i < sizeof(MixerControlControls) / sizeof(char*); ++i)
1101  {
1104  }
1105 
1106  gc->setHelpText(tr("Changing the volume adjusts the selected mixer."));
1107 
1108  return gc;
1109 }
1110 
1112 {
1113  HostSpinBoxSetting *gs = new HostSpinBoxSetting("MasterMixerVolume", 0, 100,
1114  1);
1115 
1116  gs->setLabel(tr("Master mixer volume"));
1117 
1118  gs->setValue(70);
1119 
1120  gs->setHelpText(tr("Initial volume for the Master mixer. This affects "
1121  "all sound created by the audio device. Note: Do not "
1122  "set this too low."));
1123  return gs;
1124 }
1125 
1127 {
1128  HostSpinBoxSetting *gs = new HostSpinBoxSetting("PCMMixerVolume", 0, 100,
1129  1);
1130 
1131  gs->setLabel(tr("PCM mixer volume"));
1132 
1133  gs->setValue(70);
1134 
1135  gs->setHelpText(tr("Initial volume for PCM output. Using the volume "
1136  "keys in MythTV will adjust this parameter."));
1137  return gs;
1138 }
1139 
1141 {
1142  HostCheckBoxSetting *gc = new HostCheckBoxSetting("StereoPCM");
1143 
1144  gc->setLabel(tr("Stereo PCM Only"));
1145 
1146  gc->setValue(false);
1147 
1148  gc->setHelpText(tr("Enable if your amplifier or sound decoder only "
1149  "supports 2 channel PCM (typically an old HDMI 1.0 "
1150  "device). Multichannel audio will be re-encoded to "
1151  "AC-3 when required"));
1152  return gc;
1153 }
1154 
1156 {
1157  HostCheckBoxSetting *gc = new HostCheckBoxSetting("SRCQualityOverride");
1158 
1159  gc->setLabel(tr("Override SRC quality"));
1160 
1161  gc->setValue(false);
1162 
1163  gc->setHelpText(tr("Enable to override audio sample rate "
1164  "conversion quality."));
1165  return gc;
1166 }
1167 
1169 {
1170  HostComboBoxSetting *gc = new HostComboBoxSetting("SRCQuality", false);
1171 
1172  gc->setLabel(tr("Sample rate conversion"));
1173 
1174  gc->addSelection(tr("Disabled", "Sample rate conversion"), "-1");
1175  gc->addSelection(tr("Fastest", "Sample rate conversion"), "0");
1176  gc->addSelection(tr("Good", "Sample rate conversion"), "1", true); // default
1177  gc->addSelection(tr("Best", "Sample rate conversion"), "2");
1178 
1179  gc->setHelpText(tr("Set the quality of audio sample-rate "
1180  "conversion. \"%1\" (default) provides the best "
1181  "compromise between CPU usage and quality. \"%2\" "
1182  "lets the audio device handle sample-rate conversion.")
1183  .arg(tr("Good", "Sample rate conversion"))
1184  .arg(tr("Disabled", "Sample rate conversion")));
1185 
1186  return gc;
1187 }
1188 
1190 {
1191  HostCheckBoxSetting *gc = new HostCheckBoxSetting("Audio48kOverride");
1192 
1193  gc->setLabel(tr("Force audio device output to 48kHz"));
1194  gc->setValue(false);
1195 
1196  gc->setHelpText(tr("Force audio sample rate to 48kHz. Some audio devices "
1197  "will report various rates, but they ultimately "
1198  "crash."));
1199  return gc;
1200 }
1201 
1203 {
1204  HostCheckBoxSetting *gc = new HostCheckBoxSetting("PassThruDeviceOverride");
1205 
1206  gc->setLabel(tr("Separate digital output device"));
1207 
1208  gc->setValue(false);
1209 
1210  gc->setHelpText(tr("Use a distinct digital output device from default. "
1211  "(default is not checked)"));
1212  return gc;
1213 }
1214 
1216 {
1217  HostComboBoxSetting *gc = new HostComboBoxSetting("PassThruOutputDevice",
1218  true);
1219 
1220  gc->setLabel(tr("Digital output device"));
1221  //TODO Is default not equivalent to PassThroughOverride off? if so
1222  //PassThruDeviceOverridedsetting could be removed
1223  gc->addSelection(QCoreApplication::translate("(Common)", "Default"),
1224  "Default");
1225 #ifdef _WIN32
1226  gc->addSelection("DirectX:Primary Sound Driver");
1227 #else
1228  gc->addSelection("ALSA:iec958:{ AES0 0x02 }",
1229  "ALSA:iec958:{ AES0 0x02 }");
1230  gc->addSelection("ALSA:hdmi", "ALSA:hdmi");
1231  gc->addSelection("ALSA:plughw:0,3", "ALSA:plughw:0,3");
1232 #endif
1233 
1234  gc->setHelpText(tr("Audio output device to use for digital audio. This "
1235  "value is currently only used with ALSA and DirectX "
1236  "sound output."));
1237  return gc;
1238 }
1239 
1241 {
1242  HostCheckBoxSetting *gc = new HostCheckBoxSetting("SPDIFRateOverride");
1243 
1244  gc->setLabel(tr("SPDIF 48kHz rate override"));
1245 
1246  gc->setValue(false);
1247 
1248  gc->setHelpText(tr("ALSA only. By default, let ALSA determine the "
1249  "passthrough sampling rate. If checked set the sampling "
1250  "rate to 48kHz for passthrough. (default is not "
1251  "checked)"));
1252  return gc;
1253 }
1254 
1256 {
1257  HostCheckBoxSetting *gc = new HostCheckBoxSetting("HBRPassthru");
1258 
1259  gc->setLabel(tr("HBR passthrough support"));
1260 
1261  gc->setValue(true);
1262 
1263  gc->setHelpText(tr("HBR support is required for TrueHD and DTS-HD "
1264  "passthrough. If unchecked, Myth will limit the "
1265  "passthrough bitrate to 6.144Mbit/s. This will "
1266  "disable True-HD passthrough, however will allow "
1267  "DTS-HD content to be sent as DTS-HD Hi-Res. (default "
1268  "is checked)"));
1269  return gc;
1270 }
1271 
1273 {
1274  m_MPCM->setEnabled(flag);
1275 }
1276 // vim:set sw=4 ts=4 expandtab:
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:215
static void fillSelectionsFromDir(HostComboBoxSetting *comboBox, const QDir &dir, bool absPath=true)
void start(QThread::Priority=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:294
HostComboBoxSetting * m_PassThroughDeviceOverride
ButtonStandardSetting * m_rearright
HostCheckBoxSetting * HBRPassthrough()
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:46
bool event(QEvent *event) override
HostComboBoxSetting * PassThroughOutputDevice()
AudioOutput * m_audioOutput
Dialog asking for user confirmation.
void UpdateVisibility(StandardSetting *)
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:91
bool IsInvalid()
return true if class instance is marked invalid.
void edit(MythScreenType *screen) override
bool IsSupportedChannels(int channels)
MythConfirmationDialog * ShowOkPopup(const QString &message, QObject *parent, const char *slot, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
AudioOutput::ADCVect devices
HostCheckBoxSetting * m_TrueHDPassThrough
TransMythUICheckBoxSetting * m_hd
QVector< AudioDeviceConfig > ADCVect
Definition: audiooutput.h:45
AudioConfigSettings * m_parent
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)
Definition: audiooutput.cpp:61
HostCheckBoxSetting * SRCQualityOverride()
virtual int64_t LengthLastData(void) const
Definition: audiooutput.h:126
virtual void Drain(void)=0
virtual void Load(void)
Definition: element.h:83
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:311
void addSelection(const QString &label, QString value=QString(), bool select=false)
virtual void setHelpText(const QString &str)
void SetBestSupportedChannels(int channels)
Force set the greatest number of channels supported by the audio device.
void setChanged(bool changed)
HostCheckBoxSetting * m_AudioUpmix
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
HostComboBoxSetting * m_AudioUpmixType
MythScreenStack * GetMainStack()
void Init(void) override
Used after calling Load() to assign data to widgets and other UI initilisation which is prohibited in...
HostCheckBoxSetting * TrueHDPassThrough()
AudioOutputSettings m_settings
Definition: audiooutput.h:32
AudioTestThread(QObject *parent, QString main, QString passthrough, int channels, AudioOutputSettings &settings, bool hd)
HostCheckBoxSetting * MPCM()
HostCheckBoxSetting * m_DTSHDPassThrough
ButtonStandardSetting * m_lfe
virtual QString getValue(void) const
AudioOutputSettings UpdateCapabilitiesAC3(void)
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
AudioDeviceComboBox(AudioConfigSettings *)
AudioDeviceComboBox * m_OutputDevice
HostCheckBoxSetting * PassThroughOverride()
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
AudioFormat BestSupportedFormat()
ButtonStandardSetting * m_startButton
static char * GeneratePinkFrames(char *frames, int channels, int channel, int count, int bits=16)
HostComboBoxSetting * MaxAudioChannels()
virtual void Pause(bool paused)=0
virtual void setLabel(QString str)
HostSpinBoxSetting * PCMVolume()
HostCheckBoxSetting * m_DTSPassThrough
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
QString GetSetting(const QString &key, const QString &defaultval="")
void setFeature(DigitalFeature arg)
set the provided digital feature possible values are:
void setChannel(int channel)
HostComboBoxSetting * MixerDevice()
ButtonStandardSetting * m_frontright
bool haveChanged()
Return true if the setting have changed or any of its children.
bool isRunning(void) const
Definition: mthread.cpp:274
HostComboBoxSetting * MixerControl()
virtual void setEnabled(bool enabled)
bool canFeature(DigitalFeature arg)
return DigitalFeature mask.
HostComboBoxSetting * SRCQuality()
void Load(void) override
Load data which will ultimately be displayed on-screen or used to determine what appears on-screen (S...
void SetBusyPopupMessage(const QString &message)
HostSpinBoxSetting * MixerVolume()
const char * name
Definition: ParseText.cpp:328
static AudioDeviceConfig * GetAudioDeviceConfig(QString &name, QString &desc, bool willsuspendpa=false)
AudioTestThread * m_at
HostComboBoxSetting * AudioUpmixType()
virtual void addChild(StandardSetting *child)
HostCheckBoxSetting * m_AC3PassThrough
MythMainWindow * GetMythMainWindow(void)
HostComboBoxSetting * m_MaxAudioChannels
void Init(void) override
Used after calling Load() to assign data to widgets and other UI initilisation which is prohibited in...
int GetNumSetting(const QString &key, int defaultval=0)
void AudioDescriptionHelp(StandardSetting *setting)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
HostCheckBoxSetting * m_EAC3PassThrough
AudioOutputSettings UpdateCapabilities(bool restore=true, bool AC3=false)
AudioOutputSettings m_settings
bool GetBoolSetting(const QString &key, bool defaultval=false)
bool Create(void) override
HostCheckBoxSetting * SPDIFRateOverride()
HostCheckBoxSetting * DTSPassThrough()
GroupSetting()=default
HostCheckBoxSetting * EAC3PassThrough()
void edit(MythScreenType *screen) override
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:202
ButtonStandardSetting * m_surroundleft
GroupSetting * GetGroupSettings(void) const
HostCheckBoxSetting * AudioUpmix()
const char * frames[3]
Definition: element.c:46
AudioConfigScreen(MythScreenStack *parent, const char *name, GroupSetting *groupSetting)
void setValue(const QString &) override
HostCheckBoxSetting * Audio48kOverride()
AudioOutput::ADCVect & AudioDeviceVect(void)
HostCheckBoxSetting * m_MPCM
HostCheckBoxSetting * DTSHDPassThrough()
Screen in which all other widgets are contained and rendered.
HostCheckBoxSetting * m_PassThroughOverride
ButtonStandardSetting * m_frontleft
ButtonStandardSetting * m_rearleft
static ADCVect * GetOutputList(void)
void togglequality(void)
HostCheckBoxSetting * AC3PassThrough()
void addTargetedChild(const QString &value, StandardSetting *setting)
void Load(void) override
Load data which will ultimately be displayed on-screen or used to determine what appears on-screen (S...
virtual void setValue(const QString &newValue)
ButtonStandardSetting * m_surroundright
HostCheckBoxSetting * MythControlsVolume()
QString GetError(void) const
Definition: audiooutput.h:143
void UpdateCapabilities(const QString &main, const QString &passthrough, int channels, const AudioOutputSettings &settings)
static const char * MixerControlControls[]
ADCMap & AudioDeviceMap(void)
GroupSetting * m_triggerDigital
void valueChanged(const QString &)
ButtonStandardSetting * m_center
virtual bool AddFrames(void *buffer, int frames, int64_t timecode)=0
Add frames to the audiobuffer for playback.