|
MythTV
0.26-pre
|
00001 00002 // -*- Mode: c++ -*- 00003 00004 // Standard UNIX C headers 00005 #include <unistd.h> 00006 #include <fcntl.h> 00007 #include <sys/types.h> 00008 #include <sys/stat.h> 00009 00010 // Qt headers 00011 #include <QCoreApplication> 00012 #include <QEvent> 00013 #include <QDir> 00014 00015 // MythTV headers 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 // For some reason, it adds an empty entry, remove it 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 // Rescan button 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 // Set slots 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 // Scan for possible custom entry that isn't in the list 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 // Test if everything is set yet 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()) // Doing a rescan of channels 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 // Remove everything and re-add available channels 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 // Return values is used by audio test 00381 // where we mainly are interested by the number of channels 00382 // if we support AC3 and/or LPCM 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 // Rescan audio list to check of override digital device 00420 AudioRescan(); 00421 bool LPCM2 = settings.canFeature(FEATURE_LPCM) && 00422 gCoreContext->GetNumSetting("StereoPCM", false); 00423 // restore speakers configure only of StereoPCM has changed and 00424 // we have LPCM capabilities 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); // default 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); // default 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 // add it to list of known devices 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 }, //stereo 00613 { }, //not used 00614 { }, //not used 00615 { 0, 2, 1, 4, 3 }, //5.0 00616 { 0, 2, 1, 5, 4, 3 }, //5.1 00617 { 0, 2, 1, 6, 4, 5, 3 }, //6.1 00618 { 0, 2, 1, 7, 5, 4, 6, 3 }, //7.1 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 // play sample sound for about 3s 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); // .5s pause 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); //not handled 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 // Mixer settings 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 // Show Mixer config only if internal volume controls enabled 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); // default 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 // vim:set sw=4 ts=4 expandtab:
1.7.6.1