MythTV  master
audioinputoss.cpp
Go to the documentation of this file.
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 #if 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 "mythlogging.h"
32 #include <fcntl.h>
33 #include <sys/ioctl.h>
34 
35 #include <QtGlobal>
36 
37 #define LOC QString("AudioInOSS: ")
38 #define LOC_DEV QString("AudioInOSS(%1): ").arg(m_deviceName.constData())
39 
40 AudioInputOSS::AudioInputOSS(const QString &device) : AudioInput(device)
41 {
42  if (!device.isEmpty())
43  m_deviceName = device.toLatin1();
44  else
45  m_deviceName = QByteArray();
46 }
47 
48 bool AudioInputOSS::Open(uint sample_bits, uint sample_rate, uint channels)
49 {
50  m_audioSampleBits = sample_bits;
51  m_audioSampleRate = sample_rate;
52  //m_audio_channels = channels;
53 
54  if (IsOpen())
55  Close();
56 
57  // Open the device
58  m_dspFd = open(m_deviceName.constData(), O_RDONLY);
59  if (m_dspFd < 0)
60  {
61  LOG(VB_GENERAL, LOG_ERR, LOC_DEV + QString("open failed: ") + ENO);
62  Close();
63  return false;
64  }
65 
66  int chk = 0; // disable input for now
67  if (ioctl(m_dspFd, SNDCTL_DSP_SETTRIGGER, &chk) < 0)
68  {
69  LOG(VB_GENERAL, LOG_WARNING,
70  LOC_DEV + "failed to disable audio device: " + ENO);
71  }
72 
73  // Set format
74  int choice = 0;
75  QString tag;
76  switch (sample_bits)
77  {
78  case 8:
79  choice = AFMT_U8;
80  tag = "AFMT_U8";
81  break;
82  case 16:
83  default:
84 #if (Q_BYTE_ORDER == Q_BIG_ENDIAN)
85  choice = AFMT_S16_BE;
86  tag = "AFMT_S16_BE";
87 #else
88  choice = AFMT_S16_LE;
89  tag = "AFMT_S16_LE";
90 #endif
91  break;
92  }
93  int format = choice;
94  if (ioctl(m_dspFd, SNDCTL_DSP_SETFMT, &format) < 0)
95  {
96  LOG(VB_GENERAL, LOG_ERR, LOC_DEV +
97  QString("failed to set audio format %1: ").arg(tag) + ENO);
98  Close();
99  return false;
100  }
101  if (format != choice)
102  {
103  LOG(VB_GENERAL, LOG_ERR, LOC_DEV +
104  QString("set audio format not %1 as requested").arg(tag));
105  Close();
106  return false;
107  }
108 
109  // sample size
110  m_audioSampleBits = choice = sample_bits;
111  if (ioctl(m_dspFd, SNDCTL_DSP_SAMPLESIZE, &m_audioSampleBits) < 0)
112  {
113  LOG(VB_GENERAL, LOG_ERR, LOC_DEV +
114  QString("failed to set audio sample bits to %1: ")
115  .arg(sample_bits) + ENO);
116  Close();
117  return false;
118  }
119  if (m_audioSampleBits != choice)
120  {
121  LOG(VB_GENERAL, LOG_ERR, LOC_DEV +
122  QString("requested %1 sample bits, got %2")
123  .arg(choice).arg(m_audioSampleBits));
124  }
125  // channels
126  m_audioChannels = choice = channels;
127  if (ioctl(m_dspFd, SNDCTL_DSP_CHANNELS, &m_audioChannels) < 0)
128  {
129  LOG(VB_GENERAL, LOG_ERR, LOC_DEV +
130  QString("failed to set audio channels to %1: ").arg(channels)+ENO);
131  Close();
132  return false;
133  }
134  if (m_audioChannels != choice)
135  {
136  LOG(VB_GENERAL, LOG_ERR, LOC_DEV +
137  QString("requested %1 channels, got %2")
138  .arg(choice).arg(m_audioChannels));
139  }
140 
141  // sample rate
142  int choice_sample_rate = sample_rate;
143  m_audioSampleRate = choice_sample_rate;
144  if (ioctl(m_dspFd, SNDCTL_DSP_SPEED, &m_audioSampleRate) < 0)
145  {
146  LOG(VB_GENERAL, LOG_ERR, LOC_DEV +
147  QString("failed to set sample rate to %1: ").arg(sample_rate)+ENO);
148  Close();
149  return false;
150  }
151  if (m_audioSampleRate != choice_sample_rate)
152  {
153  LOG(VB_GENERAL, LOG_ERR, LOC_DEV +
154  QString("requested sample rate %1, got %2")
155  .arg(choice_sample_rate).arg(m_audioSampleRate));
156  }
157  LOG(VB_AUDIO, LOG_INFO, LOC_DEV + "device open");
158  return true;
159 }
160 
162 {
163  if (IsOpen())
164  close(m_dspFd);
165  m_dspFd = -1;
166  m_audioSampleBits = 0;
167  m_audioSampleRate = 0;
168  m_audioChannels = 0;
169  LOG(VB_AUDIO, LOG_INFO, LOC_DEV + "device closed");
170 }
171 
173 {
174  bool started = false;
175  if (IsOpen())
176  {
177  int trig = 0; // clear
178  if (ioctl(m_dspFd, SNDCTL_DSP_SETTRIGGER, &trig) < 0)
179  {
180  LOG(VB_GENERAL, LOG_WARNING,
181  LOC_DEV + "failed to disable audio device: " + ENO);
182  }
183  trig = PCM_ENABLE_INPUT; // enable input
184  if (ioctl(m_dspFd, SNDCTL_DSP_SETTRIGGER, &trig) < 0)
185  {
186  LOG(VB_GENERAL, LOG_ERR, LOC_DEV +
187  QString("Start() failed: ") + ENO);
188  }
189  else
190  {
191  LOG(VB_AUDIO, LOG_INFO, LOC_DEV + "capture started");
192  started = true;
193  }
194  }
195  return started;
196 }
197 
199 {
200  bool stopped = false;
201  int trig = 0;
202  if (ioctl(m_dspFd, SNDCTL_DSP_SETTRIGGER, &trig) < 0)
203  {
204  LOG(VB_GENERAL, LOG_ERR, LOC_DEV +
205  QString("stop action failed: ") + ENO);
206  }
207  else
208  {
209  stopped = true;
210  LOG(VB_AUDIO, LOG_INFO, LOC_DEV + "capture stopped");
211  }
212  return stopped;
213 }
214 
216 {
217  int frag = 0;
218  if (IsOpen())
219  {
220  if (ioctl(m_dspFd, SNDCTL_DSP_GETBLKSIZE, &frag) < 0)
221  {
222  LOG(VB_GENERAL, LOG_ERR, LOC_DEV +
223  QString("fragment size query failed, returned %1: ").arg(frag) +
224  ENO);
225  frag = 0;
226  }
227  }
228  LOG(VB_AUDIO, LOG_INFO, LOC_DEV + QString("block size %1").arg(frag));
229  return frag;
230 }
231 
232 int AudioInputOSS::GetSamples(void *buffer, uint num_bytes)
233 {
234  uint bytes_read = 0;
235  if (IsOpen())
236  {
237  int retries = 0;
238  while (bytes_read < num_bytes && retries < 3)
239  {
240  int this_read = read(m_dspFd, buffer, num_bytes - bytes_read);
241  if (this_read < 0)
242  {
243  LOG(VB_GENERAL, LOG_ERR, LOC_DEV +
244  QString("GetSamples read failed: ") + ENO);
245  }
246  else
247  {
248  bytes_read += this_read;
249  }
250  ++retries;
251  }
252  if (num_bytes > bytes_read)
253  {
254  LOG(VB_GENERAL, LOG_ERR, LOC_DEV +
255  QString("GetSamples short read, %1 of %2 bytes")
256  .arg(bytes_read).arg(num_bytes));
257  }
258  }
259  return bytes_read;
260 }
261 
263 {
264  int readies = 0;
265  if (IsOpen())
266  {
267  audio_buf_info ispace;
268  if (ioctl(m_dspFd, SNDCTL_DSP_GETISPACE, &ispace) < 0)
269  {
270  LOG(VB_GENERAL, LOG_ERR, LOC_DEV +
271  QString("get ready bytes failed, returned %1: ")
272  .arg(ispace.bytes) + ENO);
273  }
274  else if ((readies = ispace.bytes) > 0)
275  LOG(VB_AUDIO, LOG_DEBUG, LOC_DEV + QString("ready bytes %1")
276  .arg(readies));
277  }
278  return readies;
279 }
280 
281 /* vim: set expandtab tabstop=4 shiftwidth=4: */
AudioInputOSS::IsOpen
bool IsOpen(void) override
Definition: audioinputoss.h:34
ENO
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:72
AudioInputOSS::GetNumReadyBytes
int GetNumReadyBytes(void) override
Definition: audioinputoss.cpp:262
AudioInput::m_audioChannels
int m_audioChannels
Definition: audioinput.h:51
discid.disc.read
def read(device=None, features=[])
Definition: disc.py:35
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
AudioInputOSS::AudioInputOSS
AudioInputOSS(const QString &device)
Definition: audioinputoss.cpp:40
LOC_DEV
#define LOC_DEV
Definition: audioinputoss.cpp:38
AudioInputOSS::GetSamples
int GetSamples(void *buffer, uint num_bytes) override
Definition: audioinputoss.cpp:232
AudioInputOSS::m_deviceName
QByteArray m_deviceName
Definition: audioinputoss.h:46
close
#define close
Definition: compat.h:17
AudioInputOSS::Stop
bool Stop(void) override
Definition: audioinputoss.cpp:198
AudioInput
Definition: audioinput.h:27
mythlogging.h
AudioInput::m_audioSampleRate
int m_audioSampleRate
Definition: audioinput.h:53
AudioInput::m_audioSampleBits
int m_audioSampleBits
Definition: audioinput.h:52
AudioInputOSS::m_dspFd
int m_dspFd
Definition: audioinputoss.h:47
uint
unsigned int uint
Definition: compat.h:144
AudioInputOSS::Start
bool Start(void) override
Definition: audioinputoss.cpp:172
AudioInputOSS::Close
void Close(void) override
Definition: audioinputoss.cpp:161
AudioInputOSS::Open
bool Open(uint sample_bits, uint sample_rate, uint channels) override
Definition: audioinputoss.cpp:48
audioinputoss.h
AudioInputOSS::GetBlockSize
int GetBlockSize(void) override
Definition: audioinputoss.cpp:215