root / oss.c @ 08cea4ee
History | View | Annotate | Download (11.6 kB)
1 |
/*
|
---|---|
2 |
* QEMU OSS Audio output driver
|
3 |
*
|
4 |
* Copyright (c) 2003 Vassili Karpov (malc)
|
5 |
*
|
6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 |
* of this software and associated documentation files (the "Software"), to deal
|
8 |
* in the Software without restriction, including without limitation the rights
|
9 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 |
* copies of the Software, and to permit persons to whom the Software is
|
11 |
* furnished to do so, subject to the following conditions:
|
12 |
*
|
13 |
* The above copyright notice and this permission notice shall be included in
|
14 |
* all copies or substantial portions of the Software.
|
15 |
*
|
16 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 |
* THE SOFTWARE.
|
23 |
*/
|
24 |
#include <fcntl.h> |
25 |
#include <errno.h> |
26 |
#include <stdio.h> |
27 |
#include <unistd.h> |
28 |
#include <string.h> |
29 |
#include <stdlib.h> |
30 |
#include <limits.h> |
31 |
#include <inttypes.h> |
32 |
#include <sys/types.h> |
33 |
#include <sys/ioctl.h> |
34 |
#include <sys/soundcard.h> |
35 |
|
36 |
#include "vl.h" |
37 |
|
38 |
/* http://www.df.lth.se/~john_e/gems/gem002d.html */
|
39 |
/* http://www.multi-platforms.com/Tips/PopCount.htm */
|
40 |
static inline uint32_t popcount (uint32_t u) |
41 |
{ |
42 |
u = ((u&0x55555555) + ((u>>1)&0x55555555)); |
43 |
u = ((u&0x33333333) + ((u>>2)&0x33333333)); |
44 |
u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f)); |
45 |
u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff)); |
46 |
u = ( u&0x0000ffff) + (u>>16); |
47 |
return u;
|
48 |
} |
49 |
|
50 |
static inline uint32_t lsbindex (uint32_t u) |
51 |
{ |
52 |
return popcount ((u&-u)-1); |
53 |
} |
54 |
|
55 |
#define MIN(a, b) ((a)>(b)?(b):(a))
|
56 |
#define MAX(a, b) ((a)<(b)?(b):(a))
|
57 |
|
58 |
#define DEREF(x) (void)x |
59 |
#define log(...) fprintf (stderr, "oss: " __VA_ARGS__) |
60 |
#define ERRFail(...) do { \ |
61 |
int _errno = errno; \
|
62 |
fprintf (stderr, "oss: " __VA_ARGS__); \
|
63 |
fprintf (stderr, "system error: %s\n", strerror (_errno)); \
|
64 |
abort (); \ |
65 |
} while (0) |
66 |
#define Fail(...) do { \ |
67 |
fprintf (stderr, "oss: " __VA_ARGS__); \
|
68 |
fprintf (stderr, "\n"); \
|
69 |
abort (); \ |
70 |
} while (0) |
71 |
|
72 |
#ifdef DEBUG_OSS
|
73 |
#define lwarn(...) fprintf (stderr, "oss: " __VA_ARGS__) |
74 |
#define linfo(...) fprintf (stderr, "oss: " __VA_ARGS__) |
75 |
#define ldebug(...) fprintf (stderr, "oss: " __VA_ARGS__) |
76 |
#else
|
77 |
#define lwarn(...)
|
78 |
#define linfo(...)
|
79 |
#define ldebug(...)
|
80 |
#endif
|
81 |
|
82 |
|
83 |
#define IOCTL(args) do { \ |
84 |
int ret = ioctl args; \
|
85 |
if (-1 == ret) { \ |
86 |
ERRFail (#args); \
|
87 |
} \ |
88 |
ldebug ("ioctl " #args " = %d\n", ret); \ |
89 |
} while (0) |
90 |
|
91 |
static int audio_fd = -1; |
92 |
static int freq; |
93 |
static int conf_nfrags = 4; |
94 |
static int conf_fragsize; |
95 |
static int nfrags; |
96 |
static int fragsize; |
97 |
static int bufsize; |
98 |
static int nchannels; |
99 |
static int fmt; |
100 |
static int rpos; |
101 |
static int wpos; |
102 |
static int atom; |
103 |
static int live; |
104 |
static int leftover; |
105 |
static int bytes_per_second; |
106 |
static void *buf; |
107 |
static enum {DONT, DSP, TID} estimate = TID; |
108 |
|
109 |
static void (*copy_fn)(void *, void *, int); |
110 |
|
111 |
static void copy_no_conversion (void *dst, void *src, int size) |
112 |
{ |
113 |
memcpy (dst, src, size); |
114 |
} |
115 |
|
116 |
static void copy_u16_to_s16 (void *dst, void *src, int size) |
117 |
{ |
118 |
int i;
|
119 |
uint16_t *out, *in; |
120 |
|
121 |
out = dst; |
122 |
in = src; |
123 |
|
124 |
for (i = 0; i < size / 2; i++) { |
125 |
out[i] = in[i] + 0x8000;
|
126 |
} |
127 |
} |
128 |
|
129 |
static void pab (struct audio_buf_info *abinfo) |
130 |
{ |
131 |
DEREF (abinfo); |
132 |
|
133 |
ldebug ("fragments %d, fragstotal %d, fragsize %d, bytes %d\n"
|
134 |
"rpos %d, wpos %d, live %d\n",
|
135 |
abinfo->fragments, |
136 |
abinfo->fragstotal, |
137 |
abinfo->fragsize, |
138 |
abinfo->bytes, |
139 |
rpos, wpos, live); |
140 |
} |
141 |
|
142 |
void AUD_reset (int rfreq, int rnchannels, audfmt_e rfmt) |
143 |
{ |
144 |
int fmt_;
|
145 |
int bits16;
|
146 |
|
147 |
if (-1 == audio_fd) { |
148 |
AUD_open (rfreq, rnchannels, rfmt); |
149 |
return;
|
150 |
} |
151 |
|
152 |
switch (rfmt) {
|
153 |
case AUD_FMT_U8:
|
154 |
bits16 = 0;
|
155 |
fmt_ = AFMT_U8; |
156 |
copy_fn = copy_no_conversion; |
157 |
atom = 1;
|
158 |
break;
|
159 |
|
160 |
case AUD_FMT_S8:
|
161 |
Fail ("can not play 8bit signed");
|
162 |
|
163 |
case AUD_FMT_S16:
|
164 |
bits16 = 1;
|
165 |
fmt_ = AFMT_S16_LE; |
166 |
copy_fn = copy_no_conversion; |
167 |
atom = 2;
|
168 |
break;
|
169 |
|
170 |
case AUD_FMT_U16:
|
171 |
bits16 = 1;
|
172 |
fmt_ = AFMT_S16_LE; |
173 |
copy_fn = copy_u16_to_s16; |
174 |
atom = 2;
|
175 |
break;
|
176 |
|
177 |
default:
|
178 |
abort (); |
179 |
} |
180 |
|
181 |
if ((fmt_ == fmt) && (bits16 + 1 == nchannels) && (rfreq == freq)) |
182 |
return;
|
183 |
else {
|
184 |
AUD_open (rfreq, rnchannels, rfmt); |
185 |
} |
186 |
} |
187 |
|
188 |
void AUD_open (int rfreq, int rnchannels, audfmt_e rfmt) |
189 |
{ |
190 |
int fmt_;
|
191 |
int mmmmssss;
|
192 |
struct audio_buf_info abinfo;
|
193 |
int _fmt;
|
194 |
int _freq;
|
195 |
int _nchannels;
|
196 |
int bits16;
|
197 |
|
198 |
bits16 = 0;
|
199 |
|
200 |
switch (rfmt) {
|
201 |
case AUD_FMT_U8:
|
202 |
bits16 = 0;
|
203 |
fmt_ = AFMT_U8; |
204 |
copy_fn = copy_no_conversion; |
205 |
atom = 1;
|
206 |
break;
|
207 |
|
208 |
case AUD_FMT_S8:
|
209 |
Fail ("can not play 8bit signed");
|
210 |
|
211 |
case AUD_FMT_S16:
|
212 |
bits16 = 1;
|
213 |
fmt_ = AFMT_S16_LE; |
214 |
copy_fn = copy_no_conversion; |
215 |
atom = 2;
|
216 |
break;
|
217 |
|
218 |
case AUD_FMT_U16:
|
219 |
bits16 = 1;
|
220 |
fmt_ = AFMT_S16_LE; |
221 |
copy_fn = copy_u16_to_s16; |
222 |
atom = 2;
|
223 |
break;
|
224 |
|
225 |
default:
|
226 |
abort (); |
227 |
} |
228 |
|
229 |
if (buf) {
|
230 |
free (buf); |
231 |
buf = 0;
|
232 |
} |
233 |
|
234 |
if (-1 != audio_fd) |
235 |
close (audio_fd); |
236 |
|
237 |
audio_fd = open ("/dev/dsp", O_WRONLY | O_NONBLOCK);
|
238 |
if (-1 == audio_fd) { |
239 |
ERRFail ("can not open /dev/dsp");
|
240 |
} |
241 |
|
242 |
_fmt = fmt_; |
243 |
_freq = rfreq; |
244 |
_nchannels = rnchannels; |
245 |
|
246 |
IOCTL ((audio_fd, SNDCTL_DSP_RESET, 1));
|
247 |
IOCTL ((audio_fd, SNDCTL_DSP_SAMPLESIZE, &_fmt)); |
248 |
IOCTL ((audio_fd, SNDCTL_DSP_CHANNELS, &_nchannels)); |
249 |
IOCTL ((audio_fd, SNDCTL_DSP_SPEED, &_freq)); |
250 |
IOCTL ((audio_fd, SNDCTL_DSP_NONBLOCK)); |
251 |
|
252 |
/* from oss.pdf:
|
253 |
|
254 |
The argument to this call is an integer encoded as 0xMMMMSSSS (in
|
255 |
hex). The 16 least significant bits determine the fragment
|
256 |
size. The size is 2^SSSS. For examp le SSSS=0008 gives fragment
|
257 |
size of 256 bytes (2^8). The minimum is 16 bytes (SSSS=4) and the
|
258 |
maximum is total_buffer_size/2. Some devices or processor
|
259 |
architectures may require larger fragments - in this case the
|
260 |
requested fragment size is automatically increased.
|
261 |
|
262 |
So ahem... 4096 = 2^12, and grand total 0x0004000c
|
263 |
*/
|
264 |
|
265 |
mmmmssss = (conf_nfrags << 16) | conf_fragsize;
|
266 |
IOCTL ((audio_fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)); |
267 |
|
268 |
linfo ("_fmt = %d, fmt = %d\n"
|
269 |
"_channels = %d, rnchannels = %d\n"
|
270 |
"_freq = %d, freq = %d\n",
|
271 |
_fmt, fmt_, |
272 |
_nchannels, rnchannels, |
273 |
_freq, rfreq); |
274 |
|
275 |
if (_fmt != fmt_) {
|
276 |
Fail ("format %d != %d", _fmt, fmt_);
|
277 |
} |
278 |
|
279 |
if (_nchannels != rnchannels) {
|
280 |
Fail ("channels %d != %d", _nchannels, rnchannels);
|
281 |
} |
282 |
|
283 |
if (_freq != rfreq) {
|
284 |
Fail ("freq %d != %d", _freq, rfreq);
|
285 |
} |
286 |
|
287 |
IOCTL ((audio_fd, SNDCTL_DSP_GETOSPACE, &abinfo)); |
288 |
|
289 |
nfrags = abinfo.fragstotal; |
290 |
fragsize = abinfo.fragsize; |
291 |
freq = _freq; |
292 |
fmt = _fmt; |
293 |
nchannels = rnchannels; |
294 |
atom <<= nchannels >> 1;
|
295 |
bufsize = nfrags * fragsize; |
296 |
|
297 |
bytes_per_second = (freq << (nchannels >> 1)) << bits16;
|
298 |
|
299 |
linfo ("bytes per second %d\n", bytes_per_second);
|
300 |
|
301 |
linfo ("fragments %d, fragstotal %d, fragsize %d, bytes %d, bufsize %d\n",
|
302 |
abinfo.fragments, |
303 |
abinfo.fragstotal, |
304 |
abinfo.fragsize, |
305 |
abinfo.bytes, |
306 |
bufsize); |
307 |
|
308 |
if (NULL == buf) { |
309 |
buf = malloc (bufsize); |
310 |
if (NULL == buf) { |
311 |
abort (); |
312 |
} |
313 |
} |
314 |
|
315 |
rpos = 0;
|
316 |
wpos = 0;
|
317 |
live = 0;
|
318 |
} |
319 |
|
320 |
int AUD_write (void *in_buf, int size) |
321 |
{ |
322 |
int to_copy, temp;
|
323 |
uint8_t *in, *out; |
324 |
|
325 |
to_copy = MIN (bufsize - live, size); |
326 |
|
327 |
temp = to_copy; |
328 |
|
329 |
in = in_buf; |
330 |
out = buf; |
331 |
|
332 |
while (temp) {
|
333 |
int copy;
|
334 |
|
335 |
copy = MIN (temp, bufsize - wpos); |
336 |
copy_fn (out + wpos, in, copy); |
337 |
|
338 |
wpos += copy; |
339 |
if (wpos == bufsize) {
|
340 |
wpos = 0;
|
341 |
} |
342 |
|
343 |
temp -= copy; |
344 |
in += copy; |
345 |
live += copy; |
346 |
} |
347 |
|
348 |
return to_copy;
|
349 |
} |
350 |
|
351 |
void AUD_run (void) |
352 |
{ |
353 |
int res;
|
354 |
int bytes;
|
355 |
struct audio_buf_info abinfo;
|
356 |
|
357 |
if (0 == live) |
358 |
return;
|
359 |
|
360 |
res = ioctl (audio_fd, SNDCTL_DSP_GETOSPACE, &abinfo); |
361 |
|
362 |
if (-1 == res) { |
363 |
int err;
|
364 |
|
365 |
err = errno; |
366 |
lwarn ("SNDCTL_DSP_GETOSPACE failed with %s\n", strerror (err));
|
367 |
} |
368 |
|
369 |
bytes = abinfo.bytes; |
370 |
bytes = MIN (live, bytes); |
371 |
#if 0
|
372 |
bytes = (bytes / fragsize) * fragsize;
|
373 |
#endif
|
374 |
|
375 |
while (bytes) {
|
376 |
int left, play, written;
|
377 |
|
378 |
left = bufsize - rpos; |
379 |
play = MIN (left, bytes); |
380 |
written = write (audio_fd, (void *) ((uint32_t) buf + rpos), play);
|
381 |
|
382 |
if (-1 == written) { |
383 |
if (EAGAIN == errno || EINTR == errno) {
|
384 |
return;
|
385 |
} |
386 |
else {
|
387 |
ERRFail ("write audio");
|
388 |
} |
389 |
} |
390 |
|
391 |
play = written; |
392 |
live -= play; |
393 |
rpos += play; |
394 |
bytes -= play; |
395 |
|
396 |
if (rpos == bufsize) {
|
397 |
rpos = 0;
|
398 |
} |
399 |
} |
400 |
} |
401 |
|
402 |
static int get_dsp_bytes (void) |
403 |
{ |
404 |
int res;
|
405 |
struct count_info info;
|
406 |
|
407 |
res = ioctl (audio_fd, SNDCTL_DSP_GETOPTR, &info); |
408 |
if (-1 == res) { |
409 |
int err;
|
410 |
|
411 |
err = errno; |
412 |
lwarn ("SNDCTL_DSP_GETOPTR failed with %s\n", strerror (err));
|
413 |
return -1; |
414 |
} |
415 |
else {
|
416 |
ldebug ("bytes %d\n", info.bytes);
|
417 |
return info.bytes;
|
418 |
} |
419 |
} |
420 |
|
421 |
void AUD_adjust_estimate (int _leftover) |
422 |
{ |
423 |
leftover = _leftover; |
424 |
} |
425 |
|
426 |
int AUD_get_free (void) |
427 |
{ |
428 |
int free, elapsed;
|
429 |
|
430 |
free = bufsize - live; |
431 |
|
432 |
if (0 == free) |
433 |
return 0; |
434 |
|
435 |
elapsed = free; |
436 |
switch (estimate) {
|
437 |
case DONT:
|
438 |
break;
|
439 |
|
440 |
case DSP:
|
441 |
{ |
442 |
static int old_bytes; |
443 |
int bytes;
|
444 |
|
445 |
bytes = get_dsp_bytes (); |
446 |
if (bytes <= 0) |
447 |
return free;
|
448 |
|
449 |
elapsed = bytes - old_bytes; |
450 |
old_bytes = bytes; |
451 |
ldebug ("dsp elapsed %d bytes\n", elapsed);
|
452 |
break;
|
453 |
} |
454 |
|
455 |
case TID:
|
456 |
{ |
457 |
static uint64_t old_ticks;
|
458 |
uint64_t ticks, delta; |
459 |
uint64_t ua_elapsed; |
460 |
uint64_t al_elapsed; |
461 |
|
462 |
ticks = cpu_get_ticks (); |
463 |
delta = ticks - old_ticks; |
464 |
old_ticks = ticks; |
465 |
|
466 |
ua_elapsed = (delta * bytes_per_second) / ticks_per_sec; |
467 |
al_elapsed = ua_elapsed & ~3ULL;
|
468 |
|
469 |
ldebug ("tid elapsed %llu bytes\n", ua_elapsed);
|
470 |
|
471 |
if (al_elapsed > (uint64_t) INT_MAX)
|
472 |
elapsed = INT_MAX; |
473 |
else
|
474 |
elapsed = al_elapsed; |
475 |
|
476 |
elapsed += leftover; |
477 |
} |
478 |
} |
479 |
|
480 |
if (elapsed > free) {
|
481 |
lwarn ("audio can not keep up elapsed %d free %d\n", elapsed, free);
|
482 |
return free;
|
483 |
} |
484 |
else {
|
485 |
return elapsed;
|
486 |
} |
487 |
} |
488 |
|
489 |
int AUD_get_live (void) |
490 |
{ |
491 |
return live;
|
492 |
} |
493 |
|
494 |
int AUD_get_buffer_size (void) |
495 |
{ |
496 |
return bufsize;
|
497 |
} |
498 |
|
499 |
void AUD_init (void) |
500 |
{ |
501 |
int fsp;
|
502 |
int _fragsize = 4096; |
503 |
|
504 |
DEREF (pab); |
505 |
|
506 |
fsp = _fragsize; |
507 |
if (0 != (fsp & (fsp - 1))) { |
508 |
Fail ("fragment size %d is not power of 2", fsp);
|
509 |
} |
510 |
|
511 |
conf_fragsize = lsbindex (fsp); |
512 |
} |