Index: libs/libmythtv/NuppelVideoPlayer.cpp
===================================================================
--- libs/libmythtv/NuppelVideoPlayer.cpp	(revision 15618)
+++ libs/libmythtv/NuppelVideoPlayer.cpp	(working copy)
@@ -206,6 +206,7 @@
       audio_passthru_device(QString::null),
       audio_channels(2),            audio_bits(-1),
       audio_samplerate(44100),      audio_stretchfactor(1.0f),
+      audio_codec(NULL),
       // Picture-in-Picture
       pipplayer(NULL), setpipplayer(NULL), needsetpipplayer(false),
       // Preview window support
@@ -767,7 +768,8 @@
     if (audioOutput)
     {
         audioOutput->Reconfigure(audio_bits, audio_channels,
-                                 audio_samplerate, audio_passthru);
+                                 audio_samplerate, audio_passthru,
+                                 audio_codec);
         errMsg = audioOutput->GetError();
         if (!errMsg.isEmpty())
             audioOutput->SetStretchFactor(audio_stretchfactor);
@@ -3650,6 +3652,11 @@
     audio_passthru = passthru;
 }
 
+void NuppelVideoPlayer::SetAudioCodec(void *ac)
+{
+    audio_codec = ac;
+}
+
 void NuppelVideoPlayer::SetEffDsp(int dsprate)
 {
     if (audioOutput)
Index: libs/libmythtv/avformatdecoder.cpp
===================================================================
--- libs/libmythtv/avformatdecoder.cpp	(revision 15618)
+++ libs/libmythtv/avformatdecoder.cpp	(working copy)
@@ -51,9 +51,6 @@
 
 #define MAX_AC3_FRAME_SIZE 6144
 
-/** Set to zero to allow any number of AC3 channels. */
-#define MAX_OUTPUT_CHANNELS 2
-
 static int cc608_parity(uint8_t byte);
 static int cc608_good_parity(const int *parity_table, uint16_t data);
 static void cc608_build_parity_table(int *parity_table);
@@ -400,7 +397,8 @@
       // Audio
       audioSamples(new short int[AVCODEC_MAX_AUDIO_FRAME_SIZE]),
       allow_ac3_passthru(false),    allow_dts_passthru(false),
-      disable_passthru(false),      dummy_frame(NULL),
+      disable_passthru(false),      max_channels(2),
+      dummy_frame(NULL),
       // DVD
       lastdvdtitle(-1), lastcellstart(0),
       dvdmenupktseen(false), indvdstill(false),
@@ -417,6 +415,7 @@
 
     allow_ac3_passthru = gContext->GetNumSetting("AC3PassThru", false);
     allow_dts_passthru = gContext->GetNumSetting("DTSPassThru", false);
+    max_channels = (uint) gContext->GetNumSetting("MaxChannels", 2);
 
     audioIn.sample_size = -32; // force SetupAudioStream to run once
     itv = GetNVP()->GetInteractiveTV();
@@ -1587,7 +1586,13 @@
                             <<") already open, leaving it alone.");
                 }
                 //assert(enc->codec_id);
+                VERBOSE(VB_GENERAL, LOC + QString("codec %1 has %2 channels")
+                        .arg(codec_id_string(enc->codec_id))
+                        .arg(enc->channels));
 
+#if 0
+                // HACK MULTICHANNEL DTS passthru disabled for multichannel,
+                // dont know how to handle this
                 // HACK BEGIN REALLY UGLY HACK FOR DTS PASSTHRU
                 if (enc->codec_id == CODEC_ID_DTS)
                 {
@@ -1596,6 +1601,7 @@
                     // enc->bit_rate = what??;
                 }
                 // HACK END REALLY UGLY HACK FOR DTS PASSTHRU
+#endif
 
                 bitrate += enc->bit_rate;
                 break;
@@ -3288,7 +3294,11 @@
                     if (!curstream->codec->channels)
                     {
                         QMutexLocker locker(&avcodeclock);
-                        curstream->codec->channels = MAX_OUTPUT_CHANNELS;
+                        VERBOSE(VB_IMPORTANT, LOC +
+                                QString("Setting channels to %1")
+                                .arg(audioOut.channels));
+
+                        curstream->codec->channels = audioOut.channels;
                         ret = avcodec_decode_audio(
                             curstream->codec, audioSamples,
                             &data_size, ptr, len);
@@ -3349,8 +3359,8 @@
                         AVCodecContext *ctx = curstream->codec;
 
                         if ((ctx->channels == 0) ||
-                            (ctx->channels > MAX_OUTPUT_CHANNELS))
-                            ctx->channels = MAX_OUTPUT_CHANNELS;
+                            (ctx->channels > audioOut.channels))
+                            ctx->channels = audioOut.channels;
 
                         ret = avcodec_decode_audio(
                             ctx, audioSamples, &data_size, ptr, len);
@@ -3783,6 +3793,11 @@
 
 void AvFormatDecoder::SetDisablePassThrough(bool disable)
 {
+    // can only disable never reenable as once
+    // timestretch is on its on for the session
+    if (disable_passthru)
+        return;
+
     if (selectedTrack[kTrackTypeAudio].av_stream_index < 0)
     {
         disable_passthru = disable;
@@ -3815,6 +3830,7 @@
     AVCodecContext *codec_ctx = NULL;
     AudioInfo old_in  = audioIn;
     AudioInfo old_out = audioOut;
+    bool using_passthru = false;
 
     if ((currentTrack[kTrackTypeAudio] >= 0) &&
         (selectedTrack[kTrackTypeAudio].av_stream_index <=
@@ -3826,37 +3842,62 @@
         assert(curstream->codec);
         codec_ctx = curstream->codec;        
         bool do_ac3_passthru = (allow_ac3_passthru && !transcoding &&
-                                !disable_passthru &&
                                 (codec_ctx->codec_id == CODEC_ID_AC3));
         bool do_dts_passthru = (allow_dts_passthru && !transcoding &&
-                                !disable_passthru &&
                                 (codec_ctx->codec_id == CODEC_ID_DTS));
+        using_passthru = do_ac3_passthru || do_dts_passthru;
         info = AudioInfo(codec_ctx->codec_id,
                          codec_ctx->sample_rate, codec_ctx->channels,
-                         do_ac3_passthru || do_dts_passthru);
+                         using_passthru && !disable_passthru);
     }
 
     if (info == audioIn)
         return false; // no change
 
+    QString ptmsg = (using_passthru) ? " using passthru" : "";
     VERBOSE(VB_AUDIO, LOC + "Initializing audio parms from " +
             QString("audio track #%1").arg(currentTrack[kTrackTypeAudio]+1));
 
     audioOut = audioIn = info;
-    if (audioIn.do_passthru)
+    if (using_passthru)
     {
         // A passthru stream looks like a 48KHz 2ch (@ 16bit) to the sound card
-        audioOut.channels    = 2;
-        audioOut.sample_rate = 48000;
-        audioOut.sample_size = 4;
+        AudioInfo digInfo = audioOut;
+        if (!disable_passthru)
+        {
+            digInfo.channels    = 2;
+            digInfo.sample_rate = 48000;
+            digInfo.sample_size = 4;
+        }
+        if (audioOut.channels > (int) max_channels)
+        {
+            audioOut.channels = (int) max_channels;
+            audioOut.sample_size = audioOut.channels * 2;
+            codec_ctx->channels = audioOut.channels;
+        }
+        VERBOSE(VB_AUDIO, LOC + "Audio format changed digital passthrough " +
+                QString("%1\n\t\t\tfrom %2 ; %3\n\t\t\tto   %4 ; %5")
+                .arg(digInfo.toString())
+                .arg(old_in.toString()).arg(old_out.toString())
+                .arg(audioIn.toString()).arg(audioOut.toString()));
+
+        if (digInfo.sample_rate > 0)
+            GetNVP()->SetEffDsp(digInfo.sample_rate * 100);
+
+        GetNVP()->SetAudioParams(digInfo.bps(), digInfo.channels,
+                                 digInfo.sample_rate, audioIn.do_passthru);
+        // allow the audio stuff to reencode
+        GetNVP()->SetAudioCodec(codec_ctx);
+        GetNVP()->ReinitAudio();
+        return true;
     }
     else
     {
-        if (audioOut.channels > MAX_OUTPUT_CHANNELS)
+        if (audioOut.channels > (int) max_channels)
         {
-            audioOut.channels = MAX_OUTPUT_CHANNELS;
+            audioOut.channels = (int) max_channels;
             audioOut.sample_size = audioOut.channels * 2;
-            codec_ctx->channels = MAX_OUTPUT_CHANNELS;
+            codec_ctx->channels = audioOut.channels;
         }
     }
 
@@ -3871,8 +3912,12 @@
     GetNVP()->SetAudioParams(audioOut.bps(), audioOut.channels,
                              audioOut.sample_rate,
                              audioIn.do_passthru);
-    GetNVP()->ReinitAudio();
 
+    // allow the audio stuff to reencode
+    GetNVP()->SetAudioCodec(using_passthru?codec_ctx:NULL);
+    QString errMsg = GetNVP()->ReinitAudio();
+    bool audiook = errMsg.isEmpty();
+
     return true;
 }
 
Index: libs/libmythtv/NuppelVideoPlayer.h
===================================================================
--- libs/libmythtv/NuppelVideoPlayer.h	(revision 15618)
+++ libs/libmythtv/NuppelVideoPlayer.h	(working copy)
@@ -127,6 +127,7 @@
     void SetAudioInfo(const QString &main, const QString &passthru, uint rate);
     void SetAudioParams(int bits, int channels, int samplerate, bool passthru);
     void SetEffDsp(int dsprate);
+    void SetAudioCodec(void *ac);
 
     // Sets
     void SetParentWidget(QWidget *widget)     { parentWidget = widget; }
@@ -683,6 +684,7 @@
     int      audio_bits;
     int      audio_samplerate;
     float    audio_stretchfactor;
+    void    *audio_codec;
     bool     audio_passthru;
 
     // Picture-in-Picture
Index: libs/libmythtv/avformatdecoder.h
===================================================================
--- libs/libmythtv/avformatdecoder.h	(revision 15618)
+++ libs/libmythtv/avformatdecoder.h	(working copy)
@@ -261,6 +261,8 @@
     bool              allow_ac3_passthru;
     bool              allow_dts_passthru;
     bool              disable_passthru;
+    uint              max_channels;
+
     VideoFrame       *dummy_frame;
 
     AudioInfo         audioIn;
Index: libs/libs.pro
===================================================================
--- libs/libs.pro	(revision 15618)
+++ libs/libs.pro	(working copy)
@@ -6,6 +6,7 @@
 # Directories
 SUBDIRS += libavutil libavcodec libavformat libmythsamplerate 
 SUBDIRS += libmythsoundtouch libmythmpeg2 libmythdvdnav
+SUBDIRS += libmythfreesurround
 
 mingw : SUBDIRS += libmyth libmythupnp libmythui
 !mingw: SUBDIRS += libmythupnp libmythui libmyth
Index: libs/libavcodec/ac3_parser.c
===================================================================
--- libs/libavcodec/ac3_parser.c	(revision 15618)
+++ libs/libavcodec/ac3_parser.c	(working copy)
@@ -84,7 +84,8 @@
     return 0;
 }
 
