Ticket #3405: 3405-v4.patch
File 3405-v4.patch, 41.0 KB (added by , 15 years ago) |
---|
-
libs/libmythtv/NuppelVideoRecorder.cpp
old new 5 5 #include <sys/types.h> 6 6 #include <sys/stat.h> 7 7 #include "mythconfig.h" 8 #ifdef HAVE_SYS_SOUNDCARD_H9 #include <sys/soundcard.h>10 #elif HAVE_SOUNDCARD_H11 #include <soundcard.h>12 #endif13 8 #include <sys/ioctl.h> 14 9 #include <sys/mman.h> 15 10 #include <cerrno> … … 17 12 18 13 #include <QStringList> 19 14 15 #include <algorithm> 20 16 #include <iostream> 21 17 using namespace std; 22 18 23 19 #include "libmyth/mythcontext.h" 24 20 #include "libmythdb/mythverbose.h" 25 21 #include "NuppelVideoRecorder.h" 22 #include "audioinput.h" 26 23 #include "vbitext/cc.h" 27 24 #include "channelbase.h" 28 25 #include "filtermanager.h" … … 58 55 #define LOC_ERR QString("NVR(%1) Error: ").arg(videodevice) 59 56 60 57 NuppelVideoRecorder::NuppelVideoRecorder(TVRec *rec, ChannelBase *channel) 61 : RecorderBase(rec) 58 : RecorderBase(rec), audio_device(NULL) 62 59 { 63 60 channelObj = channel; 64 61 … … 190 187 lame_close(gf); 191 188 if (strm) 192 189 delete [] strm; 190 if (audio_device) 191 { 192 delete audio_device; 193 audio_device = NULL; 194 } 193 195 if (fd >= 0) 194 196 close(fd); 195 197 if (seektable) … … 612 614 { 613 615 if (AudioInit() != 0) 614 616 { 615 VERBOSE(VB_IMPORTANT, LOC_ERR + " Could not detect audio blocksize");617 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to init audio input device"); 616 618 } 617 619 618 620 if (videocodec == "hardware-mjpeg") … … 668 670 669 671 int NuppelVideoRecorder::AudioInit(bool skipdevice) 670 672 { 671 int afmt, afd; 672 int frag, blocksize = 4096; 673 int blocksize = 4096; 673 674 int tmp; 674 675 675 676 if (!skipdevice) … … 679 680 (void) afd; 680 681 (void) frag; 681 682 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."); 684 685 685 686 return 1; 686 687 #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) 706 690 { 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"); 709 692 return 1; 710 693 } 711 694 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"); 722 698 return 1; 723 699 } 724 700 725 if ( -1 == ioctl(afd, SNDCTL_DSP_GETBLKSIZE, &blocksize))701 if ((blocksize = audio_device->GetBlockSize()) <= 0) 726 702 { 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"); 730 706 } 731 707 732 close(afd);708 audio_device->Close(); 733 709 #endif 734 710 } 735 711 736 712 audio_bytes_per_sample = audio_channels * audio_bits / 8; 737 blocksize *= 4;738 739 713 audio_buffer_size = blocksize; 714 VERBOSE(VB_AUDIO, LOC + QString("AudioInit: audio buffer size %1 bytes") 715 .arg(audio_buffer_size)); 740 716 741 717 if (compressaudio) 742 718 { … … 756 732 757 733 if (audio_bits != 16) 758 734 { 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"); 761 737 compressaudio = false; 762 738 } 763 739 } … … 1301 1277 { 1302 1278 // this is supported by the cx88 and various ati cards. 1303 1279 vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; 1304 1305 1280 if (ioctl(fd, VIDIOC_S_FMT, &vfmt) < 0) 1306 1281 { 1307 1282 VERBOSE(VB_IMPORTANT, LOC_ERR + "v4l2: Unable to set desired format"); … … 2255 2230 2256 2231 void NuppelVideoRecorder::doAudioThread(void) 2257 2232 { 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) 2275 2234 { 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"); 2279 2236 return; 2280 2237 } 2281 2238 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)) 2291 2240 { 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"); 2294 2242 return; 2295 2243 } 2296 2244 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()) 2300 2246 { 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"); 2306 2248 return; 2307 2249 } 2308 2250 2251 struct timeval anow; 2252 unsigned char *buffer = new unsigned char[audio_buffer_size]; 2253 int act = 0, lastread = 0; 2309 2254 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; 2335 2256 2336 2257 // Qt4 requires a QMutex as a parameter... 2337 2258 // not sure if this is the best solution. Mutex Must be locked before wait. 2338 2259 QMutex mutex; 2339 2260 mutex.lock(); 2340 2261 2341 audiopaused = false;2342 2262 while (childrenLive) 2343 2263 { 2344 2264 if (request_pause) … … 2354 2274 } 2355 2275 audiopaused = false; 2356 2276 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) 2359 2279 { 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); 2364 2284 } 2365 2285 2366 2286 /* record the current time */ … … 2368 2288 (like we used to.) Measure to see how much stuff is in there, 2369 2289 and correct for it when calculating the timestamp */ 2370 2290 gettimeofday(&anow, &tzone); 2371 i octl( afd, SNDCTL_DSP_GETISPACE, &ispace);2291 int bytes_read = max(audio_device->GetNumReadyBytes(), 0); 2372 2292 2373 2293 act = act_audio_buffer; 2374 2294 … … 2389 2309 audio chunk. So, subtract off the length of the chunk 2390 2310 and the length of audio still in the capture buffer. */ 2391 2311 audiobuffer[act]->timecode -= (int)( 2392 ( ispace.fragments * ispace.fragsize+ audio_buffer_size)2312 (bytes_read + audio_buffer_size) 2393 2313 * 1000.0 / (audio_samplerate * audio_bytes_per_sample)); 2394 2314 2395 2315 memcpy(audiobuffer[act]->buffer, buffer, audio_buffer_size); … … 2404 2324 } 2405 2325 2406 2326 delete [] buffer; 2407 close(afd); 2408 #endif 2327 2328 if (audio_device->IsOpen()) 2329 audio_device->Close(); 2409 2330 } 2410 2331 2411 2332 struct VBIData -
libs/libmythtv/libmythtv.pro
old new 96 96 cygwin:QMAKE_LFLAGS_SHLIB += -Wl,--noinhibit-exec 97 97 cygwin:DEFINES += _WIN32 98 98 99 # Enable Linux Open Sound System support 100 using_oss:DEFINES += USING_OSS 99 # Enable sound systems support 100 using_alsa:DEFINES += USING_ALSA 101 using_arts:DEFINES += USING_ARTS 102 using_jack:DEFINES += USING_JACK 103 using_oss: DEFINES += USING_OSS 104 macx: DEFINES += USING_COREAUDIO 105 101 106 # Enable Valgrind, i.e. disable some timeouts 102 107 using_valgrind:DEFINES += USING_VALGRIND 103 108 -
libs/libmythtv/NuppelVideoRecorder.h
old new 44 44 class ChannelBase; 45 45 class FilterManager; 46 46 class FilterChain; 47 class AudioInput; 47 48 48 49 class MPUBLIC NuppelVideoRecorder : public RecorderBase, public CC608Reader 49 50 { … … 153 154 int inputchannel; 154 155 int compression; 155 156 int compressaudio; 157 AudioInput *audio_device; 156 158 unsigned long long audiobytes; 157 159 int audio_channels; 158 160 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 26 class 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 38 AudioInputOSS::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 48 bool 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 123 void 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 134 bool 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 154 bool 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 169 int 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 186 int 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 214 int 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 231 void 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 239 bool AudioInputOSS::OssFatal(int err, QString msg) 240 { 241 OssError(err, msg); 242 Close(); 243 return false; 244 } 245 246 void 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 27 class 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 28 AudioInputALSA::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 40 bool 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 65 void 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 75 bool 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 88 bool 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 100 int 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 137 int 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 157 bool 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 261 bool 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 286 snd_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 340 bool 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 365 bool 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 374 bool 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 88 88 89 89 using_oss { 90 90 DEFINES += USING_OSS 91 SOURCES += audiooutputoss.cpp92 HEADERS += audiooutputoss.h91 SOURCES *= audiooutputoss.cpp audioinputoss.cpp audioinput.cpp 92 HEADERS *= audiooutputoss.h audioinputoss.h audioinput.h 93 93 LIBS += $$OSS_LIBS 94 94 } 95 95 … … 155 155 156 156 using_alsa { 157 157 DEFINES += USE_ALSA 158 HEADERS += audiooutputalsa.h159 SOURCES += audiooutputalsa.cpp158 HEADERS *= audiooutputalsa.h audioinputalsa.h audioinput.h 159 SOURCES *= audiooutputalsa.cpp audioinputalsa.cpp audioinput.cpp 160 160 LIBS += $$ALSA_LIBS 161 161 } 162 162 -
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 29 AudioInput::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 37 AudioInput *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 28 class 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