Ticket #3405: 3405-v2.patch

File 3405-v2.patch, 33.0 KB (added by danielk, 16 years ago)

This just updates the patch for the current trunk. It still needs to handle error conditions better.

  • libs/libmythtv/NuppelVideoRecorder.cpp

     
    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.h>
    1914
     15#include <algorithm>
    2016#include <iostream>
    2117using namespace std;
    2218
    2319#include "mythcontext.h"
    2420#include "NuppelVideoRecorder.h"
     21#include "audioinput.h"
    2522#include "vbitext/cc.h"
    2623#include "channelbase.h"
    2724#include "filtermanager.h"
     
    5754#define LOC_ERR QString("NVR(%1) Error: ").arg(videodevice)
    5855
    5956NuppelVideoRecorder::NuppelVideoRecorder(TVRec *rec, ChannelBase *channel)
    60     : RecorderBase(rec)
     57    : RecorderBase(rec), audio_device(NULL)
    6158{
    6259    channelObj = channel;
    6360
     
    189186        lame_close(gf); 
    190187    if (strm)
    191188        delete [] strm;
     189    if (audio_device)
     190    {
     191        delete audio_device;
     192        audio_device = NULL;
     193    }
    192194    if (fd >= 0)
    193195        close(fd);
    194196    if (seektable)
     
    663665
    664666int NuppelVideoRecorder::AudioInit(bool skipdevice)
    665667{
    666     int afmt, afd;
    667     int frag, blocksize = 4096;
     668    int blocksize = 4096;
    668669    int tmp;
    669670
    670671    if (!skipdevice)
     
    679680
    680681        return 1;
    681682#else
    682         if (-1 == (afd = open(audiodevice.ascii(), O_RDONLY | O_NONBLOCK)))
     683        audio_device = AudioInput::CreateDevice(audiodevice);
     684        if (!audio_device)
    683685        {
    684             VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Cannot open DSP '%1'")
    685                     .arg(audiodevice));
    686             perror("open");
     686            VERBOSE(VB_IMPORTANT,
     687                    LOC_ERR + "AudioInit: Unable to create device");
    687688            return 1;
    688689        }
    689  
    690         fcntl(afd, F_SETFL, fcntl(afd, F_GETFL) & ~O_NONBLOCK);
    691  
    692         //ioctl(afd, SNDCTL_DSP_RESET, 0);
    693    
    694         frag = (8 << 16) | (10); //8 buffers, 1024 bytes each
    695         ioctl(afd, SNDCTL_DSP_SETFRAGMENT, &frag);
    696  
    697         afmt = AFMT_S16_LE;
    698         ioctl(afd, SNDCTL_DSP_SETFMT, &afmt);
    699         if (afmt != AFMT_S16_LE)
    700         {
    701             close(afd);
    702             VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't get 16 bit DSP");
    703             return 1;
    704         }
    705690
    706         if (ioctl(afd, SNDCTL_DSP_SAMPLESIZE, &audio_bits) < 0 ||
    707             ioctl(afd, SNDCTL_DSP_CHANNELS, &audio_channels) < 0 ||
    708             ioctl(afd, SNDCTL_DSP_SPEED, &audio_samplerate) < 0)
     691        if (!audio_device->Open(audio_bits, audio_samplerate, audio_channels))
    709692        {
    710             close(afd);
    711             QString msg = LOC_ERR +
    712                 QString("AudioInit(): %1 : error setting audio input device"
    713                         " to %2kHz/%3bits/%4channel").arg(audiodevice).
    714                 arg(audio_samplerate).arg(audio_bits).arg(audio_channels);
    715             VERBOSE(VB_IMPORTANT, msg);
     693            VERBOSE(VB_IMPORTANT,
     694                    LOC_ERR + "AudioInit: Unable to open device");
    716695            return 1;
    717696        }
    718697
    719         if (-1 == ioctl(afd, SNDCTL_DSP_GETBLKSIZE, &blocksize))
     698        blocksize = audio_device->GetBlockSize();
     699
     700        if (-1 == blocksize)
    720701        {
    721             close(afd);
    722             VERBOSE(VB_IMPORTANT, LOC_ERR + "AudioInit(): Can't get DSP blocksize");
    723             return(1);
     702            VERBOSE(VB_GENERAL,
     703                    LOC_ERR + "AudioInit: Unable to determine block size,"
     704                    "using default of 1024 bytes");
     705            blocksize = 1024;
    724706        }
    725707
    726         close(afd);
     708        VERBOSE(VB_AUDIO,
     709                LOC + QString("AudioInit: Using buffer size of %1 bytes")
     710                .arg(blocksize));
     711
     712        audio_device->Close();
    727713#endif
    728714    }
    729715
    730     audio_bytes_per_sample = audio_channels * audio_bits / 8;
    731     blocksize *= 4;
    732 
    733716    audio_buffer_size = blocksize;
    734717
    735718    if (compressaudio)
     
    22322215
    22332216void NuppelVideoRecorder::doAudioThread(void)
    22342217{
    2235 #if !defined (HAVE_SYS_SOUNDCARD_H) && !defined(HAVE_SOUNDCARD_H)
    2236     VERBOSE(VB_IMPORTANT, LOC +
    2237             QString("doAudioThread() This Unix doesn't support"
    2238                     " device files for audio access. Skipping"));
    2239     return;
    2240 #else
    2241     int afmt = 0, trigger = 0;
    2242     int afd = 0, act = 0, lastread = 0;
    2243     int frag = 0, blocksize = 0;
    2244     unsigned char *buffer;
    2245     audio_buf_info ispace;
    2246     struct timeval anow;
    2247 
    2248     act_audio_sample = 0;
    2249 
    2250     if (-1 == (afd = open(audiodevice.ascii(), O_RDONLY | O_NONBLOCK)))
     2218    if (!audio_device)
    22512219    {
    2252         VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Cannot open DSP '%1', exiting").
    2253                 arg(audiodevice));
    2254         perror("open");
     2220        VERBOSE(VB_GENERAL, LOC + "Audio: no audio device");
    22552221        return;
    22562222    }
    2257 
    2258     fcntl(afd, F_SETFL, fcntl(afd, F_GETFL) & ~O_NONBLOCK);
    2259     //ioctl(afd, SNDCTL_DSP_RESET, 0);
    2260 
    2261     frag = (8 << 16) | (10); //8 buffers, 1024 bytes each
    2262     ioctl(afd, SNDCTL_DSP_SETFRAGMENT, &frag);
    2263 
    2264     afmt = AFMT_S16_LE;
    2265     ioctl(afd, SNDCTL_DSP_SETFMT, &afmt);
    2266     if (afmt != AFMT_S16_LE)
     2223 
     2224    int act = 0, lastread = 0;
     2225    unsigned char *buffer;
     2226    struct timeval anow;
     2227   
     2228    if (!audio_device->Open(audio_bits,
     2229                            audio_samplerate,
     2230                            audio_channels))
    22672231    {
    2268         VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't get 16 bit DSP, exiting");
    2269         close(afd);
     2232        VERBOSE(VB_IMPORTANT, LOC_ERR + "Audio: Unable to open device");
    22702233        return;
    22712234    }
    22722235
    2273     if (ioctl(afd, SNDCTL_DSP_SAMPLESIZE, &audio_bits) < 0 ||
    2274         ioctl(afd, SNDCTL_DSP_CHANNELS, &audio_channels) < 0 ||
    2275         ioctl(afd, SNDCTL_DSP_SPEED, &audio_samplerate) < 0)
    2276     {
    2277         VERBOSE(VB_IMPORTANT, LOC_ERR + QString(" %1: error setting audio input device to "
    2278                                       "%2 kHz/%3 bits/%4 channel").
    2279                 arg(audiodevice).arg(audio_samplerate).
    2280                 arg(audio_bits).arg(audio_channels));
    2281         close(afd);
    2282         return;
    2283     }
    2284 
    22852236    audio_bytes_per_sample = audio_channels * audio_bits / 8;
    22862237
    2287     if (-1 == ioctl(afd, SNDCTL_DSP_GETBLKSIZE,  &blocksize))
    2288     {
    2289         VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't get DSP blocksize, exiting");
    2290         close(afd);
    2291         return;
    2292     }
    2293 
    2294     blocksize *= 4;  // allways read 4*blocksize
    2295 
    2296     if (blocksize != audio_buffer_size)
    2297     {
    2298         VERBOSE(VB_IMPORTANT, LOC +
    2299                 QString("Warning, audio blocksize = '%1' while audio_buffer_size='%2'").
    2300                 arg(blocksize).arg(audio_buffer_size));
    2301     }
    2302 
    23032238    buffer = new unsigned char[audio_buffer_size];
    23042239
    2305     /* trigger record */
    2306     trigger = 0;
    2307     ioctl(afd,SNDCTL_DSP_SETTRIGGER,&trigger);
    2308 
    2309     trigger = PCM_ENABLE_INPUT;
    2310     ioctl(afd,SNDCTL_DSP_SETTRIGGER,&trigger);
    2311 
    23122240    audiopaused = false;
     2241   
     2242    if (!audio_device->Start())
     2243    {
     2244        VERBOSE(VB_IMPORTANT, LOC_ERR + "Audio: Unable to start capture");
     2245        return;
     2246    }
     2247   
    23132248    while (childrenLive)
    23142249    {
    23152250        if (request_pause)
     
    23252260        }
    23262261        audiopaused = false;
    23272262
    2328         if (audio_buffer_size != (lastread = read(afd, buffer,
    2329                                                   audio_buffer_size)))
     2263        lastread = audio_device->GetSamples(buffer, audio_buffer_size);
     2264        if (audio_buffer_size != lastread)
    23302265        {
    23312266            VERBOSE(VB_IMPORTANT, LOC_ERR +
    23322267                    QString("Only read %1 bytes of %2 bytes from '%3").
    2333                     arg(lastread).arg(audio_buffer_size).arg(audiodevice));
    2334             perror("read audio");
     2268                    arg(lastread).arg(audio_buffer_size).arg(audiodevice) +
     2269                    ENO);
    23352270        }
    23362271
    23372272        /* record the current time */
     
    23392274           (like we used to.) Measure to see how much stuff is in there,
    23402275           and correct for it when calculating the timestamp */
    23412276        gettimeofday(&anow, &tzone);
    2342         ioctl( afd, SNDCTL_DSP_GETISPACE, &ispace );
     2277        int bytes_read = max(audio_device->GetNumReadyBytes(), 0);
    23432278
    23442279        act = act_audio_buffer;
    23452280
     
    23602295           audio chunk. So, subtract off the length of the chunk
    23612296           and the length of audio still in the capture buffer. */
    23622297        audiobuffer[act]->timecode -= (int)(
    2363                 (ispace.fragments * ispace.fragsize + audio_buffer_size)
     2298                (bytes_read + audio_buffer_size)
    23642299                 * 1000.0 / (audio_samplerate * audio_bytes_per_sample));
    23652300
    23662301        memcpy(audiobuffer[act]->buffer, buffer, audio_buffer_size);
     
    23752310    }
    23762311
    23772312    delete [] buffer;
    2378     close(afd);
    2379 #endif
     2313
     2314    if (audio_device->IsOpen())
     2315        audio_device->Close();
    23802316}
    23812317
    23822318struct VBIData
  • libs/libmythtv/libmythtv.pro

     
    8787cygwin:QMAKE_LFLAGS_SHLIB += -Wl,--noinhibit-exec
    8888cygwin:DEFINES += _WIN32
    8989
    90 # Enable Linux Open Sound System support
    91 using_oss:DEFINES += USING_OSS
     90# Enable sound systems support
     91using_alsa:DEFINES += USING_ALSA
     92using_arts:DEFINES += USING_ARTS
     93using_jack:DEFINES += USING_JACK
     94using_oss: DEFINES += USING_OSS
     95macx:      DEFINES += USING_COREAUDIO
     96
    9297# Enable Valgrind, i.e. disable some timeouts
    9398using_valgrind:DEFINES += USING_VALGRIND
    9499
  • libs/libmythtv/NuppelVideoRecorder.h

     
    4444class ChannelBase;
    4545class FilterManager;
    4646class FilterChain;
     47class AudioInput;
    4748
    4849class MPUBLIC NuppelVideoRecorder : public RecorderBase, public CC608Reader
    4950{
     
    152153    int inputchannel;
    153154    int compression;
    154155    int compressaudio;
     156    AudioInput *audio_device;
    155157    unsigned long long audiobytes;
    156158    int audio_channels;
    157159    int audio_bits;
  • libs/libmythtv/videosource.cpp

     
    833833{
    834834  public:
    835835    AudioDevice(const CaptureCard &parent) :
    836         PathSetting(this, true),
     836        PathSetting(this, false),
    837837        CaptureCardDBStorage(this, parent, "audiodevice")
    838838    {
    839839        setLabel(QObject::tr("Audio device"));
     840#ifdef USING_OSS
    840841        QDir dev("/dev", "dsp*", QDir::Name, QDir::System);
    841842        fillSelectionsFromDir(dev);
    842843        dev.setPath("/dev/sound");
    843844        fillSelectionsFromDir(dev);
    844         addSelection(QObject::tr("(None)"), "/dev/null");
     845#endif
     846#ifdef USING_ALSA
     847    addSelection("ALSA:default", "ALSA:default");
     848#endif
     849#ifdef USING_ARTS
     850    //addSelection("ARTS:", "ARTS:");
     851#endif
     852#ifdef USING_JACK
     853    //addSelection("JACK:output", "JACK:output");
     854#endif
     855#ifdef USING_COREAUDIO
     856    //addSelection("CoreAudio:", "CoreAudio:");
     857#endif
     858        addSelection(QObject::tr("(None)"), "NULL");
    845859    };
    846860};
    847861
  • 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.h>
     25
     26class AudioInput
     27{
     28  public:
     29    virtual ~AudioInput() {}
     30
     31    virtual bool Open(uint depth, uint sample_rate, uint channels) = 0;
     32    virtual bool IsOpen(void) const = 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 *buffer, uint num_samples) = 0;
     40    virtual int GetNumReadyBytes(void) = 0;
     41
     42    // Factory function
     43    static AudioInput *CreateDevice(const QString &device);
     44
     45  protected:
     46    AudioInput(const QString &device);
     47    QString m_device_name;
     48    int     m_audio_channels;
     49    int     m_audio_sample_size;
     50    int     m_audio_sample_rate;
     51};
     52
     53
     54#endif /* _AUDIOINPUT_H_ */
     55
  • 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 *
     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 <fcntl.h>
     23#include <unistd.h>
     24#include <sys/types.h>
     25#include <sys/stat.h>
     26#include <sys/ioctl.h>
     27
     28#include "mythconfig.h"
     29#ifdef HAVE_SYS_SOUNDCARD_H
     30    #include <sys/soundcard.h>
     31#elif HAVE_SOUNDCARD_H
     32    #include <soundcard.h>
     33#endif
     34
     35#include "audioinputoss.h"
     36#include "mythcontext.h"
     37
     38#define LOC QString("AudInOSS(%1): ").arg(m_device_name)
     39#define LOC_WARN QString("AudInOSS(%1) Warning: ").arg(m_device_name)
     40#define LOC_ERR QString("AudInOSS(%1) Error: ").arg(m_device_name)
     41
     42AudioInputOSS::AudioInputOSS(const QString &device) :
     43    AudioInput(device), m_audio_fd(-1)
     44{
     45}
     46
     47AudioInputOSS::~AudioInputOSS()
     48{
     49    Close();
     50}
     51
     52bool AudioInputOSS::Open(uint sample_size, uint sample_rate, uint channels)
     53{
     54    int desired_format = AFMT_S16_LE, format;
     55
     56    if (IsOpen())
     57        Close();
     58
     59    // Open the device
     60    const QString tmp = QDeepCopy<QString>(m_device_name);
     61    m_audio_fd = open(tmp.ascii(), O_RDONLY | O_NONBLOCK);
     62    if (m_audio_fd < 0)
     63    {
     64        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Cannot open '%1'")
     65                .arg(m_device_name) + ENO);
     66
     67        return false;
     68    }
     69
     70    // Disable trigger
     71    int trigger = 0;
     72    int ret = ioctl(m_audio_fd, SNDCTL_DSP_SETTRIGGER, &trigger);
     73    if (0 != ret)
     74    {
     75        VERBOSE(VB_AUDIO, LOC_WARN + "Can't stop capture" + ENO);
     76    }
     77
     78    // Get file descriptor flags
     79    int flags = fcntl(m_audio_fd, F_GETFL);
     80    if (-1 == flags)
     81    {
     82        VERBOSE(VB_AUDIO, LOC_WARN + "Unable to get blocking status" + ENO);
     83    }
     84    else
     85    {
     86        // Set blocking IO
     87        ret = fcntl(m_audio_fd, F_SETFL, flags & ~O_NONBLOCK);
     88        if (-1 == ret)
     89            VERBOSE(VB_AUDIO, LOC_WARN + "Unable to set blocking" + ENO);
     90    }
     91
     92    // Set buffering hints
     93    {
     94        int bufcnt  = 8;  // 8 buffers
     95        int bufbits = 10; // 1<<10 = 1024 bytes each
     96        int frag = (bufcnt << 16) | (bufbits);
     97        ret = ioctl(m_audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag);
     98    }
     99
     100    // Set format
     101    format = desired_format;
     102    ret = ioctl(m_audio_fd, SNDCTL_DSP_SETFMT, &format);
     103    if ((-1 == ret) || (desired_format != format))
     104    {
     105        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to set desired format");
     106        goto err_exit;
     107    }
     108
     109    // Set sample size
     110    m_audio_sample_size = sample_size;
     111    ret = ioctl(m_audio_fd, SNDCTL_DSP_SAMPLESIZE, &m_audio_sample_size);
     112    if (ret < 0)
     113    {
     114        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to set sample size" + ENO);
     115        goto err_exit;
     116    }
     117
     118    // Set channels
     119    m_audio_channels = channels;
     120    ret = ioctl(m_audio_fd, SNDCTL_DSP_CHANNELS, &m_audio_channels);
     121    if (ret < 0)
     122    {
     123        VERBOSE(VB_IMPORTANT, LOC_ERR +
     124                "Unable to set number of channels" + ENO);
     125        goto err_exit;
     126    }
     127
     128    // Set sample rate
     129    m_audio_sample_rate = sample_rate;
     130    ret = ioctl(m_audio_fd, SNDCTL_DSP_SPEED, &m_audio_sample_rate);
     131    if (ret < 0)
     132    {
     133        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to set sample rate" + ENO);
     134        goto err_exit;
     135    }
     136
     137    return true;
     138
     139  err_exit:
     140    close(m_audio_fd);
     141    m_audio_fd          = -1;
     142    m_audio_sample_size =  0;
     143    m_audio_sample_rate =  0;
     144    m_audio_channels    =  0;
     145    return false;
     146}
     147
     148void AudioInputOSS::Close(void)
     149{
     150    VERBOSE(VB_AUDIO, LOC + QString("Closing device '%1' %2")
     151            .arg(m_device_name).arg(IsOpen()));
     152
     153    if (IsOpen())
     154    {
     155        close(m_audio_fd);
     156        m_audio_fd          = -1;
     157        m_audio_sample_size =  0;
     158        m_audio_sample_rate =  0;
     159        m_audio_channels    =  0;
     160    }
     161}
     162
     163bool AudioInputOSS::Start(void)
     164{
     165    if (!IsOpen())
     166        return false;
     167
     168    int trigger = PCM_ENABLE_INPUT;
     169    int ret = ioctl(m_audio_fd, SNDCTL_DSP_SETTRIGGER, &trigger);
     170    if (-1 == ret)
     171    {
     172        VERBOSE(VB_AUDIO, LOC + "Unable to start capture" + ENO);
     173        return false;
     174    }
     175
     176    VERBOSE(VB_AUDIO, LOC + "Started capture");
     177
     178    return true;
     179}
     180
     181bool AudioInputOSS::Stop(void)
     182{
     183    VERBOSE(VB_IMPORTANT, LOC_ERR + "Not implemented");
     184    return false;
     185}
     186
     187int AudioInputOSS::GetBlockSize(void)
     188{
     189    if (!IsOpen())
     190        return -1;
     191
     192    int fragment_size;
     193    int ret = ioctl(m_audio_fd, SNDCTL_DSP_GETBLKSIZE, &fragment_size);
     194
     195    if (-1 == ret)
     196    {
     197        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to query fragment size" + ENO);
     198        return -1;
     199    }
     200
     201    return fragment_size;
     202}
     203
     204int AudioInputOSS::GetSamples(void *buffer, uint num_bytes)
     205{
     206    if (!IsOpen())
     207        return -1;
     208
     209    if (0 != (num_bytes % ((m_audio_sample_size * m_audio_channels) / 8)))
     210    {
     211        VERBOSE(VB_IMPORTANT, LOC_ERR + "Invalid num_bytes");
     212        return -1;
     213    }
     214
     215    // TODO FIXME This will fail if the read is interrupted by a signal...
     216    int bytes_read = read(m_audio_fd, buffer, num_bytes);
     217
     218    return bytes_read;
     219}
     220
     221int AudioInputOSS::GetNumReadyBytes(void)
     222{
     223    if (!IsOpen())
     224        return -1;
     225
     226    audio_buf_info ispace;
     227    int ret = ioctl(m_audio_fd, SNDCTL_DSP_GETISPACE, &ispace);
     228    if (-1 == ret)
     229    {
     230        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to get ready bytes" + ENO);
     231    }
     232
     233    return ispace.bytes;
     234}
     235
     236/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • libs/libmyth/audioinputoss.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 _AUDIOINPUTOSS_H_
     22#define _AUDIOINPUTOSS_H_
     23
     24#include "audioinput.h"
     25
     26class AudioInputOSS : public AudioInput
     27{
     28  public:
     29    AudioInputOSS(const QString &device);
     30    virtual ~AudioInputOSS();
     31
     32    virtual bool Open(uint depth, uint sample_rate, uint channels);
     33    virtual bool IsOpen(void) const { return m_audio_fd >= 0; }
     34    virtual void Close(void);
     35
     36    virtual bool Start(void);
     37    virtual bool Stop(void);
     38
     39    virtual int GetBlockSize(void);
     40    virtual int GetSamples(void *buffer, uint num_samples);
     41    virtual int GetNumReadyBytes(void);
     42
     43  private:
     44    int m_audio_fd;
     45};
     46
     47#endif /* _AUDIOINPUTOSS_H_ */
     48
  • libs/libmyth/audioinputalsa.cpp

     
     1/*
     2 * Copyright (C) 2007  Anand K. Mistry
     3 * Copyright (C) 2007  Daniel Kristjansson
     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 <fcntl.h>
     22#include <unistd.h>
     23#include <sys/types.h>
     24#include <sys/stat.h>
     25#include <sys/ioctl.h>
     26
     27#include <alsa/asoundlib.h>
     28
     29#include "audioinputalsa.h"
     30#include "mythcontext.h"
     31
     32#define LOC QString("AudInALSA(%1): ").arg(m_device_name)
     33#define LOC_WARN QString("AudInALSA(%1) Warning: ").arg(m_device_name)
     34#define LOC_ERR QString("AudInALSA(%1) Error: ").arg(m_device_name)
     35
     36AudioInputALSA::AudioInputALSA(const QString &device) :
     37    AudioInput(device), m_audio_handle(NULL)
     38{
     39}
     40
     41AudioInputALSA::~AudioInputALSA()
     42{
     43    Close();
     44}
     45
     46bool AudioInputALSA::Open(uint sample_size, uint sample_rate, uint channels)
     47{
     48    if (IsOpen())
     49        Close();
     50
     51    // Open the device
     52    const QString tmp = QDeepCopy<QString>(m_device_name);
     53    int ret = snd_pcm_open((snd_pcm_t**)(&m_audio_handle),
     54                           tmp.ascii(), SND_PCM_STREAM_CAPTURE, 0);
     55
     56    if (ret)
     57    {
     58        m_audio_handle = NULL;
     59        VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Cannot open '%1'")
     60                .arg(m_device_name));
     61
     62        return false;
     63    }
     64
     65    // Allocate hw params structure
     66    snd_pcm_hw_params_t *hw_params = NULL;
     67    ret = snd_pcm_hw_params_malloc(&hw_params);
     68    if (ret)
     69    {
     70        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to allocate hw params");
     71        goto err_exit;
     72    }
     73
     74    // Initialize hw params
     75    ret = snd_pcm_hw_params_any(((snd_pcm_t*) m_audio_handle), hw_params);
     76    if (ret)
     77    {
     78        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to init hw params");
     79        goto err_exit;
     80    }
     81
     82    // Set interleaved access
     83    ret = snd_pcm_hw_params_set_access(((snd_pcm_t*) m_audio_handle),
     84                                       hw_params,
     85                                       SND_PCM_ACCESS_RW_INTERLEAVED);
     86    if (ret)
     87    {
     88        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to set interleaved");
     89        goto err_exit;
     90    }
     91
     92    // Set format
     93    ret = snd_pcm_hw_params_set_format(((snd_pcm_t*) m_audio_handle),
     94                                       hw_params,
     95                                       SND_PCM_FORMAT_S16_LE);
     96    if (ret)
     97    {
     98        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to set desired format");
     99        goto err_exit;
     100    }
     101
     102    // Set sampling rate
     103    m_audio_sample_rate = sample_rate;
     104    ret = snd_pcm_hw_params_set_rate(((snd_pcm_t*) m_audio_handle),
     105                                     hw_params, m_audio_sample_rate, 0);
     106    if (ret)
     107    {
     108        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to set sample rate" + ENO);
     109        goto err_exit;
     110    }
     111
     112    // Set channels
     113    m_audio_channels = channels;
     114    ret = snd_pcm_hw_params_set_channels(((snd_pcm_t*) m_audio_handle),
     115                                         hw_params, m_audio_channels);
     116    if (ret)
     117    {
     118        VERBOSE(VB_IMPORTANT, LOC_ERR +
     119                "Unable to set number of channels" + ENO);
     120        goto err_exit;
     121    }
     122
     123    // Apply settings
     124    ret = snd_pcm_hw_params(((snd_pcm_t*) m_audio_handle), hw_params);
     125    if (ret)
     126    {
     127        VERBOSE(VB_IMPORTANT, LOC_ERR +
     128                "Unable to apply settings to device" + ENO);
     129        goto err_exit;
     130    }
     131
     132    snd_pcm_hw_params_free(hw_params);
     133
     134    // Set sample size
     135    m_audio_sample_size = sample_size;
     136
     137    return true;
     138
     139  err_exit:
     140    snd_pcm_close(((snd_pcm_t*) m_audio_handle));
     141    m_audio_handle      = NULL;
     142    m_audio_sample_size = 0;
     143    m_audio_sample_rate = 0;
     144    m_audio_channels    = 0;
     145    return false;
     146}
     147
     148void AudioInputALSA::Close(void)
     149{
     150    VERBOSE(VB_AUDIO, LOC + QString("Closing device '%1' %2")
     151            .arg(m_device_name).arg(IsOpen()));
     152
     153    if (IsOpen())
     154    {
     155        snd_pcm_close(((snd_pcm_t*) m_audio_handle));
     156        m_audio_handle      = NULL;
     157        m_audio_sample_size = 0;
     158        m_audio_sample_rate = 0;
     159        m_audio_channels    = 0;
     160    }
     161}
     162
     163bool AudioInputALSA::Start(void)
     164{
     165    if (!IsOpen())
     166        return false;
     167
     168    int ret = snd_pcm_prepare(((snd_pcm_t*) m_audio_handle));
     169    if (0 != ret)
     170    {
     171        VERBOSE(VB_AUDIO, LOC + "Unable to start capture");
     172        return false;
     173    }
     174
     175    VERBOSE(VB_AUDIO, LOC + "Started capture on " + m_device_name);
     176
     177    return true;
     178}
     179
     180bool AudioInputALSA::Stop(void)
     181{
     182    VERBOSE(VB_IMPORTANT, LOC_ERR + "Not implemented");
     183    return false;
     184}
     185
     186int AudioInputALSA::GetBlockSize(void)
     187{
     188    if (!IsOpen())
     189        return -1;
     190
     191    snd_pcm_uframes_t buffer_size, period_size;
     192
     193    int ret = snd_pcm_get_params(((snd_pcm_t*) m_audio_handle),
     194                                 &buffer_size, &period_size);
     195
     196    if (0 != ret)
     197    {
     198        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to query fragment size" + ENO);
     199        return -1;
     200    }
     201
     202    return (period_size * m_audio_channels * m_audio_sample_size) / 8;
     203}
     204
     205int AudioInputALSA::GetSamples(void *buffer, uint num_bytes)
     206{
     207    if (!IsOpen())
     208        return -1;
     209
     210    uint frame_size = (m_audio_sample_size * m_audio_channels) / 8;
     211
     212    if (0 != (num_bytes % frame_size))
     213    {
     214        VERBOSE(VB_IMPORTANT, LOC_ERR + "Invalid num_bytes");
     215        return -1;
     216    }
     217
     218    int ret = snd_pcm_readi(((snd_pcm_t*) m_audio_handle),
     219                            buffer, num_bytes / frame_size);
     220
     221    if ((-EINTR == ret) || (-EPIPE == ret) || (-ESTRPIPE == ret))
     222    {
     223        ret = snd_pcm_recover(((snd_pcm_t*) m_audio_handle), ret, 1);
     224        if ((ret < 0) && (-EAGAIN != ret))
     225        {
     226            VERBOSE(VB_IMPORTANT, LOC_ERR +
     227                    "Failed to recover from error" + ENO);
     228            return -1;
     229        }
     230        ret = 0;
     231    }
     232
     233    return (ret>=0) ? ret * frame_size : -1;
     234}
     235
     236int AudioInputALSA::GetNumReadyBytes(void)
     237{
     238    if (!IsOpen())
     239        return -1;
     240
     241    snd_pcm_sframes_t delay;
     242    int ret = snd_pcm_delay(((snd_pcm_t*) m_audio_handle), &delay);
     243
     244    if (0 != ret)
     245    {
     246        VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to get ready bytes" + ENO);
     247        return -1;
     248    }
     249
     250    return (delay * m_audio_channels * m_audio_sample_size) / 8;
     251}
     252
     253/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • libs/libmyth/libmyth.pro

     
    8585
    8686using_oss {
    8787    DEFINES += USING_OSS
    88     SOURCES += audiooutputoss.cpp
    89     HEADERS += audiooutputoss.h
     88    SOURCES *= audiooutputoss.cpp audioinputoss.cpp audioinput.cpp
     89    HEADERS *= audiooutputoss.h   audioinputoss.h   audioinput.h
    9090}
    9191
    9292unix:!cygwin {
     
    175175
    176176using_alsa {
    177177    DEFINES += USE_ALSA
    178     HEADERS += audiooutputalsa.h
    179     SOURCES += audiooutputalsa.cpp
     178    HEADERS *= audiooutputalsa.h   audioinputalsa.h   audioinput.h
     179    SOURCES *= audiooutputalsa.cpp audioinputalsa.cpp audioinput.cpp
    180180    LIBS += $$ALSA_LIBS
    181181}
    182182
  • libs/libmyth/audioinput.cpp

     
     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#include "audioinput.h"
     22#include "mythcontext.h"
     23#include "audioinputalsa.h"
     24#include "audioinputoss.h"
     25
     26#define LOC QString("AudIn(%1): ").arg(device)
     27#define LOC_WARN QString("AudIn(%1) Warning: ").arg(device)
     28#define LOC_ERR QString("AudIn(%1) Error: ").arg(device)
     29
     30AudioInput::AudioInput(const QString &device) :
     31    m_device_name(QString::null), m_audio_channels(0),
     32    m_audio_sample_size(0),       m_audio_sample_rate(0)
     33{
     34    if (!device.isEmpty())
     35        m_device_name = QDeepCopy<QString>(device);
     36}
     37
     38AudioInput *AudioInput::CreateDevice(const QString &device)
     39{
     40    AudioInput *dev = NULL;
     41
     42    if (device.isEmpty())
     43    {
     44        VERBOSE(VB_IMPORTANT, LOC_ERR + "Device string is empty");
     45        return NULL;
     46    }
     47
     48    if ((device == "NULL") || (device == "/dev/null"))
     49    {
     50        VERBOSE(VB_AUDIO, LOC + "Using NULL audio in");
     51    }
     52    else if (device.startsWith("ALSA:"))
     53    {
     54#ifdef USE_ALSA
     55        QString tmp = QDeepCopy<QString>(device);
     56        dev = new AudioInputALSA(tmp.remove(0,5));
     57#else
     58        VERBOSE(VB_IMPORTANT, LOC_ERR + "ALSA input support not available");
     59#endif
     60    }
     61    else if (device.startsWith("/"))
     62    {
     63#ifdef USING_OSS
     64        dev = new AudioInputOSS(device);
     65#else
     66        VERBOSE(VB_IMPORTANT, LOC_ERR + "OSS input support not available");
     67#endif
     68    }
     69    else
     70    {
     71        VERBOSE(VB_IMPORTANT, LOC_ERR +
     72                QString("Unrecognized audio in '%1' device").arg(device));
     73    }
     74
     75    return dev;
     76}
  • libs/libmyth/audioinputalsa.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 _AUDIOINPUTALSA_H_
     22#define _AUDIOINPUTALSA_H_
     23
     24#include "audioinput.h"
     25
     26class AudioInputALSA : public AudioInput
     27{
     28  public:
     29    AudioInputALSA(const QString &device);
     30    virtual ~AudioInputALSA();
     31
     32    virtual bool Open(uint depth, uint sample_rate, uint channels);
     33    virtual bool IsOpen(void) const { return m_audio_handle; }
     34    virtual void Close(void);
     35
     36    virtual bool Start(void);
     37    virtual bool Stop(void);
     38
     39    virtual int GetBlockSize(void);
     40    virtual int GetSamples(void *buffer, uint num_samples);
     41    virtual int GetNumReadyBytes(void);
     42
     43  private:
     44    void *m_audio_handle;
     45};
     46
     47#endif /* _AUDIOINPUTALSA_H_ */
     48