Statistics
| Branch: | Revision:

root / audio / ossaudio.c @ 077805fa

History | View | Annotate | Download (23.9 kB)

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 "main-loop.h"
35
#include "host-utils.h"
36
#include "qemu-char.h"
37
#include "audio.h"
38

    
39
#define AUDIO_CAP "oss"
40
#include "audio_int.h"
41

    
42
#if defined OSS_GETVERSION && defined SNDCTL_DSP_POLICY
43
#define USE_DSP_POLICY
44
#endif
45

    
46
typedef struct OSSVoiceOut {
47
    HWVoiceOut hw;
48
    void *pcm_buf;
49
    int fd;
50
    int wpos;
51
    int nfrags;
52
    int fragsize;
53
    int mmapped;
54
    int pending;
55
} OSSVoiceOut;
56

    
57
typedef struct OSSVoiceIn {
58
    HWVoiceIn hw;
59
    void *pcm_buf;
60
    int fd;
61
    int nfrags;
62
    int fragsize;
63
} OSSVoiceIn;
64

    
65
static struct {
66
    int try_mmap;
67
    int nfrags;
68
    int fragsize;
69
    const char *devpath_out;
70
    const char *devpath_in;
71
    int debug;
72
    int exclusive;
73
    int policy;
74
} conf = {
75
    .try_mmap = 0,
76
    .nfrags = 4,
77
    .fragsize = 4096,
78
    .devpath_out = "/dev/dsp",
79
    .devpath_in = "/dev/dsp",
80
    .debug = 0,
81
    .exclusive = 0,
82
    .policy = 5
83
};
84

    
85
struct oss_params {
86
    int freq;
87
    audfmt_e fmt;
88
    int nchannels;
89
    int nfrags;
90
    int fragsize;
91
};
92

    
93
static void GCC_FMT_ATTR (2, 3) oss_logerr (int err, const char *fmt, ...)
94
{
95
    va_list ap;
96

    
97
    va_start (ap, fmt);
98
    AUD_vlog (AUDIO_CAP, fmt, ap);
99
    va_end (ap);
100

    
101
    AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
102
}
103

    
104
static void GCC_FMT_ATTR (3, 4) oss_logerr2 (
105
    int err,
106
    const char *typ,
107
    const char *fmt,
108
    ...
109
    )
110
{
111
    va_list ap;
112

    
113
    AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
114

    
115
    va_start (ap, fmt);
116
    AUD_vlog (AUDIO_CAP, fmt, ap);
117
    va_end (ap);
118

    
119
    AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
120
}
121

    
122
static void oss_anal_close (int *fdp)
123
{
124
    int err;
125

    
126
    qemu_set_fd_handler (*fdp, NULL, NULL, NULL);
127
    err = close (*fdp);
128
    if (err) {
129
        oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp);
130
    }
131
    *fdp = -1;
