Statistics
| Branch: | Revision:

root / oss.c @ d329a6fb

History | View | Annotate | Download (13.4 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 <ctype.h>
28
#include <fcntl.h>
29
#include <errno.h>
30
#include <stdio.h>
31
#include <unistd.h>
32
#include <string.h>
33
#include <stdlib.h>
34
#include <limits.h>
35
#include <inttypes.h>
36
#include <sys/mman.h>
37
#include <sys/types.h>
38
#include <sys/ioctl.h>
39
#include <sys/soundcard.h>
40

    
41

    
42
/* http://www.df.lth.se/~john_e/gems/gem002d.html */
43
/* http://www.multi-platforms.com/Tips/PopCount.htm */
44
static inline uint32_t popcount (uint32_t u)
45
{
46
  u = ((u&0x55555555) + ((u>>1)&0x55555555));
47
  u = ((u&0x33333333) + ((u>>2)&0x33333333));
48
  u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
49
  u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
50
  u = ( u&0x0000ffff) + (u>>16);
51
  return u;
52
}
53

    
54
static inline uint32_t lsbindex (uint32_t u)
55
{
56
  return popcount ((u&-u)-1);
57
}
58

    
59
#define MIN(a, b) ((a)>(b)?(b):(a))
60
#define MAX(a, b) ((a)<(b)?(b):(a))
61

    
62
#define DEREF(x) (void)x
63
#define log(...) fprintf (stderr, "oss: " __VA_ARGS__)
64
#define ERRFail(...) do {                                       \
65
    int _errno = errno;                                         \
66
    fprintf (stderr, "oss: " __VA_ARGS__);                      \
67
    fprintf (stderr, "system error: %s\n", strerror (_errno));  \
68
    abort ();                                                   \
69
} while (0)
70
#define Fail(...) do {                          \
71
    fprintf (stderr, "oss: " __VA_ARGS__);      \
72
    fprintf (stderr, "\n");                     \
73
    abort ();                                   \
74
} while (0)
75

    
76
#ifdef DEBUG_OSS
77
#define lwarn(...) fprintf (stderr, "oss: " __VA_ARGS__)
78
#define linfo(...) fprintf (stderr, "oss: " __VA_ARGS__)
79
#define ldebug(...) fprintf (stderr, "oss: " __VA_ARGS__)
80
#else
81
#define lwarn(...)
82
#define linfo(...)
83
#define ldebug(...)
84
#endif
85

    
86

    
87
#define IOCTL(args) do {                        \
88
  int ret = ioctl args;                         \
89
  if (-1 == ret) {                              \
90
    ERRFail (#args);                            \
91
  }                                             \
92
  ldebug ("ioctl " #args " = %d\n", ret);       \
93
} while (0)
94

    
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;
127

    
128
static void copy_no_conversion (void *dst, void *src, int size)
129
{
130
    memcpy (dst, src, size);
131
}
132

    
133
static void copy_u16_to_s16 (void *dst, void *src, int size)
134
{
135
    int i;
136
    uint16_t *out, *in;
137

    
138
    out = dst;
139
    in = src;
140

    
141
    for (i = 0; i < size / 2; i++) {
142
        out[i] = in[i] + 0x8000;
143
    }
144
}
145

    
146
static void pab (struct audio_buf_info *abinfo)
147
{
148
    DEREF (abinfo);
149

    
150
    ldebug ("fragments %d, fragstotal %d, fragsize %d, bytes %d\n"
151
            "rpos %d, wpos %d, live %d\n",
152
            abinfo->fragments,
153
            abinfo->fragstotal,
154
            abinfo->fragsize,
155
            abinfo->bytes,
156
            rpos, wpos, live);
157
}
158

    
159
static void do_open ()
160
{
161
    int mmmmssss;
162
    audio_buf_info abinfo;
163
    int fmt, freq, nchannels;
164

    
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;
171
    }
172

    
173
    if (-1 != oss.fd)
174
        close (oss.fd);
175

    
176
    oss.fd = open ("/dev/dsp", O_RDWR | O_NONBLOCK);
177
    if (-1 == oss.fd) {
178
        ERRFail ("can not open /dev/dsp");
179
    }
180

    
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
    }
206

    
207
    IOCTL ((oss.fd, SNDCTL_DSP_GETOSPACE, &abinfo));
208

    
209
    oss.nfrags = abinfo.fragstotal;
210
    oss.fragsize = abinfo.fragsize;
211
    oss.bufsize = oss.nfrags * oss.fragsize;
212
    oss.old_optr = 0;
213

    
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
        }
238
    else {
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));
264
    }
265
}
266

    
267
static void maybe_open (int req_freq, int req_nchannels,
268
                        audfmt_e req_fmt, int force_open)
269
{
270
    int oss_fmt, bits16;
271

    
272
    switch (req_fmt) {
273
    case AUD_FMT_U8:
274
        bits16 = 0;
275
        oss_fmt = AFMT_U8;
276
        oss.copy_fn = copy_no_conversion;
277
        break;
278

    
279
    case AUD_FMT_S8:
280
        Fail ("can not play 8bit signed");
281

    
282
    case AUD_FMT_S16:
283
        bits16 = 1;
284
        oss_fmt = AFMT_S16_LE;
285
        oss.copy_fn = copy_no_conversion;
286
        break;
287

    
288
    case AUD_FMT_U16:
289
        bits16 = 1;
290
        oss_fmt = AFMT_S16_LE;
291
        oss.copy_fn = copy_u16_to_s16;
292
        break;
293

    
294
    default:
295
        abort ();
296
    }
297

    
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 ();
309
    }