-static int ac3_sync(const uint8_t *buf, int *channels, int *sample_rate,
+/* Made public for MythTV ac3 remixing */
+/*static*/ int ac3_sync(const uint8_t *buf, int *channels, int *sample_rate,
                     int *bit_rate, int *samples)
 {
     int err;
Index: libs/libavcodec/liba52.c
===================================================================
--- libs/libavcodec/liba52.c	(revision 15618)
+++ libs/libavcodec/liba52.c	(working copy)
@@ -134,6 +134,181 @@
     }
 }
 
+static inline int16_t convert(int32_t i)
+{
+    return av_clip_int16(i - 0x43c00000);
+}
+
+void float2s16_2 (float * _f, int16_t * s16)
+{
+    int i;
+    int32_t * f = (int32_t *) _f;
+
+    for (i = 0; i < 256; i++) {
+	s16[2*i] = convert (f[i]);
+	s16[2*i+1] = convert (f[i+256]);
+    }
+}
+
+void float2s16_4 (float * _f, int16_t * s16)
+{
+    int i;
+    int32_t * f = (int32_t *) _f;
+
+    for (i = 0; i < 256; i++) {
+	s16[4*i] = convert (f[i]);
+	s16[4*i+1] = convert (f[i+256]);
+	s16[4*i+2] = convert (f[i+512]);
+	s16[4*i+3] = convert (f[i+768]);
+    }
+}
+
+void float2s16_5 (float * _f, int16_t * s16)
+{
+    int i;
+    int32_t * f = (int32_t *) _f;
+
+    for (i = 0; i < 256; i++) {
+	s16[5*i] = convert (f[i]);
+	s16[5*i+1] = convert (f[i+256]);
+	s16[5*i+2] = convert (f[i+512]);
+	s16[5*i+3] = convert (f[i+768]);
+	s16[5*i+4] = convert (f[i+1024]);
+    }
+}
+
+#define LIKEAC3DEC 1
+int channels_multi (int flags)
+{
+    if (flags & A52_LFE)
+	return 6;
+    else if (flags & 1)	/* center channel */
+	return 5;
+    else if ((flags & A52_CHANNEL_MASK) == A52_2F2R)
+	return 4;
+    else
+	return 2;
+}
+
+void float2s16_multi (float * _f, int16_t * s16, int flags)
+{
+    int i;
+    int32_t * f = (int32_t *) _f;
+
+    switch (flags) {
+    case A52_MONO:
+	for (i = 0; i < 256; i++) {
+	    s16[5*i] = s16[5*i+1] = s16[5*i+2] = s16[5*i+3] = 0;
+	    s16[5*i+4] = convert (f[i]);
+	}
+	break;
+    case A52_CHANNEL:
+    case A52_STEREO:
+    case A52_DOLBY:
+	float2s16_2 (_f, s16);
+	break;
+    case A52_3F:
+	for (i = 0; i < 256; i++) {
+	    s16[5*i] = convert (f[i]);
+	    s16[5*i+1] = convert (f[i+512]);
+	    s16[5*i+2] = s16[5*i+3] = 0;
+	    s16[5*i+4] = convert (f[i+256]);
+	}
+	break;
+    case A52_2F2R:
+	float2s16_4 (_f, s16);
+	break;
+    case A52_3F2R:
+	float2s16_5 (_f, s16);
+	break;
+    case A52_MONO | A52_LFE:
+	for (i = 0; i < 256; i++) {
+#if LIKEAC3DEC
+	    s16[6*i] = s16[6*i+2] = s16[6*i+3] = s16[6*i+4] = 0;
+	    s16[6*i+1] = convert (f[i+256]);
+	    s16[6*i+5] = convert (f[i]);
+#else
+	    s16[6*i] = s16[6*i+1] = s16[6*i+2] = s16[6*i+3] = 0;
+	    s16[6*i+4] = convert (f[i+256]);
+	    s16[6*i+5] = convert (f[i]);
+#endif
+	}
+	break;
+    case A52_CHANNEL | A52_LFE:
+    case A52_STEREO | A52_LFE:
+    case A52_DOLBY | A52_LFE:
+	for (i = 0; i < 256; i++) {
+#if LIKEAC3DEC
+	    s16[6*i] = convert (f[i+256]);
+	    s16[6*i+2] = convert (f[i+512]);
+	    s16[6*i+1] = s16[6*i+3] = s16[6*i+4] = 0;
+	    s16[6*i+5] = convert (f[i]);
+#else
+	    s16[6*i] = convert (f[i+256]);
+	    s16[6*i+1] = convert (f[i+512]);
+	    s16[6*i+2] = s16[6*i+3] = s16[6*i+4] = 0;
+	    s16[6*i+5] = convert (f[i]);
+#endif
+	}
+	break;
+    case A52_3F | A52_LFE:
+	for (i = 0; i < 256; i++) {
+#if LIKEAC3DEC
+	    s16[6*i] = convert (f[i+256]);
+	    s16[6*i+2] = convert (f[i+768]);
+	    s16[6*i+3] = s16[6*i+4] = 0;
+	    s16[6*i+1] = convert (f[i+512]);
+	    s16[6*i+5] = convert (f[i]);
+#else
+	    s16[6*i] = convert (f[i+256]);
+	    s16[6*i+1] = convert (f[i+768]);
+	    s16[6*i+2] = s16[6*i+3] = 0;
+	    s16[6*i+4] = convert (f[i+512]);
+	    s16[6*i+5] = convert (f[i]);
+#endif
+	}
+	break;
+    case A52_2F2R | A52_LFE:
+	for (i = 0; i < 256; i++) {
+#if LIKEAC3DEC
+	    s16[6*i] = convert (f[i+256]);
+	    s16[6*i+1] = 0;
+	    s16[6*i+2] = convert (f[i+512]);
+	    s16[6*i+3] = convert (f[i+768]);
+	    s16[6*i+4] = convert (f[i+1024]);
+	    s16[6*i+5] = convert (f[i]);
+#else
+	    s16[6*i] = convert (f[i+256]);
+	    s16[6*i+1] = convert (f[i+512]);
+	    s16[6*i+2] = convert (f[i+768]);
+	    s16[6*i+3] = convert (f[i+1024]);
+	    s16[6*i+4] = 0;
+	    s16[6*i+5] = convert (f[i]);
+#endif
+	}
+	break;
+    case A52_3F2R | A52_LFE:
+	for (i = 0; i < 256; i++) {
+#if LIKEAC3DEC
+	    s16[6*i] = convert (f[i+256]);
+	    s16[6*i+1] = convert (f[i+512]);
+	    s16[6*i+2] = convert (f[i+768]);
+	    s16[6*i+3] = convert (f[i+1024]);
+	    s16[6*i+4] = convert (f[i+1280]);
+	    s16[6*i+5] = convert (f[i]);
+#else
+	    s16[6*i] = convert (f[i+256]);
+	    s16[6*i+1] = convert (f[i+768]);
+	    s16[6*i+2] = convert (f[i+1024]);
+	    s16[6*i+3] = convert (f[i+1280]);
+	    s16[6*i+4] = convert (f[i+512]);
+	    s16[6*i+5] = convert (f[i]);
+#endif
+	}
+	break;
+    }
+}
+
 /**** end */
 
 #define HEADER_SIZE 7
@@ -177,6 +352,8 @@
                     /* update codec info */
                     avctx->sample_rate = sample_rate;
                     s->channels = ac3_channels[s->flags & 7];
+                    if (avctx->cqp >= 0)
+                        avctx->channels = avctx->cqp;
                     if (s->flags & A52_LFE)
                         s->channels++;
                     if (avctx->channels == 0)
