Ticket #3405: 3405-v4.patch

File 3405-v4.patch, 41.0 KB (added by Alan Calvert <cal@…>, 17 years ago)

@ 18856

  • libs/libmythtv/NuppelVideoRecorder.cpp

    old new  
    55#include <sys/types.h>
    66#include <sys/stat.h>
    77#include "mythconfig.h"
    8 #ifdef HAVE_SYS_SOUNDCARD_H
    9     #include <sys/soundcard.h>
    10 #elif HAVE_SOUNDCARD_H
    11     #include <soundcard.h>
    12 #endif
    138#include <sys/ioctl.h>
    149#include <sys/mman.h>
    1510#include <cerrno>
     
    1712
    1813#include <QStringList>
    1914
     15#include <algorithm>
    2016#include <iostream>
    2117using namespace std;
    2218
    2319#include "libmyth/mythcontext.h"
    2420#include "libmythdb/mythverbose.h"
    2521#include "NuppelVideoRecorder.h"
     22#include "audioinput.h"
    2623#include "vbitext/cc.h"
    2724#include "channelbase.h"
    2825#include "filtermanager.h"
     
    5855#define LOC_ERR QString("NVR(%1) Error: ").arg(videodevice)
    5956
    6057NuppelVideoRecorder::NuppelVideoRecorder(TVRec *rec, ChannelBase *channel)
    61     : RecorderBase(rec)
     58    : RecorderBase(rec), audio_device(NULL)
    6259{
    6360    channelObj = channel;
    6461
     
    190187        lame_close(gf); 
    191188    if (strm)
    192189        delete [] strm;
     190    if (audio_device)
     191    {
     192        delete audio_device;
     193        audio_device = NULL;
     194    }
    193195    if (fd >= 0)
    194196        close(fd);
    195197    if (seektable)
     
    612614{
    613615    if (AudioInit() != 0)   
    614616    {
    615         VERBOSE(VB_IMPORTANT, LOC_ERR + "Could not detect audio blocksize");
     617        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to init audio input device");
    616618    }
    617619 
    618620    if (videocodec == "hardware-mjpeg")
     
    668670
    669671int NuppelVideoRecorder::AudioInit(bool skipdevice)
    670672{
    671     int afmt, afd;
    672     int frag, blocksize = 4096;
     673    int blocksize = 4096;
    673674    int tmp;
    674675
    675676    if (!skipdevice)
     
    679680        (void) afd;
    680681        (void) frag;
    681682
    682         VERBOSE(VB_IMPORTANT, LOC_ERR +
    683                 "This Unix doesn't support device files for audio access.");
     683        VERBOSE(VB_IMPORTANT, LOC_ERR
     684                + "This Unix doesn't support device files for audio access.");
    684685
    685686        return 1;
    686687#else
    687         QByteArray adevice = audiodevice.toAscii();
    688         if (-1 == (afd = open(adevice.constData(), O_RDONLY | O_NONBLOCK)))
    689         {
    690             VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Cannot open DSP '%1'")
    691                     .arg(audiodevice));
    692             perror("open");
    693             return 1;
    694         }
    695  
    696         fcntl(afd, F_SETFL, fcntl(afd, F_GETFL) & ~O_NONBLOCK);
    697  
    698         //ioctl(afd, SNDCTL_DSP_RESET, 0);
    699    
    700         frag = (8 << 16) | (10); //8 buffers, 1024 bytes each
    701         ioctl(afd, SNDCTL_DSP_SETFRAGMENT, &frag);
    702  
    703         afmt = AFMT_S16_LE;
    704         ioctl(afd, SNDCTL_DSP_SETFMT, &afmt);
    705         if (afmt != AFMT_S16_LE)
     688        audio_device = AudioInput::CreateDevice(audiodevice.toAscii());
     689        if (!audio_device)
    706690        {
    707             close(afd);
    708             VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't get 16 bit DSP");
     691            VERBOSE(VB_IMPORTANT, LOC_ERR + "AudioInit: unable to create device");
    709692            return 1;
    710693        }
    711694
    712         if (ioctl(afd, SNDCTL_DSP_SAMPLESIZE, &audio_bits) < 0 ||
    713             ioctl(afd, SNDCTL_DSP_CHANNELS, &audio_channels) < 0 ||
    714             ioctl(afd, SNDCTL_DSP_SPEED, &audio_samplerate) < 0)
    715         {
    716             close(afd);
    717             QString msg = LOC_ERR +
    718                 QString("AudioInit(): %1 : error setting audio input device"
    719                         " to %2kHz/%3bits/%4channel").arg(audiodevice).
    720                 arg(audio_samplerate).arg(audio_bits).arg(audio_channels);
    721             VERBOSE(VB_IMPORTANT, msg);
     695        if (!audio_device->Open(audio_bits, audio_samplerate, audio_channels))
     696        {
     697            VERBOSE(VB_IMPORTANT, LOC_ERR + "AudioInit: Unable to open device");
    722698            return 1;
    723699        }
    724700
    725         if (-1 == ioctl(afd, SNDCTL_DSP_GETBLKSIZE, &blocksize))
     701        if ((blocksize = audio_device->GetBlockSize()) <= 0)
    726702        {
    727             close(afd);
    728             VERBOSE(VB_IMPORTANT, LOC_ERR + "AudioInit(): Can't get DSP blocksize");
    729             return(1);
     703            blocksize = 1024;
     704            VERBOSE(VB_GENERAL, LOC_ERR + "AudioInit unable to determine block "
     705                                          "size, using default of 1024 bytes");
    730706        }
    731707
    732         close(afd);
     708        audio_device->Close();
    733709#endif
    734710    }
    735711
    736712    audio_bytes_per_sample = audio_channels * audio_bits / 8;
    737     blocksize *= 4;
    738 
    739713    audio_buffer_size = blocksize;
     714    VERBOSE(VB_AUDIO, LOC + QString("AudioInit: audio buffer size %1 bytes")
     715                                    .arg(audio_buffer_size));
    740716
    741717    if (compressaudio)
    742718    {
     
    756732
    757733        if (audio_bits != 16)
    758734        {
    759             VERBOSE(VB_IMPORTANT, LOC_ERR +
    760                     "AudioInit(): lame support requires 16bit audio");
     735            VERBOSE(VB_IMPORTANT, LOC_ERR
     736                     + "AudioInit(): lame support requires 16bit audio");
    761737            compressaudio = false;
    762738        }
    763739    }
     
    13011277    {
    13021278        // this is supported by the cx88 and various ati cards.
    13031279        vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
    1304 
    13051280        if (ioctl(fd, VIDIOC_S_FMT, &vfmt) < 0)
    13061281        {
    13071282            VERBOSE(VB_IMPORTANT, LOC_ERR + "v4l2: Unable to set desired format");
     
    22552230
    22562231void NuppelVideoRecorder::doAudioThread(void)
    22572232{
    2258 #if !defined (HAVE_SYS_SOUNDCARD_H) && !defined(HAVE_SOUNDCARD_H)
    2259     VERBOSE(VB_IMPORTANT, LOC +
    2260             QString("doAudioThread() This Unix doesn't support"
    2261                     " device files for audio access. Skipping"));
    2262     return;
    2263 #else
    2264     int afmt = 0, trigger = 0;
    2265     int afd = 0, act = 0, lastread = 0;
    2266     int frag = 0, blocksize = 0;
    2267     unsigned char *buffer;
    2268     audio_buf_info ispace;
    2269     struct timeval anow;
    2270 
    2271     act_audio_sample = 0;
    2272 
    2273     QByteArray adevice = audiodevice.toAscii();
    2274     if (-1 == (afd = open(adevice.constData(), O_RDONLY | O_NONBLOCK)))
     2233    if (!audio_device)
    22752234    {
    2276         VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Cannot open DSP '%1', exiting").
    2277                 arg(audiodevice));
    2278         perror("open");
     2235        VERBOSE(VB_GENERAL, LOC + "Audio: no audio device");
    22792236        return;
    22802237    }
    22812238
    2282     fcntl(afd, F_SETFL, fcntl(afd, F_GETFL) & ~O_NONBLOCK);
    2283     //ioctl(afd, SNDCTL_DSP_RESET, 0);
    2284 
    2285     frag = (8 << 16) | (10); //8 buffers, 1024 bytes each
    2286     ioctl(afd, SNDCTL_DSP_SETFRAGMENT, &frag);
    2287 
    2288     afmt = AFMT_S16_LE;
    2289     ioctl(afd, SNDCTL_DSP_SETFMT, &afmt);
    2290     if (afmt != AFMT_S16_LE)
     2239    if (!audio_device->Open(audio_bits, audio_samplerate, audio_channels))
    22912240    {
    2292         VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't get 16 bit DSP, exiting");
    2293         close(afd);
     2241        VERBOSE(VB_IMPORTANT, LOC_ERR + "Audio: Unable to open device");
    22942242        return;
    22952243    }
    22962244
    2297     if (ioctl(afd, SNDCTL_DSP_SAMPLESIZE, &audio_bits) < 0 ||
    2298         ioctl(afd, SNDCTL_DSP_CHANNELS, &audio_channels) < 0 ||
    2299         ioctl(afd, SNDCTL_DSP_SPEED, &audio_samplerate) < 0)
     2245    if (!audio_device->Start())
    23002246    {
    2301         VERBOSE(VB_IMPORTANT, LOC_ERR + QString(" %1: error setting audio input device to "
    2302                                       "%2 kHz/%3 bits/%4 channel").
    2303                 arg(audiodevice).arg(audio_samplerate).
    2304                 arg(audio_bits).arg(audio_channels));
    2305         close(afd);
     2247        VERBOSE(VB_IMPORTANT, LOC_ERR + "Audio: Unable to start capture");
    23062248        return;
    23072249    }
    23082250
     2251    struct timeval anow;
     2252    unsigned char *buffer = new unsigned char[audio_buffer_size];
     2253    int act = 0, lastread = 0;
    23092254    audio_bytes_per_sample = audio_channels * audio_bits / 8;
    2310 
    2311     if (-1 == ioctl(afd, SNDCTL_DSP_GETBLKSIZE,  &blocksize))
    2312     {
    2313         VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't get DSP blocksize, exiting");
    2314         close(afd);
    2315         return;
    2316     }
    2317 
    2318     blocksize *= 4;  // allways read 4*blocksize
    2319 
    2320     if (blocksize != audio_buffer_size)
    2321     {
    2322         VERBOSE(VB_IMPORTANT, LOC +
    2323                 QString("Warning, audio blocksize = '%1' while audio_buffer_size='%2'").
    2324                 arg(blocksize).arg(audio_buffer_size));
    2325     }
    2326 
    2327     buffer = new unsigned char[audio_buffer_size];
    2328 
    2329     /* trigger record */
    2330     trigger = 0;
    2331     ioctl(afd,SNDCTL_DSP_SETTRIGGER,&trigger);
    2332 
    2333     trigger = PCM_ENABLE_INPUT;
    2334     ioctl(afd,SNDCTL_DSP_SETTRIGGER,&trigger);
     2255    audiopaused = false;
    23352256
    23362257    // Qt4 requires a QMutex as a parameter...
    23372258    // not sure if this is the best solution.  Mutex Must be locked before wait.
    23382259    QMutex mutex;
    23392260    mutex.lock();
    23402261
    2341     audiopaused = false;
    23422262    while (childrenLive)
    23432263    {
    23442264        if (request_pause)
     
    23542274        }
    23552275        audiopaused = false;
    23562276
    2357         if (audio_buffer_size != (lastread = read(afd, buffer,
    2358                                                   audio_buffer_size)))
     2277        lastread = audio_device->GetSamples(buffer, audio_buffer_size);
     2278        if (audio_buffer_size != lastread)
    23592279        {
    2360             VERBOSE(VB_IMPORTANT, LOC_ERR +
    2361                     QString("Only read %1 bytes of %2 bytes from '%3").
    2362                     arg(lastread).arg(audio_buffer_size).arg(audiodevice));
    2363             perror("read audio");
     2280            VERBOSE(VB_IMPORTANT, LOC_ERR
     2281                    + QString("Short read, %1 of %2 bytes from ")
     2282                              .arg(lastread).arg(audio_buffer_size)
     2283                    + audiodevice);
    23642284        }
    23652285
    23662286        /* record the current time */
     
    23682288           (like we used to.) Measure to see how much stuff is in there,
    23692289           and correct for it when calculating the timestamp */
    23702290        gettimeofday(&anow, &tzone);
    2371         ioctl( afd, SNDCTL_DSP_GETISPACE, &ispace );
     2291        int bytes_read = max(audio_device->GetNumReadyBytes(), 0);
    23722292
    23732293        act = act_audio_buffer;
    23742294
     
    23892309           audio chunk. So, subtract off the length of the chunk
    23902310           and the length of audio still in the capture buffer. */
    23912311        audiobuffer[act]->timecode -= (int)(
    2392                 (ispace.fragments * ispace.fragsize + audio_buffer_size)
     2312                (bytes_read + audio_buffer_size)
    23932313                 * 1000.0 / (audio_samplerate * audio_bytes_per_sample));
    23942314
    23952315        memcpy(audiobuffer[act]->buffer, buffer, audio_buffer_size);
     
    24042324    }
    24052325
    24062326    delete [] buffer;
    2407     close(afd);
    2408 #endif
     2327
     2328    if (audio_device->IsOpen())
     2329        audio_device->Close();
    24092330}
    24102331
    24112332struct VBIData
  • libs/libmythtv/libmythtv.pro

    old new  
    9696cygwin:QMAKE_LFLAGS_SHLIB += -Wl,--noinhibit-exec
    9797cygwin:DEFINES += _WIN32
    9898
    99 # Enable Linux Open Sound System support
    100 using_oss:DEFINES += USING_OSS
     99# Enable sound systems support
     100using_alsa:DEFINES += USING_ALSA
     101using_arts:DEFINES += USING_ARTS
     102using_jack:DEFINES += USING_JACK
     103using_oss: DEFINES += USING_OSS
     104macx:      DEFINES += USING_COREAUDIO
     105
    101106# Enable Valgrind, i.e. disable some timeouts
    102107using_valgrind:DEFINES += USING_VALGRIND
    103108
  • libs/libmythtv/NuppelVideoRecorder.h

    old new  
    4444class ChannelBase;
    4545class FilterManager;
    4646class FilterChain;
     47class AudioInput;
    4748
    4849class MPUBLIC NuppelVideoRecorder : public RecorderBase, public CC608Reader
    4950{
     
    153154    int inputchannel;
    154155    int compression;
    155156    int compressaudio;
     157    AudioInput *audio_device;
    156158    unsigned long long audiobytes;
    157159    int audio_channels;
    158160    int audio_bits;
  • new file mythtv/libs/libmyth/audioinput.h

    - +  
     1/*
     2 * Copyright (C) 2007  Anand K. Mistry
     3 *
     4 * This program is free software; you can redistribute it and/or
     5 * modify it under the terms of the GNU General Public License
     6 * as published by the Free Software Foundation; either version 2
     7 * of the License, or (at your option) any later version.
     8 *
     9 * This program is distributed in the hope that it will be useful,
     10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 * GNU General Public License for more details.
     13 *
     14 * You should have received a copy of the GNU General Public License
     15 * along with this program; if not, write to the Free Software
     16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
     17 * 02110-1301, USA.
     18 */
     19/* vim: set expandtab tabstop=4 shiftwidth=4: */
     20
     21#ifndef _AUDIOINPUT_H_
     22#define _AUDIOINPUT_H_
     23
     24#include <QString>
     25
     26class AudioInput
     27{
     28  public:
     29    virtual ~AudioInput() {}
     30
     31    virtual bool Open(uint sample_bits, uint sample_rate, uint channels) = 0;
     32    virtual bool IsOpen(void) = 0;
     33    virtual void Close(void) = 0;
     34
     35    virtual bool Start(void) = 0;
     36    virtual bool Stop(void) = 0;
     37
     38    virtual int GetBlockSize(void) = 0;
     39    virtual int GetSamples(void *buf, uint nbytes) = 0;
     40    virtual int GetNumReadyBytes(void) = 0;
     41
     42    // Factory function
     43    static AudioInput *CreateDevice(const QByteArray &device);
     44
     45  protected:
     46    AudioInput(const QString &device);
     47
     48    QByteArray m_audio_device;
     49    int        m_audio_channels;
     50    int        m_audio_sample_bits;
     51    int        m_audio_sample_rate;
     52};
     53#endif /* _AUDIOINPUT_H_ */
     54 No newline at end of file
  • new file mythtv/libs/libmyth/audioinputoss.cpp

    - +  
     1/*
     2 * Copyright (C) 2007  Anand K. Mistry
     3 * Copyright (C) 2007  Daniel Kristjansson
     4 * Copyright (C) 2003-2007 Others who contributed to NuppelVideoRecorder.cpp
     5 * Copyright (C) 2008  Alan Calvert
     6 *
     7 * This program is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU General Public License
     9 * as published by the Free Software Foundation; either version 2
     10 * of the License, or (at your option) any later version.
     11 *
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16 *
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
     20 * 02110-1301, USA.
     21 */
     22
     23#include "mythconfig.h"
     24#ifdef HAVE_SYS_SOUNDCARD_H
     25    #include <sys/soundcard.h>
     26#elif HAVE_SOUNDCARD_H
     27    #include <soundcard.h>
     28#endif
     29
     30#include "audioinputoss.h"
     31#include "mythcontext.h"
     32#include <fcntl.h>
     33#include <sys/ioctl.h>
     34
     35#define LOC QString("AudioInputOSS: ")
     36#define LOC_ERR QString("AudioInputOSS error: ")
     37
     38AudioInputOSS::AudioInputOSS(const QString &device) : AudioInput(device)
     39{
     40    if (!device.isEmpty())
     41        m_device_name = QByteArray(device.toAscii());
     42    else
     43        m_device_name = QByteArray();
     44    dsp_fd = -1;
     45    log_tag = QString( "device '" + m_device_name + "', ");
     46}
     47
     48bool AudioInputOSS::Open(uint sample_bits, uint sample_rate, uint channels)
     49{
     50    m_audio_sample_bits = sample_bits;
     51    m_audio_sample_rate = sample_rate;
     52    //m_audio_channels = channels;
     53    int chk;
     54
     55    if (IsOpen())
     56        Close();
     57
     58    // Open the device
     59    dsp_fd = open(m_device_name.constData(), O_RDONLY);
     60    if (dsp_fd < 0)
     61        return OssFatal(dsp_fd, "open failed");
     62
     63    chk = 0; // disable input for now
     64    ioctl(dsp_fd, SNDCTL_DSP_SETTRIGGER, &chk);
     65
     66    // Set format
     67    int format, choice;
     68    QString tag = QString::null;
     69    switch (sample_bits)
     70    {
     71        case 8:
     72            choice = AFMT_U8;
     73            tag = "AFMT_U8";
     74            break;
     75        case 16:
     76        default:
     77#ifdef WORDS_BIGENDIAN
     78            choice = AFMT_S16_BE;
     79            tag = "AFMT_S16_BE";
     80#else
     81            choice = AFMT_S16_LE;
     82            tag = "AFMT_S16_LE";
     83#endif
     84            break;
     85    }
     86    format = choice;
     87    if ((chk = ioctl(dsp_fd, SNDCTL_DSP_SETFMT, &format) < 0))
     88        return OssFatal(chk, QString("failed to set audio format %1").arg(tag));
     89    if (format != choice)
     90        return OssFatal(0, QString("set audio format not %1 as requested")
     91                                   .arg(tag));
     92
     93    // sample size
     94    m_audio_sample_bits = choice = sample_bits;
     95    if ((chk = ioctl(dsp_fd, SNDCTL_DSP_SAMPLESIZE, &m_audio_sample_bits)) < 0)
     96        return OssFatal(chk, QString("failed to set audio sample bits to %1")
     97                                     .arg(sample_bits));
     98    if (m_audio_sample_bits != choice)
     99        OssError(0, QString("requested %1 sample bits, got %2")
     100                            .arg(choice).arg(m_audio_sample_bits));
     101    // channels
     102    m_audio_channels = choice = channels;
     103    if ((chk = ioctl(dsp_fd, SNDCTL_DSP_CHANNELS, &m_audio_channels)) < 0)
     104        return OssFatal(chk, QString("failed to set audio channels to %1")
     105                                     .arg(channels));
     106    if (m_audio_channels != choice)
     107        OssError(0, QString("requested %1 channels, got %2 ")
     108                            .arg(choice).arg(m_audio_channels));
     109
     110    // sample rate
     111    uint choice_sample_rate;
     112    m_audio_sample_rate = choice_sample_rate = sample_rate;
     113    if ((chk = ioctl(dsp_fd, SNDCTL_DSP_SPEED, &m_audio_sample_rate)) < 0)
     114        return OssFatal(chk, QString("failed to set sample rate to %1")
     115                                     .arg(sample_rate));
     116    if (m_audio_sample_rate != choice_sample_rate)
     117        OssError(0, QString("requested sample rate %1, got %2")
     118                            .arg(choice_sample_rate).arg(m_audio_sample_rate));
     119    OssInfo("device open");
     120    return true;
     121}
     122
     123void AudioInputOSS::Close(void)
     124{
     125    if (IsOpen())
     126        close(dsp_fd);
     127    dsp_fd = -1;
     128    m_audio_sample_bits = 0;
     129    m_audio_sample_rate = 0;
     130    m_audio_channels = 0;
     131    OssInfo("device closed");
     132}
     133
     134bool AudioInputOSS::Start(void)
     135{
     136    bool started = false;
     137    if (IsOpen())
     138    {
     139        int chk;
     140        int trig = 0; // clear
     141        ioctl(dsp_fd, SNDCTL_DSP_SETTRIGGER, &trig);
     142        trig = PCM_ENABLE_INPUT; // enable input
     143        if ((chk = ioctl(dsp_fd, SNDCTL_DSP_SETTRIGGER, &trig)) < 0)
     144            OssError(chk, "Start() failed");
     145        else
     146        {
     147            OssInfo("capture started");
     148            started = true;
     149        }
     150    }
     151    return started;
     152}
     153
     154bool AudioInputOSS::Stop(void)
     155{
     156    bool stopped = false;
     157    int chk;
     158    int trig = 0;
     159    if ((chk = ioctl(dsp_fd, SNDCTL_DSP_SETTRIGGER, &trig)) < 0)
     160        OssError(chk, "stop action failed");
     161    else
     162    {
     163        stopped = true;
     164        OssInfo("capture stopped");
     165    }
     166    return stopped;
     167}
     168
     169int AudioInputOSS::GetBlockSize(void)
     170{
     171    int frag = 0;
     172    if (IsOpen())
     173    {
     174        int chk;
     175        if ((chk = ioctl(dsp_fd, SNDCTL_DSP_GETBLKSIZE, &frag)) < 0)
     176        {
     177            OssError(chk, QString("fragment size query failed, returned %1")
     178                                  .arg(frag));
     179            frag = 0;
     180        }
     181    }
     182    OssInfo(QString("block size %1").arg(frag));
     183    return frag;
     184}
     185
     186int AudioInputOSS::GetSamples(void *buffer, uint num_bytes)
     187{
     188    int bytes_read = 0;
     189    if (IsOpen())
     190    {
     191        unsigned char* bufptr = (unsigned char*)buffer;
     192        int this_read;
     193        int retries = 0;
     194        while (bytes_read < num_bytes && retries < 3)
     195        {
     196            this_read = read(dsp_fd, buffer, num_bytes - bytes_read);
     197            if (this_read < 0)
     198                OssError(this_read, "GetSamples read failed");
     199           else
     200            {
     201                bytes_read += this_read;
     202                bufptr += this_read;
     203            }
     204            ++retries;
     205        }
     206        if (num_bytes > (uint)bytes_read)
     207            VERBOSE(VB_IMPORTANT, LOC_ERR + log_tag
     208                    + QString("GetSamples short read, %1 of %2 bytes")
     209                              .arg(bytes_read).arg(num_bytes));
     210    }
     211    return bytes_read;
     212}
     213
     214int AudioInputOSS::GetNumReadyBytes(void)
     215{
     216    int readies = 0;
     217    if (IsOpen())
     218    {
     219        audio_buf_info ispace;
     220        int chk;
     221        if ((chk = ioctl(dsp_fd, SNDCTL_DSP_GETISPACE, &ispace)) < 0)
     222            OssError(chk, QString("get ready bytes failed, returned %1")
     223                                  .arg(ispace.bytes));
     224        else if ((readies = ispace.bytes) > 0)
     225            VERBOSE(VB_AUDIO+VB_EXTRA, LOC + log_tag
     226                    + QString("ready bytes %1").arg(readies));
     227    }
     228    return readies;
     229}
     230
     231void AudioInputOSS::OssError(int err, QString msg)
     232{
     233    QString suffix = QString::null;
     234    if (err < 0)
     235        suffix = QString(": %1").arg(strerror(err));
     236    VERBOSE(VB_IMPORTANT, LOC_ERR + log_tag + msg + suffix);
     237}
     238
     239bool AudioInputOSS::OssFatal(int err, QString msg)
     240{
     241    OssError(err, msg);
     242    Close();
     243    return false;
     244}
     245
     246void AudioInputOSS::OssInfo(QString msg)
     247{
     248    VERBOSE(VB_AUDIO, LOC + log_tag + msg);
     249}
     250/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • new file mythtv/libs/libmyth/audioinputoss.h

    - +  
     1/*
     2 * Copyright (C) 2007  Anand K. Mistry
     3 * Copyright (C) 2008  Alan Calvert
     4 *
     5 * This program is free software; you can redistribute it and/or
     6 * modify it under the terms of the GNU General Public License
     7 * as published by the Free Software Foundation; either version 2
     8 * of the License, or (at your option) any later version.
     9 *
     10 * This program is distributed in the hope that it will be useful,
     11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 * GNU General Public License for more details.
     14 *
     15 * You should have received a copy of the GNU General Public License
     16 * along with this program; if not, write to the Free Software
     17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
     18 * 02110-1301, USA.
     19 */
     20/* vim: set expandtab tabstop=4 shiftwidth=4: */
     21
     22#ifndef _AUDIOINPUTOSS_H_
     23#define _AUDIOINPUTOSS_H_
     24
     25#include "audioinput.h"
     26
     27class AudioInputOSS : public AudioInput
     28{
     29    public:
     30        AudioInputOSS(const QString &device);
     31        ~AudioInputOSS() { Close(); };
     32
     33        bool Open(uint sample_bits, uint sample_rate, uint channels);
     34        inline bool IsOpen(void) { return (dsp_fd > -1); }
     35        void Close(void);
     36
     37        bool Start(void);
     38        bool Stop(void);
     39
     40        int GetBlockSize(void);
     41        int GetSamples(void *buffer, uint num_samples);
     42        int GetNumReadyBytes(void);
     43
     44    private:
     45        void OssInfo(QString msg);
     46        void OssError(int err, QString msg);
     47        bool OssFatal(int err, QString msg);
     48
     49        QByteArray m_device_name;
     50        int dsp_fd;
     51        QString log_tag;
     52};
     53#endif /* _AUDIOINPUTOSS_H_ */
     54
  • new file mythtv/libs/libmyth/audioinputalsa.cpp

    - +  
     1/*
     2 * Copyright (C) 2007  Anand K. Mistry
     3 * Copyright (C) 2007  Daniel Kristjansson
     4 * Copyright (C) 2008  Alan Calvert
     5 *
     6 * This program is free software; you can redistribute it and/or
     7 * modify it under the terms of the GNU General Public License
     8 * as published by the Free Software Foundation; either version 2
     9 * of the License, or (at your option) any later version.
     10 *
     11 * This program is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 * GNU General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License
     17 * along with this program; if not, write to the Free Software
     18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
     19 * 02110-1301, USA.
     20 */
     21
     22#include "audioinputalsa.h"
     23#include "mythcontext.h"
     24
     25#define LOC QString("AudioInputALSA Info: ")
     26#define LOC_ERR QString("AudioInputALSA Error: ")
     27
     28AudioInputALSA::AudioInputALSA(const QString &device):
     29    AudioInput(device),
     30    pcm_handle(NULL),
     31    myth_block_bytes(0)
     32{
     33    if (!device.isEmpty())
     34        alsa_device = QByteArray(device.toAscii().right(device.size() - 5));
     35    else
     36        alsa_device = QByteArray();
     37    log_tag = "device '" + alsa_device + "', ";
     38}
     39
     40bool AudioInputALSA::Open(uint sample_bits, uint sample_rate, uint channels)
     41{
     42    if (pcm_handle != NULL)
     43        Close();
     44    m_audio_sample_rate = sample_rate;
     45    m_audio_channels = channels;
     46    m_audio_sample_bits = sample_bits;
     47    snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE;
     48    AlsaBad(snd_config_update_free_global(), "free global snd config failed");
     49    if (AlsaBad(snd_pcm_open(&pcm_handle, alsa_device.constData(), stream, 0),
     50                "pcm open failed"))                      // note blocking mode!
     51    {
     52        pcm_handle = NULL;
     53        return false;
     54    }
     55    if (!(PrepHwParams() && PrepSwParams()))
     56    {
     57        snd_pcm_close(pcm_handle);
     58        pcm_handle = NULL;
     59        return false;
     60    }
     61    VERBOSE(VB_AUDIO, LOC + log_tag + "pcm open ok");
     62    return true;
     63}
     64
     65void AudioInputALSA::Close(void)
     66{
     67    if (pcm_handle != NULL)
     68    {
     69        Stop();
     70        AlsaBad(snd_pcm_close(pcm_handle), "Close() close failed");
     71    }
     72    pcm_handle = NULL;
     73}
     74
     75bool AudioInputALSA::Start(void)
     76{
     77    bool started = false;
     78    if (pcm_handle != NULL
     79        && !AlsaBad(snd_pcm_prepare(pcm_handle), "Start() prepare failed")
     80        && !AlsaBad(snd_pcm_start(pcm_handle), "Start() start failed"))
     81    {
     82        started = true;
     83        VERBOSE(VB_AUDIO, LOC + log_tag + "capture started");
     84    }
     85    return started;
     86}
     87
     88bool AudioInputALSA::Stop(void)
     89{
     90    bool stopped = false;
     91    if (pcm_handle != NULL
     92        && !AlsaBad(snd_pcm_drop(pcm_handle), "Stop() drop failed"))
     93    {
     94        stopped = true;
     95        VERBOSE(VB_AUDIO, LOC + log_tag + "capture stopped");
     96    }
     97    return stopped;
     98}
     99
     100int AudioInputALSA::GetSamples(void *buf, uint nbytes)
     101{
     102    if (!pcm_handle)
     103       return 0;
     104    snd_pcm_uframes_t nframes = snd_pcm_bytes_to_frames(pcm_handle, nbytes);
     105    snd_pcm_uframes_t frames_read;
     106    int pcm_state;
     107    int chk;
     108    switch ((pcm_state = snd_pcm_state(pcm_handle)))
     109    {
     110        case SND_PCM_STATE_XRUN:
     111        case SND_PCM_STATE_SUSPENDED:
     112            if (!XrunRecovery())
     113                break;
     114        case SND_PCM_STATE_PREPARED:
     115            if ((chk = snd_pcm_start(pcm_handle) < 0))
     116            {
     117                VERBOSE(VB_IMPORTANT, LOC_ERR + log_tag
     118                        + QString("restart failed: %1").arg(snd_strerror(chk)));
     119                 break;
     120            }
     121            VERBOSE(VB_AUDIO+VB_EXTRA, LOC + log_tag
     122                    + "SND_PCM_STATE_PREPARED, start ok");
     123            // and fall through to read ...
     124        case SND_PCM_STATE_RUNNING:
     125            frames_read = PcmRead(buf, nbytes);
     126            break;
     127        default:
     128            VERBOSE(VB_AUDIO, LOC + log_tag
     129                    + QString("alarm! SND_PCM_STATE %1 through GetSamples")
     130                              .arg(pcm_state));
     131            break;
     132    }
     133    return snd_pcm_frames_to_bytes(pcm_handle, frames_read);
     134}
     135
     136
     137int AudioInputALSA::GetNumReadyBytes(void)
     138{
     139    int bytes_avail = 0;
     140    if (pcm_handle != NULL)
     141    {
     142        snd_pcm_sframes_t frames_avail;
     143        int pcm_state = snd_pcm_state(pcm_handle);
     144        switch (pcm_state)
     145        {
     146            case SND_PCM_STATE_PREPARED:
     147            case SND_PCM_STATE_RUNNING:
     148                if (!AlsaBad((frames_avail = snd_pcm_avail_update(pcm_handle)),
     149                             "bad frames available update"))
     150                    bytes_avail = snd_pcm_frames_to_bytes(pcm_handle,
     151                                                          frames_avail);
     152        }
     153    }
     154    return bytes_avail;
     155}
     156
     157bool AudioInputALSA::PrepHwParams(void)
     158{
     159
     160    snd_pcm_hw_params_t *hwparams;
     161    snd_pcm_hw_params_alloca(&hwparams);
     162    if (AlsaBad(snd_pcm_hw_params_any(pcm_handle, hwparams),
     163                "failed to init hw params"))
     164        return false;
     165    snd_pcm_access_t axs = SND_PCM_ACCESS_RW_INTERLEAVED;// Forget mmap, it
     166                                                         // isn't worth it here.
     167    if (AlsaBad(snd_pcm_hw_params_set_access(pcm_handle, hwparams, axs),
     168                "failed to set interleaved rw io"))
     169        return false;
     170    snd_pcm_format_t format =
     171        (m_audio_sample_bits > 8) ? SND_PCM_FORMAT_S16 : SND_PCM_FORMAT_U8;
     172    if (AlsaBad(snd_pcm_hw_params_set_format(pcm_handle, hwparams, format),
     173                QString("failed to set sample format %1")
     174                        .arg(snd_pcm_format_description(format))))
     175        return false;
     176    if (AlsaBad(snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
     177                m_audio_channels), QString("failed to set channels to %1")
     178                                           .arg(m_audio_channels)))
     179    {
     180        uint x_chans;
     181        if(!AlsaBad(snd_pcm_hw_params_get_channels_min(hwparams, &x_chans),
     182                    QString("unable to get min channel count")))
     183            VERBOSE(VB_AUDIO, LOC + log_tag + QString("minimum channels: %1")
     184                                                       .arg(x_chans));
     185
     186        if(!AlsaBad(snd_pcm_hw_params_get_channels_max(hwparams, &x_chans),
     187                    QString("unable to get max channel count")))
     188            VERBOSE(VB_AUDIO, LOC + log_tag + QString("maximum channels: %1")
     189                                                       .arg(x_chans));
     190        return false;
     191    }
     192    if (AlsaBad(snd_pcm_hw_params_set_rate(pcm_handle, hwparams,
     193                m_audio_sample_rate, 0), QString("failed to set sample rate %1")
     194                                                 .arg(m_audio_sample_rate)))
     195    {
     196        uint rate_num = 0;
     197        uint rate_den = 0;
     198        if (!AlsaBad(snd_pcm_hw_params_get_rate_numden(hwparams, &rate_num,
     199                     &rate_den), "snd_pcm_hw_params_get_rate_numden failed"))
     200            if (m_audio_sample_rate != (int)(rate_num / rate_den))
     201                VERBOSE(VB_IMPORTANT, LOC_ERR + log_tag
     202                        + QString("device reports sample rate as %1")
     203                                  .arg(rate_num / rate_den));
     204        return false;
     205    }
     206    uint latency = 64000; // 64 msec
     207    snd_pcm_uframes_t buffer_size;
     208    uint period_time;
     209    if (!AlsaBad(snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hwparams,
     210                 &latency, NULL), "initial buffer time/latency setting failed"))
     211    {
     212        if (AlsaBad(snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size),
     213                    "failed to get buffer size"))
     214            return false;
     215        if (AlsaBad(snd_pcm_hw_params_get_buffer_time(hwparams, &latency, NULL),
     216                    "failed to get latency setting"))
     217            return false;
     218        period_time = latency / 4;
     219        if (AlsaBad(snd_pcm_hw_params_set_period_time_near(pcm_handle, hwparams,
     220                    &period_time, NULL), "failed to set period time"))
     221            return false;
     222        if (AlsaBad(snd_pcm_hw_params_get_period_size(hwparams, &period_size,
     223                    NULL), "failed to get period size"))
     224            return false;
     225    }
     226    else
     227    {
     228        VERBOSE(VB_AUDIO, LOC + "hwparams settings, Plan B");
     229        period_time = latency / 4;
     230        if (AlsaBad(snd_pcm_hw_params_set_period_time_near(pcm_handle, hwparams,
     231                    &period_time, NULL), "failed to set period time"))
     232            return false;
     233        if (AlsaBad(snd_pcm_hw_params_get_period_size(hwparams, &period_size,
     234                    NULL), "failed to get period size"))
     235            return false;
     236        buffer_size = period_size * 4;
     237        if (AlsaBad(snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams,
     238                    &buffer_size), "failed to set buffer size"))
     239            return false;
     240        if (AlsaBad(snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size),
     241                    "failed to get buffer size"))
     242            return false;
     243    }
     244    if (AlsaBad(snd_pcm_hw_params (pcm_handle, hwparams),
     245                "failed to set hwparams"))
     246        return false;
     247    if (AlsaBad(snd_pcm_hw_params_get_periods(hwparams, &periods, NULL),
     248                "failed to get periods"))
     249        return false;
     250    myth_block_bytes = snd_pcm_frames_to_bytes(pcm_handle, period_size);
     251    VERBOSE(VB_AUDIO, LOC + log_tag
     252            + QString("channels %1, sample rate %2, latency %3 msec, period "
     253                      "size %4, periods %5").arg(m_audio_channels)
     254                      .arg(m_audio_sample_rate).arg(latency / 1000.0, -1, 'f', 1)
     255                      .arg(period_size).arg(periods));
     256    VERBOSE(VB_AUDIO+VB_EXTRA, LOC + log_tag + QString("myth block size %1")
     257                                                       .arg(myth_block_bytes));
     258    return true;
     259}
     260
     261bool AudioInputALSA::PrepSwParams(void)
     262{
     263    snd_pcm_sw_params_t* swparams;
     264    snd_pcm_sw_params_alloca(&swparams);
     265        snd_pcm_uframes_t boundary;
     266    if (AlsaBad(snd_pcm_sw_params_current(pcm_handle, swparams),
     267               "failed to get swparams"))
     268        return false;
     269    // explicit start, not auto start
     270    if (AlsaBad(snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams,
     271                INT_MAX), "failed to set start threshold"))
     272                return false;
     273   if (AlsaBad(snd_pcm_sw_params_get_boundary(swparams, &boundary),
     274               "failed to get boundary"))
     275        return false;
     276    if (AlsaBad(snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams,
     277                boundary), "failed to set stop threshold"))
     278                return false;
     279    if (AlsaBad(snd_pcm_sw_params(pcm_handle, swparams),
     280                "failed to set software parameters"))
     281        return false;
     282
     283    return true;
     284}
     285
     286snd_pcm_uframes_t AudioInputALSA::PcmRead(void *buf, uint nbytes)
     287{
     288    unsigned char* bufptr = (unsigned char*)buf;
     289    snd_pcm_uframes_t to_read = snd_pcm_bytes_to_frames(pcm_handle, nbytes);
     290    snd_pcm_uframes_t nframes = to_read;
     291    snd_pcm_sframes_t nread;
     292    snd_pcm_sframes_t avail;
     293    int retries = 0;
     294    while (nframes > 0 && retries < 3)
     295    {
     296        if ((avail = snd_pcm_avail_update(pcm_handle)) < 0
     297            && !Recovery(avail))
     298        {
     299            ++retries;
     300            continue;
     301        }
     302        if ((nread = snd_pcm_readi(pcm_handle, bufptr, nframes)) >= 0)
     303        {
     304            nframes -= nread;
     305            bufptr += snd_pcm_frames_to_bytes(pcm_handle, nread);
     306        }
     307        else
     308        {
     309            switch (nread)
     310            {
     311                case -EAGAIN:
     312                    break;
     313                case -EBADFD:
     314                    VERBOSE(VB_IMPORTANT, LOC_ERR + log_tag
     315                            + QString("in a state unfit to read (%1): %2")
     316                                      .arg(nread).arg(snd_strerror(nread)));
     317                    break;
     318                case -EINTR:
     319                case -EPIPE:
     320                case -ESTRPIPE:
     321                    Recovery(nread);
     322                    break;
     323                default:
     324                    VERBOSE(VB_IMPORTANT, LOC_ERR + log_tag
     325                            + QString("weird state %1 thru "
     326                                      "snd_pcm_readi: %2").arg(nread)
     327                                      .arg(snd_strerror(nread)));
     328                    break;
     329            }
     330        }
     331        ++retries;
     332    }
     333    if (nframes > 0)
     334        VERBOSE(VB_AUDIO, LOC_ERR + log_tag
     335                + QString("short pcm read, %1 of %2 frames")
     336                          .arg(to_read - nframes).arg(to_read));
     337    return (to_read - nframes);
     338}
     339
     340bool AudioInputALSA::Recovery(int err)
     341{
     342    if (err > 0)
     343        err = -err;
     344    bool isgood = false;
     345    bool suspense = false;
     346    switch (err)
     347    {
     348        case -EINTR:
     349            isgood = true; // nothin' to see here
     350            break;
     351        case -ESTRPIPE:
     352            suspense = true;
     353        case -EPIPE:
     354            if (!AlsaBad(snd_pcm_prepare(pcm_handle),
     355                         QString("failed to recover from %1")
     356                                 .arg((suspense) ? "suspend" : "underrun")))
     357                isgood = true;
     358            break;
     359        default:
     360            break;
     361    }
     362    return isgood;
     363}
     364
     365bool AudioInputALSA::AlsaBad(int op_result, QString errmsg)
     366{                            // (op_result < 0) => return true
     367    bool bad = (op_result < 0);
     368    if (bad)
     369        VERBOSE(VB_IMPORTANT, LOC_ERR + log_tag + errmsg
     370                + QString(": %1").arg(snd_strerror(op_result)));
     371    return bad;
     372}
     373
     374bool AudioInputALSA::XrunRecovery(void)
     375{
     376    bool recov = Stop() && Start();
     377    VERBOSE(VB_AUDIO, LOC + log_tag + "xrun recovery "
     378            + (recov ? "good" : "not good"));
     379    return recov;
     380}
     381/* vim: set expandtab tabstop=4 shiftwidth=4: */
     382 No newline at end of file
  • libs/libmyth/libmyth.pro

    old new  
    8888
    8989using_oss {
    9090    DEFINES += USING_OSS
    91     SOURCES += audiooutputoss.cpp
    92     HEADERS += audiooutputoss.h
     91    SOURCES *= audiooutputoss.cpp audioinputoss.cpp audioinput.cpp
     92    HEADERS *= audiooutputoss.h   audioinputoss.h   audioinput.h
    9393    LIBS += $$OSS_LIBS
    9494}
    9595
     
    155155
    156156using_alsa {
    157157    DEFINES += USE_ALSA
    158     HEADERS += audiooutputalsa.h
    159     SOURCES += audiooutputalsa.cpp
     158    HEADERS *= audiooutputalsa.h   audioinputalsa.h   audioinput.h
     159    SOURCES *= audiooutputalsa.cpp audioinputalsa.cpp audioinput.cpp
    160160    LIBS += $$ALSA_LIBS
    161161}
    162162
  • new file mythtv/libs/libmyth/audioinput.cpp

    - +  
     1/*
     2 * Copyright (C) 2007  Anand K. Mistry
     3 * Copyright (C) 2008  Alan Calvert
     4 *
     5 * This program is free software; you can redistribute it and/or
     6 * modify it under the terms of the GNU General Public License
     7 * as published by the Free Software Foundation; either version 2
     8 * of the License, or (at your option) any later version.
     9 *
     10 * This program is distributed in the hope that it will be useful,
     11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 * GNU General Public License for more details.
     14 *
     15 * You should have received a copy of the GNU General Public License
     16 * along with this program; if not, write to the Free Software
     17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
     18 * 02110-1301, USA.
     19 */
     20
     21#include "mythcontext.h"
     22#include "audioinput.h"
     23#include "audioinputoss.h"
     24#include "audioinputalsa.h"
     25
     26#define LOC QString("AudioInput: ")
     27#define LOC_ERR QString("AudioInput error: ")
     28
     29AudioInput::AudioInput(const QString &device)
     30{
     31    m_audio_device = QByteArray(device.toAscii());
     32    m_audio_channels = 0;
     33    m_audio_sample_bits = 0;
     34    m_audio_sample_rate = 0;
     35}
     36
     37AudioInput *AudioInput::CreateDevice(const QByteArray &device)
     38{
     39    AudioInput *audio = NULL;
     40    if (device.startsWith("/"))
     41    {
     42#       ifdef USING_OSS
     43            audio = new AudioInputOSS(device);
     44#       else
     45            VERBOSE(VB_IMPORTANT, LOC_ERR
     46                    + "device " + device + ", OSS input support not available");
     47#       endif
     48    }
     49
     50    else if (device.startsWith("ALSA:"))
     51    {
     52#       ifdef USE_ALSA
     53            audio = new AudioInputALSA(device);
     54#       else
     55            VERBOSE(VB_IMPORTANT, LOC_ERR
     56                    + "device " + device + ", ALSA input support not available");
     57#       endif
     58    }
     59
     60    else
     61        VERBOSE(VB_IMPORTANT, LOC_ERR
     62                + "unknown audio input device '" + device + "'");
     63
     64    return audio;
     65}
     66/* vim: set expandtab tabstop=4 shiftwidth=4: */
     67 No newline at end of file
  • new file mythtv/libs/libmyth/audioinputalsa.h

    - +  
     1/*
     2 * Copyright (C) 2007  Anand K. Mistry
     3 * Copyright (C) 2008  Alan Calvert
     4 *
     5 * This program is free software; you can redistribute it and/or
     6 * modify it under the terms of the GNU General Public License
     7 * as published by the Free Software Foundation; either version 2
     8 * of the License, or (at your option) any later version.
     9 *
     10 * This program is distributed in the hope that it will be useful,
     11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 * GNU General Public License for more details.
     14 *
     15 * You should have received a copy of the GNU General Public License
     16 * along with this program; if not, write to the Free Software
     17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
     18 * 02110-1301, USA.
     19 */
     20
     21#ifndef _AUDIOINPUTALSA_H_
     22#define _AUDIOINPUTALSA_H_
     23
     24#include "audioinput.h"
     25
     26#include <alsa/asoundlib.h>
     27
     28class AudioInputALSA : public AudioInput
     29{
     30  public:
     31    AudioInputALSA(const QString &device);
     32    ~AudioInputALSA() { Close(); };
     33
     34    bool Open(uint sample_bits, uint sample_rate, uint channels);
     35    inline bool IsOpen(void) { return (pcm_handle != NULL); }
     36    void Close(void);
     37
     38    bool Start(void);
     39    bool Stop(void);
     40
     41    inline int GetBlockSize(void) { return myth_block_bytes; };
     42    int GetSamples(void *buf, uint nbytes);
     43    int GetNumReadyBytes(void);
     44
     45  private:
     46    bool PrepHwParams(void);
     47    bool PrepSwParams(void);
     48    snd_pcm_uframes_t PcmRead(void *buf, uint nbytes);
     49    bool Recovery(int err);
     50    bool XrunRecovery(void);
     51    bool AlsaBad(int op_result, QString errmsg); // (op_result < 0) => false
     52
     53    QByteArray          alsa_device;
     54    snd_pcm_t*          pcm_handle;
     55    snd_pcm_uframes_t   period_size;
     56    uint                periods;
     57    int                 myth_block_bytes;
     58    QString             log_tag;
     59};
     60#endif /* _AUDIOINPUTALSA_H_ */
     61/* vim: set expandtab tabstop=4 shiftwidth=4: */
     62