~ahs3/+junk/cq-qemu

« back to all changes in this revision

Viewing changes to audio/ossaudio.c

  • Committer: Al Stone
  • Date: 2012-02-09 01:17:20 UTC
  • Revision ID: albert.stone@canonical.com-20120209011720-tztl7ik3qayz80p4
first commit to bzr for qemu

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * QEMU OSS audio driver
 
3
 *
 
4
 * Copyright (c) 2003-2005 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 <stdlib.h>
 
25
#include <sys/mman.h>
 
26
#include <sys/types.h>
 
27
#include <sys/ioctl.h>
 
28
#ifdef __OpenBSD__
 
29
#include <soundcard.h>
 
30
#else
 
31
#include <sys/soundcard.h>
 
32
#endif
 
33
#include "qemu-common.h"
 
34
#include "host-utils.h"
 
35
#include "qemu-char.h"
 
36
#include "audio.h"
 
37
 
 
38
#define AUDIO_CAP "oss"
 
39
#include "audio_int.h"
 
40
 
 
41
#if defined OSS_GETVERSION && defined SNDCTL_DSP_POLICY
 
42
#define USE_DSP_POLICY
 
43
#endif
 
44
 
 
45
typedef struct OSSVoiceOut {
 
46
    HWVoiceOut hw;
 
47
    void *pcm_buf;
 
48
    int fd;
 
49
    int wpos;
 
50
    int nfrags;
 
51
    int fragsize;
 
52
    int mmapped;
 
53
    int pending;
 
54
} OSSVoiceOut;
 
55
 
 
56
typedef struct OSSVoiceIn {
 
57
    HWVoiceIn hw;
 
58
    void *pcm_buf;
 
59
    int fd;
 
60
    int nfrags;
 
61
    int fragsize;
 
62
} OSSVoiceIn;
 
63
 
 
64
static struct {
 
65
    int try_mmap;
 
66
    int nfrags;
 
67
    int fragsize;
 
68
    const char *devpath_out;
 
69
    const char *devpath_in;
 
70
    int debug;
 
71
    int exclusive;
 
72
    int policy;
 
73
} conf = {
 
74
    .try_mmap = 0,
 
75
    .nfrags = 4,
 
76
    .fragsize = 4096,
 
77
    .devpath_out = "/dev/dsp",
 
78
    .devpath_in = "/dev/dsp",
 
79
    .debug = 0,
 
80
    .exclusive = 0,
 
81
    .policy = 5
 
82
};
 
83
 
 
84
struct oss_params {
 
85
    int freq;
 
86
    audfmt_e fmt;
 
87
    int nchannels;
 
88
    int nfrags;
 
89
    int fragsize;
 
90
};
 
91
 
 
92
static void GCC_FMT_ATTR (2, 3) oss_logerr (int err, const char *fmt, ...)
 
93
{
 
94
    va_list ap;
 
95
 
 
96
    va_start (ap, fmt);
 
97
    AUD_vlog (AUDIO_CAP, fmt, ap);
 
98
    va_end (ap);
 
99
 
 
100
    AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
 
101
}
 
102
 
 
103
static void GCC_FMT_ATTR (3, 4) oss_logerr2 (
 
104
    int err,
 
105
    const char *typ,
 
106
    const char *fmt,
 
107
    ...
 
108
    )
 
109
{
 
110
    va_list ap;
 
111
 
 
112
    AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
 
113
 
 
114
    va_start (ap, fmt);
 
115
    AUD_vlog (AUDIO_CAP, fmt, ap);
 
116
    va_end (ap);
 
117
 
 
118
    AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
 
119
}
 
120
 
 
121
static void oss_anal_close (int *fdp)
 
122
{
 
123
    int err;
 
124
 
 
125
    qemu_set_fd_handler (*fdp, NULL, NULL, NULL);
 
126
    err = close (*fdp);
 
127
    if (err) {
 
128
        oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp);
 
129
    }
 
130
    *fdp = -1;
 
131
}
 
132
 
 
133
static void oss_helper_poll_out (void *opaque)
 
