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