--- mythtv.orig/libs/libmythtv/NuppelVideoRecorder.cpp
+++ mythtv/libs/libmythtv/NuppelVideoRecorder.cpp
@@ -5,11 +5,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include "mythconfig.h"
-#ifdef HAVE_SYS_SOUNDCARD_H
-    #include <sys/soundcard.h>
-#elif HAVE_SOUNDCARD_H
-    #include <soundcard.h>
-#endif
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <cerrno>
@@ -17,12 +12,14 @@
 
 #include <QStringList>
 
+#include <algorithm>
 #include <iostream>
 using namespace std;
 
 #include "libmyth/mythcontext.h"
 #include "libmythdb/mythverbose.h"
 #include "NuppelVideoRecorder.h"
+#include "audioinput.h"
 #include "vbitext/cc.h"
 #include "channelbase.h"
 #include "filtermanager.h"
@@ -58,7 +55,7 @@
 #define LOC_ERR QString("NVR(%1) Error: ").arg(videodevice)
 
 NuppelVideoRecorder::NuppelVideoRecorder(TVRec *rec, ChannelBase *channel)
-    : RecorderBase(rec)
+    : RecorderBase(rec), audio_device(NULL)
 {
     channelObj = channel;
 
@@ -190,6 +187,11 @@
         lame_close(gf);  
     if (strm)
         delete [] strm;
+    if (audio_device)
+    {
+        delete audio_device;
+        audio_device = NULL;
+    }
     if (fd >= 0)
         close(fd);
     if (seektable)
@@ -612,7 +614,7 @@
 {
     if (AudioInit() != 0)   
     {
-        VERBOSE(VB_IMPORTANT, LOC_ERR + "Could not detect audio blocksize");
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to init audio input device");
     }
  
     if (videocodec == "hardware-mjpeg")
@@ -668,8 +670,7 @@
 
 int NuppelVideoRecorder::AudioInit(bool skipdevice)
 {
-    int afmt, afd;
-    int frag, blocksize = 4096;
+    int blocksize = 4096;
     int tmp;
 
     if (!skipdevice)
@@ -679,64 +680,39 @@
         (void) afd;
         (void) frag;
 
-        VERBOSE(VB_IMPORTANT, LOC_ERR +
-                "This Unix doesn't support device files for audio access.");
+        VERBOSE(VB_IMPORTANT, LOC_ERR
+                + "This Unix doesn't support device files for audio access.");
 
         return 1;
 #else
-        QByteArray adevice = audiodevice.toAscii();
-        if (-1 == (afd = open(adevice.constData(), O_RDONLY | O_NONBLOCK)))
-        {
-            VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Cannot open DSP '%1'")
-                    .arg(audiodevice));
-            perror("open");
-            return 1;
-        }
- 
-        fcntl(afd, F_SETFL, fcntl(afd, F_GETFL) & ~O_NONBLOCK);
- 
-        //ioctl(afd, SNDCTL_DSP_RESET, 0);
-   
-        frag = (8 << 16) | (10); //8 buffers, 1024 bytes each
-        ioctl(afd, SNDCTL_DSP_SETFRAGMENT, &frag);
- 
-        afmt = AFMT_S16_LE;
-        ioctl(afd, SNDCTL_DSP_SETFMT, &afmt);
-        if (afmt != AFMT_S16_LE) 
+        audio_device = AudioInput::CreateDevice(audiodevice.toAscii());
+        if (!audio_device)
         {
-            close(afd);
-            VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't get 16 bit DSP");
+            VERBOSE(VB_IMPORTANT, LOC_ERR + "AudioInit: unable to create device");
             return 1;
         }
 
-        if (ioctl(afd, SNDCTL_DSP_SAMPLESIZE, &audio_bits) < 0 ||
-            ioctl(afd, SNDCTL_DSP_CHANNELS, &audio_channels) < 0 ||
-            ioctl(afd, SNDCTL_DSP_SPEED, &audio_samplerate) < 0)
-        {
-            close(afd);
-            QString msg = LOC_ERR +
-                QString("AudioInit(): %1 : error setting audio input device"
-                        " to %2kHz/%3bits/%4channel").arg(audiodevice).
-                arg(audio_samplerate).arg(audio_bits).arg(audio_channels);
-            VERBOSE(VB_IMPORTANT, msg);
+        if (!audio_device->Open(audio_bits, audio_samplerate, audio_channels))
+        {
+            VERBOSE(VB_IMPORTANT, LOC_ERR + "AudioInit: Unable to open device");
             return 1;
         }
 
-        if (-1 == ioctl(afd, SNDCTL_DSP_GETBLKSIZE, &blocksize)) 
+        if ((blocksize = audio_device->GetBlockSize()) <= 0)
         {
-            close(afd);
-            VERBOSE(VB_IMPORTANT, LOC_ERR + "AudioInit(): Can't get DSP blocksize");
-            return(1);
+            blocksize = 1024;
+            VERBOSE(VB_GENERAL, LOC_ERR + "AudioInit unable to determine block "
+                                          "size, using default of 1024 bytes");
         }
 
-        close(afd);
+        audio_device->Close();
 #endif
     }
 
     audio_bytes_per_sample = audio_channels * audio_bits / 8;
-    blocksize *= 4;
-
     audio_buffer_size = blocksize;
+    VERBOSE(VB_AUDIO, LOC + QString("AudioInit: audio buffer size %1 bytes")
+                                    .arg(audio_buffer_size));
 
     if (compressaudio)
     {
@@ -756,8 +732,8 @@
 
         if (audio_bits != 16) 
         {
-            VERBOSE(VB_IMPORTANT, LOC_ERR +
-                    "AudioInit(): lame support requires 16bit audio");
+            VERBOSE(VB_IMPORTANT, LOC_ERR
+                     + "AudioInit(): lame support requires 16bit audio");
             compressaudio = false;
         }
     }
@@ -1301,7 +1277,6 @@
     {
         // this is supported by the cx88 and various ati cards.
         vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-
         if (ioctl(fd, VIDIOC_S_FMT, &vfmt) < 0)
         {
             VERBOSE(VB_IMPORTANT, LOC_ERR + "v4l2: Unable to set desired format");
@@ -2255,90 +2230,35 @@
 
 void NuppelVideoRecorder::doAudioThread(void)
 {
-#if !defined (HAVE_SYS_SOUNDCARD_H) && !defined(HAVE_SOUNDCARD_H)
-    VERBOSE(VB_IMPORTANT, LOC +
-            QString("doAudioThread() This Unix doesn't support"
-                    " device files for audio access. Skipping"));
-    return;
-#else
-    int afmt = 0, trigger = 0;
-    int afd = 0, act = 0, lastread = 0;
-    int frag = 0, blocksize = 0;
-    unsigned char *buffer;
-    audio_buf_info ispace;
-    struct timeval anow;
-
-    act_audio_sample = 0;
-
-    QByteArray adevice = audiodevice.toAscii();
-    if (-1 == (afd = open(adevice.constData(), O_RDONLY | O_NONBLOCK))) 
+    if (!audio_device)
     {
-        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Cannot open DSP '%1', exiting").
-                arg(audiodevice));
-        perror("open");
+        VERBOSE(VB_GENERAL, LOC + "Audio: no audio device");
         return;
     }
 
-    fcntl(afd, F_SETFL, fcntl(afd, F_GETFL) & ~O_NONBLOCK);
-    //ioctl(afd, SNDCTL_DSP_RESET, 0);
-
-    frag = (8 << 16) | (10); //8 buffers, 1024 bytes each
-    ioctl(afd, SNDCTL_DSP_SETFRAGMENT, &frag);
-
-    afmt = AFMT_S16_LE;
-    ioctl(afd, SNDCTL_DSP_SETFMT, &afmt);
-    if (afmt != AFMT_S16_LE) 
+    if (!audio_device->Open(audio_bits, audio_samplerate, audio_channels))
     {
-        VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't get 16 bit DSP, exiting");
-        close(afd);
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Audio: Unable to open device");
         return;
     }
 
-    if (ioctl(afd, SNDCTL_DSP_SAMPLESIZE, &audio_bits) < 0 ||
-        ioctl(afd, SNDCTL_DSP_CHANNELS, &audio_channels) < 0 ||
-        ioctl(afd, SNDCTL_DSP_SPEED, &audio_samplerate) < 0)
+    if (!audio_device->Start())
     {
-        VERBOSE(VB_IMPORTANT, LOC_ERR + QString(" %1: error setting audio input device to "
-                                      "%2 kHz/%3 bits/%4 channel").
-                arg(audiodevice).arg(audio_samplerate).
-                arg(audio_bits).arg(audio_channels));
-        close(afd);
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Audio: Unable to start capture");
         return;
     }
 
+    struct timeval anow;
+    unsigned char *buffer = new unsigned char[audio_buffer_size];
+    int act = 0, lastread = 0;
     audio_bytes_per_sample = audio_channels * audio_bits / 8;
-
-    if (-1 == ioctl(afd, SNDCTL_DSP_GETBLKSIZE,  &blocksize)) 
-    {
-        VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't get DSP blocksize, exiting");
-        close(afd);
-        return;
-    }
-
-    blocksize *= 4;  // allways read 4*blocksize
-
-    if (blocksize != audio_buffer_size) 
-    {
-        VERBOSE(VB_IMPORTANT, LOC +
-                QString("Warning, audio blocksize = '%1' while audio_buffer_size='%2'").
-                arg(blocksize).arg(audio_buffer_size));
-    }
-
-    buffer = new unsigned char[audio_buffer_size];
-
-    /* trigger record */
-    trigger = 0;
-    ioctl(afd,SNDCTL_DSP_SETTRIGGER,&trigger);
-
-    trigger = PCM_ENABLE_INPUT;
-    ioctl(afd,SNDCTL_DSP_SETTRIGGER,&trigger);
+    audiopaused = false;
 
     // Qt4 requires a QMutex as a parameter...
     // not sure if this is the best solution.  Mutex Must be locked before wait.
     QMutex mutex;
     mutex.lock();
 
-    audiopaused = false;
     while (childrenLive) 
     {
         if (request_pause)
@@ -2354,13 +2274,13 @@
         }
         audiopaused = false;
 
-        if (audio_buffer_size != (lastread = read(afd, buffer,
-                                                  audio_buffer_size))) 
+        lastread = audio_device->GetSamples(buffer, audio_buffer_size);
+        if (audio_buffer_size != lastread)
         {
-            VERBOSE(VB_IMPORTANT, LOC_ERR +
-                    QString("Only read %1 bytes of %2 bytes from '%3").
-                    arg(lastread).arg(audio_buffer_size).arg(audiodevice));
-            perror("read audio");
+            VERBOSE(VB_IMPORTANT, LOC_ERR
+                    + QString("Short read, %1 of %2 bytes from ")
+                              .arg(lastread).arg(audio_buffer_size)
+                    + audiodevice);
         }
 
         /* record the current time */
@@ -2368,7 +2288,7 @@
            (like we used to.) Measure to see how much stuff is in there,
            and correct for it when calculating the timestamp */
         gettimeofday(&anow, &tzone);
-        ioctl( afd, SNDCTL_DSP_GETISPACE, &ispace );
+        int bytes_read = max(audio_device->GetNumReadyBytes(), 0);
 
         act = act_audio_buffer;
 
@@ -2389,7 +2309,7 @@
            audio chunk. So, subtract off the length of the chunk
            and the length of audio still in the capture buffer. */
         audiobuffer[act]->timecode -= (int)( 
-                (ispace.fragments * ispace.fragsize + audio_buffer_size)
+                (bytes_read + audio_buffer_size)
                  * 1000.0 / (audio_samplerate * audio_bytes_per_sample));
 
         memcpy(audiobuffer[act]->buffer, buffer, audio_buffer_size);
@@ -2404,8 +2324,9 @@
     }
 
     delete [] buffer;
-    close(afd);
-#endif
+
+    if (audio_device->IsOpen())
+        audio_device->Close();
 }
 
 struct VBIData
--- mythtv.orig/libs/libmythtv/libmythtv.pro
+++ mythtv/libs/libmythtv/libmythtv.pro
@@ -96,8 +96,13 @@
 cygwin:QMAKE_LFLAGS_SHLIB += -Wl,--noinhibit-exec
 cygwin:DEFINES += _WIN32
 
-# Enable Linux Open Sound System support
-using_oss:DEFINES += USING_OSS
+# Enable sound systems support
+using_alsa:DEFINES += USING_ALSA
+using_arts:DEFINES += USING_ARTS
+using_jack:DEFINES += USING_JACK
+using_oss: DEFINES += USING_OSS
+macx:      DEFINES += USING_COREAUDIO
+
 # Enable Valgrind, i.e. disable some timeouts
 using_valgrind:DEFINES += USING_VALGRIND
 
--- mythtv.orig/libs/libmythtv/NuppelVideoRecorder.h
+++ mythtv/libs/libmythtv/NuppelVideoRecorder.h
@@ -44,6 +44,7 @@
 class ChannelBase;
 class FilterManager;
 class FilterChain;
+class AudioInput;
 
 class MPUBLIC NuppelVideoRecorder : public RecorderBase, public CC608Reader
 {
@@ -153,6 +154,7 @@
     int inputchannel;
     int compression;
     int compressaudio;
+    AudioInput *audio_device;
     unsigned long long audiobytes;
     int audio_channels; 
     int audio_bits;
--- /dev/null
+++ mythtv/libs/libmyth/audioinput.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007  Anand K. Mistry
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+
+#ifndef _AUDIOINPUT_H_
+#define _AUDIOINPUT_H_
+
+#include <QString>
+
+class AudioInput
+{
+  public:
+    virtual ~AudioInput() {}
+
+    virtual bool Open(uint sample_bits, uint sample_rate, uint channels) = 0;
+    virtual bool IsOpen(void) = 0;
+    virtual void Close(void) = 0;
+
+    virtual bool Start(void) = 0;
+    virtual bool Stop(void) = 0;
+
+    virtual int GetBlockSize(void) = 0;
+    virtual int GetSamples(void *buf, uint nbytes) = 0;
+    virtual int GetNumReadyBytes(void) = 0;
+
+    // Factory function
+    static AudioInput *CreateDevice(const QByteArray &device);
+
+  protected:
+    AudioInput(const QString &device);
+
+    QByteArray m_audio_device;
+    int        m_audio_channels;
+    int        m_audio_sample_bits;
+    int        m_audio_sample_rate;
+};
+#endif /* _AUDIOINPUT_H_ */
\ No newline at end of file
--- /dev/null
+++ mythtv/libs/libmyth/audioinputoss.cpp
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2007  Anand K. Mistry
+ * Copyright (C) 2007  Daniel Kristjansson
+ * Copyright (C) 2003-2007 Others who contributed to NuppelVideoRecorder.cpp
+ * Copyright (C) 2008  Alan Calvert
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "mythconfig.h"
+#ifdef HAVE_SYS_SOUNDCARD_H
+    #include <sys/soundcard.h>
+#elif HAVE_SOUNDCARD_H
+    #include <soundcard.h>
+#endif
+
+#include "audioinputoss.h"
+#include "mythcontext.h"
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#define LOC QString("AudioInputOSS: ")
+#define LOC_ERR QString("AudioInputOSS error: ")
+
+AudioInputOSS::AudioInputOSS(const QString &device) : AudioInput(device)
+{
+    if (!device.isEmpty())
+        m_device_name = QByteArray(device.toAscii());
+    else
+        m_device_name = QByteArray();
+    dsp_fd = -1;
+    log_tag = QString( "device '" + m_device_name + "', ");
+}
+
+bool AudioInputOSS::Open(uint sample_bits, uint sample_rate, uint channels)
+{
+    m_audio_sample_bits = sample_bits;
+    m_audio_sample_rate = sample_rate;
+    //m_audio_channels = channels;
+    int chk;
+
+    if (IsOpen())
+        Close();
+
+    // Open the device
+    dsp_fd = open(m_device_name.constData(), O_RDONLY);
+    if (dsp_fd < 0)
+        return OssFatal(dsp_fd, "open failed");
+
+    chk = 0; // disable input for now
+    ioctl(dsp_fd, SNDCTL_DSP_SETTRIGGER, &chk);
+
+    // Set format
+    int format, choice;
+    QString tag = QString::null;
+    switch (sample_bits)
+    {
+        case 8:
+            choice = AFMT_U8;
+            tag = "AFMT_U8";
+            break;
+        case 16:
+        default:
+#ifdef WORDS_BIGENDIAN
+            choice = AFMT_S16_BE;
+            tag = "AFMT_S16_BE";
+#else
+            choice = AFMT_S16_LE;
+            tag = "AFMT_S16_LE";
+#endif
+            break;
+    }
+    format = choice;
+    if ((chk = ioctl(dsp_fd, SNDCTL_DSP_SETFMT, &format) < 0))
+        return OssFatal(chk, QString("failed to set audio format %1").arg(tag));
+    if (format != choice)
+        return OssFatal(0, QString("set audio format not %1 as requested")
+                                   .arg(tag));
+
+    // sample size
+    m_audio_sample_bits = choice = sample_bits;
+    if ((chk = ioctl(dsp_fd, SNDCTL_DSP_SAMPLESIZE, &m_audio_sample_bits)) < 0)
+        return OssFatal(chk, QString("failed to set audio sample bits to %1")
+                                     .arg(sample_bits));
+    if (m_audio_sample_bits != choice)
+        OssError(0, QString("requested %1 sample bits, got %2")
+                            .arg(choice).arg(m_audio_sample_bits));
+    // channels
+    m_audio_channels = choice = channels;
+    if ((chk = ioctl(dsp_fd, SNDCTL_DSP_CHANNELS, &m_audio_channels)) < 0)
+        return OssFatal(chk, QString("failed to set audio channels to %1")
+                                     .arg(channels));
+    if (m_audio_channels != choice)
+        OssError(0, QString("requested %1 channels, got %2 ")
+                            .arg(choice).arg(m_audio_channels));
+
+    // sample rate
+    uint choice_sample_rate;
+    m_audio_sample_rate = choice_sample_rate = sample_rate;
+    if ((chk = ioctl(dsp_fd, SNDCTL_DSP_SPEED, &m_audio_sample_rate)) < 0)
+        return OssFatal(chk, QString("failed to set sample rate to %1")
+                                     .arg(sample_rate));
+    if (m_audio_sample_rate != choice_sample_rate)
+        OssError(0, QString("requested sample rate %1, got %2")
+                            .arg(choice_sample_rate).arg(m_audio_sample_rate));
+    OssInfo("device open");
+    return true;
+}
+
+void AudioInputOSS::Close(void)
+{
+    if (IsOpen())
+        close(dsp_fd);
+    dsp_fd = -1;
+    m_audio_sample_bits = 0;
+    m_audio_sample_rate = 0;
+    m_audio_channels = 0;
+    OssInfo("device closed");
+}
+
+bool AudioInputOSS::Start(void)
+{
+    bool started = false;
+    if (IsOpen())
+    {
+        int chk;
+        int trig = 0; // clear
+        ioctl(dsp_fd, SNDCTL_DSP_SETTRIGGER, &trig);
+        trig = PCM_ENABLE_INPUT; // enable input
+        if ((chk = ioctl(dsp_fd, SNDCTL_DSP_SETTRIGGER, &trig)) < 0)
+            OssError(chk, "Start() failed");
+        else
+        {
+            OssInfo("capture started");
+            started = true;
+        }
+    }
+    return started;
+}
+
+bool AudioInputOSS::Stop(void)
+{
+    bool stopped = false;
+    int chk;
+    int trig = 0;
+    if ((chk = ioctl(dsp_fd, SNDCTL_DSP_SETTRIGGER, &trig)) < 0)
+        OssError(chk, "stop action failed");
+    else
+    {
+        stopped = true;
+        OssInfo("capture stopped");
+    }
+    return stopped;
+}
+
+int AudioInputOSS::GetBlockSize(void)
+{
+    int frag = 0;
+    if (IsOpen())
+    {
+        int chk;
+        if ((chk = ioctl(dsp_fd, SNDCTL_DSP_GETBLKSIZE, &frag)) < 0)
+        {
+            OssError(chk, QString("fragment size query failed, returned %1")
+                                  .arg(frag));
+            frag = 0;
+        }
+    }
+    OssInfo(QString("block size %1").arg(frag));
+    return frag;
+}
+
+int AudioInputOSS::GetSamples(void *buffer, uint num_bytes)
+{
+    int bytes_read = 0;
+    if (IsOpen())
+    {
+        unsigned char* bufptr = (unsigned char*)buffer;
+        int this_read;
+        int retries = 0;
+        while (bytes_read < num_bytes && retries < 3)
+        {
+            this_read = read(dsp_fd, buffer, num_bytes - bytes_read);
+            if (this_read < 0)
+                OssError(this_read, "GetSamples read failed");
+           else
+            {
+                bytes_read += this_read;
+                bufptr += this_read;
+            }
+            ++retries;
+        }
+        if (num_bytes > (uint)bytes_read)
+            VERBOSE(VB_IMPORTANT, LOC_ERR + log_tag
+                    + QString("GetSamples short read, %1 of %2 bytes")
+                              .arg(bytes_read).arg(num_bytes));
+    }
+    return bytes_read;
+}
+
+int AudioInputOSS::GetNumReadyBytes(void)
+{
+    int readies = 0;
+    if (IsOpen())
+    {
+        audio_buf_info ispace;
+        int chk;
+        if ((chk = ioctl(dsp_fd, SNDCTL_DSP_GETISPACE, &ispace)) < 0)
+            OssError(chk, QString("get ready bytes failed, returned %1")
+                                  .arg(ispace.bytes));
+        else if ((readies = ispace.bytes) > 0)
+            VERBOSE(VB_AUDIO+VB_EXTRA, LOC + log_tag
+                    + QString("ready bytes %1").arg(readies));
+    }
+    return readies;
+}
+
+void AudioInputOSS::OssError(int err, QString msg)
+{
+    QString suffix = QString::null;
+    if (err < 0)
+        suffix = QString(": %1").arg(strerror(err));
+    VERBOSE(VB_IMPORTANT, LOC_ERR + log_tag + msg + suffix);
+}
+
+bool AudioInputOSS::OssFatal(int err, QString msg)
+{
+    OssError(err, msg);
+    Close();
+    return false;
+}
+
+void AudioInputOSS::OssInfo(QString msg)
+{
+    VERBOSE(VB_AUDIO, LOC + log_tag + msg);
+}
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
--- /dev/null
+++ mythtv/libs/libmyth/audioinputoss.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2007  Anand K. Mistry
+ * Copyright (C) 2008  Alan Calvert
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+
+#ifndef _AUDIOINPUTOSS_H_
+#define _AUDIOINPUTOSS_H_
+
+#include "audioinput.h"
+
+class AudioInputOSS : public AudioInput
+{
+    public:
+        AudioInputOSS(const QString &device);
+        ~AudioInputOSS() { Close(); };
+
+        bool Open(uint sample_bits, uint sample_rate, uint channels);
+        inline bool IsOpen(void) { return (dsp_fd > -1); }
+        void Close(void);
+
+        bool Start(void);
+        bool Stop(void);
+
+        int GetBlockSize(void);
+        int GetSamples(void *buffer, uint num_samples);
+        int GetNumReadyBytes(void);
+
+    private:
+        void OssInfo(QString msg);
+        void OssError(int err, QString msg);
+        bool OssFatal(int err, QString msg);
+
+        QByteArray m_device_name;
+        int dsp_fd;
+        QString log_tag;
+};
+#endif /* _AUDIOINPUTOSS_H_ */
+
--- /dev/null
+++ mythtv/libs/libmyth/audioinputalsa.cpp
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2007  Anand K. Mistry
+ * Copyright (C) 2007  Daniel Kristjansson
+ * Copyright (C) 2008  Alan Calvert
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "audioinputalsa.h"
+#include "mythcontext.h"
+
+#define LOC QString("AudioInputALSA Info: ")
+#define LOC_ERR QString("AudioInputALSA Error: ")
+
+AudioInputALSA::AudioInputALSA(const QString &device):
+    AudioInput(device),
+    pcm_handle(NULL),
+    myth_block_bytes(0)
+{
+    if (!device.isEmpty())
+        alsa_device = QByteArray(device.toAscii().right(device.size() - 5));
+    else
+        alsa_device = QByteArray();
+    log_tag = "device '" + alsa_device + "', ";
+}
+
+bool AudioInputALSA::Open(uint sample_bits, uint sample_rate, uint channels)
+{
+    if (pcm_handle != NULL)
+        Close();
+    m_audio_sample_rate = sample_rate;
+    m_audio_channels = channels;
+    m_audio_sample_bits = sample_bits;
+    snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE;
+    AlsaBad(snd_config_update_free_global(), "free global snd config failed");
+    if (AlsaBad(snd_pcm_open(&pcm_handle, alsa_device.constData(), stream, 0),
+                "pcm open failed"))                      // note blocking mode!
+    {
+        pcm_handle = NULL;
+        return false;
+    }
+    if (!(PrepHwParams() && PrepSwParams()))
+    {
+        snd_pcm_close(pcm_handle);
+        pcm_handle = NULL;
+        return false;
+    }
+    VERBOSE(VB_AUDIO, LOC + log_tag + "pcm open ok");
+    return true;
+}
+
+void AudioInputALSA::Close(void)
+{
+    if (pcm_handle != NULL)
+    {
+        Stop();
+        AlsaBad(snd_pcm_close(pcm_handle), "Close() close failed");
+    }
+    pcm_handle = NULL;
+}
+
+bool AudioInputALSA::Start(void)
+{
+    bool started = false;
+    if (pcm_handle != NULL
+        && !AlsaBad(snd_pcm_prepare(pcm_handle), "Start() prepare failed")
+        && !AlsaBad(snd_pcm_start(pcm_handle), "Start() start failed"))
+    {
+        started = true;
+        VERBOSE(VB_AUDIO, LOC + log_tag + "capture started");
+    }
+    return started;
+}
+
+bool AudioInputALSA::Stop(void)
+{
+    bool stopped = false;
+    if (pcm_handle != NULL
+        && !AlsaBad(snd_pcm_drop(pcm_handle), "Stop() drop failed"))
+    {
+        stopped = true;
+        VERBOSE(VB_AUDIO, LOC + log_tag + "capture stopped");
+    }
+    return stopped;
+}
+
+int AudioInputALSA::GetSamples(void *buf, uint nbytes)
+{
+    if (!pcm_handle)
+       return 0;
+    snd_pcm_uframes_t nframes = snd_pcm_bytes_to_frames(pcm_handle, nbytes);
+    snd_pcm_uframes_t frames_read;
+    int pcm_state;
+    int chk;
+    switch ((pcm_state = snd_pcm_state(pcm_handle)))
+    {
+        case SND_PCM_STATE_XRUN:
+        case SND_PCM_STATE_SUSPENDED:
+            if (!XrunRecovery())
+                break;
+        case SND_PCM_STATE_PREPARED:
+            if ((chk = snd_pcm_start(pcm_handle) < 0))
+            {
+                VERBOSE(VB_IMPORTANT, LOC_ERR + log_tag
+                        + QString("restart failed: %1").arg(snd_strerror(chk)));
+                 break;
+            }
+            VERBOSE(VB_AUDIO+VB_EXTRA, LOC + log_tag
+                    + "SND_PCM_STATE_PREPARED, start ok");
+            // and fall through to read ...
+        case SND_PCM_STATE_RUNNING:
+            frames_read = PcmRead(buf, nbytes);
+            break;
+        default:
+            VERBOSE(VB_AUDIO, LOC + log_tag
+                    + QString("alarm! SND_PCM_STATE %1 through GetSamples")
+                              .arg(pcm_state));
+            break;
+    }
+    return snd_pcm_frames_to_bytes(pcm_handle, frames_read);
+}
+
+
+int AudioInputALSA::GetNumReadyBytes(void)
+{
+    int bytes_avail = 0;
+    if (pcm_handle != NULL)
+    {
+        snd_pcm_sframes_t frames_avail;
+        int pcm_state = snd_pcm_state(pcm_handle);
+        switch (pcm_state)
+        {
+            case SND_PCM_STATE_PREPARED:
+            case SND_PCM_STATE_RUNNING:
+                if (!AlsaBad((frames_avail = snd_pcm_avail_update(pcm_handle)),
+                             "bad frames available update"))
+                    bytes_avail = snd_pcm_frames_to_bytes(pcm_handle,
+                                                          frames_avail);
+        }
+    }
+    return bytes_avail;
+}
+
+bool AudioInputALSA::PrepHwParams(void)
+{
+
+    snd_pcm_hw_params_t *hwparams;
+    snd_pcm_hw_params_alloca(&hwparams);
+    if (AlsaBad(snd_pcm_hw_params_any(pcm_handle, hwparams),
+                "failed to init hw params"))
+        return false;
+    snd_pcm_access_t axs = SND_PCM_ACCESS_RW_INTERLEAVED;// Forget mmap, it
+                                                         // isn't worth it here.
+    if (AlsaBad(snd_pcm_hw_params_set_access(pcm_handle, hwparams, axs),
+                "failed to set interleaved rw io"))
+        return false;
+    snd_pcm_format_t format =
+        (m_audio_sample_bits > 8) ? SND_PCM_FORMAT_S16 : SND_PCM_FORMAT_U8;
+    if (AlsaBad(snd_pcm_hw_params_set_format(pcm_handle, hwparams, format),
+                QString("failed to set sample format %1")
+                        .arg(snd_pcm_format_description(format))))
+        return false;
+    if (AlsaBad(snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
+                m_audio_channels), QString("failed to set channels to %1")
+                                           .arg(m_audio_channels)))
+    {
+        uint x_chans;
+        if(!AlsaBad(snd_pcm_hw_params_get_channels_min(hwparams, &x_chans),
+                    QString("unable to get min channel count")))
+            VERBOSE(VB_AUDIO, LOC + log_tag + QString("minimum channels: %1")
+                                                       .arg(x_chans));
+
+        if(!AlsaBad(snd_pcm_hw_params_get_channels_max(hwparams, &x_chans),
+                    QString("unable to get max channel count")))
+            VERBOSE(VB_AUDIO, LOC + log_tag + QString("maximum channels: %1")
+                                                       .arg(x_chans));
+        return false;
+    }
+    if (AlsaBad(snd_pcm_hw_params_set_rate(pcm_handle, hwparams,
+                m_audio_sample_rate, 0), QString("failed to set sample rate %1")
+                                                 .arg(m_audio_sample_rate)))
+    {
+        uint rate_num = 0;
+        uint rate_den = 0;
+        if (!AlsaBad(snd_pcm_hw_params_get_rate_numden(hwparams, &rate_num,
+                     &rate_den), "snd_pcm_hw_params_get_rate_numden failed"))
+            if (m_audio_sample_rate != (int)(rate_num / rate_den))
+                VERBOSE(VB_IMPORTANT, LOC_ERR + log_tag
+                        + QString("device reports sample rate as %1")
+                                  .arg(rate_num / rate_den));
+        return false;
+    }
+    uint latency = 64000; // 64 msec
+    snd_pcm_uframes_t buffer_size;
+    uint period_time;
+    if (!AlsaBad(snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hwparams,
+                 &latency, NULL), "initial buffer time/latency setting failed"))
+    {
+        if (AlsaBad(snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size),
+                    "failed to get buffer size"))
+            return false;
+        if (AlsaBad(snd_pcm_hw_params_get_buffer_time(hwparams, &latency, NULL),
+                    "failed to get latency setting"))
+            return false;
+        period_time = latency / 4;
+        if (AlsaBad(snd_pcm_hw_params_set_period_time_near(pcm_handle, hwparams,
+                    &period_time, NULL), "failed to set period time"))
+            return false;
+        if (AlsaBad(snd_pcm_hw_params_get_period_size(hwparams, &period_size,
+                    NULL), "failed to get period size"))
+            return false;
+    }
+    else
+    {
+        VERBOSE(VB_AUDIO, LOC + "hwparams settings, Plan B");
+        period_time = latency / 4;
+        if (AlsaBad(snd_pcm_hw_params_set_period_time_near(pcm_handle, hwparams,
+                    &period_time, NULL), "failed to set period time"))
+            return false;
+        if (AlsaBad(snd_pcm_hw_params_get_period_size(hwparams, &period_size,
+                    NULL), "failed to get period size"))
+            return false;
+        buffer_size = period_size * 4;
+        if (AlsaBad(snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams,
+                    &buffer_size), "failed to set buffer size"))
+            return false;
+        if (AlsaBad(snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size),
+                    "failed to get buffer size"))
+            return false;
+    }
+    if (AlsaBad(snd_pcm_hw_params (pcm_handle, hwparams),
+                "failed to set hwparams"))
+        return false;
+    if (AlsaBad(snd_pcm_hw_params_get_periods(hwparams, &periods, NULL),
+                "failed to get periods"))
+        return false;
+    myth_block_bytes = snd_pcm_frames_to_bytes(pcm_handle, period_size);
+    VERBOSE(VB_AUDIO, LOC + log_tag
+            + QString("channels %1, sample rate %2, latency %3 msec, period "
+                      "size %4, periods %5").arg(m_audio_channels)
+                      .arg(m_audio_sample_rate).arg(latency / 1000.0, -1, 'f', 1)
+                      .arg(period_size).arg(periods));
+    VERBOSE(VB_AUDIO+VB_EXTRA, LOC + log_tag + QString("myth block size %1")
+                                                       .arg(myth_block_bytes));
+    return true;
+}
+
+bool AudioInputALSA::PrepSwParams(void)
+{
+    snd_pcm_sw_params_t* swparams;
+    snd_pcm_sw_params_alloca(&swparams);
+	snd_pcm_uframes_t boundary;
+    if (AlsaBad(snd_pcm_sw_params_current(pcm_handle, swparams),
+               "failed to get swparams"))
+        return false;
+    // explicit start, not auto start
+    if (AlsaBad(snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams,
+                INT_MAX), "failed to set start threshold"))
+		return false;
+   if (AlsaBad(snd_pcm_sw_params_get_boundary(swparams, &boundary),
+               "failed to get boundary"))
+        return false;
+    if (AlsaBad(snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams,
+                boundary), "failed to set stop threshold"))
+		return false;
+    if (AlsaBad(snd_pcm_sw_params(pcm_handle, swparams),
+                "failed to set software parameters"))
+        return false;
+
+    return true;
+}
+
+snd_pcm_uframes_t AudioInputALSA::PcmRead(void *buf, uint nbytes)
+{
+    unsigned char* bufptr = (unsigned char*)buf;
+    snd_pcm_uframes_t to_read = snd_pcm_bytes_to_frames(pcm_handle, nbytes);
+    snd_pcm_uframes_t nframes = to_read;
+    snd_pcm_sframes_t nread;
+    snd_pcm_sframes_t avail;
+    int retries = 0;
+    while (nframes > 0 && retries < 3)
+    {
+        if ((avail = snd_pcm_avail_update(pcm_handle)) < 0
+            && !Recovery(avail))
+        {
+            ++retries;
+            continue;
+        }
+        if ((nread = snd_pcm_readi(pcm_handle, bufptr, nframes)) >= 0)
+        {
+            nframes -= nread;
+            bufptr += snd_pcm_frames_to_bytes(pcm_handle, nread);
+        }
+        else
+        {
+            switch (nread)
+            {
+                case -EAGAIN:
+                    break;
+                case -EBADFD:
+                    VERBOSE(VB_IMPORTANT, LOC_ERR + log_tag
+                            + QString("in a state unfit to read (%1): %2")
+                                      .arg(nread).arg(snd_strerror(nread)));
+                    break;
+                case -EINTR:
+                case -EPIPE:
+                case -ESTRPIPE:
+                    Recovery(nread);
+                    break;
+                default:
+                    VERBOSE(VB_IMPORTANT, LOC_ERR + log_tag
+                            + QString("weird state %1 thru "
+                                      "snd_pcm_readi: %2").arg(nread)
+                                      .arg(snd_strerror(nread)));
+                    break;
+            }
+        }
+        ++retries;
+    }
+    if (nframes > 0)
+        VERBOSE(VB_AUDIO, LOC_ERR + log_tag
+                + QString("short pcm read, %1 of %2 frames")
+                          .arg(to_read - nframes).arg(to_read));
+    return (to_read - nframes);
+}
+
+bool AudioInputALSA::Recovery(int err)
+{
+    if (err > 0)
+        err = -err;
+    bool isgood = false;
+    bool suspense = false;
+    switch (err)
+    {
+        case -EINTR:
+            isgood = true; // nothin' to see here
+            break;
+        case -ESTRPIPE:
+            suspense = true;
+        case -EPIPE:
+            if (!AlsaBad(snd_pcm_prepare(pcm_handle),
+                         QString("failed to recover from %1")
+                                 .arg((suspense) ? "suspend" : "underrun")))
+                isgood = true;
+            break;
+        default:
+            break;
+    }
+    return isgood;
+}
+
+bool AudioInputALSA::AlsaBad(int op_result, QString errmsg)
+{                            // (op_result < 0) => return true
+    bool bad = (op_result < 0);
+    if (bad)
+        VERBOSE(VB_IMPORTANT, LOC_ERR + log_tag + errmsg
+                + QString(": %1").arg(snd_strerror(op_result)));
+    return bad;
+}
+
+bool AudioInputALSA::XrunRecovery(void)
+{
+    bool recov = Stop() && Start();
+    VERBOSE(VB_AUDIO, LOC + log_tag + "xrun recovery "
+            + (recov ? "good" : "not good"));
+    return recov;
+}
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
\ No newline at end of file
--- mythtv.orig/libs/libmyth/libmyth.pro
+++ mythtv/libs/libmyth/libmyth.pro
@@ -88,8 +88,8 @@
 
 using_oss {
     DEFINES += USING_OSS
-    SOURCES += audiooutputoss.cpp
-    HEADERS += audiooutputoss.h
+    SOURCES *= audiooutputoss.cpp audioinputoss.cpp audioinput.cpp
+    HEADERS *= audiooutputoss.h   audioinputoss.h   audioinput.h
     LIBS += $$OSS_LIBS
 }
 