134
{
 
135
    (void) opaque;
 
136
    audio_run ("oss_poll_out");
 
137
}
 
138
 
 
139
static void oss_helper_poll_in (void *opaque)
 
140
{
 
141
    (void) opaque;
 
142
    audio_run ("oss_poll_in");
 
143
}
 
144
 
 
145
static int oss_poll_out (HWVoiceOut *hw)
 
146
{
 
147
    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 
148
 
 
149
    return qemu_set_fd_handler (oss->fd, NULL, oss_helper_poll_out, NULL);
 
150
}
 
151
 
 
152
static int oss_poll_in (HWVoiceIn *hw)
 
153
{
 
154
    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 
155
 
 
156
    return qemu_set_fd_handler (oss->fd, oss_helper_poll_in, NULL, NULL);
 
157
}
 
158
 
 
159
static int oss_write (SWVoiceOut *sw, void *buf, int len)
 
160
{
 
161
    return audio_pcm_sw_write (sw, buf, len);
 
162
}
 
163
 
 
164
static int aud_to_ossfmt (audfmt_e fmt, int endianness)
 
165
{
 
166
    switch (fmt) {
 
167
    case AUD_FMT_S8:
 
168
        return AFMT_S8;
 
169
 
 
170
    case AUD_FMT_U8:
 
171
        return AFMT_U8;
 
172
 
 
173
    case AUD_FMT_S16:
 
174
        if (endianness) {
 
175
            return AFMT_S16_BE;
 
176
        }
 
177
        else {
 
178
            return AFMT_S16_LE;
 
179
        }
 
180
 
 
181
    case AUD_FMT_U16:
 
182
        if (endianness) {
 
183
            return AFMT_U16_BE;
 
184
        }
 
185
        else {
 
186
            return AFMT_U16_LE;
 
187
        }
 
188
 
 
189
    default:
 
190
        dolog ("Internal logic error: Bad audio format %d\n", fmt);
 
191
#ifdef DEBUG_AUDIO
 
192
        abort ();
 
193
#endif
 
194
        return AFMT_U8;
 
195
    }
 
196
}
 
197
 
 
198
static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness)
 
199
{
 
200
    switch (ossfmt) {
 
201
    case AFMT_S8:
 
202
        *endianness = 0;
 
203
        *fmt = AUD_FMT_S8;
 
204
        break;
 
205
 
 
206
    case AFMT_U8:
 
207
        *endianness = 0;
 
208
        *fmt = AUD_FMT_U8;
 
209
        break;
 
210
 
 
211
    case AFMT_S16_LE:
 
212
        *endianness = 0;
 
213
        *fmt = AUD_FMT_S16;
 
214
        break;
 
215
 
 
216
    case AFMT_U16_LE:
 
217
        *endianness = 0;
 
218
        *fmt = AUD_FMT_U16;
 
219
        break;
 
220
 
 
221
    case AFMT_S16_BE:
 
222
        *endianness = 1;
 
223
        *fmt = AUD_FMT_S16;
 
224
        break;
 
225
 
 
226
    case AFMT_U16_BE:
 
227
        *endianness = 1;
 
228
        *fmt = AUD_FMT_U16;
 
229
        break;
 
230
 
 
231
    default:
 
232
        dolog ("Unrecognized audio format %d\n", ossfmt);
 
233
        return -1;
 
234
    }
 
235
 
 
236
    return 0;
 
237
}
 
238
 
 
239
#if defined DEBUG_MISMATCHES || defined DEBUG
 
240
static void oss_dump_info (struct oss_params *req, struct oss_params *obt)
 
241
{
 
242
    dolog ("parameter | requested value | obtained value\n");
 
243
    dolog ("format    |      %10d |     %10d\n", req->fmt, obt->fmt);
 
244
    dolog ("channels  |      %10d |     %10d\n",
 
245
           req->nchannels, obt->nchannels);
 
246
    dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
 
247
    dolog ("nfrags    |      %10d |     %10d\n", req->nfrags, obt->nfrags);
 
248
    dolog ("fragsize  |      %10d |     %10d\n",
 
249
           req->fragsize, obt->fragsize);
 
250
}
 