132
}
133

    
134
static void oss_helper_poll_out (void *opaque)
135
{
136
    (void) opaque;
137
    audio_run ("oss_poll_out");
138
}
139

    
140
static void oss_helper_poll_in (void *opaque)
141
{
142
    (void) opaque;
143
    audio_run ("oss_poll_in");
144
}
145

    
146
static int oss_poll_out (HWVoiceOut *hw)
147
{
148
    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
149

    
150
    return qemu_set_fd_handler (oss->fd, NULL, oss_helper_poll_out, NULL);
151
}
152

    
153
static int oss_poll_in (HWVoiceIn *hw)
154
{
155
    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
156

    
157
    return qemu_set_fd_handler (oss->fd, oss_helper_poll_in, NULL, NULL);
158
}
159

    
160
static int oss_write (SWVoiceOut *sw, void *buf, int len)
161
{
162
    return audio_pcm_sw_write (sw, buf, len);
163
}
164

    
165
static int aud_to_ossfmt (audfmt_e fmt, int endianness)
166
{
167
    switch (fmt) {
168
    case AUD_FMT_S8:
169
        return AFMT_S8;
170

    
171
    case AUD_FMT_U8:
172
        return AFMT_U8;
173

    
174
    case AUD_FMT_S16:
175
        if (endianness) {
176
            return AFMT_S16_BE;
177
        }
178
        else {
179
            return AFMT_S16_LE;
180
        }
181

    
182
    case AUD_FMT_U16:
183
        if (endianness) {
184
            return AFMT_U16_BE;
185
        }
186
        else {
187
            return AFMT_U16_LE;
188
        }
189

    
190
    default:
191
        dolog ("Internal logic error: Bad audio format %d\n", fmt);
192
#ifdef DEBUG_AUDIO
193
        abort ();
194
#endif
195
        return AFMT_U8;
196
    }
197
}
198

    
199
static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness)
200
{
201
    switch (ossfmt) {
202
    case AFMT_S8:
203
        *endianness = 0;
204
        *fmt = AUD_FMT_S8;
205
        break;
206

    
207
    case AFMT_U8:
208
        *endianness = 0;
209
        *fmt = AUD_FMT_U8;
210
        break;
211

    
212
    case AFMT_S16_LE:
213
        *endianness = 0;
214
        *fmt = AUD_FMT_S16;
215
        break;
216

    
217
    case AFMT_U16_LE:
218
        *endianness = 0;
219
        *fmt = AUD_FMT_U16;
220
        break;
221

    
222
    case AFMT_S16_BE:
223
        *endianness = 1;
224
        *fmt = AUD_FMT_S16;
225
        break;
226

    
227
    case AFMT_U16_BE:
228
        *endianness = 1;
229
        *fmt = AUD_FMT_U16;
230
        break;
231

    
232
    default:
233
        dolog ("Unrecognized audio format %d\n", ossfmt);
234
        return -1;
235
    }
236

    
237
    return 0;
238
}
239

    
240
#if defined DEBUG_MISMATCHES || defined DEBUG
241
static void oss_dump_info (struct oss_params *req, struct oss_params *obt)
242
{
243
    dolog ("parameter | requested value | obtained value\n");
244
    dolog ("format    |      %10d |     %10d\n", req->fmt, obt->fmt);
245
    dolog ("channels  |      %10d |     %10d\n",
246
           req->nchannels, obt->nchannels);
247
    dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
248
    dolog ("nfrags    |      %10d |     %10d\n", req->nfrags, obt->nfrags);
249
    dolog ("fragsize  |      %10d |     %10d\n",
250
           req->fragsize, obt->fragsize);
251
}
252
#endif
253

    
254
#ifdef USE_DSP_POLICY
255
static int oss_get_version (int fd, int *version, const char *typ)
256
{
257
    if (ioctl (fd, OSS_GETVERSION, &version)) {
258
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
259
        /*
260
         * Looks like atm (20100109) FreeBSD knows OSS_GETVERSION
261
         * since 7.x, but currently only on the mixer device (or in
262
         * the Linuxolator), and in the native version that part of
263
         * the code is in fact never reached so the ioctl fails anyway.
264
         * Until this is fixed, just check the errno and if its what
265
         * FreeBSD's sound drivers return atm assume they are new enough.
266
         */
267
        if (errno == EINVAL) {
268
            *version = 0x040000;
269
            return 0;
270
        }
271
#endif
272
        oss_logerr2 (errno, typ, "Failed to get OSS version\n");
273
        return -1;
274
    }
275
    return 0;
276
}
277
#endif
278

    
279
static int oss_open (int in, struct oss_params *req,
280
                     struct oss_params *obt, int *pfd)
