]>
Commit | Line | Data |
---|---|---|
27503323 FB |
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 | */ | |
67b915a5 FB |
24 | #include "vl.h" |
25 | ||
26 | #ifndef _WIN32 | |
27503323 FB |
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 | ||
27503323 FB |
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 | ||
8a7ddc38 | 464 | ticks = qemu_get_clock(rt_clock); |
27503323 FB |
465 | delta = ticks - old_ticks; |
466 | old_ticks = ticks; | |
467 | ||
8a7ddc38 | 468 | ua_elapsed = (delta * bytes_per_second) / 1000; |
27503323 FB |
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 | } | |
67b915a5 FB |
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 |