251
#endif
 
252
 
 
253
#ifdef USE_DSP_POLICY
 
254
static int oss_get_version (int fd, int *version, const char *typ)
 
255
{
 
256
    if (ioctl (fd, OSS_GETVERSION, &version)) {
 
257
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 
258
        /*
 
259
         * Looks like atm (20100109) FreeBSD knows OSS_GETVERSION
 
260
         * since 7.x, but currently only on the mixer device (or in
 
261
         * the Linuxolator), and in the native version that part of
 
262
         * the code is in fact never reached so the ioctl fails anyway.
 
263
         * Until this is fixed, just check the errno and if its what
 
264
         * FreeBSD's sound drivers return atm assume they are new enough.
 
265
         */
 
266
        if (errno == EINVAL) {
 
267
            *version = 0x040000;
 
268
            return 0;
 
269
        }
 
270
#endif
 
271
        oss_logerr2 (errno, typ, "Failed to get OSS version\n");
 
272
        return -1;
 
273
    }
 
274
    return 0;
 
275
}
 
276
#endif
 
277
 
 
278
static int oss_open (int in, struct oss_params *req,
 
279
                     struct oss_params *obt, int *pfd)
 
280
{
 
281
    int fd;
 
282
    int oflags = conf.exclusive ? O_EXCL : 0;
 
283
    audio_buf_info abinfo;
 
284
    int fmt, freq, nchannels;
 
285
    int setfragment = 1;
 
286
    const char *dspname = in ? conf.devpath_in : conf.devpath_out;
 
287
    const char *typ = in ? "ADC" : "DAC";
 
288
 
 
289
    /* Kludge needed to have working mmap on Linux */
 
290
    oflags |= conf.try_mmap ? O_RDWR : (in ? O_RDONLY : O_WRONLY);
 
291
 
 
292
    fd = open (dspname, oflags | O_NONBLOCK);
 
293
    if (-1 == fd) {
 
294
        oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname);
 
295
        return -1;
 
296
    }
 
297
 
 
298
    freq = req->freq;
 
299
    nchannels = req->nchannels;
 
300
    fmt = req->fmt;
 
301
 
 
302
    if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
 
303
        oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt);
 
304
        goto err;
 
305
    }
 
306
 
 
307
    if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) {
 
308
        oss_logerr2 (errno, typ, "Failed to set number of channels %d\n",
 
309
                     req->nchannels);
 
310
        goto err;
 
311
    }
 
312
 
 
313
    if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) {
 
314
        oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->freq);
 
315
        goto err;
 
316
    }
 
317
 
 
318
    if (ioctl (fd, SNDCTL_DSP_NONBLOCK, NULL)) {
 
319
        oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n");
 
320
        goto err;
 
321
    }
 
322
 
 
323
#ifdef USE_DSP_POLICY
 
324
    if (conf.policy >= 0) {
 
325
        int version;
 
326
 
 
327
        if (!oss_get_version (fd, &version, typ)) {
 
328
            if (conf.debug) {
 
329
                dolog ("OSS version = %#x\n", version);
 
330
            }
 
331
 
 
332
            if (version >= 0x040000) {
 
333
                int policy = conf.policy;
 
334
                if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) {
 
335
                    oss_logerr2 (errno, typ,
 
336
                                 "Failed to set timing policy to %d\n",
 
337
                                 conf.policy);
 
338
                    goto err;
 
339
                }
 
340
                setfragment = 0;
 
341
            }
 
342
        }
 
343
    }
 
344
#endif
 
345
 
 
346
    if (setfragment) {
 
347
        int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize);
 
348
        if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
 
349
            oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
 
350
                         req->nfrags, req->fragsize);
 
351
            goto err;
 
352
        }
 
353
    }
 
354
 
 
355
    if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) {
 
356
        oss_logerr2 (errno, typ, "Failed to get buffer length\n");
 
357
        goto err;
 
358
    }
 
