Index: libs/libmythtv/NuppelVideoRecorder.cpp
===================================================================
--- libs/libmythtv/NuppelVideoRecorder.cpp	(revision 16136)
+++ libs/libmythtv/NuppelVideoRecorder.cpp	(working copy)
@@ -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,11 +12,13 @@
 
 #include <qstringlist.h>
 
+#include <algorithm>
 #include <iostream>
 using namespace std;
 
 #include "mythcontext.h"
 #include "NuppelVideoRecorder.h"
+#include "audioinput.h"
 #include "vbitext/cc.h"
 #include "channelbase.h"
 #include "filtermanager.h"
@@ -57,7 +54,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;
 
@@ -189,6 +186,11 @@
         lame_close(gf);  
     if (strm)
         delete [] strm;
+    if (audio_device)
+    {
+        delete audio_device;
+        audio_device = NULL;
+    }
     if (fd >= 0)
         close(fd);
     if (seektable)
@@ -663,8 +665,7 @@
 
 int NuppelVideoRecorder::AudioInit(bool skipdevice)
 {
-    int afmt, afd;
-    int frag, blocksize = 4096;
+    int blocksize = 4096;
     int tmp;
 
     if (!skipdevice)
@@ -679,57 +680,39 @@
 
         return 1;
 #else
-        if (-1 == (afd = open(audiodevice.ascii(), O_RDONLY | O_NONBLOCK)))
+        audio_device = AudioInput::CreateDevice(audiodevice);
+        if (!audio_device)
         {
-            VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Cannot open DSP '%1'")
-                    .arg(audiodevice));
-            perror("open");
+            VERBOSE(VB_IMPORTANT,
+                    LOC_ERR + "AudioInit: Unable to create device");
             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) 
-        {
-            close(afd);
-            VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't get 16 bit DSP");
-            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)
+        if (!audio_device->Open(audio_bits, audio_samplerate, audio_channels))
         {
-            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);
+            VERBOSE(VB_IMPORTANT, 
+                    LOC_ERR + "AudioInit: Unable to open device");
             return 1;
         }
 
-        if (-1 == ioctl(afd, SNDCTL_DSP_GETBLKSIZE, &blocksize)) 
+        blocksize = audio_device->GetBlockSize();
+
+        if (-1 == blocksize)
         {
-            close(afd);
-            VERBOSE(VB_IMPORTANT, LOC_ERR + "AudioInit(): Can't get DSP blocksize");
-            return(1);
+            VERBOSE(VB_GENERAL,
+                    LOC_ERR + "AudioInit: Unable to determine block size,"
+                    "using default of 1024 bytes");
+            blocksize = 1024;
         }
 
-        close(afd);
+        VERBOSE(VB_AUDIO, 
+                LOC + QString("AudioInit: Using buffer size of %1 bytes")
+                .arg(blocksize));
+
+        audio_device->Close();
 #endif
     }
 
-    audio_bytes_per_sample = audio_channels * audio_bits / 8;
-    blocksize *= 4;
-
     audio_buffer_size = blocksize;
 
     if (compressaudio)
@@ -2232,84 +2215,36 @@
 
 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;
-
-    if (-1 == (afd = open(audiodevice.ascii(), 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) 
+ 
+    int act = 0, lastread = 0;
+    unsigned char *buffer;
+    struct timeval anow;
+    
+    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)
-    {
-        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);
-        return;
-    }
-
     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;
+    
+    if (!audio_device->Start())
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Audio: Unable to start capture");
+        return;
+    }
+    
     while (childrenLive) 
     {
         if (request_pause)
@@ -2325,13 +2260,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");
+                    arg(lastread).arg(audio_buffer_size).arg(audiodevice) +
+                    ENO);
         }
 
         /* record the current time */
@@ -2339,7 +2274,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;
 
@@ -2360,7 +2295,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);
@@ -2375,8 +2310,9 @@
     }
 
     delete [] buffer;
-    close(afd);
-#endif
+
+    if (audio_device->IsOpen())
+        audio_device->Close();
 }
 
 struct VBIData
Index: libs/libmythtv/libmythtv.pro
===================================================================
--- libs/libmythtv/libmythtv.pro	(revision 16136)
+++ libs/libmythtv/libmythtv.pro	(working copy)
@@ -87,8 +87,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
 
