Commit d329a6fb2213e53008a9b1cd186fe2ff258fa272
1 parent
7ebb5e41
audip fixes (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@911 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
275 additions
and
198 deletions
hw/sb16.c
| ... | ... | @@ -26,7 +26,10 @@ |
| 26 | 26 | #define MIN(a, b) ((a)>(b)?(b):(a)) |
| 27 | 27 | #define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0]))) |
| 28 | 28 | |
| 29 | -#define log(...) fprintf (stderr, "sb16: " __VA_ARGS__) | |
| 29 | +#define log(...) do { \ | |
| 30 | + fprintf (stderr, "sb16: " __VA_ARGS__); \ | |
| 31 | + fputc ('\n', stderr); \ | |
| 32 | +} while (0) | |
| 30 | 33 | |
| 31 | 34 | /* #define DEBUG_SB16 */ |
| 32 | 35 | #ifdef DEBUG_SB16 |
| ... | ... | @@ -44,6 +47,8 @@ |
| 44 | 47 | #define IO_WRITE_PROTO(name) \ |
| 45 | 48 | void name (void *opaque, uint32_t nport, uint32_t val) |
| 46 | 49 | |
| 50 | +static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; | |
| 51 | + | |
| 47 | 52 | static struct { |
| 48 | 53 | int ver_lo; |
| 49 | 54 | int ver_hi; |
| ... | ... | @@ -76,7 +81,7 @@ typedef struct SB16State { |
| 76 | 81 | int v2x6; |
| 77 | 82 | |
| 78 | 83 | uint8_t in_data[10]; |
| 79 | - uint8_t out_data[10]; | |
| 84 | + uint8_t out_data[50]; | |
| 80 | 85 | |
| 81 | 86 | int left_till_irq; |
| 82 | 87 | |
| ... | ... | @@ -223,6 +228,20 @@ static void command (SB16State *dsp, uint8_t cmd) |
| 223 | 228 | /* IMS uses those when probing for sound devices */ |
| 224 | 229 | return; |
| 225 | 230 | |
| 231 | + case 0x04: | |
| 232 | + dsp->needed_bytes = 1; | |
| 233 | + break; | |
| 234 | + | |
| 235 | + case 0x05: | |
| 236 | + case 0x0e: | |
| 237 | + dsp->needed_bytes = 2; | |
| 238 | + break; | |
| 239 | + | |
| 240 | + case 0x0f: | |
| 241 | + dsp->needed_bytes = 1; | |
| 242 | + dsp_out_data (dsp, 0); | |
| 243 | + break; | |
| 244 | + | |
| 226 | 245 | case 0x10: |
| 227 | 246 | dsp->needed_bytes = 1; |
| 228 | 247 | break; |
| ... | ... | @@ -274,8 +293,8 @@ static void command (SB16State *dsp, uint8_t cmd) |
| 274 | 293 | uint8_t d0; |
| 275 | 294 | |
| 276 | 295 | d0 = 4; |
| 277 | - if (dsp->fmt_signed) d0 |= 16; | |
| 278 | - if (dsp->fmt_stereo) d0 |= 32; | |
| 296 | + /* if (dsp->fmt_signed) d0 |= 16; */ | |
| 297 | + /* if (dsp->fmt_stereo) d0 |= 32; */ | |
| 279 | 298 | dma_cmd (cmd == 0x90 ? 0xc4 : 0xc0, d0, -1); |
| 280 | 299 | cmd = -1; |
| 281 | 300 | break; |
| ... | ... | @@ -324,6 +343,14 @@ static void command (SB16State *dsp, uint8_t cmd) |
| 324 | 343 | dsp_out_data(dsp, sb.ver_hi); |
| 325 | 344 | return; |
| 326 | 345 | |
| 346 | + case 0xe3: | |
| 347 | + { | |
| 348 | + int i; | |
| 349 | + for (i = sizeof (e3) - 1; i >= 0; --i) | |
| 350 | + dsp_out_data (dsp, e3[i]); | |
| 351 | + return; | |
| 352 | + } | |
| 353 | + | |
| 327 | 354 | case 0xf2: |
| 328 | 355 | dsp_out_data(dsp, 0xaa); |
| 329 | 356 | dsp->mixer_regs[0x82] |= dsp->mixer_regs[0x80]; |
| ... | ... | @@ -360,6 +387,11 @@ static void complete (SB16State *dsp) |
| 360 | 387 | } |
| 361 | 388 | else { |
| 362 | 389 | switch (dsp->cmd) { |
| 390 | + case 0x05: | |
| 391 | + case 0x04: | |
| 392 | + case 0x0e: | |
| 393 | + case 0x0f: | |
| 394 | + break; | |
| 363 | 395 | |
| 364 | 396 | case 0x10: |
| 365 | 397 | break; |
| ... | ... | @@ -425,8 +457,10 @@ static IO_WRITE_PROTO (dsp_write) |
| 425 | 457 | |
| 426 | 458 | iport = nport - sb.port; |
| 427 | 459 | |
| 460 | + ldebug ("write %#x %#x\n", nport, iport); | |
| 428 | 461 | switch (iport) { |
| 429 | 462 | case 0x6: |
| 463 | + control (0); | |
| 430 | 464 | if (0 == val) |
| 431 | 465 | dsp->v2x6 = 0; |
| 432 | 466 | else if ((1 == val) && (0 == dsp->v2x6)) { |
| ... | ... | @@ -477,7 +511,7 @@ static IO_READ_PROTO (dsp_read) |
| 477 | 511 | if (dsp->out_data_len) { |
| 478 | 512 | retval = dsp->out_data[--dsp->out_data_len]; |
| 479 | 513 | } else { |
| 480 | - log("empty output buffer\n"); | |
| 514 | + log("empty output buffer"); | |
| 481 | 515 | goto error; |
| 482 | 516 | } |
| 483 | 517 | break; |
| ... | ... | @@ -487,7 +521,7 @@ static IO_READ_PROTO (dsp_read) |
| 487 | 521 | break; |
| 488 | 522 | |
| 489 | 523 | case 0xd: /* timer interrupt clear */ |
| 490 | - log("timer interrupt clear\n"); | |
| 524 | + log("timer interrupt clear"); | |
| 491 | 525 | goto error; |
| 492 | 526 | |
| 493 | 527 | case 0xe: /* data available status | irq 8 ack */ |
| ... | ... | @@ -669,7 +703,7 @@ static int magic_of_irq (int irq) |
| 669 | 703 | case 10: |
| 670 | 704 | return 8; |
| 671 | 705 | default: |
| 672 | - log ("bad irq %d\n", irq); | |
| 706 | + log ("bad irq %d", irq); | |
| 673 | 707 | return 2; |
| 674 | 708 | } |
| 675 | 709 | } |
| ... | ... | @@ -687,7 +721,7 @@ static int irq_of_magic (int magic) |
| 687 | 721 | case 8: |
| 688 | 722 | return 10; |
| 689 | 723 | default: |
| 690 | - log ("bad irq magic %d\n", magic); | |
| 724 | + log ("bad irq magic %d", magic); | |
| 691 | 725 | return 2; |
| 692 | 726 | } |
| 693 | 727 | } | ... | ... |
oss.c
| ... | ... | @@ -24,6 +24,7 @@ |
| 24 | 24 | #include "vl.h" |
| 25 | 25 | |
| 26 | 26 | #ifndef _WIN32 |
| 27 | +#include <ctype.h> | |
| 27 | 28 | #include <fcntl.h> |
| 28 | 29 | #include <errno.h> |
| 29 | 30 | #include <stdio.h> |
| ... | ... | @@ -32,6 +33,7 @@ |
| 32 | 33 | #include <stdlib.h> |
| 33 | 34 | #include <limits.h> |
| 34 | 35 | #include <inttypes.h> |
| 36 | +#include <sys/mman.h> | |
| 35 | 37 | #include <sys/types.h> |
| 36 | 38 | #include <sys/ioctl.h> |
| 37 | 39 | #include <sys/soundcard.h> |
| ... | ... | @@ -90,25 +92,38 @@ static inline uint32_t lsbindex (uint32_t u) |
| 90 | 92 | ldebug ("ioctl " #args " = %d\n", ret); \ |
| 91 | 93 | } while (0) |
| 92 | 94 | |
| 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); | |
| 95 | +static struct { | |
| 96 | + int fd; | |
| 97 | + int freq; | |
| 98 | + int bits16; | |
| 99 | + int nchannels; | |
| 100 | + int rpos; | |
| 101 | + int wpos; | |
| 102 | + int live; | |
| 103 | + int oss_fmt; | |
| 104 | + int bytes_per_second; | |
| 105 | + int is_mapped; | |
| 106 | + void *buf; | |
| 107 | + int bufsize; | |
| 108 | + int nfrags; | |
| 109 | + int fragsize; | |
| 110 | + int old_optr; | |
| 111 | + int leftover; | |
| 112 | + uint64_t old_ticks; | |
| 113 | + void (*copy_fn)(void *, void *, int); | |
| 114 | +} oss = { .fd = -1 }; | |
| 115 | + | |
| 116 | +static struct { | |
| 117 | + int try_mmap; | |
| 118 | + int nfrags; | |
| 119 | + int fragsize; | |
| 120 | +} conf = { | |
| 121 | + .try_mmap = 0, | |
| 122 | + .nfrags = 4, | |
| 123 | + .fragsize = 4096 | |
| 124 | +}; | |
| 125 | + | |
| 126 | +static enum {DONT, DSP, TID} est = DONT; | |
| 112 | 127 | |
| 113 | 128 | static void copy_no_conversion (void *dst, void *src, int size) |
| 114 | 129 | { |
| ... | ... | @@ -141,70 +156,124 @@ static void pab (struct audio_buf_info *abinfo) |
| 141 | 156 | rpos, wpos, live); |
| 142 | 157 | } |
| 143 | 158 | |
| 144 | -void AUD_reset (int rfreq, int rnchannels, audfmt_e rfmt) | |
| 159 | +static void do_open () | |
| 145 | 160 | { |
| 146 | - int fmt_; | |
| 147 | - int bits16; | |
| 161 | + int mmmmssss; | |
| 162 | + audio_buf_info abinfo; | |
| 163 | + int fmt, freq, nchannels; | |
| 148 | 164 | |
| 149 | - if (-1 == audio_fd) { | |
| 150 | - AUD_open (rfreq, rnchannels, rfmt); | |
| 151 | - return; | |
| 165 | + if (oss.buf) { | |
| 166 | + if (-1 == munmap (oss.buf, oss.bufsize)) { | |
| 167 | + ERRFail ("failed to unmap audio buffer %p %d", | |
| 168 | + oss.buf, oss.bufsize); | |
| 169 | + } | |
| 170 | + oss.buf = NULL; | |
| 152 | 171 | } |
| 153 | 172 | |
| 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; | |
| 173 | + if (-1 != oss.fd) | |
| 174 | + close (oss.fd); | |
| 161 | 175 | |
| 162 | - case AUD_FMT_S8: | |
| 163 | - Fail ("can not play 8bit signed"); | |
| 176 | + oss.fd = open ("/dev/dsp", O_RDWR | O_NONBLOCK); | |
| 177 | + if (-1 == oss.fd) { | |
| 178 | + ERRFail ("can not open /dev/dsp"); | |
| 179 | + } | |
| 164 | 180 | |
| 165 | - case AUD_FMT_S16: | |
| 166 | - bits16 = 1; | |
| 167 | - fmt_ = AFMT_S16_LE; | |
| 168 | - copy_fn = copy_no_conversion; | |
| 169 | - atom = 2; | |
| 170 | - break; | |
| 181 | + fmt = oss.oss_fmt; | |
| 182 | + freq = oss.freq; | |
| 183 | + nchannels = oss.nchannels; | |
| 184 | + | |
| 185 | + IOCTL ((oss.fd, SNDCTL_DSP_RESET, 1)); | |
| 186 | + IOCTL ((oss.fd, SNDCTL_DSP_SAMPLESIZE, &fmt)); | |
| 187 | + IOCTL ((oss.fd, SNDCTL_DSP_CHANNELS, &nchannels)); | |
| 188 | + IOCTL ((oss.fd, SNDCTL_DSP_SPEED, &freq)); | |
| 189 | + IOCTL ((oss.fd, SNDCTL_DSP_NONBLOCK)); | |
| 190 | + | |
| 191 | + mmmmssss = (conf.nfrags << 16) | conf.fragsize; | |
| 192 | + IOCTL ((oss.fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)); | |
| 193 | + | |
| 194 | + if ((oss.oss_fmt != fmt) | |
| 195 | + || (oss.nchannels != nchannels) | |
| 196 | + || (oss.freq != freq)) { | |
| 197 | + Fail ("failed to set audio parameters\n" | |
| 198 | + "parameter | requested value | obtained value\n" | |
| 199 | + "format | %10d | %10d\n" | |
| 200 | + "channels | %10d | %10d\n" | |
| 201 | + "frequency | %10d | %10d\n", | |
| 202 | + oss.oss_fmt, fmt, | |
| 203 | + oss.nchannels, nchannels, | |
| 204 | + oss.freq, freq); | |
| 205 | + } | |
| 171 | 206 | |
| 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; | |
| 207 | + IOCTL ((oss.fd, SNDCTL_DSP_GETOSPACE, &abinfo)); | |
| 178 | 208 | |
| 179 | - default: | |
| 180 | - abort (); | |
| 181 | - } | |
| 209 | + oss.nfrags = abinfo.fragstotal; | |
| 210 | + oss.fragsize = abinfo.fragsize; | |
| 211 | + oss.bufsize = oss.nfrags * oss.fragsize; | |
| 212 | + oss.old_optr = 0; | |
| 182 | 213 | |
| 183 | - if ((fmt_ == fmt) && (bits16 + 1 == nchannels) && (rfreq == freq)) | |
| 184 | - return; | |
| 214 | + oss.bytes_per_second = (freq << (nchannels >> 1)) << oss.bits16; | |
| 215 | + | |
| 216 | + linfo ("bytes per second %d\n", oss.bytes_per_second); | |
| 217 | + | |
| 218 | + linfo ("fragments %d, fragstotal %d, fragsize %d, bytes %d, bufsize %d\n", | |
| 219 | + abinfo.fragments, | |
| 220 | + abinfo.fragstotal, | |
| 221 | + abinfo.fragsize, | |
| 222 | + abinfo.bytes, | |
| 223 | + oss.bufsize); | |
| 224 | + | |
| 225 | + oss.buf = MAP_FAILED; | |
| 226 | + oss.is_mapped = 0; | |
| 227 | + | |
| 228 | + if (conf.try_mmap) { | |
| 229 | + oss.buf = mmap (NULL, oss.bufsize, PROT_WRITE, MAP_SHARED, oss.fd, 0); | |
| 230 | + if (MAP_FAILED == oss.buf) { | |
| 231 | + int err; | |
| 232 | + | |
| 233 | + err = errno; | |
| 234 | + log ("failed to mmap audio, size %d, fd %d\n" | |
| 235 | + "syserr: %s\n", | |
| 236 | + oss.bufsize, oss.fd, strerror (err)); | |
| 237 | + } | |
| 185 | 238 | else { |
| 186 | - AUD_open (rfreq, rnchannels, rfmt); | |
| 239 | + est = TID; | |
| 240 | + oss.is_mapped = 1; | |
| 241 | + } | |
| 242 | + } | |
| 243 | + | |
| 244 | + if (MAP_FAILED == oss.buf) { | |
| 245 | + est = TID; | |
| 246 | + oss.buf = mmap (NULL, oss.bufsize, PROT_READ | PROT_WRITE, | |
| 247 | + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); | |
| 248 | + if (MAP_FAILED == oss.buf) { | |
| 249 | + ERRFail ("mmap audio buf, size %d", oss.bufsize); | |
| 250 | + } | |
| 251 | + } | |
| 252 | + | |
| 253 | + oss.rpos = 0; | |
| 254 | + oss.wpos = 0; | |
| 255 | + oss.live = 0; | |
| 256 | + | |
| 257 | + if (oss.is_mapped) { | |
| 258 | + int trig; | |
| 259 | + | |
| 260 | + trig = 0; | |
| 261 | + IOCTL ((oss.fd, SNDCTL_DSP_SETTRIGGER, &trig)); | |
| 262 | + trig = PCM_ENABLE_OUTPUT; | |
| 263 | + IOCTL ((oss.fd, SNDCTL_DSP_SETTRIGGER, &trig)); | |
| 187 | 264 | } |
| 188 | 265 | } |
| 189 | 266 | |
| 190 | -void AUD_open (int rfreq, int rnchannels, audfmt_e rfmt) | |
| 267 | +static void maybe_open (int req_freq, int req_nchannels, | |
| 268 | + audfmt_e req_fmt, int force_open) | |
| 191 | 269 | { |
| 192 | - int fmt_; | |
| 193 | - int mmmmssss; | |
| 194 | - struct audio_buf_info abinfo; | |
| 195 | - int _fmt; | |
| 196 | - int _freq; | |
| 197 | - int _nchannels; | |
| 198 | - int bits16; | |
| 270 | + int oss_fmt, bits16; | |
| 199 | 271 | |
| 200 | - bits16 = 0; | |
| 201 | - | |
| 202 | - switch (rfmt) { | |
| 272 | + switch (req_fmt) { | |
| 203 | 273 | case AUD_FMT_U8: |
| 204 | 274 | bits16 = 0; |
| 205 | - fmt_ = AFMT_U8; | |
| 206 | - copy_fn = copy_no_conversion; | |
| 207 | - atom = 1; | |
| 275 | + oss_fmt = AFMT_U8; | |
| 276 | + oss.copy_fn = copy_no_conversion; | |
| 208 | 277 | break; |
| 209 | 278 | |
| 210 | 279 | case AUD_FMT_S8: |
| ... | ... | @@ -212,111 +281,42 @@ void AUD_open (int rfreq, int rnchannels, audfmt_e rfmt) |
| 212 | 281 | |
| 213 | 282 | case AUD_FMT_S16: |
| 214 | 283 | bits16 = 1; |
| 215 | - fmt_ = AFMT_S16_LE; | |
| 216 | - copy_fn = copy_no_conversion; | |
| 217 | - atom = 2; | |
| 284 | + oss_fmt = AFMT_S16_LE; | |
| 285 | + oss.copy_fn = copy_no_conversion; | |
| 218 | 286 | break; |
| 219 | 287 | |
| 220 | 288 | case AUD_FMT_U16: |
| 221 | 289 | bits16 = 1; |
| 222 | - fmt_ = AFMT_S16_LE; | |
| 223 | - copy_fn = copy_u16_to_s16; | |
| 224 | - atom = 2; | |
| 290 | + oss_fmt = AFMT_S16_LE; | |
| 291 | + oss.copy_fn = copy_u16_to_s16; | |
| 225 | 292 | break; |
| 226 | 293 | |
| 227 | 294 | default: |
| 228 | 295 | abort (); |
| 229 | 296 | } |
| 230 | 297 | |
| 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); | |
| 298 | + if (force_open | |
| 299 | + || (-1 == oss.fd) | |
| 300 | + || (oss_fmt != oss.oss_fmt) | |
| 301 | + || (req_nchannels != oss.nchannels) | |
| 302 | + || (req_freq != oss.freq) | |
| 303 | + || (bits16 != oss.bits16)) { | |
| 304 | + oss.oss_fmt = oss_fmt; | |
| 305 | + oss.nchannels = req_nchannels; | |
| 306 | + oss.freq = req_freq; | |
| 307 | + oss.bits16 = bits16; | |
| 308 | + do_open (); | |
| 283 | 309 | } |
| 310 | +} | |
| 284 | 311 | |
| 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 | - } | |
| 312 | +void AUD_reset (int req_freq, int req_nchannels, audfmt_e req_fmt) | |
| 313 | +{ | |
| 314 | + maybe_open (req_freq, req_nchannels, req_fmt, 0); | |
| 315 | +} | |
| 316 | 316 | |
| 317 | - rpos = 0; | |
| 318 | - wpos = 0; | |
| 319 | - live = 0; | |
| 317 | +void AUD_open (int req_freq, int req_nchannels, audfmt_e req_fmt) | |
| 318 | +{ | |
| 319 | + maybe_open (req_freq, req_nchannels, req_fmt, 1); | |
| 320 | 320 | } |
| 321 | 321 | |
| 322 | 322 | int AUD_write (void *in_buf, int size) |
| ... | ... | @@ -324,27 +324,27 @@ int AUD_write (void *in_buf, int size) |
| 324 | 324 | int to_copy, temp; |
| 325 | 325 | uint8_t *in, *out; |
| 326 | 326 | |
| 327 | - to_copy = MIN (bufsize - live, size); | |
| 327 | + to_copy = MIN (oss.bufsize - oss.live, size); | |
| 328 | 328 | |
| 329 | 329 | temp = to_copy; |
| 330 | 330 | |
| 331 | 331 | in = in_buf; |
| 332 | - out = buf; | |
| 332 | + out = oss.buf; | |
| 333 | 333 | |
| 334 | 334 | while (temp) { |
| 335 | 335 | int copy; |
| 336 | 336 | |
| 337 | - copy = MIN (temp, bufsize - wpos); | |
| 338 | - copy_fn (out + wpos, in, copy); | |
| 337 | + copy = MIN (temp, oss.bufsize - oss.wpos); | |
| 338 | + oss.copy_fn (out + oss.wpos, in, copy); | |
| 339 | 339 | |
| 340 | - wpos += copy; | |
| 341 | - if (wpos == bufsize) { | |
| 342 | - wpos = 0; | |
| 340 | + oss.wpos += copy; | |
| 341 | + if (oss.wpos == oss.bufsize) { | |
| 342 | + oss.wpos = 0; | |
| 343 | 343 | } |
| 344 | 344 | |
| 345 | 345 | temp -= copy; |
| 346 | 346 | in += copy; |
| 347 | - live += copy; | |
| 347 | + oss.live += copy; | |
| 348 | 348 | } |
| 349 | 349 | |
| 350 | 350 | return to_copy; |
| ... | ... | @@ -356,10 +356,34 @@ void AUD_run (void) |
| 356 | 356 | int bytes; |
| 357 | 357 | struct audio_buf_info abinfo; |
| 358 | 358 | |
| 359 | - if (0 == live) | |
| 359 | + if (0 == oss.live) | |
| 360 | 360 | return; |
| 361 | 361 | |
| 362 | - res = ioctl (audio_fd, SNDCTL_DSP_GETOSPACE, &abinfo); | |
| 362 | + if (oss.is_mapped) { | |
| 363 | + count_info info; | |
| 364 | + | |
| 365 | + res = ioctl (oss.fd, SNDCTL_DSP_GETOPTR, &info); | |
| 366 | + if (-1 == res) { | |
| 367 | + int err; | |
| 368 | + | |
| 369 | + err = errno; | |
| 370 | + lwarn ("SNDCTL_DSP_GETOPTR failed with %s\n", strerror (err)); | |
| 371 | + return; | |
| 372 | + } | |
| 373 | + | |
| 374 | + if (info.ptr > oss.old_optr) { | |
| 375 | + bytes = info.ptr - oss.old_optr; | |
| 376 | + } | |
| 377 | + else { | |
| 378 | + bytes = oss.bufsize + info.ptr - oss.old_optr; | |
| 379 | + } | |
| 380 | + | |
| 381 | + oss.old_optr = info.ptr; | |
| 382 | + oss.live -= bytes; | |
| 383 | + return; | |
| 384 | + } | |
| 385 | + | |
| 386 | + res = ioctl (oss.fd, SNDCTL_DSP_GETOSPACE, &abinfo); | |
| 363 | 387 | |
| 364 | 388 | if (-1 == res) { |
| 365 | 389 | int err; |
| ... | ... | @@ -369,7 +393,7 @@ void AUD_run (void) |
| 369 | 393 | } |
| 370 | 394 | |
| 371 | 395 | bytes = abinfo.bytes; |
| 372 | - bytes = MIN (live, bytes); | |
| 396 | + bytes = MIN (oss.live, bytes); | |
| 373 | 397 | #if 0 |
| 374 | 398 | bytes = (bytes / fragsize) * fragsize; |
| 375 | 399 | #endif |
| ... | ... | @@ -377,9 +401,9 @@ void AUD_run (void) |
| 377 | 401 | while (bytes) { |
| 378 | 402 | int left, play, written; |
| 379 | 403 | |
| 380 | - left = bufsize - rpos; | |
| 404 | + left = oss.bufsize - oss.rpos; | |
| 381 | 405 | play = MIN (left, bytes); |
| 382 | - written = write (audio_fd, (void *) ((uint32_t) buf + rpos), play); | |
| 406 | + written = write (oss.fd, (void *) ((uint32_t) oss.buf + oss.rpos), play); | |
| 383 | 407 | |
| 384 | 408 | if (-1 == written) { |
| 385 | 409 | if (EAGAIN == errno || EINTR == errno) { |
| ... | ... | @@ -391,12 +415,12 @@ void AUD_run (void) |
| 391 | 415 | } |
| 392 | 416 | |
| 393 | 417 | play = written; |
| 394 | - live -= play; | |
| 395 | - rpos += play; | |
| 418 | + oss.live -= play; | |
| 419 | + oss.rpos += play; | |
| 396 | 420 | bytes -= play; |
| 397 | 421 | |
| 398 | - if (rpos == bufsize) { | |
| 399 | - rpos = 0; | |
| 422 | + if (oss.rpos == oss.bufsize) { | |
| 423 | + oss.rpos = 0; | |
| 400 | 424 | } |
| 401 | 425 | } |
| 402 | 426 | } |
| ... | ... | @@ -406,7 +430,7 @@ static int get_dsp_bytes (void) |
| 406 | 430 | int res; |
| 407 | 431 | struct count_info info; |
| 408 | 432 | |
| 409 | - res = ioctl (audio_fd, SNDCTL_DSP_GETOPTR, &info); | |
| 433 | + res = ioctl (oss.fd, SNDCTL_DSP_GETOPTR, &info); | |
| 410 | 434 | if (-1 == res) { |
| 411 | 435 | int err; |
| 412 | 436 | |
| ... | ... | @@ -420,22 +444,22 @@ static int get_dsp_bytes (void) |
| 420 | 444 | } |
| 421 | 445 | } |
| 422 | 446 | |
| 423 | -void AUD_adjust_estimate (int _leftover) | |
| 447 | +void AUD_adjust_estimate (int leftover) | |
| 424 | 448 | { |
| 425 | - leftover = _leftover; | |
| 449 | + oss.leftover = leftover; | |
| 426 | 450 | } |
| 427 | 451 | |
| 428 | 452 | int AUD_get_free (void) |
| 429 | 453 | { |
| 430 | 454 | int free, elapsed; |
| 431 | 455 | |
| 432 | - free = bufsize - live; | |
| 456 | + free = oss.bufsize - oss.live; | |
| 433 | 457 | |
| 434 | 458 | if (0 == free) |
| 435 | 459 | return 0; |
| 436 | 460 | |
| 437 | 461 | elapsed = free; |
| 438 | - switch (estimate) { | |
| 462 | + switch (est) { | |
| 439 | 463 | case DONT: |
| 440 | 464 | break; |
| 441 | 465 | |
| ... | ... | @@ -456,16 +480,15 @@ int AUD_get_free (void) |
| 456 | 480 | |
| 457 | 481 | case TID: |
| 458 | 482 | { |
| 459 | - static uint64_t old_ticks; | |
| 460 | 483 | uint64_t ticks, delta; |
| 461 | 484 | uint64_t ua_elapsed; |
| 462 | 485 | uint64_t al_elapsed; |
| 463 | 486 | |
| 464 | 487 | ticks = qemu_get_clock(rt_clock); |
| 465 | - delta = ticks - old_ticks; | |
| 466 | - old_ticks = ticks; | |
| 488 | + delta = ticks - oss.old_ticks; | |
| 489 | + oss.old_ticks = ticks; | |
| 467 | 490 | |
| 468 | - ua_elapsed = (delta * bytes_per_second) / 1000; | |
| 491 | + ua_elapsed = (delta * oss.bytes_per_second) / 1000; | |
| 469 | 492 | al_elapsed = ua_elapsed & ~3ULL; |
| 470 | 493 | |
| 471 | 494 | ldebug ("tid elapsed %llu bytes\n", ua_elapsed); |
| ... | ... | @@ -475,7 +498,7 @@ int AUD_get_free (void) |
| 475 | 498 | else |
| 476 | 499 | elapsed = al_elapsed; |
| 477 | 500 | |
| 478 | - elapsed += leftover; | |
| 501 | + elapsed += oss.leftover; | |
| 479 | 502 | } |
| 480 | 503 | } |
| 481 | 504 | |
| ... | ... | @@ -490,27 +513,47 @@ int AUD_get_free (void) |
| 490 | 513 | |
| 491 | 514 | int AUD_get_live (void) |
| 492 | 515 | { |
| 493 | - return live; | |
| 516 | + return oss.live; | |
| 494 | 517 | } |
| 495 | 518 | |
| 496 | 519 | int AUD_get_buffer_size (void) |
| 497 | 520 | { |
| 498 | - return bufsize; | |
| 521 | + return oss.bufsize; | |
| 522 | +} | |
| 523 | + | |
| 524 | +#define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE" | |
| 525 | +#define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS" | |
| 526 | +#define QC_OSS_MMAP "QEMU_OSS_MMAP" | |
| 527 | + | |
| 528 | +static int get_conf_val (const char *key, int defval) | |
| 529 | +{ | |
| 530 | + int val = defval; | |
| 531 | + char *strval; | |
| 532 | + | |
| 533 | + strval = getenv (key); | |
| 534 | + if (strval) { | |
| 535 | + val = atoi (strval); | |
| 536 | + } | |
| 537 | + | |
| 538 | + return val; | |
| 499 | 539 | } |
| 500 | 540 | |
| 501 | 541 | void AUD_init (void) |
| 502 | 542 | { |
| 503 | 543 | int fsp; |
| 504 | - int _fragsize = 4096; | |
| 505 | 544 | |
| 506 | 545 | DEREF (pab); |
| 507 | 546 | |
| 508 | - fsp = _fragsize; | |
| 547 | + conf.fragsize = get_conf_val (QC_OSS_FRAGSIZE, conf.fragsize); | |
| 548 | + conf.nfrags = get_conf_val (QC_OSS_NFRAGS, conf.nfrags); | |
| 549 | + conf.try_mmap = get_conf_val (QC_OSS_MMAP, conf.try_mmap); | |
| 550 | + | |
| 551 | + fsp = conf.fragsize; | |
| 509 | 552 | if (0 != (fsp & (fsp - 1))) { |
| 510 | 553 | Fail ("fragment size %d is not power of 2", fsp); |
| 511 | 554 | } |
| 512 | 555 | |
| 513 | - conf_fragsize = lsbindex (fsp); | |
| 556 | + conf.fragsize = lsbindex (fsp); | |
| 514 | 557 | } |
| 515 | 558 | |
| 516 | 559 | #else | ... | ... |