00001
00002
00003
00004
00005 #include <unistd.h>
00006 #include <fcntl.h>
00007 #include <sys/types.h>
00008 #include <sys/stat.h>
00009
00010
00011 #include <QCoreApplication>
00012 #include <QEvent>
00013 #include <QDir>
00014
00015
00016 #include "mythconfig.h"
00017 #include "mythcorecontext.h"
00018 #include "mythdbcon.h"
00019 #include "audiooutpututil.h"
00020 #include "audiogeneralsettings.h"
00021 #include "mythdialogbox.h"
00022 #include "mythlogging.h"
00023
00024 extern "C" {
00025 #include "libavformat/avformat.h"
00026 }
00027
00028
00029 class TriggeredItem : public TriggeredConfigurationGroup
00030 {
00031 public:
00032 TriggeredItem(Setting *checkbox, ConfigurationGroup *group) :
00033 TriggeredConfigurationGroup(false, false, false, false)
00034 {
00035 setTrigger(checkbox);
00036
00037 addTarget("1", group);
00038 addTarget("0", new VerticalConfigurationGroup(true));
00039 }
00040 TriggeredItem(Setting *checkbox, Setting *setting) :
00041 TriggeredConfigurationGroup(false, false, false, false)
00042 {
00043 setTrigger(checkbox);
00044
00045 addTarget("1", setting);
00046 addTarget("0", new VerticalConfigurationGroup(false, false));
00047 }
00048 };
00049
00050 AudioDeviceComboBox::AudioDeviceComboBox(AudioConfigSettings *parent) :
00051 HostComboBox("AudioOutputDevice", true), m_parent(parent)
00052 {
00053 setLabel(QObject::tr("Audio output device"));
00054 #ifdef USING_ALSA
00055 QString dflt = "ALSA:default";
00056 #elif USING_PULSEOUTPUT
00057 QString dflt = "PulseAudio:default";
00058 #elif CONFIG_DARWIN
00059 QString dflt = "CoreAudio:";
00060 #elif USING_MINGW
00061 QString dflt = "Windows:";
00062 #else
00063 QString dflt = "NULL";
00064 #endif
00065 QString current = gCoreContext->GetSetting(QString("AudioOutputDevice"),
00066 dflt);
00067 addSelection(current, current, true);
00068
00069 connect(this, SIGNAL(valueChanged(const QString&)),
00070 this, SLOT(AudioDescriptionHelp(const QString&)));
00071 }
00072
00073 void AudioDeviceComboBox::AudioRescan()
00074 {
00075 AudioOutput::ADCVect &vect = m_parent->AudioDeviceVect();
00076 AudioOutput::ADCVect::const_iterator it;
00077
00078 if (vect.empty())
00079 return;
00080
00081 QString value = getValue();
00082 clearSelections();
00083 resetMaxCount(vect.size());
00084
00085 bool found = false;
00086 for (it = vect.begin(); it != vect.end(); ++it)
00087 addSelection(it->name, it->name,
00088 value == it->name ? (found = true) : false);
00089 if (!found)
00090 {
00091 resetMaxCount(vect.size()+1);
00092 addSelection(value, value, true);
00093 }
00094
00095 removeSelection(QString::null);
00096 }
00097
00098 void AudioDeviceComboBox::AudioDescriptionHelp(const QString &device)
00099 {
00100 QString desc = m_parent->AudioDeviceMap().value(device).desc;
00101 setHelpText(desc);
00102 }
00103
00104 AudioConfigSettings::AudioConfigSettings(ConfigurationWizard *parent) :
00105 VerticalConfigurationGroup(false, true, false, false),
00106 m_OutputDevice(NULL), m_MaxAudioChannels(NULL),
00107 m_AudioUpmix(NULL), m_AudioUpmixType(NULL),
00108 m_AC3PassThrough(NULL), m_DTSPassThrough(NULL),
00109 m_EAC3PassThrough(NULL),m_TrueHDPassThrough(NULL), m_DTSHDPassThrough(NULL),
00110 m_parent(parent), m_lastAudioDevice("")
00111 {
00112 setLabel(QObject::tr("Audio System"));
00113 setUseLabel(false);
00114
00115 ConfigurationGroup *devicegroup = new HorizontalConfigurationGroup(false,
00116 false);
00117 devicegroup->addChild((m_OutputDevice = new AudioDeviceComboBox(this)));
00118
00119 TransButtonSetting *rescan = new TransButtonSetting("rescan");
00120 rescan->setLabel(QObject::tr("Rescan"));
00121 rescan->setHelpText(QObject::tr("Rescan for available audio devices. "
00122 "Current entry will be checked and "
00123 "capability entries populated."));
00124 devicegroup->addChild(rescan);
00125 connect(rescan, SIGNAL(pressed()), this, SLOT(AudioRescan()));
00126 addChild(devicegroup);
00127
00128 QString name = m_OutputDevice->getValue();
00129 AudioOutput::AudioDeviceConfig *adc =
00130 AudioOutput::GetAudioDeviceConfig(name, name, true);
00131 if (adc->settings.IsInvalid())
00132 {
00133 LOG(VB_GENERAL, LOG_ERR,
00134 QString("Audio device %1 isn't usable Check audio configuration")
00135 .arg(name));
00136 }
00137 audiodevs.insert(name, *adc);
00138 devices.append(*adc);
00139
00140 delete adc;
00141
00142 ConfigurationGroup *maingroup = new VerticalConfigurationGroup(false,
00143 false);
00144 addChild(maingroup);
00145
00146 m_triggerDigital = new TransCheckBoxSetting();
00147 m_AC3PassThrough = AC3PassThrough();
00148 m_DTSPassThrough = DTSPassThrough();
00149 m_EAC3PassThrough = EAC3PassThrough();
00150 m_TrueHDPassThrough = TrueHDPassThrough();
00151 m_DTSHDPassThrough = DTSHDPassThrough();
00152
00153 m_cgsettings = new HorizontalConfigurationGroup();
00154 m_cgsettings->setLabel(QObject::tr("Digital Audio Capabilities"));
00155 m_cgsettings->addChild(m_AC3PassThrough);
00156 m_cgsettings->addChild(m_DTSPassThrough);
00157 m_cgsettings->addChild(m_EAC3PassThrough);
00158 m_cgsettings->addChild(m_TrueHDPassThrough);
00159 m_cgsettings->addChild(m_DTSHDPassThrough);
00160
00161 TriggeredItem *sub1 = new TriggeredItem(m_triggerDigital, m_cgsettings);
00162
00163 maingroup->addChild(sub1);
00164
00165 maingroup->addChild((m_MaxAudioChannels = MaxAudioChannels()));
00166 maingroup->addChild((m_AudioUpmix = AudioUpmix()));
00167 maingroup->addChild((m_AudioUpmixType = AudioUpmixType()));
00168
00169 TransButtonSetting *test = new TransButtonSetting("test");
00170 test->setLabel(QObject::tr("Test"));
00171 test->setHelpText(QObject::tr("Will play a test pattern on all configured "
00172 "speakers"));
00173 connect(test, SIGNAL(pressed()), this, SLOT(StartAudioTest()));
00174 addChild(test);
00175
00176 TransButtonSetting *advanced = new TransButtonSetting("advanced");
00177 advanced->setLabel(QObject::tr("Advanced Audio Settings"));
00178 advanced->setHelpText(QObject::tr("Enable extra audio settings. Under most "
00179 "usage all options should be left alone"));
00180 connect(advanced, SIGNAL(pressed()), this, SLOT(AudioAdvanced()));
00181 addChild(advanced);
00182
00183
00184 connect(m_MaxAudioChannels, SIGNAL(valueChanged(const QString&)),
00185 this, SLOT(UpdateVisibility(const QString&)));
00186 connect(m_OutputDevice, SIGNAL(valueChanged(const QString&)),
00187 this, SLOT(UpdateCapabilities(const QString&)));
00188 connect(m_AC3PassThrough, SIGNAL(valueChanged(const QString&)),
00189 this, SLOT(UpdateCapabilitiesAC3()));
00190
00191 m_maxspeakers = gCoreContext->GetNumSetting("MaxChannels", 2);
00192 AudioRescan();
00193 }
00194
00195 void AudioConfigSettings::AudioRescan()
00196 {
00197 if (!slotlock.tryLock())
00198 return;
00199
00200 AudioOutput::ADCVect* list = AudioOutput::GetOutputList();
00201 AudioOutput::ADCVect::const_iterator it;
00202
00203 audiodevs.clear();
00204 for (it = list->begin(); it != list->end(); ++it)
00205 audiodevs.insert(it->name, *it);
00206
00207 devices = *list;
00208 delete list;
00209
00210 QString name = m_OutputDevice->getValue();
00211 if (!audiodevs.contains(name))
00212 {
00213
00214 AudioOutput::AudioDeviceConfig *adc =
00215 AudioOutput::GetAudioDeviceConfig(name, name, true);
00216 if (adc->settings.IsInvalid())
00217 {
00218 QString msg = name + QObject::tr(" is invalid or not useable.");
00219 MythPopupBox::showOkPopup(
00220 GetMythMainWindow(), QObject::tr("Warning"), msg);
00221 LOG(VB_GENERAL, LOG_ERR, QString("Audio device %1 isn't usable")
00222 .arg(name));
00223 }
00224 audiodevs.insert(name, *adc);
00225 devices.append(*adc);
00226 delete adc;
00227 }
00228 m_OutputDevice->AudioRescan();
00229 if (!CheckPassthrough())
00230 {
00231 QString msg =QObject::tr("Passthrough device is invalid or not useable."
00232 " Check configuration in Advanced Settings:") +
00233 gCoreContext->GetSetting("PassThruOutputDevice");
00234 MythPopupBox::showOkPopup(
00235 GetMythMainWindow(), QObject::tr("Warning"), msg);
00236 LOG(VB_GENERAL, LOG_ERR, QString("Audio device %1 isn't usable")
00237 .arg(name));
00238 }
00239 slotlock.unlock();
00240 UpdateCapabilities(QString::null);
00241 }
00242
00243 void AudioConfigSettings::UpdateVisibility(const QString &device)
00244 {
00245 if (!m_MaxAudioChannels && !m_AudioUpmix && !m_AudioUpmixType)
00246 return;
00247
00248 int cur_speakers = m_MaxAudioChannels->getValue().toInt();
00249 m_AudioUpmix->setEnabled(cur_speakers > 2);
00250 m_AudioUpmixType->setEnabled(cur_speakers > 2);
00251 }
00252
00253 AudioOutputSettings AudioConfigSettings::UpdateCapabilities(
00254 const QString &device, bool restore, bool AC3)
00255 {
00256 int max_speakers = 8;
00257 int realmax_speakers = 8;
00258
00259 bool invalid = false;
00260
00261 if (device.length() > 0)
00262 {
00263 restore = device != m_lastAudioDevice;
00264 m_lastAudioDevice = device;
00265 }
00266
00267 AudioOutputSettings settings, settingsdigital;
00268
00269
00270 if (!m_OutputDevice || !m_MaxAudioChannels ||
00271 !m_AC3PassThrough || !m_DTSPassThrough ||
00272 !m_EAC3PassThrough || !m_TrueHDPassThrough || !m_DTSHDPassThrough)
00273 return settings;
00274
00275 if (!slotlock.tryLock())
00276 return settings;
00277
00278 bool bAC3 = true;
00279 bool bDTS = true;
00280 bool bLPCM = true;
00281 bool bEAC3 = true;
00282 bool bTRUEHD = true;
00283 bool bDTSHD = true;
00284
00285 QString out = m_OutputDevice->getValue();
00286 if (!audiodevs.contains(out))
00287 {
00288 LOG(VB_AUDIO, LOG_ERR, QString("Update not found (%1)").arg(out));
00289 invalid = true;
00290 }
00291 else
00292 {
00293 bool bForceDigital =
00294 gCoreContext->GetNumSetting("PassThruDeviceOverride", false);
00295
00296 settings = audiodevs.value(out).settings;
00297 settingsdigital = bForceDigital ?
00298 audiodevs.value(gCoreContext->GetSetting("PassThruOutputDevice"))
00299 .settings : settings;
00300
00301 realmax_speakers = max_speakers = settings.BestSupportedChannels();
00302
00303 bAC3 = settingsdigital.canFeature(FEATURE_AC3) &&
00304 m_AC3PassThrough->boolValue();
00305 bDTS = settingsdigital.canFeature(FEATURE_DTS) &&
00306 m_DTSPassThrough->boolValue();
00307 bLPCM = settings.canFeature(FEATURE_LPCM) &&
00308 !gCoreContext->GetNumSetting("StereoPCM", false);
00309 bEAC3 = settingsdigital.canFeature(FEATURE_EAC3) &&
00310 !gCoreContext->GetNumSetting("Audio48kOverride", false);
00311 bTRUEHD = settingsdigital.canFeature(FEATURE_TRUEHD) &&
00312 !gCoreContext->GetNumSetting("Audio48kOverride", false) &&
00313 gCoreContext->GetNumSetting("HBRPassthru", true);
00314 bDTSHD = settingsdigital.canFeature(FEATURE_DTSHD) &&
00315 !gCoreContext->GetNumSetting("Audio48kOverride", false);
00316
00317 if (max_speakers > 2 && !bLPCM)
00318 max_speakers = 2;
00319 if (max_speakers == 2 && bAC3)
00320 {
00321 max_speakers = 6;
00322 if (AC3)
00323 {
00324 restore = true;
00325 }
00326 }
00327 }
00328
00329 m_triggerDigital->setValue(invalid || settingsdigital.canFeature(
00330 FEATURE_AC3 | FEATURE_DTS | FEATURE_EAC3 |
00331 FEATURE_TRUEHD | FEATURE_DTSHD));
00332 m_EAC3PassThrough->setEnabled(bEAC3);
00333 m_TrueHDPassThrough->setEnabled(bTRUEHD);
00334 m_DTSHDPassThrough->setEnabled(bDTSHD);
00335
00336 int cur_speakers = m_MaxAudioChannels->getValue().toInt();
00337 if (cur_speakers > m_maxspeakers)
00338 {
00339 m_maxspeakers = m_MaxAudioChannels->getValue().toInt();
00340 }
00341 if (restore)
00342 {
00343 cur_speakers = m_maxspeakers;
00344 }
00345
00346 if (cur_speakers > max_speakers)
00347 {
00348 LOG(VB_AUDIO, LOG_INFO, QString("Reset device %1").arg(out));
00349 cur_speakers = max_speakers;
00350 }
00351
00352
00353 m_MaxAudioChannels->clearSelections();
00354 m_MaxAudioChannels->resetMaxCount(3);
00355 for (int i = 1; i <= max_speakers; i++)
00356 {
00357 if (invalid || settings.IsSupportedChannels(i) ||
00358 settingsdigital.IsSupportedChannels(i))
00359 {
00360 QString txt;
00361
00362 switch (i)
00363 {
00364 case 2:
00365 txt = QObject::tr("Stereo");
00366 break;
00367 case 6:
00368 txt = QObject::tr("5.1");
00369 break;
00370 case 8:
00371 txt = QObject::tr("7.1");
00372 break;
00373 default:
00374 continue;
00375 }
00376 m_MaxAudioChannels->addSelection(txt, QString::number(i),
00377 i == cur_speakers);
00378 }
00379 }
00380
00381
00382
00383 settings.SetBestSupportedChannels(cur_speakers);
00384 settings.setFeature(bAC3, FEATURE_AC3);
00385 settings.setFeature(bLPCM && realmax_speakers > 2, FEATURE_LPCM);
00386
00387 slotlock.unlock();
00388 return settings;
00389 }
00390
00391 AudioOutputSettings AudioConfigSettings::UpdateCapabilitiesAC3(void)
00392 {
00393 return UpdateCapabilities(QString::null, false, true);
00394 }
00395
00396 void AudioConfigSettings::AudioAdvanced()
00397 {
00398 QString out = m_OutputDevice->getValue();
00399 bool invalid = false;
00400 AudioOutputSettings settings;
00401
00402 if (!audiodevs.contains(out))
00403 {
00404 invalid = true;
00405 }
00406 else
00407 {
00408 settings = audiodevs.value(out).settings;
00409 }
00410
00411 bool LPCM1 = settings.canFeature(FEATURE_LPCM) &&
00412 gCoreContext->GetNumSetting("StereoPCM", false);
00413
00414 AudioAdvancedSettingsGroup audiosettings(invalid ||
00415 (settings.canPassthrough() >= 0));
00416
00417 if (audiosettings.exec() == kDialogCodeAccepted)
00418 {
00419
00420 AudioRescan();
00421 bool LPCM2 = settings.canFeature(FEATURE_LPCM) &&
00422 gCoreContext->GetNumSetting("StereoPCM", false);
00423
00424
00425 UpdateCapabilities(QString::null, LPCM1 != LPCM2);
00426 }
00427 }
00428
00429 HostComboBox *AudioConfigSettings::MaxAudioChannels()
00430 {
00431 QString name = "MaxChannels";
00432 HostComboBox *gc = new HostComboBox(name, false);
00433 gc->setLabel(QObject::tr("Speaker configuration"));
00434 gc->addSelection(QObject::tr("Stereo"), "2", true);
00435 gc->setHelpText(QObject::tr("Select the maximum number of audio "
00436 "channels supported by your receiver "
00437 "and speakers."));
00438 return gc;
00439 }
00440
00441 HostCheckBox *AudioConfigSettings::AudioUpmix()
00442 {
00443 HostCheckBox *gc = new HostCheckBox("AudioDefaultUpmix");
00444 gc->setLabel(QObject::tr("Upconvert stereo to 5.1 surround"));
00445 gc->setValue(true);
00446 gc->setHelpText(QObject::tr("If enabled, MythTV will upconvert stereo "
00447 "to 5.1 audio. You can enable or disable "
00448 "the upconversion during playback at any time."));
00449 return gc;
00450 }
00451
00452 HostComboBox *AudioConfigSettings::AudioUpmixType()
00453 {
00454 HostComboBox *gc = new HostComboBox("AudioUpmixType",false);
00455 gc->setLabel(QObject::tr("Upmix Quality"));
00456 gc->addSelection(QObject::tr("Good"), "1");
00457 gc->addSelection(QObject::tr("Best"), "2", true);
00458 gc->setHelpText(QObject::tr("Set the audio surround-upconversion quality."));
00459 return gc;
00460 }
00461
00462 HostCheckBox *AudioConfigSettings::AC3PassThrough()
00463 {
00464 HostCheckBox *gc = new HostCheckBox("AC3PassThru");
00465 gc->setLabel(QObject::tr("Dolby Digital"));
00466 gc->setValue(false);
00467 gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
00468 "supports AC-3/Dolby Digital. You must use a digital "
00469 "connection. Uncheck if using an analog connection."));
00470 return gc;
00471 }
00472
00473 HostCheckBox *AudioConfigSettings::DTSPassThrough()
00474 {
00475 HostCheckBox *gc = new HostCheckBox("DTSPassThru");
00476 gc->setLabel(QObject::tr("DTS"));
00477 gc->setValue(false);
00478 gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
00479 "supports DTS. You must use a digital connection. Uncheck "
00480 "if using an analog connection"));
00481 return gc;
00482 }
00483
00484 HostCheckBox *AudioConfigSettings::EAC3PassThrough()
00485 {
00486 HostCheckBox *gc = new HostCheckBox("EAC3PassThru");
00487 gc->setLabel(QObject::tr("E-AC-3"));
00488 gc->setValue(false);
00489 gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
00490 "supports E-AC-3 (DD+). You must use a HDMI connection."));
00491 return gc;
00492 }
00493
00494 HostCheckBox *AudioConfigSettings::TrueHDPassThrough()
00495 {
00496 HostCheckBox *gc = new HostCheckBox("TrueHDPassThru");
00497 gc->setLabel(QObject::tr("TrueHD"));
00498 gc->setValue(false);
00499 gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
00500 "supports Dolby TrueHD. You must use a HDMI connection."));
00501 return gc;
00502 }
00503
00504 HostCheckBox *AudioConfigSettings::DTSHDPassThrough()
00505 {
00506 HostCheckBox *gc = new HostCheckBox("DTSHDPassThru");
00507 gc->setLabel(QObject::tr("DTS-HD"));
00508 gc->setValue(false);
00509 gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
00510 "supports DTS-HD. You must use a HDMI connection."));
00511 return gc;
00512 }
00513
00514 bool AudioConfigSettings::CheckPassthrough()
00515 {
00516 bool ok = true;
00517
00518 if (gCoreContext->GetNumSetting("PassThruDeviceOverride", false))
00519 {
00520 QString name = gCoreContext->GetSetting("PassThruOutputDevice");
00521 AudioOutput::AudioDeviceConfig *adc =
00522 AudioOutput::GetAudioDeviceConfig(name, name, true);
00523 if (adc->settings.IsInvalid())
00524 {
00525 LOG(VB_GENERAL, LOG_ERR,
00526 QString("Passthru device %1 isn't usable "
00527 "Check audio configuration").arg(name));
00528 ok = false;
00529 }
00530
00531 audiodevs.insert(name, *adc);
00532 devices.append(*adc);
00533 delete adc;
00534 }
00535 return ok;
00536 }
00537
00538 void AudioConfigSettings::StartAudioTest()
00539 {
00540 AudioOutputSettings settings = UpdateCapabilities(QString::null,
00541 false, false);
00542 QString out = m_OutputDevice->getValue();
00543 QString passthrough =
00544 gCoreContext->GetNumSetting("PassThruDeviceOverride", false) ?
00545 gCoreContext->GetSetting("PassThruOutputDevice") : QString::null;
00546 int channels = m_MaxAudioChannels->getValue().toInt();
00547
00548 AudioTestGroup audiotest(out, passthrough, channels, settings);
00549
00550 audiotest.exec();
00551 }
00552
00553 AudioTestThread::AudioTestThread(QObject *parent,
00554 QString main, QString passthrough,
00555 int channels,
00556 AudioOutputSettings settings,
00557 bool hd) :
00558 MThread("AudioTest"),
00559 m_parent(parent), m_channels(channels), m_device(main),
00560 m_passthrough(passthrough), m_interrupted(false), m_channel(-1), m_hd(hd)
00561 {
00562 m_format = hd ? settings.BestSupportedFormat() : FORMAT_S16;
00563 m_samplerate = hd ? settings.BestSupportedRate() : 48000;
00564
00565 m_audioOutput = AudioOutput::OpenAudio(m_device, m_passthrough,
00566 m_format, m_channels,
00567 0, m_samplerate,
00568 AUDIOOUTPUT_VIDEO,
00569 true, false, 0, &settings);
00570 if (result().isEmpty())
00571 {
00572 m_audioOutput->Pause(true);
00573 }
00574 }
00575
00576 QEvent::Type ChannelChangedEvent::kEventType =
00577 (QEvent::Type) QEvent::registerEventType();
00578
00579 AudioTestThread::~AudioTestThread()
00580 {
00581 cancel();
00582 wait();
00583 if (m_audioOutput)
00584 delete m_audioOutput;
00585 }
00586
00587 void AudioTestThread::cancel()
00588 {
00589 m_interrupted = true;
00590 }
00591
00592 QString AudioTestThread::result()
00593 {
00594 QString errMsg;
00595 if (!m_audioOutput)
00596 errMsg = QObject::tr("Unable to create AudioOutput.");
00597 else
00598 errMsg = m_audioOutput->GetError();
00599 return errMsg;
00600 }
00601
00602 void AudioTestThread::setChannel(int channel)
00603 {
00604 m_channel = channel;
00605 }
00606
00607 void AudioTestThread::run()
00608 {
00609 RunProlog();
00610 m_interrupted = false;
00611 int smptelayout[7][8] = {
00612 { 0, 1, 1 },
00613 { },
00614 { },
00615 { 0, 2, 1, 4, 3 },
00616 { 0, 2, 1, 5, 4, 3 },
00617 { 0, 2, 1, 6, 4, 5, 3 },
00618 { 0, 2, 1, 7, 5, 4, 6, 3 },
00619 };
00620
00621 if (m_audioOutput)
00622 {
00623 char *frames_in = new char[m_channels * 1024 * sizeof(int32_t) + 15];
00624 char *frames = (char *)(((long)frames_in + 15) & ~0xf);
00625
00626 m_audioOutput->Pause(false);
00627
00628 int begin = 0;
00629 int end = m_channels;
00630 if (m_channel >= 0)
00631 {
00632 begin = m_channel;
00633 end = m_channel + 1;
00634 }
00635 while (!m_interrupted)
00636 {
00637 for (int i = begin; i < end && !m_interrupted; i++)
00638 {
00639 int current = smptelayout[m_channels - 2][i];
00640
00641 if (m_parent)
00642 {
00643 QString channel;
00644
00645 switch(current)
00646 {
00647 case 0:
00648 channel = "frontleft";
00649 break;
00650 case 1:
00651 channel = "frontright";
00652 break;
00653 case 2:
00654 channel = "center";
00655 break;
00656 case 3:
00657 channel = "lfe";
00658 break;
00659 case 4:
00660 if (m_channels == 6)
00661 channel = "surroundleft";
00662 else if (m_channels == 7)
00663 channel = "rearright";
00664 else
00665 channel = "rearleft";
00666 break;
00667 case 5:
00668 if (m_channels == 6)
00669 channel = "surroundright";
00670 else if (m_channels == 7)
00671 channel = "surroundleft";
00672 else
00673 channel = "rearright";
00674 break;
00675 case 6:
00676 if (m_channels == 7)
00677 channel = "surroundright";
00678 else
00679 channel = "surroundleft";
00680 break;
00681 case 7:
00682 channel = "surroundright";
00683 break;
00684 }
00685 QCoreApplication::postEvent(
00686 m_parent, new ChannelChangedEvent(channel,
00687 m_channel < 0));
00688 LOG(VB_AUDIO, LOG_INFO, QString("AudioTest: %1 (%2->%3)")
00689 .arg(channel).arg(i).arg(current));
00690 }
00691
00692
00693 int top = m_samplerate / 1000 * 3;
00694 for (int j = 0; j < top && !m_interrupted; j++)
00695 {
00696 AudioOutputUtil::GeneratePinkFrames(frames, m_channels,
00697 current, 1000,
00698 m_hd ? 32 : 16);
00699 if (!m_audioOutput->AddFrames(frames, 1000 , -1))
00700 {
00701 LOG(VB_AUDIO, LOG_ERR, "AddData() Audio buffer "
00702 "overflow, audio data lost!");
00703 }
00704 usleep(m_audioOutput->LengthLastData() * 1000);
00705 }
00706 m_audioOutput->Drain();
00707 m_audioOutput->Pause(true);
00708 usleep(500000);
00709 m_audioOutput->Pause(false);
00710 }
00711 if (m_channel >= 0)
00712 break;
00713 }
00714 m_audioOutput->Pause(true);
00715
00716 delete[] frames_in;
00717 }
00718 RunEpilog();
00719 }
00720
00721 AudioTest::AudioTest(QString main, QString passthrough,
00722 int channels, AudioOutputSettings settings)
00723 : VerticalConfigurationGroup(false, true, false, false),
00724 m_frontleft(NULL), m_frontright(NULL), m_center(NULL),
00725 m_surroundleft(NULL), m_surroundright(NULL),
00726 m_rearleft(NULL), m_rearright(NULL), m_lfe(NULL),
00727 m_main(main), m_passthrough(passthrough), m_settings(settings),
00728 m_quality(false)
00729 {
00730 m_channels = gCoreContext->GetNumSetting("TestingChannels", channels);
00731 setLabel(QObject::tr("Audio Configuration Testing"));
00732
00733 m_at = new AudioTestThread(this, m_main, m_passthrough, m_channels,
00734 m_settings, m_quality);
00735 if (!m_at->result().isEmpty())
00736 {
00737 QString msg = main + QObject::tr(" is invalid or not "
00738 "useable.");
00739 MythPopupBox::showOkPopup(
00740 GetMythMainWindow(), QObject::tr("Warning"), msg);
00741 return;
00742 }
00743
00744 m_button = new TransButtonSetting("start");
00745 m_button->setLabel(QObject::tr("Test All"));
00746 m_button->setHelpText(QObject::tr("Start all channels test"));
00747 connect(m_button, SIGNAL(pressed(QString)), this, SLOT(toggle(QString)));
00748
00749 ConfigurationGroup *frontgroup =
00750 new HorizontalConfigurationGroup(false,
00751 false);
00752 ConfigurationGroup *middlegroup =
00753 new HorizontalConfigurationGroup(false,
00754 false);
00755 ConfigurationGroup *reargroup =
00756 new HorizontalConfigurationGroup(false,
00757 false);
00758 m_frontleft = new TransButtonSetting("0");
00759 m_frontleft->setLabel(QObject::tr("Front Left"));
00760 connect(m_frontleft,
00761 SIGNAL(pressed(QString)), this, SLOT(toggle(QString)));
00762 m_frontright = new TransButtonSetting(m_channels == 2 ? "1" : "2");
00763 m_frontright->setLabel(QObject::tr("Front Right"));
00764 connect(m_frontright,
00765 SIGNAL(pressed(QString)), this, SLOT(toggle(QString)));
00766 frontgroup->addChild(m_frontleft);
00767
00768 switch(m_channels)
00769 {
00770 case 8:
00771 m_rearleft = new TransButtonSetting("5");
00772 m_rearleft->setLabel(QObject::tr("Rear Left"));
00773 connect(m_rearleft,
00774 SIGNAL(pressed(QString)), this, SLOT(toggle(QString)));
00775 reargroup->addChild(m_rearleft);
00776
00777 case 7:
00778 m_rearright = new TransButtonSetting("4");
00779 m_rearright->setLabel(QObject::tr(m_channels == 8 ?
00780 "Rear Right" : "Rear Center"));
00781 connect(m_rearright,
00782 SIGNAL(pressed(QString)), this, SLOT(toggle(QString)));
00783
00784 reargroup->addChild(m_rearright);
00785
00786 case 6:
00787 m_lfe = new TransButtonSetting(m_channels == 6 ? "5" :
00788 m_channels == 7 ? "6" : "7");
00789 m_lfe->setLabel(QObject::tr("LFE"));
00790 connect(m_lfe,
00791 SIGNAL(pressed(QString)), this, SLOT(toggle(QString)));
00792
00793 case 5:
00794 m_surroundleft = new TransButtonSetting(m_channels == 6 ? "4" :
00795 m_channels == 7 ? "5" : "6");
00796 m_surroundleft->setLabel(QObject::tr("Surround Left"));
00797 connect(m_surroundleft,
00798 SIGNAL(pressed(QString)), this, SLOT(toggle(QString)));
00799 m_surroundright = new TransButtonSetting("3");
00800 m_surroundright->setLabel(QObject::tr("Surround Right"));
00801 connect(m_surroundright,
00802 SIGNAL(pressed(QString)), this, SLOT(toggle(QString)));
00803 m_center = new TransButtonSetting("1");
00804 m_center->setLabel(QObject::tr("Center"));
00805 connect(m_center,
00806 SIGNAL(pressed(QString)), this, SLOT(toggle(QString)));
00807 frontgroup->addChild(m_center);
00808 middlegroup->addChild(m_surroundleft);
00809 if (m_lfe)
00810 middlegroup->addChild(m_lfe);
00811 middlegroup->addChild(m_surroundright);
00812
00813 case 2:
00814 break;
00815 }
00816 frontgroup->addChild(m_frontright);
00817 addChild(frontgroup);
00818 addChild(middlegroup);
00819 addChild(reargroup);
00820 addChild(m_button);
00821
00822 m_hd = new TransCheckBoxSetting();
00823 m_hd->setLabel(QObject::tr("Use Highest Quality Mode"));
00824 m_hd->setHelpText(QObject::tr("Use the highest audio quality settings "
00825 "supported by your audio card. This will be "
00826 "a good place to start troubleshooting "
00827 "potential errors"));
00828 addChild(m_hd);
00829 connect(m_hd, SIGNAL(valueChanged(QString)), this, SLOT(togglequality()));
00830 }
00831
00832 AudioTest::~AudioTest()
00833 {
00834 m_at->cancel();
00835 m_at->wait();
00836 delete m_at;
00837 }
00838
00839 void AudioTest::toggle(QString str)
00840 {
00841 if (str == "start")
00842 {
00843 if (m_at->isRunning())
00844 {
00845 m_at->cancel();
00846 m_button->setLabel(QObject::tr("Test All"));
00847 if (m_frontleft)
00848 m_frontleft->setEnabled(true);
00849 if (m_frontright)
00850 m_frontright->setEnabled(true);
00851 if (m_center)
00852 m_center->setEnabled(true);
00853 if (m_surroundleft)
00854 m_surroundleft->setEnabled(true);
00855 if (m_surroundright)
00856 m_surroundright->setEnabled(true);
00857 if (m_rearleft)
00858 m_rearleft->setEnabled(true);
00859 if (m_rearright)
00860 m_rearright->setEnabled(true);
00861 if (m_lfe)
00862 m_lfe->setEnabled(true);
00863 }
00864 else
00865 {
00866 m_at->setChannel(-1);
00867 m_at->start();
00868 m_button->setLabel(QObject::tr("Stop"));
00869 }
00870 return;
00871 }
00872 if (m_at->isRunning())
00873 {
00874 m_at->cancel();
00875 m_at->wait();
00876 }
00877
00878 int channel = str.toInt();
00879 m_at->setChannel(channel);
00880
00881 m_at->start();
00882 }
00883
00884 void AudioTest::togglequality()
00885 {
00886 if (m_at->isRunning())
00887 {
00888 toggle("start");
00889 }
00890
00891 m_quality = m_hd->boolValue();
00892 delete m_at;
00893 m_at = new AudioTestThread(this, m_main, m_passthrough, m_channels,
00894 m_settings, m_quality);
00895 if (!m_at->result().isEmpty())
00896 {
00897 QString msg = QObject::tr("Audio device is invalid or not useable.");
00898 MythPopupBox::showOkPopup(
00899 GetMythMainWindow(), QObject::tr("Warning"), msg);
00900 }
00901 }
00902
00903 bool AudioTest::event(QEvent *event)
00904 {
00905 if (event->type() != ChannelChangedEvent::kEventType)
00906 return QObject::event(event);
00907
00908 ChannelChangedEvent *cce = (ChannelChangedEvent*)(event);
00909 QString channel = cce->channel;
00910
00911 if (!cce->fulltest)
00912 return false;
00913
00914 bool fl, fr, c, lfe, sl, sr, rl, rr;
00915 fl = fr = c = lfe = sl = sr = rl = rr = false;
00916
00917 if (channel == "frontleft")
00918 {
00919 fl = true;
00920 }
00921 else if (channel == "frontright")
00922 {
00923 fr = true;
00924 }
00925 else if (channel == "center")
00926 {
00927 c = true;
00928 }
00929 else if (channel == "lfe")
00930 {
00931 lfe = true;
00932 }
00933 else if (channel == "surroundleft")
00934 {
00935 sl = true;
00936 }
00937 else if (channel == "surroundright")
00938 {
00939 sr = true;
00940 }
00941 else if (channel == "rearleft")
00942 {
00943 rl = true;
00944 }
00945 else if (channel == "rearright")
00946 {
00947 rr = true;
00948 }
00949 if (m_frontleft)
00950 m_frontleft->setEnabled(fl);
00951 if (m_frontright)
00952 m_frontright->setEnabled(fr);
00953 if (m_center)
00954 m_center->setEnabled(c);
00955 if (m_surroundleft)
00956 m_surroundleft->setEnabled(sl);
00957 if (m_surroundright)
00958 m_surroundright->setEnabled(sr);
00959 if (m_rearleft)
00960 m_rearleft->setEnabled(rl);
00961 if (m_rearright)
00962 m_rearright->setEnabled(rr);
00963 if (m_lfe)
00964 m_lfe->setEnabled(lfe);
00965 return false;
00966 }
00967
00968
00969 AudioTestGroup::AudioTestGroup(QString main, QString passthrough,
00970 int channels, AudioOutputSettings settings)
00971 {
00972 addChild(new AudioTest(main, passthrough, channels, settings));
00973 }
00974
00975 HostCheckBox *AudioMixerSettings::MythControlsVolume()
00976 {
00977 HostCheckBox *gc = new HostCheckBox("MythControlsVolume");
00978 gc->setLabel(QObject::tr("Use internal volume controls"));
00979 gc->setValue(true);
00980 gc->setHelpText(QObject::tr("If enabled, MythTV will control the PCM and "
00981 "master mixer volume. Disable this option if you prefer "
00982 "to control the volume externally (for example, using "
00983 "your amplifier) or if you use an external mixer program."));
00984 return gc;
00985 }
00986
00987 HostComboBox *AudioMixerSettings::MixerDevice()
00988 {
00989 HostComboBox *gc = new HostComboBox("MixerDevice", true);
00990 gc->setLabel(QObject::tr("Mixer device"));
00991
00992 #ifdef USING_OSS
00993 QDir dev("/dev", "mixer*", QDir::Name, QDir::System);
00994 gc->fillSelectionsFromDir(dev);
00995
00996 dev.setPath("/dev/sound");
00997 if (dev.exists())
00998 {
00999 gc->fillSelectionsFromDir(dev);
01000 }
01001 #endif
01002 #ifdef USING_ALSA
01003 gc->addSelection("ALSA:default", "ALSA:default");
01004 #endif
01005 #ifdef USING_MINGW
01006 gc->addSelection("DirectX:", "DirectX:");
01007 gc->addSelection("Windows:", "Windows:");
01008 #endif
01009 #if !defined(USING_MINGW)
01010 gc->addSelection("software", "software");
01011 gc->setHelpText(QObject::tr("Setting the mixer device to \"software\" "
01012 "lets MythTV control the volume of all audio at the "
01013 "expense of a slight quality loss."));
01014 #endif
01015
01016 return gc;
01017 }
01018
01019 const char* AudioMixerSettings::MixerControlControls[] = { "PCM",
01020 "Master" };
01021
01022 HostComboBox *AudioMixerSettings::MixerControl()
01023 {
01024 HostComboBox *gc = new HostComboBox("MixerControl", true);
01025 gc->setLabel(QObject::tr("Mixer controls"));
01026 for (unsigned int i = 0; i < sizeof(MixerControlControls) / sizeof(char*);
01027 ++i)
01028 {
01029 gc->addSelection(QObject::tr(MixerControlControls[i]),
01030 MixerControlControls[i]);
01031 }
01032
01033 gc->setHelpText(QObject::tr("Changing the volume adjusts the selected mixer."));
01034 return gc;
01035 }
01036
01037 HostSlider *AudioMixerSettings::MixerVolume()
01038 {
01039 HostSlider *gs = new HostSlider("MasterMixerVolume", 0, 100, 1);
01040 gs->setLabel(QObject::tr("Master mixer volume"));
01041 gs->setValue(70);
01042 gs->setHelpText(QObject::tr("Initial volume for the Master mixer. "
01043 "This affects all sound created by the audio device. "
01044 "Note: Do not set this too low."));
01045 return gs;
01046 }
01047
01048 HostSlider *AudioMixerSettings::PCMVolume()
01049 {
01050 HostSlider *gs = new HostSlider("PCMMixerVolume", 0, 100, 1);
01051 gs->setLabel(QObject::tr("PCM mixer volume"));
01052 gs->setValue(70);
01053 gs->setHelpText(QObject::tr("Initial volume for PCM output. Using the "
01054 "volume keys in MythTV will adjust this parameter."));
01055 return gs;
01056 }
01057
01058 AudioMixerSettings::AudioMixerSettings() :
01059 TriggeredConfigurationGroup(false, true, false, false)
01060 {
01061 setLabel(QObject::tr("Audio Mixer"));
01062 setUseLabel(false);
01063
01064 Setting *volumeControl = MythControlsVolume();
01065 addChild(volumeControl);
01066
01067
01068 ConfigurationGroup *settings =
01069 new VerticalConfigurationGroup(false, true, false, false);
01070 settings->addChild(MixerDevice());
01071 settings->addChild(MixerControl());
01072 settings->addChild(MixerVolume());
01073 settings->addChild(PCMVolume());
01074
01075 ConfigurationGroup *dummy =
01076 new VerticalConfigurationGroup(false, true, false, false);
01077
01078
01079 setTrigger(volumeControl);
01080 addTarget("0", dummy);
01081 addTarget("1", settings);
01082 }
01083
01084 AudioGeneralSettings::AudioGeneralSettings()
01085 {
01086 addChild(new AudioConfigSettings(this));
01087 addChild(new AudioMixerSettings());
01088 }
01089
01090 HostCheckBox *AudioAdvancedSettings::MPCM()
01091 {
01092 HostCheckBox *gc = new HostCheckBox("StereoPCM");
01093 gc->setLabel(QObject::tr("Stereo PCM Only"));
01094 gc->setValue(false);
01095 gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
01096 "only supports 2 channel PCM (typically an old HDMI 1.0 "
01097 "device). Multichannel audio will be re-encoded to AC-3 "
01098 "when required"));
01099 return gc;
01100 }
01101
01102 HostCheckBox *AudioAdvancedSettings::SRCQualityOverride()
01103 {
01104 HostCheckBox *gc = new HostCheckBox("SRCQualityOverride");
01105 gc->setLabel(QObject::tr("Override SRC quality"));
01106 gc->setValue(false);
01107 gc->setHelpText(QObject::tr("Enable to override audio sample rate "
01108 "conversion quality."));
01109 return gc;
01110 }
01111
01112 HostComboBox *AudioAdvancedSettings::SRCQuality()
01113 {
01114 HostComboBox *gc = new HostComboBox("SRCQuality", false);
01115 gc->setLabel(QObject::tr("Sample rate conversion"));
01116 gc->addSelection(QObject::tr("Disabled"), "-1");
01117 gc->addSelection(QObject::tr("Fastest"), "0");
01118 gc->addSelection(QObject::tr("Good"), "1", true);
01119 gc->addSelection(QObject::tr("Best"), "2");
01120 gc->setHelpText(QObject::tr("Set the quality of audio sample-rate "
01121 "conversion. \"Good\" (default) provides the best "
01122 "compromise between CPU usage and quality. \"Disabled\" "
01123 "lets the audio device handle sample-rate conversion."));
01124 return gc;
01125 }
01126
01127 HostCheckBox *AudioAdvancedSettings::Audio48kOverride()
01128 {
01129 HostCheckBox *gc = new HostCheckBox("Audio48kOverride");
01130 gc->setLabel(QObject::tr("Force audio device output to 48kHz"));
01131 gc->setValue(false);
01132 gc->setHelpText(QObject::tr("Force audio sample rate to 48kHz. "
01133 "Some audio devices will report various rates, "
01134 "but they ultimately crash."));
01135 return gc;
01136 }
01137
01138 HostCheckBox *AudioAdvancedSettings::PassThroughOverride()
01139 {
01140 HostCheckBox *gc = new HostCheckBox("PassThruDeviceOverride");
01141 gc->setLabel(QObject::tr("Separate digital output device"));
01142 gc->setValue(false);
01143 gc->setHelpText(QObject::tr("Use a distinct digital output device from "
01144 "default."
01145 " (default is not checked)"));
01146 return gc;
01147 }
01148
01149 HostComboBox *AudioAdvancedSettings::PassThroughOutputDevice()
01150 {
01151 HostComboBox *gc = new HostComboBox("PassThruOutputDevice", true);
01152
01153 gc->setLabel(QObject::tr("Digital output device"));
01154 gc->addSelection(QObject::tr("Default"), "Default");
01155 #ifdef USING_MINGW
01156 gc->addSelection("DirectX:Primary Sound Driver");
01157 #else
01158 gc->addSelection("ALSA:iec958:{ AES0 0x02 }",
01159 "ALSA:iec958:{ AES0 0x02 }");
01160 gc->addSelection("ALSA:hdmi", "ALSA:hdmi");
01161 gc->addSelection("ALSA:plughw:0,3", "ALSA:plughw:0,3");
01162 #endif
01163
01164 gc->setHelpText(QObject::tr("Audio output device to use for "
01165 "digital audio. This value is currently only used "
01166 "with ALSA and DirectX sound output."));
01167 return gc;
01168 }
01169
01170 HostCheckBox *AudioAdvancedSettings::SPDIFRateOverride()
01171 {
01172 HostCheckBox *gc = new HostCheckBox("SPDIFRateOverride");
01173 gc->setLabel(QObject::tr("SPDIF 48kHz rate override"));
01174 gc->setValue(false);
01175 gc->setHelpText(QObject::tr("ALSA only. By default, let ALSA determine "
01176 "the passthrough sampling rate. If checked "
01177 "set the sampling rate to 48kHz for passthrough."
01178 " (default is not checked)"));
01179 return gc;
01180 }
01181
01182 HostCheckBox *AudioAdvancedSettings::HBRPassthrough()
01183 {
01184 HostCheckBox *gc = new HostCheckBox("HBRPassthru");
01185 gc->setLabel(QObject::tr("HBR passthrough support"));
01186 gc->setValue(true);
01187 gc->setHelpText(QObject::tr("HBR support is required for TrueHD and DTS-HD "
01188 "passthrough. If unchecked, Myth will limit the "
01189 "passthrough bitrate to 6.144Mbit/s."
01190 "This will disable True-HD passthrough, however will "
01191 "allow DTS-HD content to be sent as DTS-HD Hi-Res."
01192 " (default is checked)"));
01193 return gc;
01194 }
01195
01196 AudioAdvancedSettings::AudioAdvancedSettings(bool mpcm)
01197 {
01198 ConfigurationGroup *settings3 =
01199 new HorizontalConfigurationGroup(false, false);
01200
01201 m_PassThroughOverride = PassThroughOverride();
01202 TriggeredItem *sub3 =
01203 new TriggeredItem(m_PassThroughOverride, PassThroughOutputDevice());
01204 settings3->addChild(m_PassThroughOverride);
01205 settings3->addChild(sub3);
01206
01207 ConfigurationGroup *settings4 =
01208 new HorizontalConfigurationGroup(false, false);
01209 Setting *srcqualityoverride = SRCQualityOverride();
01210 TriggeredItem *sub4 =
01211 new TriggeredItem(srcqualityoverride, SRCQuality());
01212 settings4->addChild(srcqualityoverride);
01213 settings4->addChild(sub4);
01214
01215 ConfigurationGroup *settings5 =
01216 new HorizontalConfigurationGroup(false, false);
01217 settings5->addChild(Audio48kOverride());
01218 #if USING_ALSA
01219 settings5->addChild(SPDIFRateOverride());
01220 #endif
01221
01222 ConfigurationGroup *settings6 =
01223 new HorizontalConfigurationGroup(false, false);
01224 settings6->addChild(HBRPassthrough());
01225
01226 addChild(settings4);
01227 addChild(settings5);
01228 addChild(settings3);
01229 addChild(settings6);
01230
01231 if (mpcm)
01232 {
01233 ConfigurationGroup *settings7;
01234 settings7 = new HorizontalConfigurationGroup(false, false);
01235 settings7->addChild(MPCM());
01236 addChild(settings7);
01237 }
01238 }
01239
01240 AudioAdvancedSettingsGroup::AudioAdvancedSettingsGroup(bool mpcm)
01241 {
01242 addChild(new AudioAdvancedSettings(mpcm));
01243 }
01244