359
 
 
360
    if (!abinfo.fragstotal || !abinfo.fragsize) {
 
361
        AUD_log (AUDIO_CAP, "Returned bogus buffer information(%d, %d) for %s\n",
 
362
                 abinfo.fragstotal, abinfo.fragsize, typ);
 
363
        goto err;
 
364
    }
 
365
 
 
366
    obt->fmt = fmt;
 
367
    obt->nchannels = nchannels;
 
368
    obt->freq = freq;
 
369
    obt->nfrags = abinfo.fragstotal;
 
370
    obt->fragsize = abinfo.fragsize;
 
371
    *pfd = fd;
 
372
 
 
373
#ifdef DEBUG_MISMATCHES
 
374
    if ((req->fmt != obt->fmt) ||
 
375
        (req->nchannels != obt->nchannels) ||
 
376
        (req->freq != obt->freq) ||
 
377
        (req->fragsize != obt->fragsize) ||
 
378
        (req->nfrags != obt->nfrags)) {
 
379
        dolog ("Audio parameters mismatch\n");
 
380
        oss_dump_info (req, obt);
 
381
    }
 
382
#endif
 
383
 
 
384
#ifdef DEBUG
 
385
    oss_dump_info (req, obt);
 
386
#endif
 
387
    return 0;
 
388
 
 
389
 err:
 
390
    oss_anal_close (&fd);
 
391
    return -1;
 
392
}
 
393
 
 
394
static void oss_write_pending (OSSVoiceOut *oss)
 
395
{
 
396
    HWVoiceOut *hw = &oss->hw;
 
397
 
 
398
    if (oss->mmapped) {
 
399
        return;
 
400
    }
 
401
 
 
402
    while (oss->pending) {
 
403
        int samples_written;
 
404
        ssize_t bytes_written;
 
405
        int samples_till_end = hw->samples - oss->wpos;
 
406
        int samples_to_write = audio_MIN (oss->pending, samples_till_end);
 
407
        int bytes_to_write = samples_to_write << hw->info.shift;
 
408
        void *pcm = advance (oss->pcm_buf, oss->wpos << hw->info.shift);
 
409
 
 
410
        bytes_written = write (oss->fd, pcm, bytes_to_write);
 
411
        if (bytes_written < 0) {
 
412
            if (errno != EAGAIN) {
 
413
                oss_logerr (errno, "failed to write %d bytes\n",
 
414
                            bytes_to_write);
 
415
            }
 
416
            break;
 
417
        }
 
418
 
 
419
        if (bytes_written & hw->info.align) {
 
420
            dolog ("misaligned write asked for %d, but got %zd\n",
 
421
                   bytes_to_write, bytes_written);
 
422
            return;
 
423
        }
 
424
 
 
425
        samples_written = bytes_written >> hw->info.shift;
 
426
        oss->pending -= samples_written;
 
427
        oss->wpos = (oss->wpos + samples_written) % hw->samples;
 
428
        if (bytes_written - bytes_to_write) {
 
429
            break;
 
430
        }
 
431
    }
 
432
}
 
433
 
 
434
static int oss_run_out (HWVoiceOut *hw, int live)
 
435
{
 
436
    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 
437
    int err, decr;
 
438
    struct audio_buf_info abinfo;
 
439
    struct count_info cntinfo;
 
440
    int bufsize;
 
441
 
 
442
    bufsize = hw->samples << hw->info.shift;
 
443
 
 
444
    if (oss->mmapped) {
 
445
        int bytes, pos;
 
446
 
 
447
        err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
 
448
        if (err < 0) {
 
449
            oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
 
450
            return 0;
 
451
        }
 
452
 
 
453
        pos = hw->rpos << hw->info.shift;
 
454
        bytes = audio_ring_dist (cntinfo.ptr, pos, bufsize);
 
455
        decr = audio_MIN (bytes >> hw->info.shift, live);
 
456
    }
 
457
    else {
 
458
        err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
 
459
        if (err < 0) {
 
460
            oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
 
461
            return 0;
 
462
        }
 
463
 
 
464
        if (abinfo.bytes > bufsize) {
 
465
            if (conf.debug) {
 
466
                dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
 
467
                       "please report your OS/audio hw to av1474@comtv.ru\n",
 
468
                       abinfo.bytes, bufsize);
 
469
            }
 
470
            abinfo.bytes = bufsize;
 
471
        }
 
472
 
 
473
        if (abinfo.bytes < 0) {
 
474
            if (conf.debug) {
 
475
                dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
 
476
                       abinfo.bytes, bufsize);
 
477
            }
 
478
            return 0;
 
479
        }
 