Index: libs/libmythtv/NuppelVideoRecorder.h
===================================================================
--- libs/libmythtv/NuppelVideoRecorder.h	(revision 16136)
+++ libs/libmythtv/NuppelVideoRecorder.h	(working copy)
@@ -44,6 +44,7 @@
 class ChannelBase;
 class FilterManager;
 class FilterChain;
+class AudioInput;
 
 class MPUBLIC NuppelVideoRecorder : public RecorderBase, public CC608Reader
 {
@@ -152,6 +153,7 @@
     int inputchannel;
     int compression;
     int compressaudio;
+    AudioInput *audio_device;
     unsigned long long audiobytes;
     int audio_channels; 
     int audio_bits;
Index: libs/libmythtv/videosource.cpp
===================================================================
--- libs/libmythtv/videosource.cpp	(revision 16136)
+++ libs/libmythtv/videosource.cpp	(working copy)
@@ -833,15 +833,29 @@
 {
   public:
     AudioDevice(const CaptureCard &parent) :
-        PathSetting(this, true),
+        PathSetting(this, false),
         CaptureCardDBStorage(this, parent, "audiodevice")
     {
         setLabel(QObject::tr("Audio device"));
+#ifdef USING_OSS
         QDir dev("/dev", "dsp*", QDir::Name, QDir::System);
         fillSelectionsFromDir(dev);
         dev.setPath("/dev/sound");
         fillSelectionsFromDir(dev);
-        addSelection(QObject::tr("(None)"), "/dev/null");
+#endif
+#ifdef USING_ALSA
+    addSelection("ALSA:default", "ALSA:default");
+#endif
+#ifdef USING_ARTS
+    //addSelection("ARTS:", "ARTS:");
+#endif
+#ifdef USING_JACK
+    //addSelection("JACK:output", "JACK:output"); 
+#endif
+#ifdef USING_COREAUDIO
+    //addSelection("CoreAudio:", "CoreAudio:"); 
+#endif
+        addSelection(QObject::tr("(None)"), "NULL");
     };
 };
 
Index: libs/libmyth/audioinput.h
===================================================================
--- libs/libmyth/audioinput.h	(revision 0)
+++ libs/libmyth/audioinput.h	(revision 0)
@@ -0,0 +1,55 @@
+/*
+ * 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.h>
+
+class AudioInput 
+{
+  public:
+    virtual ~AudioInput() {}
+
+    virtual bool Open(uint depth, uint sample_rate, uint channels) = 0;
+    virtual bool IsOpen(void) const = 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 *buffer, uint num_samples) = 0;
+    virtual int GetNumReadyBytes(void) = 0;
+
+    // Factory function
+    static AudioInput *CreateDevice(const QString &device);
+
+  protected:
+    AudioInput(const QString &device);
+    QString m_device_name;
+    int     m_audio_channels;
+    int     m_audio_sample_size;
+    int     m_audio_sample_rate;
+};
+
+
+#endif /* _AUDIOINPUT_H_ */
+
Index: libs/libmyth/audioinputoss.cpp
===================================================================
--- libs/libmyth/audioinputoss.cpp	(revision 0)
+++ libs/libmyth/audioinputoss.cpp	(revision 0)
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2007  Anand K. Mistry
+ * Copyright (C) 2007  Daniel Kristjansson
+ * Copyright (C) 2003-2007 Others who contributed to NuppelVideoRecorder.cpp
+ *
+ * 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 <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#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"
+
+#define LOC QString("AudInOSS(%1): ").arg(m_device_name)
+#define LOC_WARN QString("AudInOSS(%1) Warning: ").arg(m_device_name)
+#define LOC_ERR QString("AudInOSS(%1) Error: ").arg(m_device_name)
+
+AudioInputOSS::AudioInputOSS(const QString &device) :
+    AudioInput(device), m_audio_fd(-1)
+{
+}
+
+AudioInputOSS::~AudioInputOSS()
+{
+    Close();
+}
+
+bool AudioInputOSS::Open(uint sample_size, uint sample_rate, uint channels)
+{
+    int desired_format = AFMT_S16_LE, format;
+
+    if (IsOpen())
+        Close();
+
+    // Open the device
+    const QString tmp = QDeepCopy<QString>(m_device_name);
+    m_audio_fd = open(tmp.ascii(), O_RDONLY | O_NONBLOCK);
+    if (m_audio_fd < 0)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Cannot open '%1'")
+                .arg(m_device_name) + ENO);
+
+        return false;
+    }
+
+    // Disable trigger
+    int trigger = 0;
+    int ret = ioctl(m_audio_fd, SNDCTL_DSP_SETTRIGGER, &trigger);
+    if (0 != ret)
+    {
+        VERBOSE(VB_AUDIO, LOC_WARN + "Can't stop capture" + ENO);
+    }
+
+    // Get file descriptor flags
+    int flags = fcntl(m_audio_fd, F_GETFL);
+    if (-1 == flags)
+    {
+        VERBOSE(VB_AUDIO, LOC_WARN + "Unable to get blocking status" + ENO);
+    }
+    else
+    {
+        // Set blocking IO
+        ret = fcntl(m_audio_fd, F_SETFL, flags & ~O_NONBLOCK);
+        if (-1 == ret)
+            VERBOSE(VB_AUDIO, LOC_WARN + "Unable to set blocking" + ENO);
+    }
+
+    // Set buffering hints
+    {
+        int bufcnt  = 8;  // 8 buffers
+        int bufbits = 10; // 1<<10 = 1024 bytes each
+        int frag = (bufcnt << 16) | (bufbits);
+        ret = ioctl(m_audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag);
+    }
+
+    // Set format
+    format = desired_format;
+    ret = ioctl(m_audio_fd, SNDCTL_DSP_SETFMT, &format);
+    if ((-1 == ret) || (desired_format != format))
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to set desired format");
+        goto err_exit;
+    }
+
+    // Set sample size
+    m_audio_sample_size = sample_size;
+    ret = ioctl(m_audio_fd, SNDCTL_DSP_SAMPLESIZE, &m_audio_sample_size);
+    if (ret < 0)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to set sample size" + ENO);
+        goto err_exit;
+    }
+
+    // Set channels
+    m_audio_channels = channels;
+    ret = ioctl(m_audio_fd, SNDCTL_DSP_CHANNELS, &m_audio_channels);
+    if (ret < 0)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                "Unable to set number of channels" + ENO);
+        goto err_exit;
+    }
+
+    // Set sample rate
+    m_audio_sample_rate = sample_rate;
+    ret = ioctl(m_audio_fd, SNDCTL_DSP_SPEED, &m_audio_sample_rate);
+    if (ret < 0)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to set sample rate" + ENO);
+        goto err_exit;
+    }
+
+    return true;
+
+  err_exit:
+    close(m_audio_fd);
+    m_audio_fd          = -1;
+    m_audio_sample_size =  0;
+    m_audio_sample_rate =  0;
+    m_audio_channels    =  0;
+    return false;
+}
+
+void AudioInputOSS::Close(void)
+{
+    VERBOSE(VB_AUDIO, LOC + QString("Closing device '%1' %2")
+            .arg(m_device_name).arg(IsOpen()));
+
+    if (IsOpen())
+    {
+        close(m_audio_fd);
+        m_audio_fd          = -1;
+        m_audio_sample_size =  0;
+        m_audio_sample_rate =  0;
+        m_audio_channels    =  0;
+    }
+}
+
+bool AudioInputOSS::Start(void)
+{
+    if (!IsOpen())
+        return false;
+
+    int trigger = PCM_ENABLE_INPUT;
+    int ret = ioctl(m_audio_fd, SNDCTL_DSP_SETTRIGGER, &trigger);
+    if (-1 == ret)
+    {
+        VERBOSE(VB_AUDIO, LOC + "Unable to start capture" + ENO);
+        return false;
+    }
+
+    VERBOSE(VB_AUDIO, LOC + "Started capture");
+
+    return true;
+}
+
+bool AudioInputOSS::Stop(void)
+{
+    VERBOSE(VB_IMPORTANT, LOC_ERR + "Not implemented");
+    return false;
+}
+
+int AudioInputOSS::GetBlockSize(void)
+{
+    if (!IsOpen())
+        return -1;
+
+    int fragment_size;
+    int ret = ioctl(m_audio_fd, SNDCTL_DSP_GETBLKSIZE, &fragment_size);
+
+    if (-1 == ret)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to query fragment size" + ENO);
+        return -1;
+    }
+
+    return fragment_size;
+}
+
+int AudioInputOSS::GetSamples(void *buffer, uint num_bytes)
+{
+    if (!IsOpen())
+        return -1;
+
+    if (0 != (num_bytes % ((m_audio_sample_size * m_audio_channels) / 8)))
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Invalid num_bytes");
+        return -1;
+    }
+
+    // TODO FIXME This will fail if the read is interrupted by a signal...
+    int bytes_read = read(m_audio_fd, buffer, num_bytes);
+
+    return bytes_read;
+}
+
+int AudioInputOSS::GetNumReadyBytes(void)
+{
+    if (!IsOpen())
+        return -1;
+
+    audio_buf_info ispace;
+    int ret = ioctl(m_audio_fd, SNDCTL_DSP_GETISPACE, &ispace);
+    if (-1 == ret)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to get ready bytes" + ENO);
+    }
+
+    return ispace.bytes;
+}
+
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
Index: libs/libmyth/audioinputoss.h
===================================================================
--- libs/libmyth/audioinputoss.h	(revision 0)
+++ libs/libmyth/audioinputoss.h	(revision 0)
@@ -0,0 +1,48 @@
+/*
+ * 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 _AUDIOINPUTOSS_H_
+#define _AUDIOINPUTOSS_H_
+
+#include "audioinput.h"
+
+class AudioInputOSS : public AudioInput
+{
+  public:
+    AudioInputOSS(const QString &device);
+    virtual ~AudioInputOSS();
+
+    virtual bool Open(uint depth, uint sample_rate, uint channels);
+    virtual bool IsOpen(void) const { return m_audio_fd >= 0; }
+    virtual void Close(void);
+
+    virtual bool Start(void);
+    virtual bool Stop(void);
+
+    virtual int GetBlockSize(void);
+    virtual int GetSamples(void *buffer, uint num_samples);
+    virtual int GetNumReadyBytes(void);
+
+  private:
+    int m_audio_fd;
+};
+
+#endif /* _AUDIOINPUTOSS_H_ */
+
Index: libs/libmyth/audioinputalsa.cpp
===================================================================
--- libs/libmyth/audioinputalsa.cpp	(revision 0)
+++ libs/libmyth/audioinputalsa.cpp	(revision 0)
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2007  Anand K. Mistry
+ * Copyright (C) 2007  Daniel Kristjansson
+ *
+ * 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 <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <alsa/asoundlib.h>
+
+#include "audioinputalsa.h"
+#include "mythcontext.h"
+
+#define LOC QString("AudInALSA(%1): ").arg(m_device_name)
+#define LOC_WARN QString("AudInALSA(%1) Warning: ").arg(m_device_name)
+#define LOC_ERR QString("AudInALSA(%1) Error: ").arg(m_device_name)
+
+AudioInputALSA::AudioInputALSA(const QString &device) :
+    AudioInput(device), m_audio_handle(NULL)
+{
+}
+
+AudioInputALSA::~AudioInputALSA()
+{
+    Close();
+}
+
+bool AudioInputALSA::Open(uint sample_size, uint sample_rate, uint channels)
+{
+    if (IsOpen())
+        Close();
+
+    // Open the device
+    const QString tmp = QDeepCopy<QString>(m_device_name);
+    int ret = snd_pcm_open((snd_pcm_t**)(&m_audio_handle),
+                           tmp.ascii(), SND_PCM_STREAM_CAPTURE, 0);
+
+    if (ret)
+    {
+        m_audio_handle = NULL;
+        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Cannot open '%1'")
+                .arg(m_device_name));
+
+        return false;
+    }
+
+    // Allocate hw params structure
+    snd_pcm_hw_params_t *hw_params = NULL;
+    ret = snd_pcm_hw_params_malloc(&hw_params);
+    if (ret)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to allocate hw params");
+        goto err_exit;
+    }
+
+    // Initialize hw params
+    ret = snd_pcm_hw_params_any(((snd_pcm_t*) m_audio_handle), hw_params);
+    if (ret)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to init hw params");
+        goto err_exit;
+    }
+
+    // Set interleaved access
+    ret = snd_pcm_hw_params_set_access(((snd_pcm_t*) m_audio_handle),
+                                       hw_params,
+                                       SND_PCM_ACCESS_RW_INTERLEAVED);
+    if (ret)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to set interleaved");
+        goto err_exit;
+    }
+
+    // Set format
+    ret = snd_pcm_hw_params_set_format(((snd_pcm_t*) m_audio_handle),
+                                       hw_params,
+                                       SND_PCM_FORMAT_S16_LE);
+    if (ret)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to set desired format");
+        goto err_exit;
+    }
+
+    // Set sampling rate
+    m_audio_sample_rate = sample_rate;
+    ret = snd_pcm_hw_params_set_rate(((snd_pcm_t*) m_audio_handle),
+                                     hw_params, m_audio_sample_rate, 0);
+    if (ret)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to set sample rate" + ENO);
+        goto err_exit;
+    }
+
+    // Set channels
+    m_audio_channels = channels;
+    ret = snd_pcm_hw_params_set_channels(((snd_pcm_t*) m_audio_handle),
+                                         hw_params, m_audio_channels);
+    if (ret)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                "Unable to set number of channels" + ENO);
+        goto err_exit;
+    }
+
+    // Apply settings
+    ret = snd_pcm_hw_params(((snd_pcm_t*) m_audio_handle), hw_params);
+    if (ret)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                "Unable to apply settings to device" + ENO);
+        goto err_exit;
+    }
+
+    snd_pcm_hw_params_free(hw_params);
+
+    // Set sample size
+    m_audio_sample_size = sample_size;
+
+    return true;
+
+  err_exit:
+    snd_pcm_close(((snd_pcm_t*) m_audio_handle));
+    m_audio_handle      = NULL;
+    m_audio_sample_size = 0;
+    m_audio_sample_rate = 0;
+    m_audio_channels    = 0;
+    return false;
+}
+
+void AudioInputALSA::Close(void)
+{
+    VERBOSE(VB_AUDIO, LOC + QString("Closing device '%1' %2")
+            .arg(m_device_name).arg(IsOpen()));
+
+    if (IsOpen())
+    {
+        snd_pcm_close(((snd_pcm_t*) m_audio_handle));
+        m_audio_handle      = NULL;
+        m_audio_sample_size = 0;
+        m_audio_sample_rate = 0;
+        m_audio_channels    = 0;
+    }
+}
+
+bool AudioInputALSA::Start(void)
+{
+    if (!IsOpen())
+        return false;
+
+    int ret = snd_pcm_prepare(((snd_pcm_t*) m_audio_handle));
+    if (0 != ret)
+    {
+        VERBOSE(VB_AUDIO, LOC + "Unable to start capture");
+        return false;
+    }
+
+    VERBOSE(VB_AUDIO, LOC + "Started capture on " + m_device_name);
+
+    return true;
+}
+
+bool AudioInputALSA::Stop(void)
+{
+    VERBOSE(VB_IMPORTANT, LOC_ERR + "Not implemented");
+    return false;
+}
+
+int AudioInputALSA::GetBlockSize(void)
+{
+    if (!IsOpen())
+        return -1;
+
+    snd_pcm_uframes_t buffer_size, period_size;
+
+    int ret = snd_pcm_get_params(((snd_pcm_t*) m_audio_handle),
+                                 &buffer_size, &period_size);
+
+    if (0 != ret)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to query fragment size" + ENO);
+        return -1;
+    }
+
+    return (period_size * m_audio_channels * m_audio_sample_size) / 8;
+}
+
+int AudioInputALSA::GetSamples(void *buffer, uint num_bytes)
+{
+    if (!IsOpen())
+        return -1;
+
+    uint frame_size = (m_audio_sample_size * m_audio_channels) / 8;
+
+    if (0 != (num_bytes % frame_size))
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Invalid num_bytes");
+        return -1;
+    }
+
+    int ret = snd_pcm_readi(((snd_pcm_t*) m_audio_handle),
+                            buffer, num_bytes / frame_size);
+
+    if ((-EINTR == ret) || (-EPIPE == ret) || (-ESTRPIPE == ret))
+    {
+        ret = snd_pcm_recover(((snd_pcm_t*) m_audio_handle), ret, 1);
+        if ((ret < 0) && (-EAGAIN != ret))
+        {
+            VERBOSE(VB_IMPORTANT, LOC_ERR +
+                    "Failed to recover from error" + ENO);
+            return -1;
+        }
+        ret = 0;
+    }
+
+    return (ret>=0) ? ret * frame_size : -1;
+}
+
+int AudioInputALSA::GetNumReadyBytes(void)
+{
+    if (!IsOpen())
+        return -1;
+
+    snd_pcm_sframes_t delay;
+    int ret = snd_pcm_delay(((snd_pcm_t*) m_audio_handle), &delay);
+
+    if (0 != ret)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to get ready bytes" + ENO);
+        return -1;
+    }
+
+    return (delay * m_audio_channels * m_audio_sample_size) / 8;
+}
+
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
Index: libs/libmyth/libmyth.pro
===================================================================
--- libs/libmyth/libmyth.pro	(revision 16136)
+++ libs/libmyth/libmyth.pro	(working copy)
@@ -85,8 +85,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
 }
 
 unix:!cygwin {
@@ -175,8 +175,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
 }
 