281
{
282
    int fd;
283
    int oflags = conf.exclusive ? O_EXCL : 0;
284
    audio_buf_info abinfo;
285
    int fmt, freq, nchannels;
286
    int setfragment = 1;
287
    const char *dspname = in ? conf.devpath_in : conf.devpath_out;
288
    const char *typ = in ? "ADC" : "DAC";
289

    
290
    /* Kludge needed to have working mmap on Linux */
291
    oflags |= conf.try_mmap ? O_RDWR : (in ? O_RDONLY : O_WRONLY);
292

    
293
    fd = open (dspname, oflags | O_NONBLOCK);
294
    if (-1 == fd) {
295
        oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname);
296
        return -1;
297
    }
298

    
299
    freq = req->freq;
300
    nchannels = req->nchannels;
301
    fmt = req->fmt;
302

    
303
    if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
304
        oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt);
305
        goto err;
306
    }
307

    
308
    if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) {
309
        oss_logerr2 (errno, typ, "Failed to set number of channels %d\n",
310
                     req->nchannels);
311
        goto err;
312
    }
313

    
314
    if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) {
315
        oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->freq);
316
        goto err;
317
    }
318

    
319
    if (ioctl (fd, SNDCTL_DSP_NONBLOCK, NULL)) {
320
        oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n");
321
        goto err;
322
    }
323

    
324
#ifdef USE_DSP_POLICY
325
    if (conf.policy >= 0) {
326
        int version;
327

    
328
        if (!oss_get_version (fd, &version, typ)) {
329
            if (conf.debug) {
330
                dolog ("OSS version = %#x\n", version);
331
            }
332

    
333
            if (version >= 0x040000) {
334
                int policy = conf.policy;
335
                if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) {
336
                    oss_logerr2 (errno, typ,
337
                                 "Failed to set timing policy to %d\n",
338
                                 conf.policy);
339
                    goto err;
340
                }
341
                setfragment = 0;
342
            }
343
        }
344
    }
345
#endif
346

    
347
    if (setfragment) {
348
        int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize);
349
        if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
350
            oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
351
                         req->nfrags, req->fragsize);
352
            goto err;
353
        }
354
    }
355

    
356
    if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) {
357
        oss_logerr2 (errno, typ, "Failed to get buffer length\n");
358
        goto err;
359
    }
360

    
361
    if (!abinfo.fragstotal || !abinfo.fragsize) {
362
        AUD_log (AUDIO_CAP, "Returned bogus buffer information(%d, %d) for %s\n",
363
                 abinfo.fragstotal, abinfo.fragsize, typ);
364
        goto err;
365
    }
366

    
367
    obt->fmt = fmt;
368
    obt->nchannels = nchannels;
369
    obt->freq = freq;
370
    obt->nfrags = abinfo.fragstotal;
371
    obt->fragsize = abinfo.fragsize;
372
    *pfd = fd;
373

    
374
#ifdef DEBUG_MISMATCHES
375
    if ((req->fmt != obt->fmt) ||
376
        (req->nchannels != obt->nchannels) ||
377
        (req->freq != obt->freq) ||
378
        (req->fragsize != obt->fragsize) ||
379
        (req->nfrags != obt->nfrags)) {
380
        dolog ("Audio parameters mismatch\n");
381
        oss_dump_info (req, obt);
382
    }
383
#endif
384

    
385
#ifdef DEBUG
386
    oss_dump_info (req, obt);
387
#endif
388
    return 0;
389

    
390
 err:
391
    oss_anal_close (&fd);
392
    return -1;