480
 
 
481
        decr = audio_MIN (abinfo.bytes >> hw->info.shift, live);
 
482
        if (!decr) {
 
483
            return 0;
 
484
        }
 
485
    }
 
486
 
 
487
    decr = audio_pcm_hw_clip_out (hw, oss->pcm_buf, decr, oss->pending);
 
488
    oss->pending += decr;
 
489
    oss_write_pending (oss);
 
490
 
 
491
    return decr;
 
492
}
 
493
 
 
494
static void oss_fini_out (HWVoiceOut *hw)
 
495
{
 
496
    int err;
 
497
    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 
498
 
 
499
    ldebug ("oss_fini\n");
 
500
    oss_anal_close (&oss->fd);
 
501
 
 
502
    if (oss->pcm_buf) {
 
503
        if (oss->mmapped) {
 
504
            err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
 
505
            if (err) {
 
506
                oss_logerr (errno, "Failed to unmap buffer %p, size %d\n",
 
507
                            oss->pcm_buf, hw->samples << hw->info.shift);
 
508
            }
 
509
        }
 
510
        else {
 
511
            g_free (oss->pcm_buf);
 
512
        }
 
513
        oss->pcm_buf = NULL;
 
514
    }
 
515
}
 
516
 
 
517
static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
 
518
{
 
519
    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 
520
    struct oss_params req, obt;
 
521
    int endianness;
 
522
    int err;
 
523
    int fd;
 
524
    audfmt_e effective_fmt;
 
525
    struct audsettings obt_as;
 
526
 
 
527
    oss->fd = -1;
 
528
 
 
529
    req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
 
530
    req.freq = as->freq;
 
531
    req.nchannels = as->nchannels;
 
532
    req.fragsize = conf.fragsize;
 
533
    req.nfrags = conf.nfrags;
 
534
 
 
535
    if (oss_open (0, &req, &obt, &fd)) {
 
536
        return -1;
 
537
    }
 
538
 
 
539
    err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
 
540
    if (err) {
 
541
        oss_anal_close (&fd);
 
542
        return -1;
 
543
    }
 
544
 
 
545
    obt_as.freq = obt.freq;
 
546
    obt_as.nchannels = obt.nchannels;
 
547
    obt_as.fmt = effective_fmt;
 
548
    obt_as.endianness = endianness;
 
549
 
 
550
    audio_pcm_init_info (&hw->info, &obt_as);
 
551
    oss->nfrags = obt.nfrags;
 
552
    oss->fragsize = obt.fragsize;
 
553
 
 
554
    if (obt.nfrags * obt.fragsize & hw->info.align) {
 
555
        dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
 
556
               obt.nfrags * obt.fragsize, hw->info.align + 1);
 
557
    }
 
558
 
 
559
    hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
 
560
 
 
561
    oss->mmapped = 0;
 
562
    if (conf.try_mmap) {
 
563
        oss->pcm_buf = mmap (
 
564
            NULL,
 
565
            hw->samples << hw->info.shift,
 
566
            PROT_READ | PROT_WRITE,
 
567
            MAP_SHARED,
 
568
            fd,
 
569
            0
 
570
            );
 
571
        if (oss->pcm_buf == MAP_FAILED) {
 
572
            oss_logerr (errno, "Failed to map %d bytes of DAC\n",
 
573
                        hw->samples << hw->info.shift);
 
574
        }
 
575
        else {
 
576
            int err;
 
577
            int trig = 0;
 
578
            if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
 
579
                oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
 
580
            }
 
581
            else {
 
582
                trig = PCM_ENABLE_OUTPUT;
 
583
                if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
 
584
                    oss_logerr (
 
585
                        errno,
 
586
                        "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
 
587
                        );
 
588
                }
 
589
                else {
 
590
                    oss->mmapped = 1;
 
591
                }
 
592
            }
 