@@ -199,14 +376,20 @@
             s->inbuf_ptr += len;
             buf_size -= len;
         } else {
+            int chans;
             flags = s->flags;
             if (avctx->channels == 1)
                 flags = A52_MONO;
-            else if (avctx->channels == 2)
-                flags = A52_STEREO;
+            else if (avctx->channels == 2) {
+                if (s->channels>2)
+                    flags = A52_DOLBY;
+                else
+                    flags = A52_STEREO;
+            }
             else
                 flags |= A52_ADJUST_LEVEL;
             level = 1;
+            chans = channels_multi(flags);
             if (s->a52_frame(s->state, s->inbuf, &flags, &level, 384)) {
             fail:
                 av_log(avctx, AV_LOG_ERROR, "Error decoding frame\n");
@@ -217,7 +400,7 @@
             for (i = 0; i < 6; i++) {
                 if (s->a52_block(s->state))
                     goto fail;
-                float_to_int(s->samples, out_samples + i * 256 * avctx->channels, avctx->channels);
+                float2s16_multi(s->samples, out_samples + i * 256 * chans, flags);
             }
             s->inbuf_ptr = s->inbuf;
             s->frame_size = 0;
Index: libs/libmyth/audiooutputbase.h
===================================================================
--- libs/libmyth/audiooutputbase.h	(revision 15618)
+++ libs/libmyth/audiooutputbase.h	(working copy)
@@ -16,13 +16,23 @@
 // MythTV headers
 #include "audiooutput.h"
 #include "samplerate.h"
-#include "SoundTouch.h"
 
-#define AUDBUFSIZE 768000
+namespace soundtouch {
+class SoundTouch;
+};
+class FreeSurround;
+class AudioOutputDigitalEncoder;
+struct AVCodecContext;
+
 #define AUDIO_SRC_IN_SIZE   16384
 #define AUDIO_SRC_OUT_SIZE (16384*6)
 #define AUDIO_TMP_BUF_SIZE (16384*6)
 
+//#define AUDBUFSIZE 768000
+//divisible by 12,10,8,6,4,2 and around 1024000
+//#define AUDBUFSIZE 1024080
+#define AUDBUFSIZE 1536000
+
 class AudioOutputBase : public AudioOutput
 {
  public:
@@ -35,8 +45,11 @@
     virtual ~AudioOutputBase();
 
     // reconfigure sound out for new params
-    virtual void Reconfigure(int audio_bits, int audio_channels,
-                             int audio_samplerate, bool audio_passthru);
+    virtual void Reconfigure(int audio_bits, 
+                             int audio_channels, 
+                             int audio_samplerate,
+                             bool audio_passthru,
+                             void* audio_codec = NULL);
     
     // do AddSamples calls block?
     virtual void SetBlocking(bool blocking);
@@ -45,6 +58,7 @@
     virtual void SetEffDsp(int dsprate);
 
     virtual void SetStretchFactor(float factor);
+    virtual float GetStretchFactor(void);
 
     virtual void Reset(void);
 
@@ -127,6 +141,7 @@
     bool audio_passthru;
 
     float audio_stretchfactor;
+    AVCodecContext *audio_codec;
     AudioOutputSource source;
 
     bool killaudio;
@@ -135,6 +150,8 @@
     bool set_initial_vol;
     bool buffer_output_data_for_use; //  used by AudioOutputNULL
     
+    int configured_audio_channels;
+
  private:
     // resampler
     bool need_resampler;
@@ -145,8 +162,15 @@
     short tmp_buff[AUDIO_TMP_BUF_SIZE];
 
     // timestretch
-    soundtouch::SoundTouch * pSoundStretch;
+    soundtouch::SoundTouch    *pSoundStretch;
+    AudioOutputDigitalEncoder *encoder;
+    FreeSurround              *upmixer;
 
+    int source_audio_channels;
+    int source_audio_bytes_per_sample;
+    bool needs_upmix;
+    int surround_mode;
+
     bool blocking; // do AddSamples calls block?
 
     int lastaudiolen;
@@ -164,15 +188,15 @@
 
     pthread_mutex_t avsync_lock; /* must hold avsync_lock to read or write
                                     'audiotime' and 'audiotime_updated' */
-    int audiotime; // timecode of audio leaving the soundcard (same units as
-                   //                                          timecodes) ...
+    /// timecode of audio leaving the soundcard (same units as timecodes)
+    long long audiotime;
     struct timeval audiotime_updated; // ... which was last updated at this time
 
     /* Audio circular buffer */
     unsigned char audiobuffer[AUDBUFSIZE];  /* buffer */
     int raud, waud;     /* read and write positions */
-    int audbuf_timecode;    /* timecode of audio most recently placed into
-                   buffer */
+    /// timecode of audio most recently placed into buffer
+    long long audbuf_timecode;
 
     int numlowbuffer;
 
Index: libs/libmyth/audiooutputalsa.cpp
===================================================================
--- libs/libmyth/audiooutputalsa.cpp	(revision 15618)
+++ libs/libmyth/audiooutputalsa.cpp	(working copy)
@@ -52,6 +52,15 @@
     QString real_device = (audio_passthru) ?
         audio_passthru_device : audio_main_device;
 
+    int index = real_device.find('|');
+    if (index >= 0)
+    {
+        if (audio_channels >= 2)
+            real_device = real_device.mid(index+1);
+        else
+            real_device = real_device.left(index);
+    }
+
     VERBOSE(VB_GENERAL, QString("Opening ALSA audio device '%1'.")
             .arg(real_device));
 
@@ -89,8 +98,9 @@
     }
     else
     {
-        fragment_size = 6144; // nicely divisible by 2,4,6,8 channels @ 16-bits
-        buffer_time = 500000;  // .5 seconds
+        fragment_size =
+            (audio_bits * audio_channels * audio_samplerate) / (8*30);
+        buffer_time = 100000;
         period_time = buffer_time / 4;  // 4 interrupts per buffer
     }
 
@@ -162,7 +172,8 @@
     
     tmpbuf = aubuf;
 
-    VERBOSE(VB_AUDIO, QString("WriteAudio: Preparing %1 bytes (%2 frames)")
+    VERBOSE(VB_AUDIO|VB_TIMESTAMP,
+            QString("WriteAudio: Preparing %1 bytes (%2 frames)")
             .arg(size).arg(frames));
     
     while (frames > 0) 
Index: libs/libmyth/audiooutputdigitalencoder.h
===================================================================
--- libs/libmyth/audiooutputdigitalencoder.h	(revision 0)
+++ libs/libmyth/audiooutputdigitalencoder.h	(revision 0)
@@ -0,0 +1,41 @@
+#ifndef AUDIOOUTPUTREENCODER
+#define AUDIOOUTPUTREENCODER
+
+extern "C" {
+#include "libavcodec/avcodec.h"
+};
+
+class AudioOutputDigitalEncoder
+{
+  public:
+    AudioOutputDigitalEncoder(void);
+    ~AudioOutputDigitalEncoder();
+
+    bool   Init(CodecID codec_id, int bitrate, int samplerate, int channels);
+    void   Dispose(void);
+    size_t Encode(short * buff);
+
+    inline char *GetFrameBuffer(void);
+    size_t FrameSize(void)  const { return one_frame_bytes; }
+    char  *GetOutBuff(void) const { return outbuf;          }
+
+  public:
+    size_t audio_bytes_per_sample;
+
+  private:
+    AVCodecContext *av_context;
+    char           *outbuf;
+    int             outbuf_size;
+    char           *frame_buffer;
+    size_t          one_frame_bytes;
+};
+
+inline char *AudioOutputDigitalEncoder::GetFrameBuffer(void)
+{
+    if (!frame_buffer && av_context)
+        frame_buffer = new char [one_frame_bytes];
+
+    return frame_buffer; 
+}
+
+#endif
Index: libs/libmyth/audiooutputbase.cpp
===================================================================
--- libs/libmyth/audiooutputbase.cpp	(revision 15618)
+++ libs/libmyth/audiooutputbase.cpp	(working copy)
@@ -15,6 +15,9 @@
 
 // MythTV headers
 #include "audiooutputbase.h"
+#include "audiooutputdigitalencoder.h"
+#include "SoundTouch.h"
+#include "freesurround.h"
 #include "compat.h"
 
 #define LOC QString("AO: ")
@@ -36,6 +39,7 @@
     audio_passthru_device(QDeepCopy<QString>(laudio_passthru_device)),
     audio_passthru(false),      audio_stretchfactor(1.0f),
 
+    audio_codec(NULL),
     source(lsource),            killaudio(false),
 
     pauseaudio(false),          audio_actually_paused(false),
@@ -47,8 +51,16 @@
 
     src_ctx(NULL),
 
-    pSoundStretch(NULL),        blocking(false),
+    pSoundStretch(NULL),        
+    encoder(NULL),
+    upmixer(NULL),
+    source_audio_channels(-1),
+    source_audio_bytes_per_sample(0),
+    needs_upmix(false),
+    surround_mode(FreeSurround::SurroundModePassive),
 
+    blocking(false),
+
     lastaudiolen(0),            samples_buffered(0),
 
     audio_thread_exists(false),
@@ -71,6 +83,7 @@
     memset(tmp_buff,           0, sizeof(short) * AUDIO_TMP_BUF_SIZE);
     memset(&audiotime_updated, 0, sizeof(audiotime_updated));
     memset(audiobuffer,        0, sizeof(char)  * AUDBUFSIZE);
+    configured_audio_channels = gContext->GetNumSetting("MaxChannels", 2);
 
     // You need to call Reconfigure from your concrete class.
     // Reconfigure(laudio_bits,       laudio_channels,
@@ -111,9 +124,41 @@
             VERBOSE(VB_GENERAL, LOC + QString("Using time stretch %1")
                                         .arg(audio_stretchfactor));
             pSoundStretch = new soundtouch::SoundTouch();
-            pSoundStretch->setSampleRate(audio_samplerate);
-            pSoundStretch->setChannels(audio_channels);
+            if (audio_codec)
+            {
+                if (!encoder)
+                {
+                    VERBOSE(VB_AUDIO, LOC +
+                            QString("Creating Encoder for codec %1 origfs %2")
+                            .arg(audio_codec->codec_id)
+                            .arg(audio_codec->frame_size));
 
+                    encoder = new AudioOutputDigitalEncoder();
+                    if (!encoder->Init(audio_codec->codec_id,
+                                audio_codec->bit_rate,
+                                audio_codec->sample_rate,
+                                audio_codec->channels
+                                ))
+                    {
+                        // eeks
+                        delete encoder;
+                        encoder = NULL;
+                        VERBOSE(VB_AUDIO, LOC +
+                                QString("Failed to Create Encoder"));
+                    }
+                }
+            }
+            if (encoder)
+            {
+                pSoundStretch->setSampleRate(audio_codec->sample_rate);
+                pSoundStretch->setChannels(audio_codec->channels);
+            }
+            else
+            {
+                pSoundStretch->setSampleRate(audio_samplerate);
+                pSoundStretch->setChannels(audio_channels);
+            }
+
             pSoundStretch->setTempo(audio_stretchfactor);
             pSoundStretch->setSetting(SETTING_SEQUENCE_MS, 35);
 
@@ -134,13 +179,57 @@
     pthread_mutex_unlock(&audio_buflock);
 }
 
+float AudioOutputBase::GetStretchFactor()
+{
+    return audio_stretchfactor;
+}
+
 void AudioOutputBase::Reconfigure(int laudio_bits, int laudio_channels, 
-                                 int laudio_samplerate, bool laudio_passthru)
+                                 int laudio_samplerate, bool laudio_passthru,
+                                 void* laudio_codec)
 {
+    int codec_id = CODEC_ID_NONE;
+    int lcodec_id = CODEC_ID_NONE;
+    int lcchannels = 0;
+    int cchannels = 0;
+    int lsource_audio_channels = laudio_channels;
+    bool lneeds_upmix = false;
+
+    if (laudio_codec)
+    {
+        lcodec_id = ((AVCodecContext*)laudio_codec)->codec_id;
+        laudio_bits = 16;
+        laudio_channels = 2;
+        lsource_audio_channels = laudio_channels;
+        laudio_samplerate = 48000;
+        lcchannels = ((AVCodecContext*)laudio_codec)->channels;
+    }
+
+    if (audio_codec)
+    {
+        codec_id = audio_codec->codec_id;
+        cchannels = ((AVCodecContext*)audio_codec)->channels;
+    }
+
+    if ((configured_audio_channels == 6) && 
+        !(laudio_codec || audio_codec))
+    {
+        laudio_channels = configured_audio_channels;
+        lneeds_upmix = true;
+        VERBOSE(VB_AUDIO,LOC + "Needs upmix");
+    }
+
+    ClearError();
+
     if (laudio_bits == audio_bits && laudio_channels == audio_channels &&
-        laudio_samplerate == audio_samplerate &&
-        laudio_passthru == audio_passthru && !need_resampler)
+        laudio_samplerate == audio_samplerate && !need_resampler &&
+        laudio_passthru == audio_passthru &&
+        lneeds_upmix == needs_upmix &&
+        lcodec_id == codec_id && lcchannels == cchannels)
+    {
+        VERBOSE(VB_AUDIO,LOC + "no change exiting");
         return;
+    }
 
     KillAudio();
     
@@ -151,10 +240,15 @@
     waud = raud = 0;
     audio_actually_paused = false;
     
+    bool redo_stretch = (pSoundStretch && audio_channels != laudio_channels);
     audio_channels = laudio_channels;
+    source_audio_channels = lsource_audio_channels;
     audio_bits = laudio_bits;
     audio_samplerate = laudio_samplerate;
+    audio_codec = (AVCodecContext*)laudio_codec;
     audio_passthru = laudio_passthru;
+    needs_upmix = lneeds_upmix;
+
     if (audio_bits != 8 && audio_bits != 16)
     {
         pthread_mutex_unlock(&avsync_lock);
@@ -162,7 +256,9 @@
         Error("AudioOutput only supports 8 or 16bit audio.");
         return;
     }
+
     audio_bytes_per_sample = audio_channels * audio_bits / 8;
+    source_audio_bytes_per_sample = source_audio_channels * audio_bits / 8;
     
     need_resampler = false;
     killaudio = false;
@@ -172,12 +268,19 @@
     
     numlowbuffer = 0;
 
+    VERBOSE(VB_GENERAL, QString("Opening audio device '%1'. ch %2(%3) sr %4")
+            .arg(audio_main_device).arg(audio_channels)
+            .arg(source_audio_channels).arg(audio_samplerate));
+ 
     // Actually do the device specific open call
     if (!OpenDevice())
     {
         VERBOSE(VB_AUDIO, LOC_ERR + "Aborting reconfigure");
         pthread_mutex_unlock(&avsync_lock);
         pthread_mutex_unlock(&audio_buflock);
+        if (GetError().isEmpty())
+            Error("Aborting reconfigure");
+        VERBOSE(VB_AUDIO, "Aborting reconfigure");
         return;
     }
 
@@ -200,6 +303,7 @@
     current_seconds = -1;
     source_bitrate = -1;
 
+    // NOTE: this won't do anything as above samplerate vars are set equal
     // Check if we need the resampler
     if (audio_samplerate != laudio_samplerate)
     {
@@ -222,16 +326,79 @@
         need_resampler = true;
     }
 
+    if (needs_upmix)
+    {
+        VERBOSE(VB_AUDIO, LOC + QString("create upmixer"));
+        if (configured_audio_channels == 6)
+        {
+            surround_mode = gContext->GetNumSetting("AudioUpmixType", 2);
+        }
+
+        upmixer = new FreeSurround(
+            audio_samplerate, 
+            source == AUDIOOUTPUT_VIDEO, 
+            (FreeSurround::SurroundMode)surround_mode);
+
+        VERBOSE(VB_AUDIO, LOC +
+                QString("create upmixer done with surround mode %1")
+                .arg(surround_mode));
+    }
+
     VERBOSE(VB_AUDIO, LOC + QString("Audio Stretch Factor: %1")
             .arg(audio_stretchfactor));
+    VERBOSE(VB_AUDIO, QString("Audio Codec Used: %1")
+            .arg((audio_codec) ?
+                 codec_id_string(audio_codec->codec_id) : "not set"));
 
-    SetStretchFactorLocked(audio_stretchfactor);
-    if (pSoundStretch)
+    if (redo_stretch)
     {
-        pSoundStretch->setSampleRate(audio_samplerate);
-        pSoundStretch->setChannels(audio_channels);
+        float laudio_stretchfactor = audio_stretchfactor;
+        delete pSoundStretch;
+        pSoundStretch = NULL;
+        audio_stretchfactor = 0.0f;
+        SetStretchFactorLocked(laudio_stretchfactor);
     }
+    else
+    {
+        SetStretchFactorLocked(audio_stretchfactor);
+        if (pSoundStretch)
+        {
+            // if its passthru then we need to reencode
+            if (audio_codec)
+            {
+                if (!encoder)
+                {
+                    VERBOSE(VB_AUDIO, LOC +
+                            QString("Creating Encoder for codec %1")
+                            .arg(audio_codec->codec_id));
 
+                    encoder = new AudioOutputDigitalEncoder();
+                    if (!encoder->Init(audio_codec->codec_id,
+                                audio_codec->bit_rate,
+                                audio_codec->sample_rate,
+                                audio_codec->channels
+                                ))
+                    {
+                        // eeks
+                        delete encoder;
+                        encoder = NULL;
+                        VERBOSE(VB_AUDIO, LOC + "Failed to Create Encoder");
+                    }
+                }
+            }
+            if (encoder)
+            {
+                pSoundStretch->setSampleRate(audio_codec->sample_rate);
+                pSoundStretch->setChannels(audio_codec->channels);
+            }
+            else
+            {
+                pSoundStretch->setSampleRate(audio_samplerate);
+                pSoundStretch->setChannels(audio_channels);
+            }
+        }
+    }
+
     // Setup visualisations, zero the visualisations buffers
     prepareVisuals();
 
@@ -290,6 +457,19 @@
         pSoundStretch = NULL;
     }
 