393
}
394

    
395
static void oss_write_pending (OSSVoiceOut *oss)
396
{
397
    HWVoiceOut *hw = &oss->hw;
398

    
399
    if (oss->mmapped) {
400
        return;
401
    }
402

    
403
    while (oss->pending) {
404
        int samples_written;
405
        ssize_t bytes_written;
406
        int samples_till_end = hw->samples - oss->wpos;
407
        int samples_to_write = audio_MIN (oss->pending, samples_till_end);
408
        int bytes_to_write = samples_to_write << hw->info.shift;
409
        void *pcm = advance (oss->pcm_buf, oss->wpos << hw->info.shift);
410

    
411
        bytes_written = write (oss->fd, pcm, bytes_to_write);
412
        if (bytes_written < 0) {
413
            if (errno != EAGAIN) {
414
                oss_logerr (errno, "failed to write %d bytes\n",
415
                            bytes_to_write);
416
            }
417
            break;
418
        }
419

    
420
        if (bytes_written & hw->info.align) {
421
            dolog ("misaligned write asked for %d, but got %zd\n",
422
                   bytes_to_write, bytes_written);
423
            return;
424
        }
425

    
426
        samples_written = bytes_written >> hw->info.shift;
427
        oss->pending -= samples_written;
428
        oss->wpos = (oss->wpos + samples_written) % hw->samples;
429
        if (bytes_written - bytes_to_write) {
430
            break;
431
        }
432
    }
433
}
434

    
435
static int oss_run_out (HWVoiceOut *hw, int live)
436
{
437
    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
438
    int err, decr;
439
    struct audio_buf_info abinfo;
440
    struct count_info cntinfo;
441
    int bufsize;
442

    
443
    bufsize = hw->samples << hw->info.shift;
444

    
445
    if (oss->mmapped) {
446
        int bytes, pos;
447

    
448
        err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
449
        if (err < 0) {
450
            oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
451
            return 0;
452
        }
453

    
454
        pos = hw->rpos << hw->info.shift;
455
        bytes = audio_ring_dist (cntinfo.ptr, pos, bufsize);
456
        decr = audio_MIN (bytes >> hw->info.shift, live);
457
    }
458
    else {
459
        err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
460
        if (err < 0) {
461
            oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
462
            return 0;
463
        }
464

    
465
        if (abinfo.bytes > bufsize) {
466
            if (conf.debug) {
467
                dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
468
                       "please report your OS/audio hw to av1474@comtv.ru\n",
469
                       abinfo.bytes, bufsize);
470
            }
471
            abinfo.bytes = bufsize;
472
        }
473

    
474
        if (abinfo.bytes < 0) {
475
            if (conf.debug) {
476
                dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
477
                       abinfo.bytes, bufsize);
478
            }
479
            return 0;
480
        }
481

    
482
        decr = audio_MIN (abinfo.bytes >> hw->info.shift, live);
483
        if (!decr) {
484
            return 0;
485
        }
486
    }
487

    
488
    decr = audio_pcm_hw_clip_out (hw, oss->pcm_buf, decr, oss->pending);
489
    oss->pending += decr;
490
    oss_write_pending (oss);
491

    
492
    return decr;
493
}
494

    
495
static void oss_fini_out (HWVoiceOut *hw)
496
{
497
    int err;
498
    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
499

    
500
    ldebug ("oss_fini\n");
501
    oss_anal_close (&oss->fd);
502

    
503
    if (oss->pcm_buf) {
504
        if (oss->mmapped) {
505
            err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
506
            if (err) {
507
                oss_logerr (errno, "Failed to unmap buffer %p, size %d\n",
508
                            oss->pcm_buf, hw->samples << hw->info.shift);
509
            }
510
        }
511
        else {
512
            g_free (oss->pcm_buf);
513
        }
514
        oss->pcm_buf = NULL;
515
    }
516
}
517

    
518
static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
519
{
520
    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
521
    struct oss_params req, obt;
522
    int endianness;
523
    int err;
524
    int fd;
525
    audfmt_e effective_fmt;
526
    struct audsettings obt_as;
527

    
528
    oss->fd = -1;
529

    
530
    req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
531
    req.freq = as->freq;
532
    req.nchannels = as->nchannels;
533
    req.fragsize = conf.fragsize;
534
    req.nfrags = conf.nfrags;
535

    
536
    if (oss_open (0, &req, &obt, &fd)) {
537
        return -1;
538
    }
539

    
540
    err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
541
    if (err) {
542
        oss_anal_close (&fd);
543
        return -1;
544
    }
545

    
546
    obt_as.freq = obt.freq;
547
    obt_as.nchannels = obt.nchannels;
548
    obt_as.fmt = effective_fmt;
549
    obt_as.endianness = endianness;
550

    
551
    audio_pcm_init_info (&hw->info, &obt_as);
552
    oss->nfrags = obt.nfrags;
553
    oss->fragsize = obt.fragsize;
554

    
555
    if (obt.nfrags * obt.fragsize & hw->info.align) {
556
        dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
557
               obt.nfrags * obt.fragsize, hw->info.align + 1);
558
    }
