]> Git Repo - qemu.git/blame - oss.c
SDL Audio support and SB16 fixes (malc)
[qemu.git] / oss.c
CommitLineData
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
d75d9f6b
FB
26#include <stdio.h>
27#include <limits.h>
28#include <stdlib.h>
29#include <string.h>
30
31/* TODO: Graceful error handling */
32
33#if defined(_WIN32)
34#define USE_SDL_AUDIO
35#endif
36
37#define MIN(a, b) ((a)>(b)?(b):(a))
38#define MAX(a, b) ((a)<(b)?(b):(a))
39
40#define DEREF(x) (void)x
41#define dolog(...) fprintf (stderr, "audio: " __VA_ARGS__)
42#define ERRFail(...) do { \
43 int _errno = errno; \
44 fprintf (stderr, "audio: " __VA_ARGS__); \
45 fprintf (stderr, "\nsystem error: %s\n", strerror (_errno)); \
46 abort (); \
47} while (0)
48#define Fail(...) do { \
49 fprintf (stderr, "audio: " __VA_ARGS__); \
50 fprintf (stderr, "\n"); \
51 abort (); \
52} while (0)
53
54#ifdef DEBUG_AUDIO
55#define lwarn(...) fprintf (stderr, "audio: " __VA_ARGS__)
56#define linfo(...) fprintf (stderr, "audio: " __VA_ARGS__)
57#define ldebug(...) fprintf (stderr, "audio: " __VA_ARGS__)
58#else
59#define lwarn(...)
60#define linfo(...)
61#define ldebug(...)
62#endif
63
64static int get_conf_val (const char *key, int defval)
65{
66 int val = defval;
67 char *strval;
68
69 strval = getenv (key);
70 if (strval) {
71 val = atoi (strval);
72 }
73
74 return val;
75}
76
77static void copy_no_conversion (void *dst, void *src, int size)
78{
79 memcpy (dst, src, size);
80}
81
82static void copy_u16_to_s16 (void *dst, void *src, int size)
83{
84 int i;
85 uint16_t *out, *in;
86
87 out = dst;
88 in = src;
89
90 for (i = 0; i < size / 2; i++) {
91 out[i] = in[i] + 0x8000;
92 }
93}
94
95#ifdef USE_SDL_AUDIO
96#include <SDL/SDL.h>
97#include <SDL/SDL_thread.h>
98
99static struct {
100 int samples;
101} conf = {
102 .samples = 4096
103};
104
105typedef struct AudioState {
106 int freq;
107 int bits16;
108 int nchannels;
109 int rpos;
110 int wpos;
111 volatile int live;
112 volatile int exit;
113 int bytes_per_second;
114 Uint8 *buf;
115 int bufsize;
116 int leftover;
117 uint64_t old_ticks;
118 SDL_AudioSpec spec;
119 SDL_mutex *mutex;
120 SDL_sem *sem;
121 void (*copy_fn)(void *, void *, int);
122} AudioState;
123
124static AudioState sdl_audio;
125
126void AUD_run (void)
127{
128}
129
130static void own (AudioState *s)
131{
132 /* SDL_LockAudio (); */
133 if (SDL_mutexP (s->mutex))
134 dolog ("SDL_mutexP: %s\n", SDL_GetError ());
135}
136
137static void disown (AudioState *s)
138{
139 /* SDL_UnlockAudio (); */
140 if (SDL_mutexV (s->mutex))
141 dolog ("SDL_mutexV: %s\n", SDL_GetError ());
142}
143
144static void sem_wait (AudioState *s)
145{
146 if (SDL_SemWait (s->sem))
147 dolog ("SDL_SemWait: %s\n", SDL_GetError ());
148}
149
150static void sem_post (AudioState *s)
151{
152 if (SDL_SemPost (s->sem))
153 dolog ("SDL_SemPost: %s\n", SDL_GetError ());
154}
155
156static void audio_callback (void *data, Uint8 *stream, int len)
157{
158 int to_mix;
159 AudioState *s = data;
160
161 if (s->exit) return;
162 while (len) {
163 sem_wait (s);
164 if (s->exit) return;
165 own (s);
166 to_mix = MIN (len, s->live);
167 len -= to_mix;
168 /* printf ("to_mix=%d len=%d live=%d\n", to_mix, len, s->live); */
169 while (to_mix) {
170 int chunk = MIN (to_mix, s->bufsize - s->rpos);
171 /* SDL_MixAudio (stream, buf, chunk, SDL_MIX_MAXVOLUME); */
172 memcpy (stream, s->buf + s->rpos, chunk);
173
174 s->rpos += chunk;
175 s->live -= chunk;
176
177 stream += chunk;
178 to_mix -= chunk;
179
180 if (s->rpos == s->bufsize) s->rpos = 0;
181 }
182 disown (s);
183 }
184}
185
186static void sem_zero (AudioState *s)
187{
188 int res;
189
190 do {
191 res = SDL_SemTryWait (s->sem);
192 if (res < 0) {
193 dolog ("SDL_SemTryWait: %s\n", SDL_GetError ());
194 return;
195 }
196 } while (res != SDL_MUTEX_TIMEDOUT);
197}
198
199static void do_open (AudioState *s)
200{
201 int status;
202 SDL_AudioSpec obtained;
203
204 SDL_PauseAudio (1);
205 if (s->buf) {
206 s->exit = 1;
207 sem_post (s);
208 SDL_CloseAudio ();
209 s->exit = 0;
210 qemu_free (s->buf);
211 s->buf = NULL;
212 sem_zero (s);
213 }
214
215 s->bytes_per_second = (s->spec.freq << (s->spec.channels >> 1)) << s->bits16;
216 s->spec.samples = conf.samples;
217 s->spec.userdata = s;
218 s->spec.callback = audio_callback;
219
220 status = SDL_OpenAudio (&s->spec, &obtained);
221 if (status < 0) {
222 dolog ("SDL_OpenAudio: %s\n", SDL_GetError ());
223 goto exit;
224 }
225
226 if (obtained.freq != s->spec.freq ||
227 obtained.channels != s->spec.channels ||
228 obtained.format != s->spec.format) {
229 dolog ("Audio spec mismatch requested obtained\n"
230 "freq %5d %5d\n"
231 "channels %5d %5d\n"
232 "fmt %5d %5d\n",
233 s->spec.freq, obtained.freq,
234 s->spec.channels, obtained.channels,
235 s->spec.format, obtained.format
236 );
237 }
238
239 s->bufsize = obtained.size;
240 s->buf = qemu_mallocz (s->bufsize);
241 if (!s->buf) {
242 dolog ("qemu_mallocz(%d)\n", s->bufsize);
243 goto exit;
244 }
245 SDL_PauseAudio (0);
246
247exit:
248 s->rpos = 0;
249 s->wpos = 0;
250 s->live = 0;
251}
252
253int AUD_write (void *in_buf, int size)
254{
255 AudioState *s = &sdl_audio;
256 int to_copy, temp;
257 uint8_t *in, *out;
258
259 own (s);
260 to_copy = MIN (s->bufsize - s->live, size);
261
262 temp = to_copy;
263
264 in = in_buf;
265 out = s->buf;
266
267 while (temp) {
268 int copy;
269
270 copy = MIN (temp, s->bufsize - s->wpos);
271 s->copy_fn (out + s->wpos, in, copy);
272
273 s->wpos += copy;
274 if (s->wpos == s->bufsize) {
275 s->wpos = 0;
276 }
277
278 temp -= copy;
279 in += copy;
280 s->live += copy;
281 }
282
283 disown (s);
284 sem_post (s);
285 return to_copy;
286}
287
288static void maybe_open (AudioState *s, int req_freq, int req_nchannels,
289 audfmt_e req_fmt, int force_open)
290{
291 int sdl_fmt, bits16;
292
293 switch (req_fmt) {
294 case AUD_FMT_U8:
295 bits16 = 0;
296 sdl_fmt = AUDIO_U8;
297 s->copy_fn = copy_no_conversion;
298 break;
299
300 case AUD_FMT_S8:
301 fprintf (stderr, "audio: can not play 8bit signed\n");
302 return;
303
304 case AUD_FMT_S16:
305 bits16 = 1;
306 sdl_fmt = AUDIO_S16;
307 s->copy_fn = copy_no_conversion;
308 break;
309
310 case AUD_FMT_U16:
311 bits16 = 1;
312 sdl_fmt = AUDIO_S16;
313 s->copy_fn = copy_u16_to_s16;
314 break;
315
316 default:
317 abort ();
318 }
319
320 if (force_open
321 || (NULL == s->buf)
322 || (sdl_fmt != s->spec.format)
323 || (req_nchannels != s->spec.channels)
324 || (req_freq != s->spec.freq)
325 || (bits16 != s->bits16)) {
326
327 s->spec.format = sdl_fmt;
328 s->spec.channels = req_nchannels;
329 s->spec.freq = req_freq;
330 s->bits16 = bits16;
331 do_open (s);
332 }
333}
334
335void AUD_reset (int req_freq, int req_nchannels, audfmt_e req_fmt)
336{
337 AudioState *s = &sdl_audio;
338 own (s);
339 maybe_open (s, req_freq, req_nchannels, req_fmt, 0);
340 disown (s);
341}
342
343void AUD_open (int req_freq, int req_nchannels, audfmt_e req_fmt)
344{
345 AudioState *s = &sdl_audio;
346 own (s);
347 maybe_open (s, req_freq, req_nchannels, req_fmt, 1);
348 disown (s);
349}
350
351void AUD_adjust_estimate (int leftover)
352{
353 AudioState *s = &sdl_audio;
354 own (s);
355 s->leftover = leftover;
356 disown (s);
357}
358
359int AUD_get_free (void)
360{
361 int free, elapsed;
362 uint64_t ticks, delta;
363 uint64_t ua_elapsed;
364 uint64_t al_elapsed;
365 AudioState *s = &sdl_audio;
366
367 own (s);
368 free = s->bufsize - s->live;
369
370 if (0 == free) {
371 disown (s);
372 return 0;
373 }
374
375 elapsed = free;
376 ticks = qemu_get_clock(rt_clock);
377 delta = ticks - s->old_ticks;
378 s->old_ticks = ticks;
379
380 ua_elapsed = (delta * s->bytes_per_second) / 1000;
381 al_elapsed = ua_elapsed & ~3ULL;
382
383 ldebug ("tid elapsed %llu bytes\n", ua_elapsed);
384
385 if (al_elapsed > (uint64_t) INT_MAX)
386 elapsed = INT_MAX;
387 else
388 elapsed = al_elapsed;
389
390 elapsed += s->leftover;
391 disown (s);
392
393 if (elapsed > free) {
394 lwarn ("audio can not keep up elapsed %d free %d\n", elapsed, free);
395 return free;
396 }
397 else {
398 return elapsed;
399 }
400}
401
402int AUD_get_live (void)
403{
404 int live;
405 AudioState *s = &sdl_audio;
406
407 own (s);
408 live = s->live;
409 disown (s);
410 return live;
411}
412
413int AUD_get_buffer_size (void)
414{
415 int bufsize;
416 AudioState *s = &sdl_audio;
417
418 own (s);
419 bufsize = s->bufsize;
420 disown (s);
421 return bufsize;
422}
423
424#define QC_SDL_NSAMPLES "QEMU_SDL_NSAMPLES"
425
426static void cleanup (void)
427{
428 AudioState *s = &sdl_audio;
429 own (s);
430 s->exit = 1;
431 sem_post (s);
432 disown (s);
433}
434
435void AUD_init (void)
436{
437 AudioState *s = &sdl_audio;
438
439 atexit (cleanup);
440 SDL_InitSubSystem (SDL_INIT_AUDIO);
441 s->mutex = SDL_CreateMutex ();
442 if (!s->mutex) {
443 dolog ("SDL_CreateMutex: %s\n", SDL_GetError ());
444 return;
445 }
446
447 s->sem = SDL_CreateSemaphore (0);
448 if (!s->sem) {
449 dolog ("SDL_CreateSemaphore: %s\n", SDL_GetError ());
450 return;
451 }
452
453 conf.samples = get_conf_val (QC_SDL_NSAMPLES, conf.samples);
454}
455
456#elif !defined(_WIN32) && !defined(__APPLE__)
457
27503323
FB
458#include <fcntl.h>
459#include <errno.h>
27503323 460#include <unistd.h>
d329a6fb 461#include <sys/mman.h>
27503323
FB
462#include <sys/types.h>
463#include <sys/ioctl.h>
464#include <sys/soundcard.h>
465
27503323
FB
466/* http://www.df.lth.se/~john_e/gems/gem002d.html */
467/* http://www.multi-platforms.com/Tips/PopCount.htm */
468static inline uint32_t popcount (uint32_t u)
469{
470 u = ((u&0x55555555) + ((u>>1)&0x55555555));
471 u = ((u&0x33333333) + ((u>>2)&0x33333333));
472 u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
473 u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
474 u = ( u&0x0000ffff) + (u>>16);
475 return u;
476}
477
478static inline uint32_t lsbindex (uint32_t u)
479{
480 return popcount ((u&-u)-1);
481}
482
27503323
FB
483#define IOCTL(args) do { \
484 int ret = ioctl args; \
485 if (-1 == ret) { \
486 ERRFail (#args); \
487 } \
488 ldebug ("ioctl " #args " = %d\n", ret); \
489} while (0)
490
d75d9f6b 491typedef struct AudioState {
d329a6fb
FB
492 int fd;
493 int freq;
494 int bits16;
495 int nchannels;
496 int rpos;
497 int wpos;
498 int live;
499 int oss_fmt;
500 int bytes_per_second;
501 int is_mapped;
502 void *buf;
503 int bufsize;
504 int nfrags;
505 int fragsize;
506 int old_optr;
507 int leftover;
508 uint64_t old_ticks;
509 void (*copy_fn)(void *, void *, int);
d75d9f6b
FB
510} AudioState;
511
512static AudioState oss_audio = { .fd = -1 };
d329a6fb
FB
513
514static struct {
515 int try_mmap;
516 int nfrags;
517 int fragsize;
518} conf = {
519 .try_mmap = 0,
520 .nfrags = 4,
521 .fragsize = 4096
522};
523
524static enum {DONT, DSP, TID} est = DONT;
27503323 525
d75d9f6b 526static void pab (AudioState *s, struct audio_buf_info *abinfo)
27503323
FB
527{
528 DEREF (abinfo);
529
530 ldebug ("fragments %d, fragstotal %d, fragsize %d, bytes %d\n"
531 "rpos %d, wpos %d, live %d\n",
532 abinfo->fragments,
533 abinfo->fragstotal,
534 abinfo->fragsize,
535 abinfo->bytes,
d75d9f6b 536 s->rpos, s->wpos, s->live);
27503323
FB
537}
538
d75d9f6b 539static void do_open (AudioState *s)
27503323 540{
d329a6fb
FB
541 int mmmmssss;
542 audio_buf_info abinfo;
543 int fmt, freq, nchannels;
27503323 544
d75d9f6b
FB
545 if (s->buf) {
546 if (s->is_mapped) {
547 if (-1 == munmap (s->buf, s->bufsize)) {
d329a6fb 548 ERRFail ("failed to unmap audio buffer %p %d",
d75d9f6b
FB
549 s->buf, s->bufsize);
550 }
d329a6fb 551 }
d75d9f6b
FB
552 else {
553 qemu_free (s->buf);
554 }
555 s->buf = NULL;
27503323
FB
556 }
557
d75d9f6b
FB
558 if (-1 != s->fd)
559 close (s->fd);
27503323 560
d75d9f6b
FB
561 s->fd = open ("/dev/dsp", O_RDWR | O_NONBLOCK);
562 if (-1 == s->fd) {
d329a6fb
FB
563 ERRFail ("can not open /dev/dsp");
564 }
27503323 565
d75d9f6b
FB
566 fmt = s->oss_fmt;
567 freq = s->freq;
568 nchannels = s->nchannels;
d329a6fb 569
d75d9f6b
FB
570 IOCTL ((s->fd, SNDCTL_DSP_RESET, 1));
571 IOCTL ((s->fd, SNDCTL_DSP_SAMPLESIZE, &fmt));
572 IOCTL ((s->fd, SNDCTL_DSP_CHANNELS, &nchannels));
573 IOCTL ((s->fd, SNDCTL_DSP_SPEED, &freq));
574 IOCTL ((s->fd, SNDCTL_DSP_NONBLOCK));
d329a6fb
FB
575
576 mmmmssss = (conf.nfrags << 16) | conf.fragsize;
d75d9f6b 577 IOCTL ((s->fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss));
d329a6fb 578
d75d9f6b
FB
579 if ((s->oss_fmt != fmt)
580 || (s->nchannels != nchannels)
581 || (s->freq != freq)) {
d329a6fb
FB
582 Fail ("failed to set audio parameters\n"
583 "parameter | requested value | obtained value\n"
584 "format | %10d | %10d\n"
585 "channels | %10d | %10d\n"
586 "frequency | %10d | %10d\n",
d75d9f6b
FB
587 s->oss_fmt, fmt,
588 s->nchannels, nchannels,
589 s->freq, freq);
d329a6fb 590 }
27503323 591
d75d9f6b 592 IOCTL ((s->fd, SNDCTL_DSP_GETOSPACE, &abinfo));
27503323 593
d75d9f6b
FB
594 s->nfrags = abinfo.fragstotal;
595 s->fragsize = abinfo.fragsize;
596 s->bufsize = s->nfrags * s->fragsize;
597 s->old_optr = 0;
27503323 598
d75d9f6b 599 s->bytes_per_second = (freq << (nchannels >> 1)) << s->bits16;
d329a6fb 600
d75d9f6b 601 linfo ("bytes per second %d\n", s->bytes_per_second);
d329a6fb
FB
602
603 linfo ("fragments %d, fragstotal %d, fragsize %d, bytes %d, bufsize %d\n",
604 abinfo.fragments,
605 abinfo.fragstotal,
606 abinfo.fragsize,
607 abinfo.bytes,
d75d9f6b 608 s->bufsize);
d329a6fb 609
d75d9f6b
FB
610 s->buf = MAP_FAILED;
611 s->is_mapped = 0;
d329a6fb
FB
612
613 if (conf.try_mmap) {
d75d9f6b
FB
614 s->buf = mmap (NULL, s->bufsize, PROT_WRITE, MAP_SHARED, s->fd, 0);
615 if (MAP_FAILED == s->buf) {
d329a6fb
FB
616 int err;
617
618 err = errno;
d75d9f6b 619 dolog ("failed to mmap audio, size %d, fd %d\n"
d329a6fb 620 "syserr: %s\n",
d75d9f6b 621 s->bufsize, s->fd, strerror (err));
d329a6fb 622 }
27503323 623 else {
d329a6fb 624 est = TID;
d75d9f6b 625 s->is_mapped = 1;
d329a6fb
FB
626 }
627 }
628
d75d9f6b 629 if (MAP_FAILED == s->buf) {
d329a6fb 630 est = TID;
d75d9f6b
FB
631 s->buf = qemu_mallocz (s->bufsize);
632 if (!s->buf) {
633 ERRFail ("audio buf malloc failed, size %d", s->bufsize);
d329a6fb
FB
634 }
635 }
636
d75d9f6b
FB
637 s->rpos = 0;
638 s->wpos = 0;
639 s->live = 0;
d329a6fb 640
d75d9f6b 641 if (s->is_mapped) {
d329a6fb
FB
642 int trig;
643
644 trig = 0;
d75d9f6b 645 IOCTL ((s->fd, SNDCTL_DSP_SETTRIGGER, &trig));
d329a6fb 646 trig = PCM_ENABLE_OUTPUT;
d75d9f6b 647 IOCTL ((s->fd, SNDCTL_DSP_SETTRIGGER, &trig));
27503323
FB
648 }
649}
650
d75d9f6b 651static void maybe_open (AudioState *s, int req_freq, int req_nchannels,
d329a6fb 652 audfmt_e req_fmt, int force_open)
27503323 653{
d329a6fb 654 int oss_fmt, bits16;
27503323 655
d329a6fb 656 switch (req_fmt) {
27503323
FB
657 case AUD_FMT_U8:
658 bits16 = 0;
d329a6fb 659 oss_fmt = AFMT_U8;
d75d9f6b 660 s->copy_fn = copy_no_conversion;
27503323
FB
661 break;
662
663 case AUD_FMT_S8:
664 Fail ("can not play 8bit signed");
665
666 case AUD_FMT_S16:
667 bits16 = 1;
d329a6fb 668 oss_fmt = AFMT_S16_LE;
d75d9f6b 669 s->copy_fn = copy_no_conversion;
27503323
FB
670 break;
671
672 case AUD_FMT_U16:
673 bits16 = 1;
d329a6fb 674 oss_fmt = AFMT_S16_LE;
d75d9f6b 675 s->copy_fn = copy_u16_to_s16;
27503323
FB
676 break;
677
678 default:
679 abort ();
680 }
681
d329a6fb 682 if (force_open
d75d9f6b
FB
683 || (-1 == s->fd)
684 || (oss_fmt != s->oss_fmt)
685 || (req_nchannels != s->nchannels)
686 || (req_freq != s->freq)
687 || (bits16 != s->bits16)) {
688 s->oss_fmt = oss_fmt;
689 s->nchannels = req_nchannels;
690 s->freq = req_freq;
691 s->bits16 = bits16;
692 do_open (s);
27503323 693 }
d329a6fb 694}
27503323 695
d329a6fb
FB
696void AUD_reset (int req_freq, int req_nchannels, audfmt_e req_fmt)
697{
d75d9f6b
FB
698 AudioState *s = &oss_audio;
699 maybe_open (s, req_freq, req_nchannels, req_fmt, 0);
d329a6fb 700}
27503323 701
d329a6fb
FB
702void AUD_open (int req_freq, int req_nchannels, audfmt_e req_fmt)
703{
d75d9f6b
FB
704 AudioState *s = &oss_audio;
705 maybe_open (s, req_freq, req_nchannels, req_fmt, 1);
27503323
FB
706}
707
708int AUD_write (void *in_buf, int size)
709{
d75d9f6b 710 AudioState *s = &oss_audio;
27503323
FB
711 int to_copy, temp;
712 uint8_t *in, *out;
713
d75d9f6b 714 to_copy = MIN (s->bufsize - s->live, size);
27503323
FB
715
716 temp = to_copy;
717
718 in = in_buf;
d75d9f6b 719 out = s->buf;
27503323
FB
720
721 while (temp) {
722 int copy;
723
d75d9f6b
FB
724 copy = MIN (temp, s->bufsize - s->wpos);
725 s->copy_fn (out + s->wpos, in, copy);
27503323 726
d75d9f6b
FB
727 s->wpos += copy;
728 if (s->wpos == s->bufsize) {
729 s->wpos = 0;
27503323
FB
730 }
731
732 temp -= copy;
733 in += copy;
d75d9f6b 734 s->live += copy;
27503323
FB
735 }
736
737 return to_copy;
738}
739
740void AUD_run (void)
741{
742 int res;
743 int bytes;
744 struct audio_buf_info abinfo;
d75d9f6b 745 AudioState *s = &oss_audio;
27503323 746
d75d9f6b 747 if (0 == s->live)
27503323
FB
748 return;
749
d75d9f6b 750 if (s->is_mapped) {
d329a6fb
FB
751 count_info info;
752
d75d9f6b
FB
753 res = ioctl (s->fd, SNDCTL_DSP_GETOPTR, &info);
754 if (res < 0) {
d329a6fb
FB
755 int err;
756
757 err = errno;
758 lwarn ("SNDCTL_DSP_GETOPTR failed with %s\n", strerror (err));
759 return;
760 }
761
d75d9f6b
FB
762 if (info.ptr > s->old_optr) {
763 bytes = info.ptr - s->old_optr;
d329a6fb
FB
764 }
765 else {
d75d9f6b 766 bytes = s->bufsize + info.ptr - s->old_optr;
d329a6fb
FB
767 }
768
d75d9f6b
FB
769 s->old_optr = info.ptr;
770 s->live -= bytes;
d329a6fb
FB
771 return;
772 }
773
d75d9f6b 774 res = ioctl (s->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
27503323 775
d75d9f6b 776 if (res < 0) {
27503323
FB
777 int err;
778
779 err = errno;
780 lwarn ("SNDCTL_DSP_GETOSPACE failed with %s\n", strerror (err));
d75d9f6b 781 return;
27503323
FB
782 }
783
784 bytes = abinfo.bytes;
d75d9f6b 785 bytes = MIN (s->live, bytes);
27503323
FB
786#if 0
787 bytes = (bytes / fragsize) * fragsize;
788#endif
789
790 while (bytes) {
791 int left, play, written;
792
d75d9f6b 793 left = s->bufsize - s->rpos;
27503323 794 play = MIN (left, bytes);
d75d9f6b 795 written = write (s->fd, (uint8_t *)s->buf + s->rpos, play);
27503323
FB
796
797 if (-1 == written) {
798 if (EAGAIN == errno || EINTR == errno) {
799 return;
800 }
801 else {
802 ERRFail ("write audio");
803 }
804 }
805
806 play = written;
d75d9f6b
FB
807 s->live -= play;
808 s->rpos += play;
27503323
FB
809 bytes -= play;
810
d75d9f6b
FB
811 if (s->rpos == s->bufsize) {
812 s->rpos = 0;
27503323
FB
813 }
814 }
815}
816
817static int get_dsp_bytes (void)
818{
819 int res;
820 struct count_info info;
d75d9f6b 821 AudioState *s = &oss_audio;
27503323 822
d75d9f6b 823 res = ioctl (s->fd, SNDCTL_DSP_GETOPTR, &info);
27503323
FB
824 if (-1 == res) {
825 int err;
826
827 err = errno;
828 lwarn ("SNDCTL_DSP_GETOPTR failed with %s\n", strerror (err));
829 return -1;
830 }
831 else {
832 ldebug ("bytes %d\n", info.bytes);
833 return info.bytes;
834 }
835}
836
d329a6fb 837void AUD_adjust_estimate (int leftover)
27503323 838{
d75d9f6b
FB
839 AudioState *s = &oss_audio;
840 s->leftover = leftover;
27503323
FB
841}
842
843int AUD_get_free (void)
844{
845 int free, elapsed;
d75d9f6b 846 AudioState *s = &oss_audio;
27503323 847
d75d9f6b 848 free = s->bufsize - s->live;
27503323 849
d75d9f6b 850 if (free <= 0)
27503323
FB
851 return 0;
852
853 elapsed = free;
d329a6fb 854 switch (est) {
27503323
FB
855 case DONT:
856 break;
857
858 case DSP:
859 {
860 static int old_bytes;
861 int bytes;
862
863 bytes = get_dsp_bytes ();
864 if (bytes <= 0)
865 return free;
866
867 elapsed = bytes - old_bytes;
868 old_bytes = bytes;
869 ldebug ("dsp elapsed %d bytes\n", elapsed);
870 break;
871 }
872
873 case TID:
874 {
27503323
FB
875 uint64_t ticks, delta;
876 uint64_t ua_elapsed;
877 uint64_t al_elapsed;
878
8a7ddc38 879 ticks = qemu_get_clock(rt_clock);
d75d9f6b
FB
880 delta = ticks - s->old_ticks;
881 s->old_ticks = ticks;
27503323 882
d75d9f6b 883 ua_elapsed = (delta * s->bytes_per_second) / 1000;
27503323
FB
884 al_elapsed = ua_elapsed & ~3ULL;
885
886 ldebug ("tid elapsed %llu bytes\n", ua_elapsed);
887
888 if (al_elapsed > (uint64_t) INT_MAX)
889 elapsed = INT_MAX;
890 else
891 elapsed = al_elapsed;
892
d75d9f6b 893 elapsed += s->leftover;
27503323
FB
894 }
895 }
896
897 if (elapsed > free) {
898 lwarn ("audio can not keep up elapsed %d free %d\n", elapsed, free);
899 return free;
900 }
901 else {
902 return elapsed;
903 }
904}
905
906int AUD_get_live (void)
907{
d75d9f6b
FB
908 AudioState *s = &oss_audio;
909 return s->live;
27503323
FB
910}
911
912int AUD_get_buffer_size (void)
913{
d75d9f6b
FB
914 AudioState *s = &oss_audio;
915 return s->bufsize;
d329a6fb
FB
916}
917
918#define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE"
919#define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS"
920#define QC_OSS_MMAP "QEMU_OSS_MMAP"
921
27503323
FB
922void AUD_init (void)
923{
924 int fsp;
27503323
FB
925
926 DEREF (pab);
927
d329a6fb
FB
928 conf.fragsize = get_conf_val (QC_OSS_FRAGSIZE, conf.fragsize);
929 conf.nfrags = get_conf_val (QC_OSS_NFRAGS, conf.nfrags);
930 conf.try_mmap = get_conf_val (QC_OSS_MMAP, conf.try_mmap);
931
932 fsp = conf.fragsize;
27503323
FB
933 if (0 != (fsp & (fsp - 1))) {
934 Fail ("fragment size %d is not power of 2", fsp);
935 }
936
d329a6fb 937 conf.fragsize = lsbindex (fsp);
27503323 938}
67b915a5
FB
939
940#else
941
942void AUD_run (void)
943{
944}
945
946int AUD_write (void *in_buf, int size)
947{
948 return 0;
949}
950
951void AUD_reset (int rfreq, int rnchannels, audfmt_e rfmt)
952{
953}
954
955void AUD_adjust_estimate (int _leftover)
956{
957}
958
959int AUD_get_free (void)
960{
961 return 0;
962}
963
964int AUD_get_live (void)
965{
966 return 0;
967}
968
969int AUD_get_buffer_size (void)
970{
971 return 0;
972}
973
974void AUD_init (void)
975{
976}
977
978#endif
This page took 0.169353 seconds and 4 git commands to generate.