@@ -155,8 +155,8 @@
 
 using_alsa {
     DEFINES += USE_ALSA
-    HEADERS += audiooutputalsa.h
-    SOURCES += audiooutputalsa.cpp
+    HEADERS *= audiooutputalsa.h   audioinputalsa.h   audioinput.h
+    SOURCES *= audiooutputalsa.cpp audioinputalsa.cpp audioinput.cpp
     LIBS += $$ALSA_LIBS
 }
 
--- /dev/null
+++ mythtv/libs/libmyth/audioinput.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007  Anand K. Mistry
+ * Copyright (C) 2008  Alan Calvert
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "mythcontext.h"
+#include "audioinput.h"
+#include "audioinputoss.h"
+#include "audioinputalsa.h"
+
+#define LOC QString("AudioInput: ")
+#define LOC_ERR QString("AudioInput error: ")
+
+AudioInput::AudioInput(const QString &device)
+{
+    m_audio_device = QByteArray(device.toAscii());
+    m_audio_channels = 0;
+    m_audio_sample_bits = 0;
+    m_audio_sample_rate = 0;
+}
+
+AudioInput *AudioInput::CreateDevice(const QByteArray &device)
+{
+    AudioInput *audio = NULL;
+    if (device.startsWith("/"))
+    {
+#       ifdef USING_OSS
+            audio = new AudioInputOSS(device);
+#       else
+            VERBOSE(VB_IMPORTANT, LOC_ERR
+                    + "device " + device + ", OSS input support not available");
+#       endif
+    }
+
+    else if (device.startsWith("ALSA:"))
+    {
+#       ifdef USE_ALSA
+            audio = new AudioInputALSA(device);
+#       else
+            VERBOSE(VB_IMPORTANT, LOC_ERR
+                    + "device " + device + ", ALSA input support not available");
+#       endif
+    }
+
+    else
+        VERBOSE(VB_IMPORTANT, LOC_ERR
+                + "unknown audio input device '" + device + "'");
+
+    return audio;
+}
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
\ No newline at end of file
--- /dev/null
+++ mythtv/libs/libmyth/audioinputalsa.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2007  Anand K. Mistry
+ * Copyright (C) 2008  Alan Calvert
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef _AUDIOINPUTALSA_H_
+#define _AUDIOINPUTALSA_H_
+
+#include "audioinput.h"
+
+#include <alsa/asoundlib.h>
+
+class AudioInputALSA : public AudioInput
+{
+  public:
+    AudioInputALSA(const QString &device);
+    ~AudioInputALSA() { Close(); };
+
+    bool Open(uint sample_bits, uint sample_rate, uint channels);
+    inline bool IsOpen(void) { return (pcm_handle != NULL); }
+    void Close(void);
+
+    bool Start(void);
+    bool Stop(void);
+
+    inline int GetBlockSize(void) { return myth_block_bytes; };
+    int GetSamples(void *buf, uint nbytes);
+    int GetNumReadyBytes(void);
+
+  private:
+    bool PrepHwParams(void);
+    bool PrepSwParams(void);
+    snd_pcm_uframes_t PcmRead(void *buf, uint nbytes);
+    bool Recovery(int err);
+    bool XrunRecovery(void);
+    bool AlsaBad(int op_result, QString errmsg); // (op_result < 0) => false
+
+    QByteArray          alsa_device;
+    snd_pcm_t*          pcm_handle;
+    snd_pcm_uframes_t   period_size;
+    uint                periods;
+    int                 myth_block_bytes;
+    QString             log_tag;
+};
+#endif /* _AUDIOINPUTALSA_H_ */
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+