593
 
 
594
            if (!oss->mmapped) {
 
595
                err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
 
596
                if (err) {
 
597
                    oss_logerr (errno, "Failed to unmap buffer %p size %d\n",
 
598
                                oss->pcm_buf, hw->samples << hw->info.shift);
 
599
                }
 
600
            }
 
601
        }
 
602
    }
 
603
 
 
604
    if (!oss->mmapped) {
 
605
        oss->pcm_buf = audio_calloc (
 
606
            AUDIO_FUNC,
 
607
            hw->samples,
 
608
            1 << hw->info.shift
 
609
            );
 
610
        if (!oss->pcm_buf) {
 
611
            dolog (
 
612
                "Could not allocate DAC buffer (%d samples, each %d bytes)\n",
 
613
                hw->samples,
 
614
                1 << hw->info.shift
 
615
                );
 
616
            oss_anal_close (&fd);
 
617
            return -1;
 
618
        }
 
619
    }
 
620
 
 
621
    oss->fd = fd;
 
622
    return 0;
 
623
}
 
624
 
 
625
static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
 
626
{
 
627
    int trig;
 
628
    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 
629
 
 
630
    switch (cmd) {
 
631
    case VOICE_ENABLE:
 
632
        {
 
633
            va_list ap;
 
634
            int poll_mode;
 
635
 
 
636
            va_start (ap, cmd);
 
637
            poll_mode = va_arg (ap, int);
 
638
            va_end (ap);
 
639
 
 
640
            ldebug ("enabling voice\n");
 
641
            if (poll_mode && oss_poll_out (hw)) {
 
642
                poll_mode = 0;
 
643
            }
 
644
            hw->poll_mode = poll_mode;
 
645
 
 
646
            if (!oss->mmapped) {
 
647
                return 0;
 
648
            }
 
649
 
 
650
            audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
 
651
            trig = PCM_ENABLE_OUTPUT;
 
652
            if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
 
653
                oss_logerr (
 
654
                    errno,
 
655
                    "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
 
656
                    );
 
657
                return -1;
 
658
            }
 
659
        }
 
660
        break;
 
661
 
 
662
    case VOICE_DISABLE:
 
663
        if (hw->poll_mode) {
 
664
            qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
 
665
            hw->poll_mode = 0;
 
666
        }
 
667
 
 
668
        if (!oss->mmapped) {
 
669
            return 0;
 
670
        }
 
671
 
 
672
        ldebug ("disabling voice\n");
 
673
        trig = 0;
 
674
        if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
 
675
            oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
 
676
            return -1;
 
677
        }
 
678
        break;
 
679
    }
 
680
    return 0;
 
681
}
 
682
 
 
683
static int oss_init_in (HWVoiceIn *hw, struct audsettings *as)
 
684
{
 
685
    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 
686
    struct oss_params req, obt;
 
687
    int endianness;
 
688
    int err;
 
689
    int fd;
 
690
    audfmt_e effective_fmt;
 
691
    struct audsettings obt_as;
 
692
 
 
693
    oss->fd = -1;
 
694
 
 
695
    req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
 
696
    req.freq = as->freq;
 
697
    req.nchannels = as->nchannels;
 
698
    req.fragsize = conf.fragsize;
 
699
    req.nfrags = conf.nfrags;
 
700
    if (oss_open (1, &req, &obt, &fd)) {
 
701
        return -1;
 
702
    }
 
703
 
 
704
    err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
 
705
    if (err) {
 
706
        oss_anal_close (&fd);
 
707
        return -1;
 
708
    }
 
709
 
 
710
    obt_as.freq = obt.freq;
 
711
    obt_as.nchannels = obt.nchannels;
 
712
    obt_as.fmt = effective_fmt;
 
713
    obt_as.endianness = endianness;
 
714
 
 
715
    audio_pcm_init_info (&hw->info, &obt_as);
 
716
    oss->nfrags = obt.nfrags;
 
717
    oss->fragsize = obt.fragsize;
 
718
 
 
719
    if (obt.nfrags * obt.fragsize & hw->info.align) {
 
720
        dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
 
721
               obt.nfrags * obt.fragsize, hw->info.align + 1);
 
722
    }
 
