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
42AudioInputOSS::AudioInputOSS(const QString &device) : AudioInput(device)
43{
44 if (!device.isEmpty())
45 m_deviceName = device.toLatin1();
46 else
47 m_deviceName = QByteArray();
48}
49
50bool 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;
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
234int 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
277 {
278 readies = ispace.bytes;
279 if (readies > 0)
280 LOG(VB_AUDIO, LOG_DEBUG, LOC_DEV + QString("ready bytes %1")
281 .arg(readies));
282 }
283 }
284 return readies;
285}
286
287/* vim: set expandtab tabstop=4 shiftwidth=4: */
#define LOC_DEV
int GetBlockSize(void) override
bool Stop(void) override
bool Start(void) override
int GetNumReadyBytes(void) override
void Close(void) override
bool IsOpen(void) override
Definition: audioinputoss.h:34
int GetSamples(void *buffer, uint num_bytes) override
QByteArray m_deviceName
Definition: audioinputoss.h:46
bool Open(uint sample_bits, uint sample_rate, uint channels) override
AudioInputOSS(const QString &device)
int m_audioSampleRate
Definition: audioinput.h:53
int m_audioSampleBits
Definition: audioinput.h:52
int m_audioChannels
Definition: audioinput.h:51
#define close
Definition: compat.h:39
unsigned int uint
Definition: freesurround.h:24
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:74
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
def read(device=None, features=[])
Definition: disc.py:35