Index: libs/libmyth/audioinput.cpp
===================================================================
--- libs/libmyth/audioinput.cpp	(revision 0)
+++ libs/libmyth/audioinput.cpp	(revision 0)
@@ -0,0 +1,76 @@
+/*
+ * 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: */
+
+#include "audioinput.h"
+#include "mythcontext.h"
+#include "audioinputalsa.h"
+#include "audioinputoss.h"
+
+#define LOC QString("AudIn(%1): ").arg(device)
+#define LOC_WARN QString("AudIn(%1) Warning: ").arg(device)
+#define LOC_ERR QString("AudIn(%1) Error: ").arg(device)
+
+AudioInput::AudioInput(const QString &device) :
+    m_device_name(QString::null), m_audio_channels(0),
+    m_audio_sample_size(0),       m_audio_sample_rate(0)
+{
+    if (!device.isEmpty())
+        m_device_name = QDeepCopy<QString>(device);
+}
+
+AudioInput *AudioInput::CreateDevice(const QString &device)
+{
+    AudioInput *dev = NULL;
+
+    if (device.isEmpty())
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Device string is empty");
+        return NULL;
+    }
+
+    if ((device == "NULL") || (device == "/dev/null"))
+    {
+        VERBOSE(VB_AUDIO, LOC + "Using NULL audio in");
+    }
+    else if (device.startsWith("ALSA:"))
+    {
+#ifdef USE_ALSA
+        QString tmp = QDeepCopy<QString>(device);
+        dev = new AudioInputALSA(tmp.remove(0,5));
+#else
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "ALSA input support not available");
+#endif
+    }
+    else if (device.startsWith("/"))
+    {
+#ifdef USING_OSS
+        dev = new AudioInputOSS(device);
+#else
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "OSS input support not available");
+#endif
+    }
+    else
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                QString("Unrecognized audio in '%1' device").arg(device));
+    }
+
+    return dev;
+}
Index: libs/libmyth/audioinputalsa.h
===================================================================
--- libs/libmyth/audioinputalsa.h	(revision 0)
+++ libs/libmyth/audioinputalsa.h	(revision 0)
@@ -0,0 +1,48 @@
+/*
+ * 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 _AUDIOINPUTALSA_H_
+#define _AUDIOINPUTALSA_H_
+
+#include "audioinput.h"
+
+class AudioInputALSA : public AudioInput
+{
+  public:
+    AudioInputALSA(const QString &device);
+    virtual ~AudioInputALSA();
+
+    virtual bool Open(uint depth, uint sample_rate, uint channels);
+    virtual bool IsOpen(void) const { return m_audio_handle; }
+    virtual void Close(void);
+
+    virtual bool Start(void);
+    virtual bool Stop(void);
+
+    virtual int GetBlockSize(void);
+    virtual int GetSamples(void *buffer, uint num_samples);
+    virtual int GetNumReadyBytes(void);
+
+  private:
+    void *m_audio_handle;
+};
+
+#endif /* _AUDIOINPUTALSA_H_ */
+
