rendered paste bodydiff --git a/mythtv/libs/libmyth/audio/audiooutpututil.cpp b/mythtv/libs/libmyth/audio/audiooutpututil.cpp
index d9af347..2d096d2 100644
--- a/mythtv/libs/libmyth/audio/audiooutpututil.cpp
+++ b/mythtv/libs/libmyth/audio/audiooutpututil.cpp
@@ -3,6 +3,8 @@
using namespace std;
#include "mythconfig.h"
#include "audiooutpututil.h"
+#include <sys/types.h>
+#include <byteswap.h>
#define LOC QString("AO: ")
#define LOC_ERR QString("AO, ERROR: ")
@@ -629,3 +631,41 @@ void AudioOutputUtil::MuteChannel(int obits, int channels, int ch,
else
_MuteChannel((int *)buffer, channels, ch, frames);
}
+
+#if HAVE_BIGENDIAN
+#define LE_SHORT(v) bswap_16(v)
+#else
+#define LE_SHORT(v) (v)
+#endif
+
+char *AudioOutputUtil::GeneratePinkSamples(char *frames, int channels,
+ int channel,
+ int count)
+{
+ pink_noise_t pink;
+
+ initialize_pink_noise(&pink, 16);
+
+ double res;
+ int32_t ires;
+ int16_t *samp16 = (int16_t*) frames;
+
+ while (count-- > 0)
+ {
+ for(int chn = 0 ; chn < channels; chn++)
+ {
+ if (chn==channel)
+ {
+ res = generate_pink_noise_sample(&pink) * 0x03fffffff; /* Don't use MAX volume */
+ ires = res;
+ *samp16++ = LE_SHORT(ires >> 16);
+ }
+ else
+ {
+ *samp16++ = 0;
+ }
+ }
+ }
+ return frames;
+}
+
diff --git a/mythtv/libs/libmyth/audio/audiooutpututil.h b/mythtv/libs/libmyth/audio/audiooutpututil.h
index 858fa6e..8262f8f 100644
--- a/mythtv/libs/libmyth/audio/audiooutpututil.h
+++ b/mythtv/libs/libmyth/audio/audiooutpututil.h
@@ -4,6 +4,9 @@
using namespace std;
#include "mythverbose.h"
#include "audiooutputsettings.h"
+extern "C" {
+#include "pink.h"
+}
class MPUBLIC AudioOutputUtil
{
@@ -16,6 +19,8 @@ class MPUBLIC AudioOutputUtil
bool music, bool upmix);
static void MuteChannel(int obits, int channels, int ch,
void *buffer, int bytes);
+ static char *GeneratePinkSamples(char *frames, int channels,
+ int channel, int count);
};
#endif
diff --git a/mythtv/libs/libmyth/audio/pink.c b/mythtv/libs/libmyth/audio/pink.c
new file mode 100644
index 0000000..ef30755
--- /dev/null
+++ b/mythtv/libs/libmyth/audio/pink.c
@@ -0,0 +1,96 @@
+/*
+ patest_pink.c
+
+ generate Pink Noise using Gardner method.
+ Optimization suggested by James McCartney uses a tree
+ to select which random value to replace.
+
+ x x x x x x x x x x x x x x x x
+ x x x x x x x x
+ x x x x
+ x x
+ x
+
+ Tree is generated by counting trailing zeros in an increasing index.
+ When the index is zero, no random number is selected.
+
+ This program uses the Portable Audio library which is under development.
+ For more information see: http://www.audiomulch.com/portaudio/
+
+ Author: Phil Burk, http://www.softsynth.com
+
+ Revision History:
+
+ Copyleft 1999 Phil Burk - No rights reserved.
+*/
+
+#include <stdio.h>
+#include <math.h>
+#include "pink.h"
+
+/************************************************************/
+/* Calculate pseudo-random 32 bit number based on linear congruential method. */
+static unsigned long generate_random_number( void )
+{
+ static unsigned long rand_seed = 22222; /* Change this for different random sequences. */
+ rand_seed = (rand_seed * 196314165) + 907633515;
+ return rand_seed;
+}
+
+/* Setup PinkNoise structure for N rows of generators. */
+void initialize_pink_noise( pink_noise_t *pink, int num_rows )
+{
+ int i;
+ long pmax;
+ pink->pink_index = 0;
+ pink->pink_index_mask = (1<<num_rows) - 1;
+/* Calculate maximum possible signed random value. Extra 1 for white noise always added. */
+ pmax = (num_rows + 1) * (1<<(PINK_RANDOM_BITS-1));
+ pink->pink_scalar = 1.0f / pmax;
+/* Initialize rows. */
+ for( i=0; i<num_rows; i++ ) pink->pink_rows[i] = 0;
+ pink->pink_running_sum = 0;
+}
+
+/* generate Pink noise values between -1.0 and +1.0 */
+float generate_pink_noise_sample( pink_noise_t *pink )
+{
+ long new_random;
+ long sum;
+ float output;
+
+/* Increment and mask index. */
+ pink->pink_index = (pink->pink_index + 1) & pink->pink_index_mask;
+
+/* If index is zero, don't update any random values. */
+ if( pink->pink_index != 0 )
+ {
+ /* Determine how many trailing zeros in PinkIndex. */
+ /* This algorithm will hang if n==0 so test first. */
+ int num_zeros = 0;
+ int n = pink->pink_index;
+ while( (n & 1) == 0 )
+ {
+ n = n >> 1;
+ num_zeros++;
+ }
+
+ /* Replace the indexed ROWS random value.
+ * Subtract and add back to Running_sum instead of adding all the random
+ * values together. Only one changes each time.
+ */
+ pink->pink_running_sum -= pink->pink_rows[num_zeros];
+ new_random = ((long)generate_random_number()) >> PINK_RANDOM_SHIFT;
+ pink->pink_running_sum += new_random;
+ pink->pink_rows[num_zeros] = new_random;
+ }
+
+/* Add extra white noise value. */
+ new_random = ((long)generate_random_number()) >> PINK_RANDOM_SHIFT;
+ sum = pink->pink_running_sum + new_random;
+
+/* Scale to range of -1.0 to 0.9999. */
+ output = pink->pink_scalar * sum;
+
+ return output;
+}
diff --git a/mythtv/libs/libmyth/audio/pink.h b/mythtv/libs/libmyth/audio/pink.h
new file mode 100644
index 0000000..510bd33
--- /dev/null
+++ b/mythtv/libs/libmyth/audio/pink.h
@@ -0,0 +1,22 @@
+#ifndef AUDIOPINK
+#define AUDIOPINK
+
+#include "mythexp.h"
+
+#define PINK_MAX_RANDOM_ROWS (30)
+#define PINK_RANDOM_BITS (24)
+#define PINK_RANDOM_SHIFT ((sizeof(long)*8)-PINK_RANDOM_BITS)
+
+typedef struct
+{
+ long pink_rows[PINK_MAX_RANDOM_ROWS];
+ long pink_running_sum; /* Used to optimize summing of generators. */
+ int pink_index; /* Incremented each sample. */
+ int pink_index_mask; /* Index wrapped by ANDing with this mask. */
+ float pink_scalar; /* Used to scale within range of -1.0 to +1.0 */
+} pink_noise_t;
+
+void initialize_pink_noise( pink_noise_t *pink, int num_rows );
+float generate_pink_noise_sample( pink_noise_t *pink );
+
+#endif
diff --git a/mythtv/libs/libmyth/libmyth.pro b/mythtv/libs/libmyth/libmyth.pro
index 2178699..afa8971 100644
--- a/mythtv/libs/libmyth/libmyth.pro
+++ b/mythtv/libs/libmyth/libmyth.pro
@@ -14,7 +14,7 @@ QMAKE_CLEAN += $(TARGET) $(TARGETA) $(TARGETD) $(TARGET0) $(TARGET1) $(TARGET2)
HEADERS += audio/audiooutput.h audio/audiooutputbase.h audio/audiooutputnull.h
HEADERS += audio/audiooutpututil.h audio/audiooutputdownmix.h
HEADERS += audio/audiooutputdigitalencoder.h audio/audiosettings.h
-HEADERS += audio/audiooutputsettings.h
+HEADERS += audio/audiooutputsettings.h audio/pink.h
HEADERS += backendselect.h dbsettings.h dialogbox.h
HEADERS += generictree.h langsettings.h
HEADERS += managedlist.h mythconfigdialogs.h mythconfiggroups.h
@@ -39,7 +39,7 @@ HEADERS += rssparse.h netutils.h
# remove when everything is switched to mythui
HEADERS += virtualkeyboard_qt.h
-SOURCES += audio/audiooutput.cpp audio/audiooutputbase.cpp
+SOURCES += audio/audiooutput.cpp audio/audiooutputbase.cpp audio/pink.c
SOURCES += audio/audiooutputnull.cpp audio/audiooutputdigitalencoder.cpp
SOURCES += audio/audiooutpututil.cpp audio/audiooutputdownmix.cpp
SOURCES += audio/audiosettings.cpp audio/audiooutputsettings.cpp
diff --git a/mythtv/programs/mythfrontend/audiosettings.cpp b/mythtv/programs/mythfrontend/audiosettings.cpp
new file mode 100644
index 0000000..0e19f97
--- /dev/null
+++ b/mythtv/programs/mythfrontend/audiosettings.cpp
@@ -0,0 +1,804 @@
+
+// -*- Mode: c++ -*-
+
+// Standard UNIX C headers
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+// Qt headers
+#include <QCoreApplication>
+#include <QEvent>
+#include <QDialog>
+#include <QCursor>
+#include <QDir>
+#include <QThread>
+
+// MythTV headers
+#include "mythconfig.h"
+#include "mythcorecontext.h"
+#include "mythverbose.h"
+#include "audiosettings.h"
+#include "audiooutpututil.h"
+#include "mythscreenstack.h"
+#include "mythprogressdialog.h"
+#include "mythdialogbox.h"
+
+class TriggeredItem : public TriggeredConfigurationGroup
+{
+ public:
+ TriggeredItem(Setting *checkbox, ConfigurationGroup *group) :
+ TriggeredConfigurationGroup(false, false, false, false)
+ {
+ setTrigger(checkbox);
+
+ addTarget("1", group);
+ addTarget("0", new VerticalConfigurationGroup(true));
+ }
+ TriggeredItem(Setting *checkbox, Setting *setting) :
+ TriggeredConfigurationGroup(false, false, false, false)
+ {
+ setTrigger(checkbox);
+
+ addTarget("1", setting);
+ addTarget("0", new VerticalConfigurationGroup(false, false));
+ }
+};
+
+AudioDeviceComboBox::AudioDeviceComboBox(AudioConfigSettings *parent) :
+ HostComboBox("AudioOutputDevice", true), m_parent(parent)
+{
+ setLabel(QObject::tr("Audio output device"));
+#ifdef USING_ALSA
+ QString dflt = "ALSA:default";
+#elif USING_PULSEOUTPUT
+ QString dflt = "PulseAudio:default";
+#elif CONFIG_DARWIN
+ QString dflt = "CoreAudio:";
+#elif USING_MINGW
+ QString dflt = "Windows:";
+#else
+ QString dflt = "NULL";
+#endif
+ QString current = gCoreContext->GetSetting(QString("AudioOutputDevice"),
+ dflt);
+ addSelection(current, current, true);
+
+ connect(this, SIGNAL(valueChanged(const QString&)),
+ this, SLOT(AudioDescriptionHelp(const QString&)));
+}
+
+void AudioDeviceComboBox::AudioRescan()
+{
+ AudioOutput::ADCVect &vect = m_parent->AudioDeviceVect();
+ AudioOutput::ADCVect::const_iterator it;
+
+ if (vect.empty())
+ return;
+
+ QString value = getValue();
+ clearSelections();
+ resetMaxCount(vect.size());
+
+ bool found = false;
+ for (it = vect.begin(); it != vect.end(); it++)
+ addSelection(it->name, it->name,
+ value == it->name ? (found = true) : false);
+ if (!found)
+ {
+ resetMaxCount(vect.size()+1);
+ addSelection(value, value, true);
+ }
+ // For some reason, it adds an empty entry, remove it
+ removeSelection(QString::null);
+}
+
+void AudioDeviceComboBox::AudioDescriptionHelp(const QString &device)
+{
+ QString desc = m_parent->AudioDeviceMap().value(device).desc;
+ setHelpText(desc);
+}
+
+AudioConfigSettings::AudioConfigSettings() :
+ VerticalConfigurationGroup(false, true, false, false),
+ m_OutputDevice(NULL), m_MaxAudioChannels(NULL),
+ m_AudioUpmix(NULL), m_AudioUpmixType(NULL),
+ m_AC3PassThrough(NULL), m_DTSPassThrough(NULL),
+ m_EAC3PassThrough(NULL),m_TrueHDPassThrough(NULL),
+ m_passthrough8(false)
+{
+ setLabel(QObject::tr("Audio System"));
+ setUseLabel(false);
+
+ ConfigurationGroup *devicegroup = new HorizontalConfigurationGroup(false,
+ false);
+ devicegroup->addChild((m_OutputDevice = new AudioDeviceComboBox(this)));
+ // Rescan button
+ TransButtonSetting *rescan = new TransButtonSetting("rescan");
+ rescan->setLabel(QObject::tr("Rescan"));
+ rescan->setHelpText(QObject::tr("Rescan for available audio devices. "
+ "Current entry will be checked and "
+ "capability entries populated."));
+ devicegroup->addChild(rescan);
+ connect(rescan, SIGNAL(pressed()), this, SLOT(AudioRescan()));
+ addChild(devicegroup);
+
+ QString name = m_OutputDevice->getValue();
+ AudioOutput::AudioDeviceConfig *adc =
+ AudioOutput::GetAudioDeviceConfig(name, name, true);
+ if (adc->settings.IsInvalid())
+ VERBOSE(VB_IMPORTANT, QString("Audio device %1 isn't usable "
+ "Check audio configuration").arg(name));
+ audiodevs.insert(name, *adc);
+ devices.append(*adc);
+
+ delete adc;
+ CheckPassthrough();
+
+ ConfigurationGroup *maingroup = new VerticalConfigurationGroup(false,
+ false);
+ addChild(maingroup);
+
+ m_triggerDigital = new TransCheckBoxSetting();
+ m_AC3PassThrough = AC3PassThrough();
+ m_DTSPassThrough = DTSPassThrough();
+ m_EAC3PassThrough = EAC3PassThrough();
+ m_TrueHDPassThrough = TrueHDPassThrough();
+
+ m_cgsettings = new HorizontalConfigurationGroup();
+ m_cgsettings->setLabel(QObject::tr("Digital Audio Capabilities"));
+ m_cgsettings->addChild(m_AC3PassThrough);
+ m_cgsettings->addChild(m_DTSPassThrough);
+ m_cgsettings->addChild(m_EAC3PassThrough);
+ m_cgsettings->addChild(m_TrueHDPassThrough);
+
+ TriggeredItem *sub1 = new TriggeredItem(m_triggerDigital, m_cgsettings);
+
+ maingroup->addChild(sub1);
+
+ maingroup->addChild((m_MaxAudioChannels = MaxAudioChannels()));
+
+ TransButtonSetting *advanced = new TransButtonSetting("advanced");
+ advanced->setLabel(QObject::tr("Advanced Audio Settings"));
+ advanced->setHelpText(QObject::tr("Enable extra audio settings. Under most "
+ "usage all options should be unchecked"));
+ connect(advanced, SIGNAL(pressed()), this, SLOT(AudioAdvanced()));
+ addChild(advanced);
+
+ TransButtonSetting *test = new TransButtonSetting("test");
+ test->setLabel(QObject::tr("Test"));
+ test->setHelpText(QObject::tr("Will play a test pattern on all configured "
+ "speakers"));
+ connect(test, SIGNAL(pressed()), this, SLOT(AudioTest()));
+ addChild(test);
+
+ maingroup->addChild((m_AudioUpmix = AudioUpmix()));
+ maingroup->addChild((m_AudioUpmixType = AudioUpmixType()));
+
+ // Set slots
+ connect(m_MaxAudioChannels, SIGNAL(valueChanged(const QString&)),
+ this, SLOT(UpdateVisibility(const QString&)));
+ connect(m_OutputDevice, SIGNAL(valueChanged(const QString&)),
+ this, SLOT(UpdateCapabilities(const QString&)));
+ connect(m_AC3PassThrough, SIGNAL(valueChanged(const QString&)),
+ this, SLOT(UpdateCapabilities(const QString&)));
+ connect(m_DTSPassThrough, SIGNAL(valueChanged(const QString&)),
+ this, SLOT(UpdateCapabilities(const QString&)));
+ connect(m_EAC3PassThrough, SIGNAL(valueChanged(const QString&)),
+ this, SLOT(UpdateCapabilities(const QString&)));
+ connect(m_TrueHDPassThrough, SIGNAL(valueChanged(const QString&)),
+ this, SLOT(UpdateCapabilities(const QString&)));
+
+ AudioRescan();
+}
+
+void AudioConfigSettings::AudioRescan()
+{
+ if (!slotlock.tryLock())
+ return;
+
+ QVector<AudioOutput::AudioDeviceConfig>* list =
+ AudioOutput::GetOutputList();
+ QVector<AudioOutput::AudioDeviceConfig>::const_iterator it;
+
+ audiodevs.clear();
+ for (it = list->begin(); it != list->end(); it++)
+ audiodevs.insert(it->name, *it);
+
+ devices = *list;
+ delete list;
+
+ QString name = m_OutputDevice->getValue();
+ if (!audiodevs.contains(name))
+ {
+ // Scan for possible custom entry that isn't in the list
+ AudioOutput::AudioDeviceConfig *adc =
+ AudioOutput::GetAudioDeviceConfig(name, name, true);
+ if (adc->settings.IsInvalid())
+ {
+ QString msg = name + QObject::tr(" is invalid or not useable.");
+ MythPopupBox::showOkPopup(
+ GetMythMainWindow(), QObject::tr("Warning"), msg);
+ VERBOSE(VB_IMPORTANT, QString("Audio device %1 isn't usable ")
+ .arg(name));
+ }
+ audiodevs.insert(name, *adc);
+ devices.append(*adc);
+ delete adc;
+ }
+ m_OutputDevice->AudioRescan();
+ slotlock.unlock();
+ UpdateCapabilities(QString::null);
+}
+
+void AudioConfigSettings::AudioAdvanced()
+{
+ QString out = m_OutputDevice->getValue();
+ bool invalid = false;
+ AudioOutputSettings settings;
+
+ if (!audiodevs.contains(out))
+ {
+ invalid = true;
+ }
+ else
+ {
+ settings = audiodevs.value(out).settings;
+ }
+
+ AudioAdvancedSettingsGroup audiosettings(invalid ||
+ (settings.canLPCM() &&
+ settings.canPassthrough() >= 0));
+
+ if (audiosettings.exec() == kDialogCodeAccepted)
+ {
+ CheckPassthrough();
+ UpdateCapabilities(QString::null);
+ }
+}
+
+class AudioTestThread : public QThread
+{
+public:
+ void run()
+ {
+ char *frames_in = new char[m_channels * 48000 * sizeof(int16_t) + 15];
+ char *frames = (char *)(((long)frames_in + 15) & ~0xf);
+ for (int i = 0; i < m_channels; i++)
+ {
+ AudioOutputUtil::GeneratePinkSamples(frames, m_channels,
+ i, 48000);
+ if (!m_audioOutput->AddFrames(frames, 48000, -1))
+ {
+ VERBOSE(VB_AUDIO, "AddAudioData() "
+ "Audio buffer overflow, audio data lost!");
+ }
+ if (m_dialog)
+ {
+ // Send event here
+ //QApplication::postEvent(m_dialog, NULL);
+ }
+ sleep(1);
+ }
+ delete[] frames_in;
+ }
+ QString result()
+ {
+ QString errMsg;
+
+ if (!m_audioOutput)
+ errMsg = QObject::tr("Unable to create AudioOutput.");
+ else
+ errMsg = m_audioOutput->GetError();
+ return errMsg;
+ }
+ void setUIWindow(MythUIProgressDialog *dialog)
+ {
+ m_dialog = dialog;
+ }
+
+ AudioTestThread(QString main, QString pass, int channels)
+ : m_channels(channels), m_dialog(NULL)
+ {
+ m_audioOutput = AudioOutput::OpenAudio(main,
+ pass,
+ FORMAT_S16, channels,
+ 0, 48000,
+ AUDIOOUTPUT_VIDEO,
+ true, false);
+ }
+ ~AudioTestThread()
+ {
+ if (m_audioOutput)
+ delete m_audioOutput;
+ }
+
+private:
+ AudioOutput *m_audioOutput;
+ int m_channels;
+ MythUIProgressDialog *m_dialog;
+};
+
+void AudioConfigSettings::AudioTest()
+{
+ QString out = m_OutputDevice->getValue();
+ QString name;
+ int channels = m_MaxAudioChannels->getValue().toInt();
+ QString errMsg;
+
+ if (gCoreContext->GetNumSetting("PassThruDeviceOverride", false))
+ {
+ name = gCoreContext->GetSetting("PassThruOutputDevice");
+ }
+ AudioTestThread *att = new AudioTestThread(out, name, channels);
+
+ QString result = att->result();
+ if (!result.isEmpty())
+ {
+ MythPopupBox::showOkPopup(
+ GetMythMainWindow(), QObject::tr("Error"), errMsg);
+ delete att;
+ att = NULL;
+ }
+ else
+ {
+ // set MythUI recipient here
+ att->setUIWindow(NULL);
+ att->start();
+ }
+ if (att && att->wait())
+ {
+ delete att;
+ }
+}
+
+bool AudioConfigSettings::CheckPassthrough()
+{
+ m_passthrough8 = false;
+ if (gCoreContext->GetNumSetting("PassThruDeviceOverride", false))
+ {
+ QString name = gCoreContext->GetSetting("PassThruOutputDevice");
+ AudioOutput::AudioDeviceConfig *adc =
+ AudioOutput::GetAudioDeviceConfig(name, name, true);
+ if (adc->settings.IsInvalid())
+ {
+ VERBOSE(VB_IMPORTANT, QString("Passthru device %1 isn't usable "
+ "Check audio configuration").arg(name));
+ }
+ else
+ {
+ if (adc->settings.BestSupportedChannels() >= 8)
+ {
+ m_passthrough8 = true;
+ }
+ }
+ delete adc;
+ }
+ return m_passthrough8;
+}
+
+void AudioConfigSettings::UpdateVisibility(const QString &device)
+{
+ if (!m_MaxAudioChannels && !m_AudioUpmix && !m_AudioUpmixType)
+ return;
+
+ int cur_speakers = m_MaxAudioChannels->getValue().toInt();
+ m_AudioUpmix->setEnabled(cur_speakers > 2);
+ m_AudioUpmixType->setEnabled(cur_speakers > 2);
+}
+
+void AudioConfigSettings::UpdateCapabilities(const QString &device)
+{
+ int max_speakers = 8;
+ bool invalid = false;
+ AudioOutputSettings settings;
+
+ // Test if everything is set yet
+ if (!m_OutputDevice || !m_MaxAudioChannels ||
+ !m_AC3PassThrough || !m_DTSPassThrough ||
+ !m_EAC3PassThrough || !m_TrueHDPassThrough)
+ return;
+
+ if (!slotlock.tryLock()) // Doing a rescan of channels
+ return;
+
+ bool bForceDigital = gCoreContext->GetNumSetting("PassThruDeviceOverride",
+ false);
+
+ QString out = m_OutputDevice->getValue();
+ if (!audiodevs.contains(out))
+ {
+ VERBOSE(VB_AUDIO, QString("Update not found (%1)").arg(out));
+ invalid = true;
+ }
+ else
+ {
+ settings = audiodevs.value(out).settings;
+
+ max_speakers = settings.BestSupportedChannels();
+
+ bool bAC3 = (settings.canAC3() || bForceDigital) &&
+ m_AC3PassThrough->boolValue();
+ bool bDTS = (settings.canDTS() || bForceDigital) &&
+ m_DTSPassThrough->boolValue();
+ bool bLPCM = settings.canPassthrough() == -1 ||
+ (settings.canLPCM() &&
+ !gCoreContext->GetNumSetting("StereoPCM", false));
+
+ if (max_speakers > 2 && !bLPCM)
+ max_speakers = 2;
+ if (max_speakers == 2 && (bAC3 || bDTS))
+ max_speakers = 6;
+ }
+
+ m_triggerDigital->setValue(invalid || bForceDigital ||
+ settings.canAC3() || settings.canDTS());
+ m_EAC3PassThrough->setEnabled(invalid || m_passthrough8 ||
+ (settings.canPassthrough() >= 0 &&
+ max_speakers >= 8));
+ m_TrueHDPassThrough->setEnabled(invalid || m_passthrough8 ||
+ (settings.canPassthrough() >= 0 &&
+ max_speakers >= 8));
+ if (m_EAC3PassThrough->boolValue() || m_TrueHDPassThrough->boolValue())
+ {
+ max_speakers = 8;
+ }
+
+ int cur_speakers = m_MaxAudioChannels->getValue().toInt();
+
+ if (cur_speakers > max_speakers)
+ {
+ VERBOSE(VB_AUDIO, QString("Reset device %1").arg(out));
+ cur_speakers = max_speakers;
+ }
+
+ // Remove everything and re-add available channels
+ m_MaxAudioChannels->clearSelections();
+ m_MaxAudioChannels->resetMaxCount(3);
+ for (int i = 1; i <= max_speakers; i++)
+ {
+ if (invalid || settings.IsSupportedChannels(i) ||
+ (bForceDigital && i >= 6 ))
+ {
+ QString txt;
+
+ switch (i)
+ {
+ case 2:
+ txt = QObject::tr("Stereo");
+ break;
+ case 6:
+ txt = QObject::tr("5.1");
+ break;
+ case 8:
+ txt = QObject::tr("7.1");
+ break;
+ default:
+ continue;
+ }
+ m_MaxAudioChannels->addSelection(txt, QString::number(i),
+ i == cur_speakers);
+ }
+ }
+ slotlock.unlock();
+}
+
+HostComboBox *AudioConfigSettings::MaxAudioChannels()
+{
+ QString name = "MaxChannels";
+ HostComboBox *gc = new HostComboBox(name, false);
+ gc->setLabel(QObject::tr("Speaker configuration"));
+ gc->addSelection(QObject::tr("Stereo"), "2", true); // default
+ gc->setHelpText(QObject::tr("Select the maximum number of audio "
+ "channels supported by your receiver "
+ "and speakers."));
+ return gc;
+}
+
+HostCheckBox *AudioConfigSettings::AudioUpmix()
+{
+ HostCheckBox *gc = new HostCheckBox("AudioDefaultUpmix");
+ gc->setLabel(QObject::tr("Upconvert stereo to 5.1 surround"));
+ gc->setValue(true);
+ gc->setHelpText(QObject::tr("If enabled, MythTV will upconvert stereo "
+ "to 5.1 audio. You can enable or disable "
+ "the upconversion during playback at any time."));
+ return gc;
+}
+
+HostComboBox *AudioConfigSettings::AudioUpmixType()
+{
+ HostComboBox *gc = new HostComboBox("AudioUpmixType",false);
+ gc->setLabel(QObject::tr("Upmix Quality"));
+ gc->addSelection(QObject::tr("Good"), "1");
+ gc->addSelection(QObject::tr("Best"), "2", true); // default
+ gc->setHelpText(QObject::tr("Set the audio surround-upconversion quality."));
+ return gc;
+}
+
+HostCheckBox *AudioConfigSettings::AC3PassThrough()
+{
+ HostCheckBox *gc = new HostCheckBox("AC3PassThru");
+ gc->setLabel(QObject::tr("Dolby Digital"));
+ gc->setValue(false);
+ gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
+ "supports AC3/Dolby Digital. You must use a digital "
+ "connection. Uncheck if using an analog connection."));
+ return gc;
+}
+
+HostCheckBox *AudioConfigSettings::DTSPassThrough()
+{
+ HostCheckBox *gc = new HostCheckBox("DTSPassThru");
+ gc->setLabel(QObject::tr("DTS"));
+ gc->setValue(false);
+ gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
+ "supports DTS. You must use a digital connection. Uncheck "
+ "if using an analog connection"));
+ return gc;
+}
+
+HostCheckBox *AudioConfigSettings::EAC3PassThrough()
+{
+ HostCheckBox *gc = new HostCheckBox("EAC3PassThru");
+ gc->setLabel(QObject::tr("E-AC3/DTS-HD"));
+ gc->setValue(false);
+ gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
+ "supports E-AC3 (DD+) or DTS-HD. You must use a hdmi "
+ "connection."));
+ return gc;
+}
+
+HostCheckBox *AudioConfigSettings::TrueHDPassThrough()
+{
+ HostCheckBox *gc = new HostCheckBox("TrueHDPassThru");
+ gc->setLabel(QObject::tr("TrueHD"));
+ gc->setValue(false);
+ gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
+ "supports Dolby TrueHD. You must use a hdmi connection."));
+ return gc;
+}
+
+static HostCheckBox *MythControlsVolume()
+{
+ HostCheckBox *gc = new HostCheckBox("MythControlsVolume");
+ gc->setLabel(QObject::tr("Use internal volume controls"));
+ gc->setValue(true);
+ gc->setHelpText(QObject::tr("If enabled, MythTV will control the PCM and "
+ "master mixer volume. Disable this option if you prefer "
+ "to control the volume externally (for example, using "
+ "your amplifier) or if you use an external mixer program."));
+ return gc;
+}
+
+HostComboBox *AudioMixerSettings::MixerDevice()
+{
+ HostComboBox *gc = new HostComboBox("MixerDevice", true);
+ gc->setLabel(QObject::tr("Mixer device"));
+
+#ifdef USING_OSS
+ QDir dev("/dev", "mixer*", QDir::Name, QDir::System);
+ gc->fillSelectionsFromDir(dev);
+
+ dev.setPath("/dev/sound");
+ if (dev.exists())
+ {
+ gc->fillSelectionsFromDir(dev);
+ }
+#endif
+#ifdef USING_ALSA
+ gc->addSelection("ALSA:default", "ALSA:default");
+#endif
+#ifdef USING_MINGW
+ gc->addSelection("DirectX:", "DirectX:");
+ gc->addSelection("Windows:", "Windows:");
+#endif
+#if !defined(USING_MINGW)
+ gc->addSelection("software", "software");
+ gc->setHelpText(QObject::tr("Setting the mixer device to \"software\" "
+ "lets MythTV control the volume of all audio at the "
+ "expense of a slight quality loss."));
+#endif
+
+ return gc;
+}
+
+const char* AudioMixerSettings::MixerControlControls[] = { "PCM",
+ "Master" };
+
+HostComboBox *AudioMixerSettings::MixerControl()
+{
+ HostComboBox *gc = new HostComboBox("MixerControl", true);
+ gc->setLabel(QObject::tr("Mixer controls"));
+ for (unsigned int i = 0; i < sizeof(MixerControlControls) / sizeof(char*);
+ ++i)
+ {
+ gc->addSelection(QObject::tr(MixerControlControls[i]),
+ MixerControlControls[i]);
+ }
+
+ gc->setHelpText(QObject::tr("Changing the volume adjusts the selected "
+ "mixer."));
+ return gc;
+}
+
+HostSlider *AudioMixerSettings::MixerVolume()
+{
+ HostSlider *gs = new HostSlider("MasterMixerVolume", 0, 100, 1);
+ gs->setLabel(QObject::tr("Master mixer volume"));
+ gs->setValue(70);
+ gs->setHelpText(QObject::tr("Initial volume for the Master mixer. "
+ "This affects all sound created by the audio device. "
+ "Note: Do not set this too low."));
+ return gs;
+}
+
+HostSlider *AudioMixerSettings::PCMVolume()
+{
+ HostSlider *gs = new HostSlider("PCMMixerVolume", 0, 100, 1);
+ gs->setLabel(QObject::tr("PCM mixer volume"));
+ gs->setValue(70);
+ gs->setHelpText(QObject::tr("Initial volume for PCM output. Using the "
+ "volume keys in MythTV will adjust this parameter."));
+ return gs;
+}
+
+AudioMixerSettings::AudioMixerSettings() :
+ TriggeredConfigurationGroup(false, true, false, false)
+{
+ setLabel(QObject::tr("Audio Mixer"));
+ setUseLabel(false);
+
+ Setting *volumeControl = MythControlsVolume();
+ addChild(volumeControl);
+
+ // Mixer settings
+ ConfigurationGroup *settings =
+ new VerticalConfigurationGroup(false, true, false, false);
+ settings->addChild(MixerDevice());
+ settings->addChild(MixerControl());
+ settings->addChild(MixerVolume());
+ settings->addChild(PCMVolume());
+
+ ConfigurationGroup *dummy =
+ new VerticalConfigurationGroup(false, true, false, false);
+
+ // Show Mixer config only if internal volume controls enabled
+ setTrigger(volumeControl);
+ addTarget("0", dummy);
+ addTarget("1", settings);
+}
+
+AudioGeneralSettings::AudioGeneralSettings()
+{
+ addChild(new AudioConfigSettings());
+ addChild(new AudioMixerSettings());
+}
+
+HostCheckBox *AudioAdvancedSettings::MPCM()
+{
+ HostCheckBox *gc = new HostCheckBox("StereoPCM");
+ gc->setLabel(QObject::tr("Stereo PCM Only"));
+ gc->setValue(false);
+ gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
+ "only supports 2 channels PCM (typically an old HDMI 1.0 "
+ "device). Multi-channels audio will be re-encoded to AC3 "
+ "when required"));
+ return gc;
+}
+
+HostCheckBox *AudioAdvancedSettings::SRCQualityOverride()
+{
+ HostCheckBox *gc = new HostCheckBox("SRCQualityOverride");
+ gc->setLabel(QObject::tr("Override SRC quality"));
+ gc->setValue(false);
+ gc->setHelpText(QObject::tr("Enable to override audio sample rate "
+ "conversion quality."));
+ return gc;
+}
+
+HostComboBox *AudioAdvancedSettings::SRCQuality()
+{
+ HostComboBox *gc = new HostComboBox("SRCQuality", false);
+ gc->setLabel(QObject::tr("Sample rate conversion"));
+ gc->addSelection(QObject::tr("Disabled"), "-1");
+ gc->addSelection(QObject::tr("Fastest"), "0");
+ gc->addSelection(QObject::tr("Good"), "1", true); // default
+ gc->addSelection(QObject::tr("Best"), "2");
+ gc->setHelpText(QObject::tr("Set the quality of audio sample-rate "
+ "conversion. \"Good\" (default) provides the best "
+ "compromise between CPU usage and quality. \"Disabled\" "
+ "lets the audio device handle sample-rate conversion."));
+ return gc;
+}
+
+HostCheckBox *AudioAdvancedSettings::Audio48kOverride()
+{
+ HostCheckBox *gc = new HostCheckBox("Audio48kOverride");
+ gc->setLabel(QObject::tr("Force audio device output to 48kHz"));
+ gc->setValue(false);
+ gc->setHelpText(QObject::tr("Force audio sample rate to 48kHz. "
+ "Some audio devices will report various rates, "
+ "but they ultimately crash."));
+ return gc;
+}
+
+HostCheckBox *AudioAdvancedSettings::PassThroughOverride()
+{
+ HostCheckBox *gc = new HostCheckBox("PassThruDeviceOverride");
+ gc->setLabel(QObject::tr("Separate digital output device"));
+ gc->setValue(false);
+ gc->setHelpText(QObject::tr("Use a distinct digital output device from "
+ "default."));
+ return gc;
+}
+
+HostComboBox *AudioAdvancedSettings::PassThroughOutputDevice()
+{
+ HostComboBox *gc = new HostComboBox("PassThruOutputDevice", true);
+
+ gc->setLabel(QObject::tr("Digital output device"));
+ gc->addSelection(QObject::tr("Default"), "Default");
+#ifdef USING_MINGW
+ gc->addSelection("DirectX:Primary Sound Driver");
+#else
+ gc->addSelection("ALSA:iec958:{ AES0 0x02 }",
+ "ALSA:iec958:{ AES0 0x02 }");
+ gc->addSelection("ALSA:hdmi", "ALSA:hdmi");
+ gc->addSelection("ALSA:plughw:0,3", "ALSA:plughw:0,3");
+#endif
+
+ gc->setHelpText(QObject::tr("Deprecated. Audio output device to use for "
+ "digital audio. This value is currently only used "
+ "with ALSA and DirectX sound output."));
+ return gc;
+}
+
+AudioAdvancedSettings::AudioAdvancedSettings(bool mpcm)
+{
+ ConfigurationGroup *settings3 =
+ new HorizontalConfigurationGroup(false, false);
+
+ m_PassThroughOverride = PassThroughOverride();
+ TriggeredItem *sub3 =
+ new TriggeredItem(m_PassThroughOverride, PassThroughOutputDevice());
+ settings3->addChild(m_PassThroughOverride);
+ settings3->addChild(sub3);
+
+ ConfigurationGroup *settings4 =
+ new HorizontalConfigurationGroup(false, false);
+ Setting *srcqualityoverride = SRCQualityOverride();
+ TriggeredItem *sub4 =
+ new TriggeredItem(srcqualityoverride, SRCQuality());
+ settings4->addChild(srcqualityoverride);
+ settings4->addChild(sub4);
+
+ ConfigurationGroup *settings5 =
+ new HorizontalConfigurationGroup(false, false);
+ settings5->addChild(Audio48kOverride());
+
+ ConfigurationGroup *settings6;
+
+ if (mpcm)
+ {
+ settings6 = new HorizontalConfigurationGroup(false, false);
+ settings6->addChild(MPCM());
+ }
+
+ addChild(settings4);
+ addChild(settings5);
+ addChild(settings3);
+ if (mpcm)
+ {
+ addChild(settings6);
+ }
+}
+
+AudioAdvancedSettingsGroup::AudioAdvancedSettingsGroup(bool mpcm)
+{
+ addChild(new AudioAdvancedSettings(mpcm));
+}
+
+// vim:set sw=4 ts=4 expandtab:
+
diff --git a/mythtv/programs/mythfrontend/audiosettings.h b/mythtv/programs/mythfrontend/audiosettings.h
new file mode 100644
index 0000000..037a8be
--- /dev/null
+++ b/mythtv/programs/mythfrontend/audiosettings.h
@@ -0,0 +1,117 @@
+#ifndef MYTHAUDIOSETTINGS_H
+#define MYTHAUDIOSETTINGS_H
+
+#include <QStringList>
+#include <QObject>
+
+#include "settings.h"
+#include "mythcontext.h"
+
+#include <QMutex>
+#include "audiooutput.h"
+
+class AudioDeviceComboBox;
+
+class AudioConfigSettings : public VerticalConfigurationGroup
+{
+ Q_OBJECT
+
+ public:
+ AudioConfigSettings();
+
+ typedef QMap<QString,AudioOutput::AudioDeviceConfig> ADCMap;
+
+ ADCMap &AudioDeviceMap(void) { return audiodevs; };
+ AudioOutput::ADCVect &AudioDeviceVect(void) { return devices; };
+
+ private slots:
+ void UpdateVisibility(const QString&);
+ void UpdateCapabilities(const QString&);
+ void AudioRescan();
+ void AudioAdvanced();
+ void AudioTest();
+
+ private:
+ AudioDeviceComboBox *OutputDevice();
+ HostComboBox *MaxAudioChannels();
+ HostCheckBox *AudioUpmix();
+ HostComboBox *AudioUpmixType();
+ HostCheckBox *AC3PassThrough();
+ HostCheckBox *DTSPassThrough();
+ HostCheckBox *EAC3PassThrough();
+ HostCheckBox *TrueHDPassThrough();
+ bool CheckPassthrough();
+
+ ConfigurationGroup *m_cgsettings;
+ AudioDeviceComboBox *m_OutputDevice;
+ HostComboBox *m_MaxAudioChannels;
+ HostCheckBox *m_AudioUpmix;
+ HostComboBox *m_AudioUpmixType;
+ TransCheckBoxSetting *m_triggerDigital;
+ HostCheckBox *m_AC3PassThrough;
+ HostCheckBox *m_DTSPassThrough;
+ HostCheckBox *m_EAC3PassThrough;
+ HostCheckBox *m_TrueHDPassThrough;
+ ADCMap audiodevs;
+ AudioOutput::ADCVect devices;
+ QMutex slotlock;
+ bool m_passthrough8;
+};
+
+class AudioDeviceComboBox : public HostComboBox
+{
+ Q_OBJECT
+ public:
+ AudioDeviceComboBox(AudioConfigSettings*);
+ void AudioRescan();
+
+ private slots:
+ void AudioDescriptionHelp(const QString&);
+
+ private:
+ AudioConfigSettings *m_parent;
+};
+
+class AudioMixerSettings : public TriggeredConfigurationGroup
+{
+ public:
+ AudioMixerSettings();
+ private:
+ HostComboBox *MixerDevice();
+ HostComboBox *MixerControl();
+ HostSlider *MixerVolume();
+ HostSlider *PCMVolume();
+ static const char *MixerControlControls[];
+};
+
+class AudioGeneralSettings : public ConfigurationWizard
+{
+ public:
+ AudioGeneralSettings();
+};
+
+class AudioAdvancedSettings : public VerticalConfigurationGroup
+{
+ Q_OBJECT
+
+ public:
+ AudioAdvancedSettings(bool mpcm);
+ HostCheckBox *MPCM();
+ HostCheckBox *SRCQualityOverride();
+ HostComboBox *SRCQuality();
+ HostCheckBox *Audio48kOverride();
+ HostCheckBox *PassThroughOverride();
+ HostComboBox *PassThroughOutputDevice();
+
+ TransCheckBoxSetting *m_triggerMPCM;
+ HostCheckBox *m_MPCM;
+ HostCheckBox *m_PassThroughOverride;
+};
+
+class AudioAdvancedSettingsGroup : public ConfigurationWizard
+{
+ public:
+ AudioAdvancedSettingsGroup(bool mpcm);
+};
+
+#endif
diff --git a/mythtv/programs/mythfrontend/globalsettings.cpp b/mythtv/programs/mythfrontend/globalsettings.cpp
index 3e17a46..57f91a5 100644
--- a/mythtv/programs/mythfrontend/globalsettings.cpp
+++ b/mythtv/programs/mythfrontend/globalsettings.cpp
@@ -29,6 +29,7 @@
#include "iso639.h"
#include "playbackbox.h"
#include "globalsettings.h"
+#include "audiosettings.h"
#include "recordingprofile.h"
#include "mythxdisplay.h"
#include "DisplayRes.h"
@@ -39,556 +40,6 @@
#include "mythdirs.h"
#include "mythuihelper.h"
-class TriggeredItem : public TriggeredConfigurationGroup
-{
- public:
- TriggeredItem(Setting *checkbox, ConfigurationGroup *group) :
- TriggeredConfigurationGroup(false, false, false, false)
- {
- setTrigger(checkbox);
-
- addTarget("1", group);
- addTarget("0", new VerticalConfigurationGroup(true));
- }
- TriggeredItem(Setting *checkbox, Setting *setting) :
- TriggeredConfigurationGroup(false, false, false, false)
- {
- setTrigger(checkbox);
-
- addTarget("1", setting);
- addTarget("0", new VerticalConfigurationGroup(false, false));
- }
-};
-
-AudioDeviceComboBox::AudioDeviceComboBox(AudioConfigSettings *parent) :
- HostComboBox("AudioOutputDevice", true), m_parent(parent)
-{
- setLabel(QObject::tr("Audio output device"));
-#ifdef USING_ALSA
- QString dflt = "ALSA:default";
-#elif USING_PULSEOUTPUT
- QString dflt = "PulseAudio:default";
-#elif CONFIG_DARWIN
- QString dflt = "CoreAudio:";
-#elif USING_MINGW
- QString dflt = "Windows:";
-#else
- QString dflt = "NULL";
-#endif
- QString current = gCoreContext->GetSetting(QString("AudioOutputDevice"),
- dflt);
- addSelection(current, current, true);
-
- connect(this, SIGNAL(valueChanged(const QString&)),
- this, SLOT(AudioDescriptionHelp(const QString&)));
-}
-
-void AudioDeviceComboBox::AudioRescan()
-{
- AudioOutput::ADCVect &vect = m_parent->AudioDeviceVect();
- AudioOutput::ADCVect::const_iterator it;
-
- if (vect.empty())
- return;
-
- QString value = getValue();
- clearSelections();
- resetMaxCount(vect.size());
-
- bool found = false;
- for (it = vect.begin(); it != vect.end(); it++)
- addSelection(it->name, it->name,
- value == it->name ? (found = true) : false);
- if (!found)
- {
- resetMaxCount(vect.size()+1);
- addSelection(value, value, true);
- }
- // For some reason, it adds an empty entry, remove it
- removeSelection(QString::null);
-}
-
-void AudioDeviceComboBox::AudioDescriptionHelp(const QString &device)
-{
- QString desc = m_parent->AudioDeviceMap().value(device).desc;
- setHelpText(desc);
-}
-
-AudioConfigSettings::AudioConfigSettings() :
- VerticalConfigurationGroup(false, true, false, false),
- m_OutputDevice(NULL), m_MaxAudioChannels(NULL),
- m_AudioUpmix(NULL), m_AudioUpmixType(NULL),
- m_AC3PassThrough(NULL), m_DTSPassThrough(NULL), m_MPCM(NULL),
- m_AdvancedAudioSettings(NULL), m_PassThroughOverride(NULL)
-{
- setLabel(QObject::tr("Audio System"));
- setUseLabel(false);
-
- // Rescan button
- TransButtonSetting *rescan = new TransButtonSetting("rescan");
- rescan->setLabel(QObject::tr("Scan for audio devices"));
- rescan->setHelpText(QObject::tr("Scan for available audio devices. "
- "Custom entry will be scanned and "
- "capability entries populated."));
- addChild(rescan);
- connect(rescan, SIGNAL(pressed()), this, SLOT(AudioRescan()));
-
- addChild((m_OutputDevice = new AudioDeviceComboBox(this)));
-
- QString name = m_OutputDevice->getValue();
- AudioOutput::AudioDeviceConfig *adc =
- AudioOutput::GetAudioDeviceConfig(name, name, true);
- if (adc->settings.IsInvalid())
- VERBOSE(VB_IMPORTANT, QString("Audio device %1 isn't usable "
- "Check audio configuration").arg(name));
- audiodevs.insert(name, *adc);
- devices.append(*adc);
- delete adc;
-
- ConfigurationGroup *maingroup = new VerticalConfigurationGroup(false,
- false);
- addChild(maingroup);
-
- m_triggerDigital = new TransCheckBoxSetting();
- m_AC3PassThrough = AC3PassThrough();
- m_DTSPassThrough = DTSPassThrough();
-
- m_cgsettings = new HorizontalConfigurationGroup();
- m_cgsettings->setLabel(QObject::tr("Digital Audio Capabilities"));
- m_cgsettings->addChild(m_AC3PassThrough);
- m_cgsettings->addChild(m_DTSPassThrough);
-
- TriggeredItem *sub1 = new TriggeredItem(m_triggerDigital, m_cgsettings);
-
- maingroup->addChild(sub1);
-
- maingroup->addChild((m_MaxAudioChannels = MaxAudioChannels()));
- maingroup->addChild((m_AudioUpmix = AudioUpmix()));
- maingroup->addChild((m_AudioUpmixType = AudioUpmixType()));
-
- m_AdvancedAudioSettings = AdvancedAudioSettings();
- addChild(m_AdvancedAudioSettings);
-
- ConfigurationGroup *group2 =
- new VerticalConfigurationGroup(false);
-
- TriggeredItem *sub2 = new TriggeredItem(m_AdvancedAudioSettings, group2);
- addChild(sub2);
-
- ConfigurationGroup *settings3 =
- new HorizontalConfigurationGroup(false, false);
-
- m_PassThroughOverride = PassThroughOverride();
- TriggeredItem *sub3 =
- new TriggeredItem(m_PassThroughOverride, PassThroughOutputDevice());
- settings3->addChild(m_PassThroughOverride);
- settings3->addChild(sub3);
-
- ConfigurationGroup *settings4 =
- new HorizontalConfigurationGroup(false, false);
- Setting *srcqualityoverride = SRCQualityOverride();
- TriggeredItem *sub4 =
- new TriggeredItem(srcqualityoverride, SRCQuality());
- settings4->addChild(srcqualityoverride);
- settings4->addChild(sub4);
-
- ConfigurationGroup *settings5 =
- new HorizontalConfigurationGroup(false, false);
- settings5->addChild(Audio48kOverride());
-
- m_triggerMPCM = new TransCheckBoxSetting();
- m_MPCM = MPCM();
- TriggeredItem *subMPCM = new TriggeredItem(m_triggerMPCM, m_MPCM);
-
- ConfigurationGroup *settings6 =
- new HorizontalConfigurationGroup(false, false);
- settings6->addChild(subMPCM);
-
- group2->addChild(settings4);
- group2->addChild(settings5);
- group2->addChild(settings3);
- group2->addChild(settings6);
-
- // Set slots
- connect(m_MaxAudioChannels, SIGNAL(valueChanged(const QString&)),
- this, SLOT(UpdateVisibility(const QString&)));
- connect(m_OutputDevice, SIGNAL(valueChanged(const QString&)),
- this, SLOT(UpdateCapabilities(const QString&)));
- connect(m_AC3PassThrough, SIGNAL(valueChanged(const QString&)),
- this, SLOT(UpdateCapabilities(const QString&)));
- connect(m_DTSPassThrough, SIGNAL(valueChanged(const QString&)),
- this, SLOT(UpdateCapabilities(const QString&)));
- connect(m_MPCM, SIGNAL(valueChanged(const QString&)),
- this, SLOT(UpdateCapabilities(const QString&)));
- connect(m_PassThroughOverride, SIGNAL(valueChanged(const QString&)),
- this, SLOT(UpdateCapabilities(const QString&)));
- connect(m_AdvancedAudioSettings, SIGNAL(valueChanged(const QString&)),
- this, SLOT(UpdateCapabilities(const QString&)));
-}
-
-void AudioConfigSettings::AudioRescan()
-{
- if (!slotlock.tryLock())
- return;
-
- QVector<AudioOutput::AudioDeviceConfig>* list =
- AudioOutput::GetOutputList();
- QVector<AudioOutput::AudioDeviceConfig>::const_iterator it;
-
- audiodevs.clear();
- for (it = list->begin(); it != list->end(); it++)
- audiodevs.insert(it->name, *it);
-
- devices = *list;
- delete list;
-
- QString name = m_OutputDevice->getValue();
- if (!audiodevs.contains(name))
- {
- // Scan for possible custom entry that isn't in the list
- AudioOutput::AudioDeviceConfig *adc =
- AudioOutput::GetAudioDeviceConfig(name, name, true);
- if (adc->settings.IsInvalid())
- {
- QString msg = name + QObject::tr(" is invalid or not useable.");
- MythPopupBox::showOkPopup(
- GetMythMainWindow(), QObject::tr("Warning"), msg);
- VERBOSE(VB_IMPORTANT, QString("Audio device %1 isn't usable ")
- .arg(name));
- }
- audiodevs.insert(name, *adc);
- devices.append(*adc);
- delete adc;
- }
- m_OutputDevice->AudioRescan();
- slotlock.unlock();
- UpdateCapabilities(QString::null);
-}
-
-void AudioConfigSettings::UpdateVisibility(const QString &device)
-{
- if (!m_MaxAudioChannels && !m_AudioUpmix && !m_AudioUpmixType)
- return;
-
- int cur_speakers = m_MaxAudioChannels->getValue().toInt();
- m_AudioUpmix->setEnabled(cur_speakers > 2);
- m_AudioUpmixType->setEnabled(cur_speakers > 2);
-}
-
-void AudioConfigSettings::UpdateCapabilities(const QString &device)
-{
- int max_speakers = 8;
- bool invalid = false;
- AudioOutputSettings settings;
-
- // Test if everything is set yet
- if (!m_OutputDevice || !m_MaxAudioChannels || !m_AdvancedAudioSettings ||
- !m_AC3PassThrough || !m_DTSPassThrough || !m_MPCM ||
- !m_PassThroughOverride)
- return;
-
- if (!slotlock.tryLock()) // Doing a rescan of channels
- return;
-
- bool bForceDigital = (m_AdvancedAudioSettings->boolValue() &&
- m_PassThroughOverride->boolValue());
-
- QString out = m_OutputDevice->getValue();
- if (!audiodevs.contains(out))
- {
- VERBOSE(VB_AUDIO, QString("Update not found (%1)").arg(out));
- invalid = true;
- }
- else
- {
- settings = audiodevs.value(out).settings;
-
- max_speakers = settings.BestSupportedChannels();
-
- bool bAC3 = (settings.canAC3() || bForceDigital) &&
- m_AC3PassThrough->boolValue();
- bool bDTS = (settings.canDTS() || bForceDigital) &&
- m_DTSPassThrough->boolValue();
- bool bLPCM = settings.canPassthrough() == -1 ||
- (settings.canLPCM() &&
- m_AdvancedAudioSettings->boolValue() && !m_MPCM->boolValue());
-
- if (max_speakers > 2 && !bLPCM)
- max_speakers = 2;
- if (max_speakers == 2 && (bAC3 || bDTS))
- max_speakers = 6;
- }
-
- m_triggerDigital->setValue(invalid || bForceDigital ||
- settings.canAC3() || settings.canDTS());
- m_triggerMPCM->setValue(invalid || (settings.canLPCM() &&
- settings.canPassthrough() >= 0));
-
- int cur_speakers = m_MaxAudioChannels->getValue().toInt();
-
- if (cur_speakers > max_speakers)
- {
- VERBOSE(VB_AUDIO, QString("Reset device %1").arg(out));
- cur_speakers = max_speakers;
- }
-
- // Remove everything and re-add available channels
- m_MaxAudioChannels->clearSelections();
- m_MaxAudioChannels->resetMaxCount(3);
- for (int i = 1; i <= max_speakers; i++)
- {
- if (invalid || settings.IsSupportedChannels(i) ||
- (bForceDigital && i == 6))
- {
- QString txt;
-
- switch (i)
- {
- case 2:
- txt = QObject::tr("Stereo");
- break;
- case 6:
- txt = QObject::tr("5.1");
- break;
- case 8:
- txt = QObject::tr("7.1");
- break;
- default:
- continue;
- }
- m_MaxAudioChannels->addSelection(txt, QString::number(i),
- i == cur_speakers);
- }
- }
- slotlock.unlock();
-}
-
-HostComboBox *AudioConfigSettings::MaxAudioChannels()
-{
- QString name = "MaxChannels";
- HostComboBox *gc = new HostComboBox(name, false);
- gc->setLabel(QObject::tr("Speaker configuration"));
- gc->addSelection(QObject::tr("Stereo"), "2", true); // default
- gc->setHelpText(QObject::tr("Select the maximum number of audio "
- "channels supported by your receiver "
- "and speakers."));
- return gc;
-}
-
-HostCheckBox *AudioConfigSettings::AudioUpmix()
-{
- HostCheckBox *gc = new HostCheckBox("AudioDefaultUpmix");
- gc->setLabel(QObject::tr("Upconvert stereo to 5.1 surround"));
- gc->setValue(true);
- gc->setHelpText(QObject::tr("If enabled, MythTV will upconvert stereo "
- "to 5.1 audio. You can enable or disable "
- "the upconversion during playback at any time."));
- return gc;
-}
-
-HostComboBox *AudioConfigSettings::AudioUpmixType()
-{
- HostComboBox *gc = new HostComboBox("AudioUpmixType",false);
- gc->setLabel(QObject::tr("Upmix Quality"));
- gc->addSelection(QObject::tr("Good"), "1");
- gc->addSelection(QObject::tr("Best"), "2", true); // default
- gc->setHelpText(QObject::tr("Set the audio surround-upconversion quality."));
- return gc;
-}
-
-HostCheckBox *AudioConfigSettings::AC3PassThrough()
-{
- HostCheckBox *gc = new HostCheckBox("AC3PassThru");
- gc->setLabel(QObject::tr("Dolby Digital"));
- gc->setValue(false);
- gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
- "supports AC3/Dolby Digital. You must use a digital "
- "connection. Uncheck if using an analog connection."));
- return gc;
-}
-
-HostCheckBox *AudioConfigSettings::DTSPassThrough()
-{
- HostCheckBox *gc = new HostCheckBox("DTSPassThru");
- gc->setLabel(QObject::tr("DTS"));
- gc->setValue(false);
- gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
- "supports DTS. You must use a digital connection. Uncheck "
- "if using an analog connection"));
- return gc;
-}
-
-HostCheckBox *AudioConfigSettings::MPCM()
-{
- HostCheckBox *gc = new HostCheckBox("StereoPCM");
- gc->setLabel(QObject::tr("Stereo PCM Only"));
- gc->setValue(false);
- gc->setHelpText(QObject::tr("Enable if your amplifier or sound decoder "
- "only supports 2 channels PCM (typically an old HDMI 1.0 "
- "device). Multi-channels audio will be re-encoded to AC3 "
- "when required"));
- return gc;
-}
-
-HostCheckBox *AudioConfigSettings::AdvancedAudioSettings()
-{
- HostCheckBox *gc = new HostCheckBox("AdvancedAudioSettings");
- gc->setLabel(QObject::tr("Advanced audio configuration"));
- gc->setValue(false);
- gc->setHelpText(QObject::tr("Enable extra audio settings."));
- return gc;
-}
-
-HostCheckBox *AudioConfigSettings::SRCQualityOverride()
-{
- HostCheckBox *gc = new HostCheckBox("SRCQualityOverride");
- gc->setLabel(QObject::tr("Override SRC quality"));
- gc->setValue(false);
- gc->setHelpText(QObject::tr("Enable to override audio sample rate "
- "conversion quality."));
- return gc;
-}
-
-HostComboBox *AudioConfigSettings::SRCQuality()
-{
- HostComboBox *gc = new HostComboBox("SRCQuality", false);
- gc->setLabel(QObject::tr("Sample rate conversion"));
- gc->addSelection(QObject::tr("Disabled"), "-1");
- gc->addSelection(QObject::tr("Fastest"), "0");
- gc->addSelection(QObject::tr("Good"), "1", true); // default
- gc->addSelection(QObject::tr("Best"), "2");
- gc->setHelpText(QObject::tr("Set the quality of audio sample-rate "
- "conversion. \"Good\" (default) provides the best "
- "compromise between CPU usage and quality. \"Disabled\" "
- "lets the audio device handle sample-rate conversion."));
- return gc;
-}
-
-HostCheckBox *AudioConfigSettings::Audio48kOverride()
-{
- HostCheckBox *gc = new HostCheckBox("Audio48kOverride");
- gc->setLabel(QObject::tr("Force audio device output to 48kHz"));
- gc->setValue(false);
- gc->setHelpText(QObject::tr("Force audio sample rate to 48kHz. "
- "Some audio devices will report various rates, "
- "but they ultimately crash."));
- return gc;
-}
-
-HostCheckBox *AudioConfigSettings::PassThroughOverride()
-{
- HostCheckBox *gc = new HostCheckBox("PassThruDeviceOverride");
- gc->setLabel(QObject::tr("Separate digital output device"));
- gc->setValue(false);
- gc->setHelpText(QObject::tr("Use a distinct digital output device from "
- "default."));
- return gc;
-}
-
-HostComboBox *AudioConfigSettings::PassThroughOutputDevice()
-{
- HostComboBox *gc = new HostComboBox("PassThruOutputDevice", true);
-
- gc->setLabel(QObject::tr("Digital output device"));
- gc->addSelection(QObject::tr("Default"), "Default");
-#ifdef USING_MINGW
- gc->addSelection("DirectX:Primary Sound Driver");
-#else
- gc->addSelection("ALSA:iec958:{ AES0 0x02 }",
- "ALSA:iec958:{ AES0 0x02 }");
- gc->addSelection("ALSA:hdmi", "ALSA:hdmi");
- gc->addSelection("ALSA:plughw:0,3", "ALSA:plughw:0,3");
-#endif
-
- gc->setHelpText(QObject::tr("Deprecated. Audio output device to use for "
- "digital audio. This value is currently only used "
- "with ALSA and DirectX sound output."));
- return gc;
-}
-
-static HostCheckBox *MythControlsVolume()
-{
- HostCheckBox *gc = new HostCheckBox("MythControlsVolume");
- gc->setLabel(QObject::tr("Use internal volume controls"));
- gc->setValue(true);
- gc->setHelpText(QObject::tr("If enabled, MythTV will control the PCM and "
- "master mixer volume. Disable this option if you prefer "
- "to control the volume externally (for example, using "
- "your amplifier) or if you use an external mixer program."));
- return gc;
-}
-
-static HostComboBox *MixerDevice()
-{
- HostComboBox *gc = new HostComboBox("MixerDevice", true);
- gc->setLabel(QObject::tr("Mixer device"));
-
-#ifdef USING_OSS
- QDir dev("/dev", "mixer*", QDir::Name, QDir::System);
- gc->fillSelectionsFromDir(dev);
-
- dev.setPath("/dev/sound");
- if (dev.exists())
- {
- gc->fillSelectionsFromDir(dev);
- }
-#endif
-#ifdef USING_ALSA
- gc->addSelection("ALSA:default", "ALSA:default");
-#endif
-#ifdef USING_MINGW
- gc->addSelection("DirectX:", "DirectX:");
- gc->addSelection("Windows:", "Windows:");
-#endif
-#if !defined(USING_MINGW)
- gc->addSelection("software", "software");
- gc->setHelpText(QObject::tr("Setting the mixer device to \"software\" "
- "lets MythTV control the volume of all audio at the "
- "expense of a slight quality loss."));
-#endif
-
- return gc;
-}
-
-static const char* MixerControlControls[] = { "PCM",
- "Master" };
-
-static HostComboBox *MixerControl()
-{
- HostComboBox *gc = new HostComboBox("MixerControl", true);
- gc->setLabel(QObject::tr("Mixer controls"));
- for (unsigned int i = 0; i < sizeof(MixerControlControls) / sizeof(char*);
- ++i)
- {
- gc->addSelection(QObject::tr(MixerControlControls[i]),
- MixerControlControls[i]);
- }
-
- gc->setHelpText(QObject::tr("Changing the volume adjusts the selected mixer."));
- return gc;
-}
-
-static HostSlider *MixerVolume()
-{
- HostSlider *gs = new HostSlider("MasterMixerVolume", 0, 100, 1);
- gs->setLabel(QObject::tr("Master mixer volume"));
- gs->setValue(70);
- gs->setHelpText(QObject::tr("Initial volume for the Master mixer. "
- "This affects all sound created by the audio device. "
- "Note: Do not set this too low."));
- return gs;
-}
-
-static HostSlider *PCMVolume()
-{
- HostSlider *gs = new HostSlider("PCMMixerVolume", 0, 100, 1);
- gs->setLabel(QObject::tr("PCM mixer volume"));
- gs->setValue(70);
- gs->setHelpText(QObject::tr("Initial volume for PCM output. Using the "
- "volume keys in MythTV will adjust this parameter."));
- return gs;
-}
-
static HostCheckBox *DecodeExtraAudio()
{
HostCheckBox *gc = new HostCheckBox("DecodeExtraAudio");
@@ -3196,36 +2647,6 @@ static HostSpinBox *EPGRecThreshold()
return gs;
}
-class AudioMixerSettingsGroup : public TriggeredConfigurationGroup
-{
- public:
- AudioMixerSettingsGroup() :
- TriggeredConfigurationGroup(false, true, false, false)
- {
- setLabel(QObject::tr("Audio Mixer"));
- setUseLabel(false);
-
- Setting *volumeControl = MythControlsVolume();
- addChild(volumeControl);
-
- // Mixer settings
- ConfigurationGroup *settings =
- new VerticalConfigurationGroup(false, true, false, false);
- settings->addChild(MixerDevice());
- settings->addChild(MixerControl());
- settings->addChild(MixerVolume());
- settings->addChild(PCMVolume());
-
- ConfigurationGroup *dummy =
- new VerticalConfigurationGroup(false, true, false, false);
-
- // Show Mixer config only if internal volume controls enabled
- setTrigger(volumeControl);
- addTarget("0", dummy);
- addTarget("1", settings);
- }
-};
-
static HostComboBox *MythLanguage()
{
HostComboBox *gc = new HostComboBox("Language");
@@ -3923,10 +3344,6 @@ MainGeneralSettings::MainGeneralSettings()
pin->addChild(SetupPinCode());
addChild(pin);
- addChild(new AudioConfigSettings());
-
- addChild(new AudioMixerSettingsGroup());
-
VerticalConfigurationGroup *general =
new VerticalConfigurationGroup(false, true, false, false);
general->setLabel(QObject::tr("General"));
diff --git a/mythtv/programs/mythfrontend/globalsettings.h b/mythtv/programs/mythfrontend/globalsettings.h
index 7c9b4d5..90cb98a 100644
--- a/mythtv/programs/mythfrontend/globalsettings.h
+++ b/mythtv/programs/mythfrontend/globalsettings.h
@@ -9,73 +9,8 @@
#include "videodisplayprofile.h"
#include <QMutex>
-#include "audiooutput.h"
class QFileInfo;
-class AudioDeviceComboBox;
-
-class AudioConfigSettings : public VerticalConfigurationGroup
-{
- Q_OBJECT
-
- public:
- AudioConfigSettings();
-
- typedef QMap<QString,AudioOutput::AudioDeviceConfig> ADCMap;
-
- ADCMap &AudioDeviceMap(void) { return audiodevs; };
- AudioOutput::ADCVect &AudioDeviceVect(void) { return devices; };
-
- private slots:
- void UpdateVisibility(const QString&);
- void UpdateCapabilities(const QString&);
- void AudioRescan();
-
- private:
- AudioDeviceComboBox *OutputDevice();
- HostComboBox *MaxAudioChannels();
- HostCheckBox *AudioUpmix();
- HostComboBox *AudioUpmixType();
- HostCheckBox *AC3PassThrough();
- HostCheckBox *DTSPassThrough();
- HostCheckBox *MPCM();
- HostCheckBox *AdvancedAudioSettings();
- HostCheckBox *SRCQualityOverride();
- HostComboBox *SRCQuality();
- HostCheckBox *Audio48kOverride();
- HostCheckBox *PassThroughOverride();
- HostComboBox *PassThroughOutputDevice();
-
- ConfigurationGroup *m_cgsettings;
- AudioDeviceComboBox *m_OutputDevice;
- HostComboBox *m_MaxAudioChannels;
- HostCheckBox *m_AudioUpmix;
- HostComboBox *m_AudioUpmixType;
- TransCheckBoxSetting *m_triggerDigital;
- TransCheckBoxSetting *m_triggerMPCM;
- HostCheckBox *m_AC3PassThrough;
- HostCheckBox *m_DTSPassThrough;
- HostCheckBox *m_MPCM;
- HostCheckBox *m_AdvancedAudioSettings;
- HostCheckBox *m_PassThroughOverride;
- ADCMap audiodevs;
- AudioOutput::ADCVect devices;
- QMutex slotlock;
-};
-
-class AudioDeviceComboBox : public HostComboBox
-{
- Q_OBJECT
- public:
- AudioDeviceComboBox(AudioConfigSettings*);
- void AudioRescan();
-
- private slots:
- void AudioDescriptionHelp(const QString&);
-
- private:
- AudioConfigSettings *m_parent;
-};
class ThemeSelector : public HostImageSelect
{
diff --git a/mythtv/programs/mythfrontend/main.cpp b/mythtv/programs/mythfrontend/main.cpp
index 7b42569..feec308 100644
--- a/mythtv/programs/mythfrontend/main.cpp
+++ b/mythtv/programs/mythfrontend/main.cpp
@@ -33,7 +33,9 @@ using namespace std;
#include "programrecpriority.h"
#include "channelrecpriority.h"
#include "custompriority.h"
+#include "audiooutput.h"
#include "globalsettings.h"
+#include "audiosettings.h"
#include "profilegroup.h"
#include "playgroup.h"
#include "networkcontrol.h"
@@ -593,6 +595,11 @@ static void TVMenuCallback(void *data, QString &selection)
QStringList strlist( QString("REFRESH_BACKEND") );
gCoreContext->SendReceiveStringList(strlist);
}
+ else if (sel == "settings audiogeneral")
+ {
+ AudioGeneralSettings audiosettings;
+ audiosettings.exec();
+ }
else if (sel == "settings playback")
{
PlaybackSettings settings;
diff --git a/mythtv/programs/mythfrontend/mythfrontend.pro b/mythtv/programs/mythfrontend/mythfrontend.pro
index 6531079..2b161ff 100644
--- a/mythtv/programs/mythfrontend/mythfrontend.pro
+++ b/mythtv/programs/mythfrontend/mythfrontend.pro
@@ -20,7 +20,7 @@ INSTALLS += setting
QMAKE_CLEAN += $(TARGET)
# Input
-HEADERS += playbackbox.h viewscheduled.h globalsettings.h
+HEADERS += playbackbox.h viewscheduled.h globalsettings.h audiosettings.h
HEADERS += manualschedule.h programrecpriority.h channelrecpriority.h
HEADERS += statusbox.h networkcontrol.h custompriority.h
HEADERS += mediarenderer.h mythfexml.h playbackboxlistitem.h
@@ -33,7 +33,7 @@ HEADERS += proglist.h proglist_helpers.h
HEADERS += playbackboxhelper.h viewschedulediff.h
HEADERS += themechooser.h
-SOURCES += main.cpp playbackbox.cpp viewscheduled.cpp
+SOURCES += main.cpp playbackbox.cpp viewscheduled.cpp audiosettings.cpp
SOURCES += globalsettings.cpp manualschedule.cpp programrecpriority.cpp
SOURCES += channelrecpriority.cpp statusbox.cpp networkcontrol.cpp
SOURCES += mediarenderer.cpp mythfexml.cpp playbackboxlistitem.cpp
diff --git a/mythtv/themes/DVR/main_settings.xml b/mythtv/themes/DVR/main_settings.xml
index 2472b9a..8d1b5f8 100644
--- a/mythtv/themes/DVR/main_settings.xml
+++ b/mythtv/themes/DVR/main_settings.xml
@@ -23,6 +23,13 @@
</button>
<button>
+ <type>SETTINGS_AUDIOGENERAL</type>
+ <text>Audio</text>
+ <description>Configure local audio output</description>
+ <action>SETTINGS AUDIOGENERAL</action>
+ </button>
+
+ <button>
<type>SCREENSETUPWIZARD</type>
<text>Screen Setup Wizards</text>
<description>Compensate for TVs with overscan</description>
diff --git a/mythtv/themes/MythCenter-wide/menu-ui.xml b/mythtv/themes/MythCenter-wide/menu-ui.xml
index 44d8178..e37aad5 100644
--- a/mythtv/themes/MythCenter-wide/menu-ui.xml
+++ b/mythtv/themes/MythCenter-wide/menu-ui.xml
@@ -286,6 +286,7 @@
<filename>watermark/appearance.png</filename>
</imagetype>
</state>
+ <state name="SETTINGS_AUDIOGENERAL" from="SETUP" />
<state name="SCREENSETUPWIZARD" from="DEFAULT">
<imagetype name="watermark">
<filename>watermark/screenwiz.png</filename>
diff --git a/mythtv/themes/MythCenter/menu-ui.xml b/mythtv/themes/MythCenter/menu-ui.xml
index d350b7d..0a22c67 100644
--- a/mythtv/themes/MythCenter/menu-ui.xml
+++ b/mythtv/themes/MythCenter/menu-ui.xml
@@ -281,6 +281,7 @@
<filename>watermark/appearance.png</filename>
</imagetype>
</state>
+ <state name="SETTINGS_GENERAL" from="SETUP" />
<state name="SCREENSETUPWIZARD" from="DEFAULT">
<imagetype name="watermark">
<filename>watermark/screenwiz.png</filename>
diff --git a/mythtv/themes/classic/main_settings.xml b/mythtv/themes/classic/main_settings.xml
index 986021d..742c6e4 100644
--- a/mythtv/themes/classic/main_settings.xml
+++ b/mythtv/themes/classic/main_settings.xml
@@ -23,6 +23,13 @@
</button>
<button>
+ <type>SETTINGS_AUDIOGENERAL</type>
+ <text>Audio</text>
+ <description>Configure local audio output</description>
+ <action>SETTINGS AUDIOGENERAL</action>
+ </button>
+
+ <button>
<type>SCREENSETUPWIZARD</type>
<text>Screen Setup Wizards</text>
<description>Compensate for TVs with overscan</description>
diff --git a/mythtv/themes/defaultmenu/main_settings.xml b/mythtv/themes/defaultmenu/main_settings.xml
index a251a3d..a3e43b6 100644
--- a/mythtv/themes/defaultmenu/main_settings.xml
+++ b/mythtv/themes/defaultmenu/main_settings.xml
@@ -23,6 +23,13 @@
</button>
<button>
+ <type>SETTINGS_AUDIOGENERAL</type>
+ <text>Audio</text>
+ <description>Configure local audio output</description>
+ <action>SETTINGS AUDIOGENERAL</action>
+ </button>
+
+ <button>
<type>SCREENSETUPWIZARD</type>
<text>Screen Setup Wizards</text>
<description>Compensate for TVs with overscan</description>
diff --git a/mythtv/themes/mediacentermenu/main_settings.xml b/mythtv/themes/mediacentermenu/main_settings.xml
index 60cdedc..d05b3cf 100644
--- a/mythtv/themes/mediacentermenu/main_settings.xml
+++ b/mythtv/themes/mediacentermenu/main_settings.xml
@@ -23,6 +23,13 @@
</button>
<button>
+ <type>SETTINGS_AUDIOGENERAL</type>
+ <text>Audio</text>
+ <description>Configure local audio output</description>
+ <action>SETTINGS AUDIOGENERAL</action>
+ </button>
+
+ <button>
<type>SCREENSETUPWIZARD</type>
<text>Screen Setup Wizards</text>
<description>Compensate for TVs with overscan</description>