559

    
560
    hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
561

    
562
    oss->mmapped = 0;
563
    if (conf.try_mmap) {
564
        oss->pcm_buf = mmap (
565
            NULL,
566
            hw->samples << hw->info.shift,
567
            PROT_READ | PROT_WRITE,
568
            MAP_SHARED,
569
            fd,
570
            0
571
            );
572
        if (oss->pcm_buf == MAP_FAILED) {
573
            oss_logerr (errno, "Failed to map %d bytes of DAC\n",
574
                        hw->samples << hw->info.shift);
575
        }
576
        else {
577
            int err;
578
            int trig = 0;
579
            if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
580
                oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
581
            }
582
            else {
583
                trig = PCM_ENABLE_OUTPUT;
584
                if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
585
                    oss_logerr (
586
                        errno,
587
                        "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
588
                        );
589
                }
590
                else {
591
                    oss->mmapped = 1;
592
                }
593
            }
594

    
595
            if (!oss->mmapped) {
596
                err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
597
                if (err) {
598
                    oss_logerr (errno, "Failed to unmap buffer %p size %d\n",
599
                                oss->pcm_buf, hw->samples << hw->info.shift);
600
                }
601
            }
602
        }
603
    }
604

    
605
    if (!oss->mmapped) {
606
        oss->pcm_buf = audio_calloc (
607
            AUDIO_FUNC,
608
            hw->samples,
609
            1 << hw->info.shift
610
            );
611
        if (!oss->pcm_buf) {
612
            dolog (
613
                "Could not allocate DAC buffer (%d samples, each %d bytes)\n",
614
                hw->samples,
615
                1 << hw->info.shift
616
                );
617
            oss_anal_close (&fd);
618
            return -1;
619
        }
620
    }
621

    
622
    oss->fd = fd;
623
    return 0;
624
}
625

    
626
static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
627
{
628
    int trig;
629
    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
630

    
631
    switch (cmd) {
632
    case VOICE_ENABLE:
633
        {
634
            va_list ap;
635
            int poll_mode;
636

    
637
            va_start (ap, cmd);
638
            poll_mode = va_arg (ap, int);
639
            va_end (ap);
640

    
641
            ldebug ("enabling voice\n");
642
            if (poll_mode && oss_poll_out (hw)) {
643
                poll_mode = 0;
644
            }
645
            hw->poll_mode = poll_mode;
646

    
647
            if (!oss->mmapped) {
648
                return 0;
649
            }
650

    
651
            audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
652
            trig = PCM_ENABLE_OUTPUT;
653
            if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
654
                oss_logerr (
655
                    errno,
656
                    "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
657
                    );
658
                return -1;
659
            }
660
        }
661
        break;
662

    
663
    case VOICE_DISABLE:
664
        if (hw->poll_mode) {
665
            qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
666
            hw->poll_mode = 0;
667
        }
668

    
669
        if (!oss->mmapped) {
670
            return 0;
671
        }
672

    
673
        ldebug ("disabling voice\n");
674
        trig = 0;
675
        if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
676
            oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
677
            return -1;
678
        }
679
        break;
680
    }
681
    return 0;