723
 
 
724
    hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
 
725
    oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
 
726
    if (!oss->pcm_buf) {
 
727
        dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
 
728
               hw->samples, 1 << hw->info.shift);
 
729
        oss_anal_close (&fd);
 
730
        return -1;
 
731
    }
 
732
 
 
733
    oss->fd = fd;
 
734
    return 0;
 
735
}
 
736
 
 
737
static void oss_fini_in (HWVoiceIn *hw)
 
738
{
 
739
    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 
740
 
 
741
    oss_anal_close (&oss->fd);
 
742
 
 
743
    if (oss->pcm_buf) {
 
744
        g_free (oss->pcm_buf);
 
745
        oss->pcm_buf = NULL;
 
746
    }
 
747
}
 
748
 
 
749
static int oss_run_in (HWVoiceIn *hw)
 
750
{
 
751
    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 
752
    int hwshift = hw->info.shift;
 
753
    int i;
 
754
    int live = audio_pcm_hw_get_live_in (hw);
 
755
    int dead = hw->samples - live;
 
756
    size_t read_samples = 0;
 
757
    struct {
 
758
        int add;
 
759
        int len;
 
760
    } bufs[2] = {
 
761
        { .add = hw->wpos, .len = 0 },
 
762
        { .add = 0,        .len = 0 }
 
763
    };
 
764
 
 
765
    if (!dead) {
 
766
        return 0;
 
767
    }
 
768
 
 
769
    if (hw->wpos + dead > hw->samples) {
 
770
        bufs[0].len = (hw->samples - hw->wpos) << hwshift;
 
771
        bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift;
 
772
    }
 
773
    else {
 
774
        bufs[0].len = dead << hwshift;
 
775
    }
 
776
 
 
777
    for (i = 0; i < 2; ++i) {
 
778
        ssize_t nread;
 
779
 
 
780
        if (bufs[i].len) {
 
781
            void *p = advance (oss->pcm_buf, bufs[i].add << hwshift);
 
782
            nread = read (oss->fd, p, bufs[i].len);
 
783
 
 
784
            if (nread > 0) {
 
785
                if (nread & hw->info.align) {
 
786
                    dolog ("warning: Misaligned read %zd (requested %d), "
 
787
                           "alignment %d\n", nread, bufs[i].add << hwshift,
 
788
                           hw->info.align + 1);
 
789
                }
 
790
                read_samples += nread >> hwshift;
 
791
                hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift);
 
792
            }
 
793
 
 
794
            if (bufs[i].len - nread) {
 
795
                if (nread == -1) {
 
796
                    switch (errno) {
 
797
                    case EINTR:
 
798
                    case EAGAIN:
 
799
                        break;
 
800
                    default:
 
801
                        oss_logerr (
 
802
                            errno,
 
803
                            "Failed to read %d bytes of audio (to %p)\n",
 
804
                            bufs[i].len, p
 
805
                            );
 
806
                        break;
 
807
                    }
 
808
                }
 
809
                break;
 
810
            }
 
811
        }
 
812
    }
 
813
 
 
814
    hw->wpos = (hw->wpos + read_samples) % hw->samples;
 
815
    return read_samples;
 
816
}
 
817
 
 
818
static int oss_read (SWVoiceIn *sw, void *buf, int size)
 
819
{
 
820
    return audio_pcm_sw_read (sw, buf, size);
 
821
}
 
822
 
 
823
static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
 
824
{
 
825
    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 
826
 
 
827
    switch (cmd) {
 
828
    case VOICE_ENABLE:
 
829
        {
 
830
            va_list ap;
 
831
            int poll_mode;
 
832
 
 
833
            va_start (ap, cmd);
 
834
            poll_mode = va_arg (ap, int);
 
835
            va_end (ap);
 
836
 
 
837
            if (poll_mode && oss_poll_in (hw)) {
 
838
                poll_mode = 0;
 
839
            }
 
840
            hw->poll_mode = poll_mode;
 
841
        }
 
842
        break;
 
843
 
 
844
    case VOICE_DISABLE:
 
845
        if (hw->poll_mode) {
 
846
            hw->poll_mode = 0;
 
847
            qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
 
848
        }
 
849
        break;
 
850
    }
 
851
    return 0;
 
852
}
 