+    if (encoder)
+    {
+        delete encoder;
+        encoder = NULL;
+    }
+
+    if (upmixer)
+    {
+        delete upmixer;
+        upmixer = NULL;
+    }
+    needs_upmix = false;
+
     CloseDevice();
 
     killAudioLock.unlock();
@@ -303,6 +483,7 @@
 
 void AudioOutputBase::Pause(bool paused)
 {
+    VERBOSE(VB_AUDIO, LOC + QString("Pause %0").arg(paused));
     pauseaudio = paused;
     audio_actually_paused = false;
 }
@@ -385,7 +566,7 @@
        The reason is that computing 'audiotime' requires acquiring the audio 
        lock, which the video thread should not do. So, we call 'SetAudioTime()'
        from the audio thread, and then call this from the video thread. */
-    int ret;
+    long long ret;
     struct timeval now;
 
     if (audiotime == 0)
@@ -397,12 +578,23 @@
 
     ret = (now.tv_sec - audiotime_updated.tv_sec) * 1000;
     ret += (now.tv_usec - audiotime_updated.tv_usec) / 1000;
-    ret = (int)(ret * audio_stretchfactor);
+    ret = (long long)(ret * audio_stretchfactor);
 
+#if 1
+    VERBOSE(VB_AUDIO|VB_TIMESTAMP, 
+            QString("GetAudiotime now=%1.%2, set=%3.%4, ret=%5, audt=%6 sf=%7")
+            .arg(now.tv_sec).arg(now.tv_usec)
+            .arg(audiotime_updated.tv_sec).arg(audiotime_updated.tv_usec)
+            .arg(ret)
+            .arg(audiotime)
+            .arg(audio_stretchfactor)
+           );
+#endif
+
     ret += audiotime;
 
     pthread_mutex_unlock(&avsync_lock);
-    return ret;
+    return (int)ret;
 }
 
 void AudioOutputBase::SetAudiotime(void)
@@ -439,15 +631,38 @@
     // include algorithmic latencies
     if (pSoundStretch)
     {
+        // add the effect of any unused but processed samples,
+        // AC3 reencode does this
+        totalbuffer += (int)(pSoundStretch->numSamples() *
+                             audio_bytes_per_sample);
         // add the effect of unprocessed samples in time stretch algo
         totalbuffer += (int)((pSoundStretch->numUnprocessedSamples() *
                               audio_bytes_per_sample) / audio_stretchfactor);
     }
-               
+
+    if (upmixer && needs_upmix)
+    {
+        totalbuffer += upmixer->sampleLatency() * audio_bytes_per_sample;
+    }
+
     audiotime = audbuf_timecode - (int)(totalbuffer * 100000.0 /
                                    (audio_bytes_per_sample * effdspstretched));
  
     gettimeofday(&audiotime_updated, NULL);
+#if 1
+    VERBOSE(VB_AUDIO|VB_TIMESTAMP, 
+            QString("SetAudiotime set=%1.%2, audt=%3 atc=%4 "
+                    "tb=%5 sb=%6 eds=%7 abps=%8 sf=%9")
+            .arg(audiotime_updated.tv_sec).arg(audiotime_updated.tv_usec)
+            .arg(audiotime)
+            .arg(audbuf_timecode)
+            .arg(totalbuffer)
+            .arg(soundcard_buffer)
+            .arg(effdspstretched)
+            .arg(audio_bytes_per_sample)
+            .arg(audio_stretchfactor)
+           );
+#endif
 
     pthread_mutex_unlock(&avsync_lock);
     pthread_mutex_unlock(&audio_buflock);