682
}
683

    
684
static int oss_init_in (HWVoiceIn *hw, struct audsettings *as)
685
{
686
    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
687
    struct oss_params req, obt;
688
    int endianness;
689
    int err;
690
    int fd;
691
    audfmt_e effective_fmt;
692
    struct audsettings obt_as;
693

    
694
    oss->fd = -1;
695

    
696
    req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
697
    req.freq = as->freq;
698
    req.nchannels = as->nchannels;
699
    req.fragsize = conf.fragsize;
700
    req.nfrags = conf.nfrags;
701
    if (oss_open (1, &req, &obt, &fd)) {
702
        return -1;
703
    }
704

    
705
    err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
706
    if (err) {
707
        oss_anal_close (&fd);
708
        return -1;
709
    }
710

    
711
    obt_as.freq = obt.freq;
712
    obt_as.nchannels = obt.nchannels;
713
    obt_as.fmt = effective_fmt;
714
    obt_as.endianness = endianness;
715

    
716
    audio_pcm_init_info (&hw->info, &obt_as);
717
    oss->nfrags = obt.nfrags;
718
    oss->fragsize = obt.fragsize;
719

    
720
    if (obt.nfrags * obt.fragsize & hw->info.align) {
721
        dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
722
               obt.nfrags * obt.fragsize, hw->info.align + 1);
723
    }
724

    
725
    hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
726
    oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
727
    if (!oss->pcm_buf) {
728
        dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
729
               hw->samples, 1 << hw->info.shift);
730
        oss_anal_close (&fd);
731
        return -1;
732
    }
733

    
734
    oss->fd = fd;
735
    return 0;
736
}
737

    
738
static void oss_fini_in (HWVoiceIn *hw)
739
{
740
    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
741

    
742
    oss_anal_close (&oss->fd);
743

    
744
    if (oss->pcm_buf) {
745
        g_free (oss->pcm_buf);
746
        oss->pcm_buf = NULL;
747
    }
748
}
749

    
750
static int oss_run_in (HWVoiceIn *hw)
751
{
752
    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
753
    int hwshift = hw->info.shift;
754
    int i;
755
    int live = audio_pcm_hw_get_live_in (hw);
756
    int dead = hw->samples - live;
757
    size_t read_samples = 0;
758
    struct {
759
        int add;
760
        int len;
761
    } bufs[2] = {
762
        { .add = hw->wpos, .len = 0 },
763
        { .add = 0,        .len = 0 }
764
    };
765

    
766
    if (!dead) {
767
        return 0;
768
    }
769

    
770
    if (hw->wpos + dead > hw->samples) {
771
        bufs[0].len = (hw->samples - hw->wpos) << hwshift;
772
        bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift;
773
    }
774
    else {
775
        bufs[0].len = dead << hwshift;
776
    }
777

    
778
    for (i = 0; i < 2; ++i) {
779
        ssize_t nread;
780

    
781
        if (bufs[i].len) {
782
            void *p = advance (oss->pcm_buf, bufs[i].add << hwshift);
783
            nread = read (oss->fd, p, bufs[i].len);
784

    
785
            if (nread > 0) {
786
                if (nread & hw->info.align) {
787
                    dolog ("warning: Misaligned read %zd (requested %d), "
788
                           "alignment %d\n", nread, bufs[i].add << hwshift,
789
                           hw->info.align + 1);
790
                }
791
                read_samples += nread >> hwshift;
792
                hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift);
793
            }
794

    
795
            if (bufs[i].len - nread) {
796
                if (nread == -1) {
797
                    switch (errno) {
798
                    case EINTR:
799
                    case EAGAIN:
800
                        break;
801
                    default:
802
                        oss_logerr (
803
                            errno,
804
                            "Failed to read %d bytes of audio (to %p)\n",
805
                            bufs[i].len, p
806
                            );
807
                        break;
808
                    }
809
                }
810
                break;
811
            }
812
        }
813
    }
814

    
815
    hw->wpos = (hw->wpos + read_samples) % hw->samples;
816
    return read_samples;
