Revision d329a6fb oss.c

b/oss.c
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 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 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 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 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 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 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 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 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 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 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 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 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 498
            else
476 499
                elapsed = al_elapsed;
477 500

  
478
            elapsed += leftover;
501
            elapsed += oss.leftover;
479 502
        }
480 503
    }
481 504

  
......
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

Also available in: Unified diff