@@ -458,13 +673,18 @@
 {
     // NOTE: This function is not threadsafe
     int afree = audiofree(true);
-    int abps = audio_bytes_per_sample;
+    int abps = (encoder) ?
+        encoder->audio_bytes_per_sample : audio_bytes_per_sample;
     int len = samples * abps;
 
     // Check we have enough space to write the data
     if (need_resampler && src_ctx)
         len = (int)ceilf(float(len) * src_data.src_ratio);
 
+    // include samples in upmix buffer that may be flushed
+    if (needs_upmix && upmixer)
+        len += upmixer->numUnprocessedSamples() * abps;
+
     if (pSoundStretch)
         len += (pSoundStretch->numUnprocessedSamples() +
                 (int)(pSoundStretch->numSamples()/audio_stretchfactor))*abps;
@@ -520,13 +740,18 @@
     // NOTE: This function is not threadsafe
 
     int afree = audiofree(true);
-    int abps = audio_bytes_per_sample;
+    int abps = (encoder) ?
+        encoder->audio_bytes_per_sample : audio_bytes_per_sample;
     int len = samples * abps;
 
     // Check we have enough space to write the data
     if (need_resampler && src_ctx)
         len = (int)ceilf(float(len) * src_data.src_ratio);
 
+    // include samples in upmix buffer that may be flushed
+    if (needs_upmix && upmixer)
+        len += upmixer->numUnprocessedSamples() * abps;
+ 
     if (pSoundStretch)
     {
         len += (pSoundStretch->numUnprocessedSamples() +
@@ -575,14 +800,16 @@
 
 int AudioOutputBase::WaitForFreeSpace(int samples)
 {
-    int len = samples * audio_bytes_per_sample;
+    int abps = (encoder) ?
+        encoder->audio_bytes_per_sample : audio_bytes_per_sample;
+    int len = samples * abps;
     int afree = audiofree(false);
 
     while (len > afree)
     {
         if (blocking)
         {
-            VERBOSE(VB_AUDIO, LOC + "Waiting for free space " +
+            VERBOSE(VB_AUDIO|VB_TIMESTAMP, LOC + "Waiting for free space " +
                     QString("(need %1, available %2)").arg(len).arg(afree));
 
             // wait for more space
@@ -591,10 +818,11 @@
         }
         else
         {
-            VERBOSE(VB_IMPORTANT, LOC_ERR +
-                    "Audio buffer overflow, audio data lost!");
-            samples = afree / audio_bytes_per_sample;
-            len = samples * audio_bytes_per_sample;
+            VERBOSE(VB_IMPORTANT, LOC_ERR + 
+                    QString("Audio buffer overflow, %1 audio samples lost!")
+                    .arg(samples - (afree / abps)));
+            samples = afree / abps;
+            len = samples * abps;
             if (src_ctx) 
             {
                 int error = src_reset(src_ctx);
@@ -619,114 +847,244 @@
     
     int afree = audiofree(false);
 
-    VERBOSE(VB_AUDIO|VB_TIMESTAMP,
-            LOC + QString("_AddSamples bytes=%1, used=%2, free=%3, timecode=%4")
-            .arg(samples * audio_bytes_per_sample)
-            .arg(AUDBUFSIZE-afree).arg(afree).arg((long)timecode));
+    int abps = (encoder) ?
+        encoder->audio_bytes_per_sample : audio_bytes_per_sample;
+
+    VERBOSE(VB_AUDIO|VB_TIMESTAMP, 
+            LOC + QString("_AddSamples samples=%1 bytes=%2, used=%3, "
+                          "free=%4, timecode=%5 needsupmix %6")
+            .arg(samples)
+            .arg(samples * abps)
+            .arg(AUDBUFSIZE-afree).arg(afree).arg(timecode)
+            .arg(needs_upmix));
     
-    len = WaitForFreeSpace(samples);
-
-    if (interleaved) 
+    if (upmixer && needs_upmix)
     {
-        char *mybuf = (char*)buffer;
-        int bdiff = AUDBUFSIZE - org_waud;
-        if (bdiff < len)
+        int out_samples = 0;
+        int step = (interleaved)?source_audio_channels:1;
+        len = WaitForFreeSpace(samples);    // test
+        for (int itemp = 0; itemp < samples; )
         {
-            memcpy(audiobuffer + org_waud, mybuf, bdiff);
-            memcpy(audiobuffer, mybuf + bdiff, len - bdiff);
+            // just in case it does a processing cycle, release the lock
+            // to allow the output loop to do output
+            pthread_mutex_unlock(&audio_buflock);
+            if (audio_bytes == 2)
+            {
+                itemp += upmixer->putSamples(
+                    (short*)buffer + itemp * step,
+                    samples - itemp,
+                    source_audio_channels,
+                    (interleaved) ? 0 : samples);
+            }
+            else
+            {
+                itemp += upmixer->putSamples(
+                    (char*)buffer + itemp * step,
+                    samples - itemp,
+                    source_audio_channels,
+                    (interleaved) ? 0 : samples);
+            }
+            pthread_mutex_lock(&audio_buflock);
+
+            int copy_samples = upmixer->numSamples();
+            if (copy_samples)
+            {
+                int copy_len = copy_samples * abps;
+                out_samples += copy_samples;
+                if (out_samples > samples)
+                    len = WaitForFreeSpace(out_samples);
+                int bdiff = AUDBUFSIZE - org_waud;
+                if (bdiff < copy_len) 
+                {
+                    int bdiff_samples = bdiff/abps;
+                    upmixer->receiveSamples(
+                        (short*)(audiobuffer + org_waud), bdiff_samples);
+                    upmixer->receiveSamples(
+                        (short*)(audiobuffer), (copy_samples - bdiff_samples));
+                }
+                else
+                {
+                    upmixer->receiveSamples(
+                        (short*)(audiobuffer + org_waud), copy_samples);
+                }
+                org_waud = (org_waud + copy_len) % AUDBUFSIZE;
+            }
         }
-        else
-            memcpy(audiobuffer + org_waud, mybuf, len);
- 
-        org_waud = (org_waud + len) % AUDBUFSIZE;
-    } 
-    else 
+
+        if (samples > 0)
+            len = WaitForFreeSpace(out_samples);
+
+        samples = out_samples;
+    }
+    else
     {
-        char **mybuf = (char**)buffer;
-        for (int itemp = 0; itemp < samples * audio_bytes; itemp += audio_bytes)
+        len = WaitForFreeSpace(samples);
+
+        if (interleaved) 
         {
-            for (int chan = 0; chan < audio_channels; chan++)
+            char *mybuf = (char*)buffer;
+            int bdiff = AUDBUFSIZE - org_waud;
+            if (bdiff < len)
             {
-                audiobuffer[org_waud++] = mybuf[chan][itemp];
-                if (audio_bits == 16)
-                    audiobuffer[org_waud++] = mybuf[chan][itemp+1];
+                memcpy(audiobuffer + org_waud, mybuf, bdiff);
+                memcpy(audiobuffer, mybuf + bdiff, len - bdiff);
+            }
+            else
+            {
+                memcpy(audiobuffer + org_waud, mybuf, len);
+            }
+     
+            org_waud = (org_waud + len) % AUDBUFSIZE;
+        } 
+        else 
+        {
+            char **mybuf = (char**)buffer;
+            for (int itemp = 0; itemp < samples * audio_bytes;
+                 itemp += audio_bytes)
+            {
+                for (int chan = 0; chan < audio_channels; chan++)
+                {
+                    audiobuffer[org_waud++] = mybuf[chan][itemp];
+                    if (audio_bits == 16)
+                        audiobuffer[org_waud++] = mybuf[chan][itemp+1];
 
-                if (org_waud >= AUDBUFSIZE)
-                    org_waud -= AUDBUFSIZE;
+                    if (org_waud >= AUDBUFSIZE)
+                        org_waud -= AUDBUFSIZE;
+                }
             }
         }
     }
 
-    if (pSoundStretch)
+    if (samples > 0)
     {
-        // does not change the timecode, only the number of samples
-        // back to orig pos
-        org_waud = waud;
-        int bdiff = AUDBUFSIZE - org_waud;
-        int nSamplesToEnd = bdiff/audio_bytes_per_sample;
-        if (bdiff < len)
+        if (pSoundStretch)
         {
-            pSoundStretch->putSamples((soundtouch::SAMPLETYPE*)(audiobuffer + 
-                                      org_waud), nSamplesToEnd);
-            pSoundStretch->putSamples((soundtouch::SAMPLETYPE*)audiobuffer,
-                                      (len - bdiff) / audio_bytes_per_sample);
-        }
-        else
-        {
-            pSoundStretch->putSamples((soundtouch::SAMPLETYPE*)(audiobuffer + 
-                                      org_waud), len / audio_bytes_per_sample);
-        }
 
-        int newLen = 0;
-        int nSamples;
-        len = WaitForFreeSpace(pSoundStretch->numSamples() * 
-                               audio_bytes_per_sample);
-        do 
-        {
-            int samplesToGet = len/audio_bytes_per_sample;
-            if (samplesToGet > nSamplesToEnd)
+            // does not change the timecode, only the number of samples
+            // back to orig pos
+            org_waud = waud;
+            int bdiff = AUDBUFSIZE - org_waud;
+            int nSamplesToEnd = bdiff/abps;
+            if (bdiff < len)
             {
-                samplesToGet = nSamplesToEnd;    
+                pSoundStretch->putSamples((soundtouch::SAMPLETYPE*)
+                                          (audiobuffer + 
+                                           org_waud), nSamplesToEnd);
+                pSoundStretch->putSamples((soundtouch::SAMPLETYPE*)audiobuffer,
+                                          (len - bdiff) / abps);
             }
+            else
+            {
+                pSoundStretch->putSamples((soundtouch::SAMPLETYPE*)
+                                          (audiobuffer + org_waud),
+                                          len / abps);
+            }
 
-            nSamples = pSoundStretch->receiveSamples((soundtouch::SAMPLETYPE*)
-                                      (audiobuffer + org_waud), samplesToGet);
-            if (nSamples == nSamplesToEnd)
+            if (encoder)
             {
-                org_waud = 0;
-                nSamplesToEnd = AUDBUFSIZE/audio_bytes_per_sample;
+                // pull out a packet's worth and reencode it until we
+                // don't have enough for any more packets
+                soundtouch::SAMPLETYPE *temp_buff = 
+                    (soundtouch::SAMPLETYPE*)encoder->GetFrameBuffer();
+                size_t frameSize = encoder->FrameSize()/abps;
+
+                VERBOSE(VB_AUDIO|VB_TIMESTAMP,
+                        QString("_AddSamples Enc sfs=%1 bfs=%2 sss=%3")
+                        .arg(frameSize)
+                        .arg(encoder->FrameSize())
+                        .arg(pSoundStretch->numSamples()));
+
+                // process the same number of samples as it creates
+                // a full encoded buffer just like before
+                while (pSoundStretch->numSamples() >= frameSize)
+                {
+                    int got = pSoundStretch->receiveSamples(
+                        temp_buff, frameSize);
+                    int amount = encoder->Encode(temp_buff);
+
+                    VERBOSE(VB_AUDIO|VB_TIMESTAMP, 
+                            QString("_AddSamples Enc bytes=%1 got=%2 left=%3")
+                            .arg(amount)
+                            .arg(got)
+                            .arg(pSoundStretch->numSamples()));
+
+                    if (!amount)
+                        continue;
+
+                    //len = WaitForFreeSpace(amount);
+                    char *ob = encoder->GetOutBuff();
+                    if (amount >= bdiff)
+                    {
+                        memcpy(audiobuffer + org_waud, ob, bdiff);
+                        ob += bdiff;
+                        amount -= bdiff;
+                        org_waud = 0;
+                    }
+                    if (amount > 0)
+                        memcpy(audiobuffer + org_waud, ob, amount);
+
+                    bdiff = AUDBUFSIZE - amount;
+                    org_waud += amount;
+                }
             }
             else
             {
-                org_waud += nSamples * audio_bytes_per_sample;
-                nSamplesToEnd -= nSamples;
+                int newLen = 0;
+                int nSamples;
+                len = WaitForFreeSpace(pSoundStretch->numSamples() * 
+                                       audio_bytes_per_sample);
+                do 
+                {
+                    int samplesToGet = len/audio_bytes_per_sample;
+                    if (samplesToGet > nSamplesToEnd)
+                    {
+                        samplesToGet = nSamplesToEnd;    
+                    }
+
+                    nSamples = pSoundStretch->receiveSamples(
+                        (soundtouch::SAMPLETYPE*)
+                        (audiobuffer + org_waud), samplesToGet);
+                    if (nSamples == nSamplesToEnd)
+                    {
+                        org_waud = 0;
+                        nSamplesToEnd = AUDBUFSIZE/audio_bytes_per_sample;
+                    }
+                    else
+                    {
+                        org_waud += nSamples * audio_bytes_per_sample;
+                        nSamplesToEnd -= nSamples;
+                    }
+
+                    newLen += nSamples * audio_bytes_per_sample;
+                    len -= nSamples * audio_bytes_per_sample;
+                } while (nSamples > 0);
             }
+        }
 
-            newLen += nSamples * audio_bytes_per_sample;
-            len -= nSamples * audio_bytes_per_sample;
-        } while (nSamples > 0);
-    }
+        waud = org_waud;
+        lastaudiolen = audiolen(false);
 
-    waud = org_waud;
-    lastaudiolen = audiolen(false);
+        if (timecode < 0)
+        {
+            // mythmusic doesn't give timestamps..
+            timecode = (int)((samples_buffered * 100000.0) / effdsp);
+        }
+        
+        samples_buffered += samples;
+        
+        /* we want the time at the end -- but the file format stores
+           time at the start of the chunk. */
+        // even with timestretch, timecode is still calculated from original
+        // sample count
+        audbuf_timecode = timecode + (int)((samples * 100000.0) / effdsp);
 
-    samples_buffered += samples;
-    
-    if (timecode < 0)
-    {
-        // mythmusic doesn't give timestamps..
-        timecode = (int)((samples_buffered * 100000.0) / effdsp);
+        if (interleaved)
+        {
+            dispatchVisual((unsigned char *)buffer, len, timecode,
+                           source_audio_channels, audio_bits);
+        }
     }
-    
-    /* we want the time at the end -- but the file format stores
-       time at the start of the chunk. */
-    // even with timestretch, timecode is still calculated from original
-    // sample count
-    audbuf_timecode = timecode + (int)((samples * 100000.0) / effdsp);
 
-    if (interleaved)
-        dispatchVisual((unsigned char *)buffer, len, timecode, audio_channels, audio_bits);
-
     pthread_mutex_unlock(&audio_buflock);
 }
 
@@ -739,7 +1097,7 @@
 
     if (source_bitrate == -1)
     {
-        source_bitrate = audio_samplerate * audio_channels * audio_bits;
+        source_bitrate = audio_samplerate * source_audio_channels * audio_bits;
     }
 
     if (ct / 1000 != current_seconds) 
@@ -747,7 +1105,7 @@
         current_seconds = ct / 1000;
         OutputEvent e(current_seconds, ct,
                       source_bitrate, audio_samplerate, audio_bits, 
-                      audio_channels);
+                      source_audio_channels);
         dispatch(e);
     }
 }
@@ -785,9 +1143,12 @@
 
             space_on_soundcard = getSpaceOnSoundcard();
 
-            if (space_on_soundcard != last_space_on_soundcard) {
-                VERBOSE(VB_AUDIO, LOC + QString("%1 bytes free on soundcard")
+            if (space_on_soundcard != last_space_on_soundcard)
+            {
+                VERBOSE(VB_AUDIO|VB_TIMESTAMP,
+                        LOC + QString("%1 bytes free on soundcard")
                         .arg(space_on_soundcard));
+
                 last_space_on_soundcard = space_on_soundcard;
             }
 
@@ -799,7 +1160,7 @@
                     WriteAudio(zeros, fragment_size);
                 } else {
                     // this should never happen now -dag
-                    VERBOSE(VB_AUDIO, LOC +
+                    VERBOSE(VB_AUDIO|VB_TIMESTAMP, LOC + 
                             QString("waiting for space on soundcard "
                                     "to write zeros: have %1 need %2")
                             .arg(space_on_soundcard).arg(fragment_size));
@@ -835,12 +1196,13 @@
         if (fragment_size > audiolen(true))
         {
             if (audiolen(true) > 0)  // only log if we're sending some audio
-                VERBOSE(VB_AUDIO, LOC +
+                VERBOSE(VB_AUDIO|VB_TIMESTAMP, LOC +
                         QString("audio waiting for buffer to fill: "
                                 "have %1 want %2")
                         .arg(audiolen(true)).arg(fragment_size));
 
-            VERBOSE(VB_AUDIO, LOC + "Broadcasting free space avail");
+            //VERBOSE(VB_AUDIO|VB_TIMESTAMP,
+            //LOC + "Broadcasting free space avail");
             pthread_mutex_lock(&audio_buflock);
             pthread_cond_broadcast(&audio_bufsig);
             pthread_mutex_unlock(&audio_buflock);
@@ -854,7 +1216,7 @@
         if (fragment_size > space_on_soundcard)
         {
             if (space_on_soundcard != last_space_on_soundcard) {
-                VERBOSE(VB_AUDIO, LOC +
+                VERBOSE(VB_AUDIO|VB_TIMESTAMP, LOC +
                         QString("audio waiting for space on soundcard: "
                                 "have %1 need %2")
                         .arg(space_on_soundcard).arg(fragment_size));
@@ -916,7 +1278,7 @@
 
         /* update raud */
         raud = (raud + fragment_size) % AUDBUFSIZE;
-        VERBOSE(VB_AUDIO, LOC + "Broadcasting free space avail");
+        //VERBOSE(VB_AUDIO|VB_TIMESTAMP, LOC + "Broadcasting free space avail");
         pthread_cond_broadcast(&audio_bufsig);
 
         written_size = fragment_size;
Index: libs/libmyth/libmyth.pro
===================================================================
--- libs/libmyth/libmyth.pro	(revision 15618)
+++ libs/libmyth/libmyth.pro	(working copy)
@@ -11,6 +11,7 @@
 
 # Input
 HEADERS += audiooutput.h audiooutputbase.h audiooutputnull.h
+HEADERS += audiooutputdigitalencoder.h
 HEADERS += backendselect.h dbsettings.h dialogbox.h
 HEADERS += DisplayRes.h DisplayResScreen.h exitcodes.h
 HEADERS += generictree.h httpcomms.h langsettings.h lcddevice.h
@@ -25,8 +26,10 @@
 HEADERS += volumebase.h volumecontrol.h virtualkeyboard.h visual.h xmlparse.h
 HEADERS += mythhdd.h mythcdrom.h
 HEADERS += compat.h
+HEADERS += audiooutputdigitalencoder.h
 
 SOURCES += audiooutput.cpp audiooutputbase.cpp audiooutputnull.cpp
+SOURCES += audiooutputdigitalencoder.cpp
 SOURCES += backendselect.cpp dbsettings.cpp dialogbox.cpp
 SOURCES += DisplayRes.cpp DisplayResScreen.cpp
 SOURCES += generictree.cpp httpcomms.cpp langsettings.cpp lcddevice.cpp
@@ -41,17 +44,25 @@
 SOURCES += volumebase.cpp volumecontrol.cpp virtualkeyboard.cpp xmlparse.cpp
 SOURCES += mythhdd.cpp mythcdrom.cpp
 
-INCLUDEPATH += ../libmythsamplerate ../libmythsoundtouch ../.. ../ ./
+INCLUDEPATH += ../libmythsamplerate ../libmythsoundtouch ../libmythfreesurround
+INCLUDEPATH += ../libavcodec ../libavutil
+INCLUDEPATH += ../.. ../ ./
 DEPENDPATH += ../libmythsamplerate ../libmythsoundtouch ../ ../libmythui
-DEPENDPATH += ../libmythupnp
+DEPENDPATH += ../libmythupnp ../libmythfreesurround ../libavcodec ../libavutil
 
-LIBS += -L../libmythsamplerate -lmythsamplerate-$${LIBVERSION}
-LIBS += -L../libmythsoundtouch -lmythsoundtouch-$${LIBVERSION}
-LIBS += -L../libmythui         -lmythui-$${LIBVERSION}
-LIBS += -L../libmythupnp       -lmythupnp-$${LIBVERSION}
 
+LIBS += -L../libmythsamplerate   -lmythsamplerate-$${LIBVERSION}
+LIBS += -L../libmythsoundtouch   -lmythsoundtouch-$${LIBVERSION}
+LIBS += -L../libmythui           -lmythui-$${LIBVERSION}
+LIBS += -L../libmythupnp         -lmythupnp-$${LIBVERSION}
+LIBS += -L../libmythfreesurround -lmythfreesurround-$${LIBVERSION}
+LIBS += -L../libavcodec          -lmythavcodec-$${LIBVERSION}
+LIBS += -L../libavutil           -lmythavutil-$${LIBVERSION}
+LIBS += -lfftw3f
+
 TARGETDEPS += ../libmythsamplerate/libmythsamplerate-$${MYTH_LIB_EXT}
 TARGETDEPS += ../libmythsoundtouch/libmythsoundtouch-$${MYTH_LIB_EXT}
+TARGETDEPS += ../libmythfreesurround/libmythfreesurround-$${MYTH_LIB_EXT}
 
 # Install headers so that plugins can compile independently
 inc.path = $${PREFIX}/include/mythtv/
@@ -221,3 +232,7 @@
 use_hidesyms {
     QMAKE_CXXFLAGS += -fvisibility=hidden
 }
+
+contains( CONFIG_LIBA52, yes ) {
+    LIBS += -la52
+}
Index: libs/libmyth/audiooutputdx.cpp
===================================================================
--- libs/libmyth/audiooutputdx.cpp	(revision 15618)
+++ libs/libmyth/audiooutputdx.cpp	(working copy)
@@ -130,8 +130,11 @@
     // FIXME: kedl: not sure what else could be required here?
 }
 
-void AudioOutputDX::Reconfigure(int audio_bits, int audio_channels,
-                                int audio_samplerate, int audio_passthru)
+void AudioOutputDX::Reconfigure(int audio_bits, 
+                                int audio_channels, 
+                                int audio_samplerate,
+                                int audio_passthru,
+                                AudioCodecMode laom)
 {
     if (dsbuffer)
         DestroyDSBuffer();
Index: libs/libmyth/audiooutputdigitalencoder.cpp
===================================================================
--- libs/libmyth/audiooutputdigitalencoder.cpp	(revision 0)
+++ libs/libmyth/audiooutputdigitalencoder.cpp	(revision 0)
@@ -0,0 +1,326 @@
+// Std C headers
+#include <cstdio>
+
+// libav headers
+extern "C" {
+#include "libavcodec/avcodec.h"
+#ifdef ENABLE_AC3_DECODER
+#include "libavcodec/parser.h"
+#else
+#include <a52dec/a52.h>
+#endif
+}
+
+// MythTV headers
+#include "config.h"
+#include "mythcontext.h"
+#include "audiooutputdigitalencoder.h"
+#include "compat.h"
+
+#define LOC QString("DEnc: ")
+#define LOC_ERR QString("DEnc, Error: ")
+
+#define MAX_AC3_FRAME_SIZE 6144
+
+AudioOutputDigitalEncoder::AudioOutputDigitalEncoder(void) :
+    av_context(NULL),
+    outbuf(NULL),
+    outbuf_size(0),
+    frame_buffer(NULL),
+    one_frame_bytes(0)
+{
+}
+
+AudioOutputDigitalEncoder::~AudioOutputDigitalEncoder()
+{
+    Dispose();
+}
+
+void AudioOutputDigitalEncoder::Dispose()
+{
+    if (av_context)
+    {
+        avcodec_close(av_context);
+        av_free(av_context);
+        av_context = NULL;
+    }
+
+    if (outbuf)
+    {
+        delete [] outbuf;
+        outbuf = NULL;
+        outbuf_size = 0;
+    }
+
+    if (frame_buffer)
+    {
+        delete [] frame_buffer;
+        frame_buffer = NULL;
+        one_frame_bytes = 0;
+    }
+}
+
+//CODEC_ID_AC3
+bool AudioOutputDigitalEncoder::Init(
+    CodecID codec_id, int bitrate, int samplerate, int channels)
+{
+    AVCodec *codec;
+    int ret;
+
+    VERBOSE(VB_AUDIO, LOC + QString("Init codecid=%1, br=%2, sr=%3, ch=%4")
+            .arg(codec_id_string(codec_id))
+            .arg(bitrate)
+            .arg(samplerate)
+            .arg(channels));
+
+    //codec = avcodec_find_encoder(codec_id);
+    // always AC3 as there is no DTS encoder at the moment 2005/1/9
+    codec = avcodec_find_encoder(CODEC_ID_AC3);
+    if (!codec)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Could not find codec");
+        return false;
+    }
+
+    av_context = avcodec_alloc_context();
+    av_context->bit_rate = bitrate;
+    av_context->sample_rate = samplerate;
+    av_context->channels = channels;
+
+    // open it */
+    ret = avcodec_open(av_context, codec);
+    if (ret < 0) 
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                "Could not open codec, invalid bitrate or samplerate");
+
+        Dispose();
+        return false;
+    }
+
+    size_t bytes_per_frame = av_context->channels * sizeof(short);
+    audio_bytes_per_sample = bytes_per_frame;
+    one_frame_bytes = bytes_per_frame * av_context->frame_size;
+
+    outbuf_size = 16384;    // ok for AC3 but DTS?
+    outbuf = new char [outbuf_size];
+    VERBOSE(VB_AUDIO, QString("DigitalEncoder::Init fs=%1, bpf=%2 ofb=%3")
+            .arg(av_context->frame_size)
+            .arg(bytes_per_frame)
+            .arg(one_frame_bytes));
+
+    return true;
+}
+
+static int DTS_SAMPLEFREQS[16] =
+{
+    0,      8000,   16000,  32000,  64000,  128000, 11025,  22050,
+    44100,  88200,  176400, 12000,  24000,  48000,  96000,  192000
+};
+
+static int DTS_BITRATES[30] =
+{
+    32000,    56000,    64000,    96000,    112000,   128000,
+    192000,   224000,   256000,   320000,   384000,   448000,
+    512000,   576000,   640000,   768000,   896000,   1024000,
+    1152000,  1280000,  1344000,  1408000,  1411200,  1472000,
+    1536000,  1920000,  2048000,  3072000,  3840000,  4096000
+};
+
+static int dts_decode_header(uint8_t *indata_ptr, int *rate,
+                             int *nblks, int *sfreq)
+{
+    uint id = ((indata_ptr[0] << 24) | (indata_ptr[1] << 16) |
+               (indata_ptr[2] << 8)  | (indata_ptr[3]));
+
+    if (id != 0x7ffe8001)
+        return -1;
+
+    int ftype = indata_ptr[4] >> 7;
+
+    int surp = (indata_ptr[4] >> 2) & 0x1f;
+    surp = (surp + 1) % 32;
+
+    *nblks = (indata_ptr[4] & 0x01) << 6 | (indata_ptr[5] >> 2);
+    ++*nblks;
+
+    int fsize = (indata_ptr[5] & 0x03) << 12 |
+                (indata_ptr[6]         << 4) | (indata_ptr[7] >> 4);
+    ++fsize;
+
+    *sfreq = (indata_ptr[8] >> 2) & 0x0f;
+    *rate = (indata_ptr[8] & 0x03) << 3 | ((indata_ptr[9] >> 5) & 0x07);
+
+    if (ftype != 1)
+    {
+        VERBOSE(VB_IMPORTANT, LOC +
+                QString("DTS: Termination frames not handled (ftype %1)")
+                .arg(ftype));
+        return -1;
+    }
+
+    if (*sfreq != 13)
+    {
+        VERBOSE(VB_IMPORTANT, LOC +
+                QString("DTS: Only 48kHz supported (sfreq %1)").arg(*sfreq));
+        return -1;
+    }
+
+    if ((fsize > 8192) || (fsize < 96))
+    {
+        VERBOSE(VB_IMPORTANT, LOC +
+                QString("DTS: fsize: %1 invalid").arg(fsize));
+        return -1;
+    }
+
+    if (*nblks != 8 && *nblks != 16 && *nblks != 32 &&
+        *nblks != 64 && *nblks != 128 && ftype == 1)
+    {
+        VERBOSE(VB_IMPORTANT, LOC +
+                QString("DTS: nblks %1 not valid for normal frame")
+                .arg(*nblks));
+        return -1;
+    }
+
+    return fsize;
+}
+
+static int dts_syncinfo(uint8_t *indata_ptr, int *flags,
+                        int *sample_rate, int *bit_rate)
+{
+    (void) flags;
+
+    int nblks;
+    int rate;
+    int sfreq;
+
+    int fsize = dts_decode_header(indata_ptr, &rate, &nblks, &sfreq);
+    if (fsize >= 0)
+    {
+        *bit_rate = (rate >= 0 && rate <= 29) ? DTS_BITRATES[rate] : 0;
+        *sample_rate = (sfreq >= 1 && sfreq <= 15)? DTS_SAMPLEFREQS[sfreq] : 0;
+    }
+
+    return fsize;
+}
+
+// until there is an easy way to do this with ffmpeg
+// get the code from libavcodec/parser.c made non static
+extern "C" int ac3_sync(const uint8_t *buf, int *channels, int *sample_rate,
+                        int *bit_rate, int *samples);
+
+static int encode_frame(
+        bool dts, 
+        unsigned char *data,
+        size_t &len)
+{
+    size_t enc_len;
+    int flags, sample_rate, bit_rate;
+
+    // we don't do any length/crc validation of the AC3 frame here; presumably
+    // the receiver will have enough sense to do that.  if someone has a
+    // receiver that doesn't, here would be a good place to put in a call
+    // to a52_crc16_block(samples+2, data_size-2) - but what do we do if the
+    // packet is bad?  we'd need to send something that the receiver would
+    // ignore, and if so, may as well just assume that it will ignore
+    // anything with a bad CRC...
+
+    uint nr_samples = 0, block_len;
+    if (dts)
+    {
+        enc_len = dts_syncinfo(data+8, &flags, &sample_rate, &bit_rate);
+        int rate, sfreq, nblks;
+        dts_decode_header(data+8, &rate, &nblks, &sfreq);
+        nr_samples = nblks * 32;
+        block_len = nr_samples * 2 * 2;
+    }
+    else
+    {
+#ifdef ENABLE_AC3_DECODER
+        enc_len = ac3_sync(
+            data + 8, &flags, &sample_rate, &bit_rate, (int*)&block_len);
+#else
+        enc_len = a52_syncinfo(data + 8, &flags, &sample_rate, &bit_rate);
+        block_len = MAX_AC3_FRAME_SIZE;
+#endif
+    }
+
+    if (enc_len == 0 || enc_len > len)
+    {
+        int l = len;
+        len = 0;
+        return l;
+    }
+
+    enc_len = min((uint)enc_len, block_len - 8);
+
+    //uint32_t x = *(uint32_t*)(data+8);
+    // in place swab
+    swab(data + 8, data + 8, enc_len);
+    //VERBOSE(VB_AUDIO|VB_TIMESTAMP, 
+    //        QString("DigitalEncoder::Encode swab test %1 %2")
+    //        .arg(x,0,16).arg(*(uint32_t*)(data+8),0,16));
+
+    // the following values come from libmpcodecs/ad_hwac3.c in mplayer.
+    // they form a valid IEC958 AC3 header.
+    data[0] = 0x72;
+    data[1] = 0xF8;
+    data[2] = 0x1F;
+    data[3] = 0x4E;
+    data[4] = 0x01;
+    if (dts)
+    {
+        switch(nr_samples)
+        {
+            case 512:
+                data[4] = 0x0B;      /* DTS-1 (512-sample bursts) */
+                break;
+
+            case 1024:
+                data[4] = 0x0C;      /* DTS-2 (1024-sample bursts) */
+                break;
+
+            case 2048:
+                data[4] = 0x0D;      /* DTS-3 (2048-sample bursts) */
+                break;
+
+            default:
+                VERBOSE(VB_IMPORTANT, LOC +
+                        QString("DTS: %1-sample bursts not supported")
+                        .arg(nr_samples));
+                data[4] = 0x00;
+                break;
+        }
+    }
+    data[5] = 0x00;
+    data[6] = (enc_len << 3) & 0xFF;
+    data[7] = (enc_len >> 5) & 0xFF;
+    memset(data + 8 + enc_len, 0, block_len - 8 - enc_len);
+    len = block_len;
+
+    return enc_len;
+}
+
+// must have exactly 1 frames worth of data
+size_t AudioOutputDigitalEncoder::Encode(short *buff)
+{
+    int encsize = 0;
+    size_t outsize = 0;
+ 
+    // put data in the correct spot for encode frame
+    outsize = avcodec_encode_audio(
+        av_context, ((uchar*)outbuf) + 8, outbuf_size - 8, buff);
+
+    size_t tmpsize = outsize;
+
+    outsize = MAX_AC3_FRAME_SIZE;
+    encsize = encode_frame(
+        /*av_context->codec_id==CODEC_ID_DTS*/ false,
+        (unsigned char*)outbuf, outsize);
+
+    VERBOSE(VB_AUDIO|VB_TIMESTAMP, 
+            QString("DigitalEncoder::Encode len1=%1 len2=%2 finallen=%3")
+                .arg(tmpsize).arg(encsize).arg(outsize));
+
+    return outsize;
+}
Index: libs/libmyth/audiooutput.h
===================================================================
--- libs/libmyth/audiooutput.h	(revision 15618)
+++ libs/libmyth/audiooutput.h	(working copy)
@@ -31,10 +31,14 @@
     virtual ~AudioOutput() { };
 
     // reconfigure sound out for new params
-    virtual void Reconfigure(int audio_bits, int audio_channels,
-                             int audio_samplerate, bool audio_passthru) = 0;
+    virtual void Reconfigure(int audio_bits, 
+                             int audio_channels, 
+                             int audio_samplerate,
+                             bool audio_passthru,
+                             void* audio_codec = NULL) = 0;
     
     virtual void SetStretchFactor(float factor);
+    virtual float GetStretchFactor(void) { return 1.0f; }
 
     // do AddSamples calls block?
     virtual void SetBlocking(bool blocking) = 0;
@@ -76,6 +80,7 @@
         lastError = msg;
         VERBOSE(VB_IMPORTANT, "AudioOutput Error: " + lastError);
     }
+    void ClearError(void) { lastError = QString::null; }
 
     void Warn(QString msg)
     {
Index: libs/libmyth/audiooutputdx.h
===================================================================
--- libs/libmyth/audiooutputdx.h	(revision 15618)
+++ libs/libmyth/audiooutputdx.h	(working copy)
@@ -35,8 +35,11 @@
     /// END HACK HACK HACK HACK
 	
     virtual void Reset(void);
-    virtual void Reconfigure(int audio_bits,       int audio_channels,
-                             int audio_samplerate, int audio_passthru);
+    virtual void Reconfigure(int audio_bits, 
+                             int audio_channels, 
+                             int audio_samplerate,
+                             bool audio_passthru,
+                             AudioCodecMode aom = AUDIOCODECMODE_NORMAL);
     virtual void SetBlocking(bool blocking);
 
     virtual bool AddSamples(char *buffer, int samples, long long timecode);
Index: programs/mythuitest/mythuitest.pro
===================================================================
--- programs/mythuitest/mythuitest.pro	(revision 15618)
+++ programs/mythuitest/mythuitest.pro	(working copy)
@@ -6,8 +6,13 @@
 TARGET = mythuitest
 CONFIG += thread opengl
 
+LIBS += -L../../libs/libavcodec -L../../libs/libavutil
+LIBS += -lmythavcodec-$$LIBVERSION -lmythavutil-$$LIBVERSION
 LIBS += $$EXTRA_LIBS
 
+TARGETDEPS += ../../libs/libavcodec/libmythavcodec-$${LIBVERSION}.$${QMAKE_EXTENSION_SHLIB}
+TARGETDEPS += ../../libs/libavutil/libmythavutil-$${LIBVERSION}.$${QMAKE_EXTENSION_SHLIB}
+
 macx {
     # Duplication of source with libmyth (e.g. oldsettings.cpp)
     # means that the linker complains, so we have to ignore duplicates 
Index: programs/mythfrontend/globalsettings.cpp
===================================================================
--- programs/mythfrontend/globalsettings.cpp	(revision 15618)
+++ programs/mythfrontend/globalsettings.cpp	(working copy)
@@ -56,7 +56,12 @@
     }
 #endif
 #ifdef USING_ALSA
-    gc->addSelection("ALSA:default", "ALSA:default");
+    gc->addSelection("ALSA:default",       "ALSA:default");
+    gc->addSelection("ALSA:surround51",    "ALSA:surround51");
+    gc->addSelection("ALSA:analog",        "ALSA:analog");
+    gc->addSelection("ALSA:digital",       "ALSA:digital");
+    gc->addSelection("ALSA:mixed-analog",  "ALSA:mixed-analog");
+    gc->addSelection("ALSA:mixed-digital", "ALSA:mixed-digital");
 #endif
 #ifdef USING_ARTS
     gc->addSelection("ARTS:", "ARTS:");
@@ -78,6 +83,33 @@
     return gc;
 }
 
+static HostComboBox *MaxAudioChannels()
+{
+    HostComboBox *gc = new HostComboBox("MaxChannels",false);
+    gc->setLabel(QObject::tr("Max Audio Channels"));
+    gc->addSelection(QObject::tr("Stereo"), "2", true); // default
+    gc->addSelection(QObject::tr("5.1"), "6");
+    gc->setHelpText(
+            QObject::tr(
+                "Set the maximum number of audio channels to be decoded. "
+                "This is for multi-channel/surround audio playback."));
+    return gc;
+}
+
+static HostComboBox *AudioUpmixType()
+{
+    HostComboBox *gc = new HostComboBox("AudioUpmixType",false);
+    gc->setLabel(QObject::tr("Upmix"));
+    gc->addSelection(QObject::tr("Passive"), "0");
+    gc->addSelection(QObject::tr("Active Simple"), "1");
+    gc->addSelection(QObject::tr("Active Linear"), "2", true); // default
+    gc->setHelpText(
+            QObject::tr(
+                "Set the audio upmix type for 2ch to 6ch conversion. "
+                "This is for multi-channel/surround audio playback."));
+    return gc;
+}
+
 static HostComboBox *PassThroughOutputDevice()
 {
     HostComboBox *gc = new HostComboBox("PassThruOutputDevice", true);
@@ -3156,6 +3188,12 @@
          vgrp0->addChild(AC3PassThrough());
          vgrp0->addChild(DTSPassThrough());
 
+         HorizontalConfigurationGroup *agrp =
+             new HorizontalConfigurationGroup(false, false, true, true);
+         agrp->addChild(MaxAudioChannels());
+         agrp->addChild(AudioUpmixType());
+         addChild(agrp);
+
          VerticalConfigurationGroup *vgrp1 =
              new VerticalConfigurationGroup(false, false, true, true);
          vgrp1->addChild(AggressiveBuffer());
Index: programs/mythtranscode/transcode.cpp
===================================================================
--- programs/mythtranscode/transcode.cpp	(revision 15618)
+++ programs/mythtranscode/transcode.cpp	(working copy)
@@ -55,13 +55,18 @@
 
     // reconfigure sound out for new params
     virtual void Reconfigure(int audio_bits, int audio_channels,
-                             int audio_samplerate, bool audio_passthru)
+                             int audio_samplerate, bool audio_passthru,
+                             void *audio_codec = NULL)
     {
+        ClearError();
         (void)audio_samplerate;
         (void)audio_passthru;
+        (void)audio_codec;
         bits = audio_bits;
         channels = audio_channels;
         bytes_per_sample = bits * channels / 8;
+        if ((uint)audio_channels > 2)
+            Error(QString("Invalid channel count %1").arg(channels));
     }
 
     // dsprate is in 100 * samples/second