817
}
818

    
819
static int oss_read (SWVoiceIn *sw, void *buf, int size)
820
{
821
    return audio_pcm_sw_read (sw, buf, size);
822
}
823

    
824
static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
825
{
826
    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
827

    
828
    switch (cmd) {
829
    case VOICE_ENABLE:
830
        {
831
            va_list ap;
832
            int poll_mode;
833

    
834
            va_start (ap, cmd);
835
            poll_mode = va_arg (ap, int);
836
            va_end (ap);
837

    
838
            if (poll_mode && oss_poll_in (hw)) {
839
                poll_mode = 0;
840
            }
841
            hw->poll_mode = poll_mode;
842
        }
843
        break;
844

    
845
    case VOICE_DISABLE:
846
        if (hw->poll_mode) {
847
            hw->poll_mode = 0;
848
            qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
849
        }
850
        break;
851
    }
852
    return 0;
853
}
854

    
855
static void *oss_audio_init (void)
856
{
857
    return &conf;
858
}
859

    
860
static void oss_audio_fini (void *opaque)
861
{
862
    (void) opaque;
863
}
864

    
865
static struct audio_option oss_options[] = {
866
    {
867
        .name  = "FRAGSIZE",
868
        .tag   = AUD_OPT_INT,
869
        .valp  = &conf.fragsize,
870
        .descr = "Fragment size in bytes"
871
    },
872
    {
873
        .name  = "NFRAGS",
874
        .tag   = AUD_OPT_INT,
875
        .valp  = &conf.nfrags,
876
        .descr = "Number of fragments"
877
    },
878
    {
879
        .name  = "MMAP",
880
        .tag   = AUD_OPT_BOOL,
881
        .valp  = &conf.try_mmap,
882
        .descr = "Try using memory mapped access"
883
    },
884
    {
885
        .name  = "DAC_DEV",
886
        .tag   = AUD_OPT_STR,
887
        .valp  = &conf.devpath_out,
888
        .descr = "Path to DAC device"
889
    },
890
    {
891
        .name  = "ADC_DEV",
892
        .tag   = AUD_OPT_STR,
893
        .valp  = &conf.devpath_in,
894
        .descr = "Path to ADC device"
895
    },
896
    {
897
        .name  = "EXCLUSIVE",
898
        .tag   = AUD_OPT_BOOL,
899
        .valp  = &conf.exclusive,
900
        .descr = "Open device in exclusive mode (vmix wont work)"
901
    },
902
#ifdef USE_DSP_POLICY
903
    {
904
        .name  = "POLICY",
905
        .tag   = AUD_OPT_INT,
906
        .valp  = &conf.policy,
907
        .descr = "Set the timing policy of the device, -1 to use fragment mode",
908
    },
909
#endif
910
    {
911
        .name  = "DEBUG",
912
        .tag   = AUD_OPT_BOOL,
913
        .valp  = &conf.debug,
914
        .descr = "Turn on some debugging messages"
915
    },
916
    { /* End of list */ }
917
};
918

    
919
static struct audio_pcm_ops oss_pcm_ops = {
920
    .init_out = oss_init_out,
921
    .fini_out = oss_fini_out,
922
    .run_out  = oss_run_out,
923
    .write    = oss_write,
924
    .ctl_out  = oss_ctl_out,
925

    
926
    .init_in  = oss_init_in,
927
    .fini_in  = oss_fini_in,
928
    .run_in   = oss_run_in,
929
    .read     = oss_read,
930
    .ctl_in   = oss_ctl_in
931
};
932

    
933
struct audio_driver oss_audio_driver = {
934
    .name           = "oss",
935
    .descr          = "OSS http://www.opensound.com",
936
    .options        = oss_options,
937
    .init           = oss_audio_init,
938
    .fini           = oss_audio_fini,
939
    .pcm_ops        = &oss_pcm_ops,
940
    .can_be_default = 1,
941
    .max_voices_out = INT_MAX,
942
    .max_voices_in  = INT_MAX,
943
    .voice_size_out = sizeof (OSSVoiceOut),
944
    .voice_size_in  = sizeof (OSSVoiceIn)
945
};