310
}
311

    
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

    
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
}
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 (oss.bufsize - oss.live, size);
328

    
329
    temp = to_copy;
330

    
331
    in = in_buf;
332
    out = oss.buf;
333

    
334
    while (temp) {
335
        int copy;
336

    
337
        copy = MIN (temp, oss.bufsize - oss.wpos);
338
        oss.copy_fn (out + oss.wpos, in, copy);
339

    
340
        oss.wpos += copy;
341
        if (oss.wpos == oss.bufsize) {
342
            oss.wpos = 0;
343
        }
344

    
345
        temp -= copy;
346
        in += copy;
347
        oss.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 == oss.live)
360
        return;
361

    
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);
387

    
388
    if (-1 == res) {
389
        int err;
390

    
391
        err = errno;
392
        lwarn ("SNDCTL_DSP_GETOSPACE failed with %s\n", strerror (err));
393
    }
394

    
395
    bytes = abinfo.bytes;
396
    bytes = MIN (oss.live, bytes);
397
#if 0
398
    bytes = (bytes / fragsize) * fragsize;
399
#endif
400

    
401
    while (bytes) {
402
        int left, play, written;
403

    
404
        left = oss.bufsize - oss.rpos;
405
        play = MIN (left, bytes);
406
        written = write (oss.fd, (void *) ((uint32_t) oss.buf + oss.rpos), play);
407

    
408
        if (-1 == written) {
409
            if (EAGAIN == errno || EINTR == errno) {
410
                return;
411
            }
412
            else {
413
                ERRFail ("write audio");
414
            }
415
        }
416

    
417
        play = written;
418
        oss.live -= play;
419
        oss.rpos += play;
420
        bytes -= play;
421

    
422
        if (oss.rpos == oss.bufsize) {
423
            oss.rpos = 0;
424
        }
425
    }
426
}
427

    
428
static int get_dsp_bytes (void)
429
{
430
    int res;
431
    struct count_info info;
432

    
433
    res = ioctl (oss.fd, SNDCTL_DSP_GETOPTR, &info);
434
    if (-1 == res) {
435
        int err;
436

    
437
        err = errno;
438
        lwarn ("SNDCTL_DSP_GETOPTR failed with %s\n", strerror (err));
439
        return -1;
440
    }
441
    else {
442
        ldebug ("bytes %d\n", info.bytes);
443
        return info.bytes;
444
    }
445
}
446

    
447
void AUD_adjust_estimate (int leftover)
448
{
449
    oss.leftover = leftover;
450
}
451

    
452
int AUD_get_free (void)
453
{
454
    int free, elapsed;
455

    
456
    free = oss.bufsize - oss.live;
457

    
458
    if (0 == free)
459
        return 0;
460

    
461
    elapsed = free;
462
    switch (est) {
463
    case DONT:
464
        break;
465

    
466
    case DSP:
467
        {
468
            static int old_bytes;
469
            int bytes;
470

    
471
            bytes = get_dsp_bytes ();
472
            if (bytes <= 0)
473
                return free;
474

    
475
            elapsed = bytes - old_bytes;
476
            old_bytes = bytes;
477
            ldebug ("dsp elapsed %d bytes\n", elapsed);
478
            break;
479
        }
480

    
481
    case TID:
482
        {
483
            uint64_t ticks, delta;
484
            uint64_t ua_elapsed;
485
            uint64_t al_elapsed;
486

    
487
            ticks = qemu_get_clock(rt_clock);
488
            delta = ticks - oss.old_ticks;
489
            oss.old_ticks = ticks;
490

    
491
            ua_elapsed = (delta * oss.bytes_per_second) / 1000;
492
            al_elapsed = ua_elapsed & ~3ULL;
493

    
494
            ldebug ("tid elapsed %llu bytes\n", ua_elapsed);
495

    
496
            if (al_elapsed > (uint64_t) INT_MAX)
497
                elapsed = INT_MAX;
498
            else
499
                elapsed = al_elapsed;
500

    
501
            elapsed += oss.leftover;
502
        }
503
    }
504

    
505
    if (elapsed > free) {
506
        lwarn ("audio can not keep up elapsed %d free %d\n", elapsed, free);
507
        return free;
508
    }
509
    else {
510
        return elapsed;
511
    }
512
}
513

    
514
int AUD_get_live (void)
515
{
516
    return oss.live;
517
}
518

    
519
int AUD_get_buffer_size (void)
520
{
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;
539
}
540

    
541
void AUD_init (void)
542
{
543
    int fsp;
544

    
545
    DEREF (pab);
546

    
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;
552
    if (0 != (fsp & (fsp - 1))) {
553
        Fail ("fragment size %d is not power of 2", fsp);
554
    }
555

    
556
    conf.fragsize = lsbindex (fsp);
557
}
558

    
559
#else
560

    
561
void AUD_run (void)
562
{
563
}
564

    
565
int AUD_write (void *in_buf, int size)
566
{
567
    return 0;
568
}
569

    
570
void AUD_reset (int rfreq, int rnchannels, audfmt_e rfmt)
571
{
572
}
573

    
574
void AUD_adjust_estimate (int _leftover)
575
{
576
}
577

    
578
int AUD_get_free (void)
579
{
580
    return 0;
581
}
582

    
583
int AUD_get_live (void)
584
{
585
    return 0;
586
}
587

    
588
int AUD_get_buffer_size (void)
589
{
590
    return 0;
591
}
592

    
593
void AUD_init (void)
594
{
595
}
596

    
597
#endif