853
 
 
854
static void *oss_audio_init (void)
 
855
{
 
856
    return &conf;
 
857
}
 
858
 
 
859
static void oss_audio_fini (void *opaque)
 
860
{
 
861
    (void) opaque;
 
862
}
 
863
 
 
864
static struct audio_option oss_options[] = {
 
865
    {
 
866
        .name  = "FRAGSIZE",
 
867
        .tag   = AUD_OPT_INT,
 
868
        .valp  = &conf.fragsize,
 
869
        .descr = "Fragment size in bytes"
 
870
    },
 
871
    {
 
872
        .name  = "NFRAGS",
 
873
        .tag   = AUD_OPT_INT,
 
874
        .valp  = &conf.nfrags,
 
875
        .descr = "Number of fragments"
 
876
    },
 
877
    {
 
878
        .name  = "MMAP",
 
879
        .tag   = AUD_OPT_BOOL,
 
880
        .valp  = &conf.try_mmap,
 
881
        .descr = "Try using memory mapped access"
 
882
    },
 
883
    {
 
884
        .name  = "DAC_DEV",
 
885
        .tag   = AUD_OPT_STR,
 
886
        .valp  = &conf.devpath_out,
 
887
        .descr = "Path to DAC device"
 
888
    },
 
889
    {
 
890
        .name  = "ADC_DEV",
 
891
        .tag   = AUD_OPT_STR,
 
892
        .valp  = &conf.devpath_in,
 
893
        .descr = "Path to ADC device"
 
894
    },
 
895
    {
 
896
        .name  = "EXCLUSIVE",
 
897
        .tag   = AUD_OPT_BOOL,
 
898
        .valp  = &conf.exclusive,
 
899
        .descr = "Open device in exclusive mode (vmix wont work)"
 
900
    },
 
901
#ifdef USE_DSP_POLICY
 
902
    {
 
903
        .name  = "POLICY",
 
904
        .tag   = AUD_OPT_INT,
 
905
        .valp  = &conf.policy,
 
906
        .descr = "Set the timing policy of the device, -1 to use fragment mode",
 
907
    },
 
908
#endif
 
909
    {
 
910
        .name  = "DEBUG",
 
911
        .tag   = AUD_OPT_BOOL,
 
912
        .valp  = &conf.debug,
 
913
        .descr = "Turn on some debugging messages"
 
914
    },
 
915
    { /* End of list */ }
 
916
};
 
917
 
 
918
static struct audio_pcm_ops oss_pcm_ops = {
 
919
    .init_out = oss_init_out,
 
920
    .fini_out = oss_fini_out,
 
921
    .run_out  = oss_run_out,
 
922
    .write    = oss_write,
 
923
    .ctl_out  = oss_ctl_out,
 
924
 
 
925
    .init_in  = oss_init_in,
 
926
    .fini_in  = oss_fini_in,
 
927
    .run_in   = oss_run_in,
 
928
    .read     = oss_read,
 
929
    .ctl_in   = oss_ctl_in
 
930
};
 
931
 
 
932
struct audio_driver oss_audio_driver = {
 
933
    .name           = "oss",
 
934
    .descr          = "OSS http://www.opensound.com",
 
935
    .options        = oss_options,
 
936
    .init           = oss_audio_init,
 
937
    .fini           = oss_audio_fini,
 
938
    .pcm_ops        = &oss_pcm_ops,
 
939
    .can_be_default = 1,
 
940
    .max_voices_out = INT_MAX,
 
941
    .max_voices_in  = INT_MAX,
 
942
    .voice_size_out = sizeof (OSSVoiceOut),
 
943
    .voice_size_in  = sizeof (OSSVoiceIn)
 
944
};