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