Statistics
| Branch: | Revision:

root / audio / esdaudio.c @ ad483a51

History | View | Annotate | Download (14.5 kB)

1
/*
2
 * QEMU ESD audio driver
3
 *
4
 * Copyright (c) 2006 Frederick Reeve (brushed up by 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 <esd.h>
25
#include "qemu-common.h"
26
#include "audio.h"
27
#include <signal.h>
28

    
29
#define AUDIO_CAP "esd"
30
#include "audio_int.h"
31
#include "audio_pt_int.h"
32

    
33
typedef struct {
34
    HWVoiceOut hw;
35
    int done;
36
    int live;
37
    int decr;
38
    int rpos;
39
    void *pcm_buf;
40
    int fd;
41
    struct audio_pt pt;
42
} ESDVoiceOut;
43

    
44
typedef struct {
45
    HWVoiceIn hw;
46
    int done;
47
    int dead;
48
    int incr;
49
    int wpos;
50
    void *pcm_buf;
51
    int fd;
52
    struct audio_pt pt;
53
} ESDVoiceIn;
54

    
55
static struct {
56
    int samples;
57
    int divisor;
58
    char *dac_host;
59
    char *adc_host;
60
} conf = {
61
    .samples = 1024,
62
    .divisor = 2,
63
};
64

    
65
static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...)
66
{
67
    va_list ap;
68

    
69
    va_start (ap, fmt);
70
    AUD_vlog (AUDIO_CAP, fmt, ap);
71
    va_end (ap);
72

    
73
    AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
74
}
75

    
76
/* playback */
77
static void *qesd_thread_out (void *arg)
78
{
79
    ESDVoiceOut *esd = arg;
80
    HWVoiceOut *hw = &esd->hw;
81
    int threshold;
82

    
83
    threshold = conf.divisor ? hw->samples / conf.divisor : 0;
84

    
85
    if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
86
        return NULL;
87
    }
88

    
89
    for (;;) {
90
        int decr, to_mix, rpos;
91

    
92
        for (;;) {
93
            if (esd->done) {
94
                goto exit;
95
            }
96

    
97
            if (esd->live > threshold) {
98
                break;
99
            }
100

    
101
            if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
102
                goto exit;
103
            }
104
        }
105

    
106
        decr = to_mix = esd->live;
107
        rpos = hw->rpos;
108

    
109
        if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
110
            return NULL;
111
        }
112

    
113
        while (to_mix) {
114
            ssize_t written;
115
            int chunk = audio_MIN (to_mix, hw->samples - rpos);
116
            struct st_sample *src = hw->mix_buf + rpos;
117

    
118
            hw->clip (esd->pcm_buf, src, chunk);
119

    
120
        again:
121
            written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift);
122
            if (written == -1) {
123
                if (errno == EINTR || errno == EAGAIN) {
124
                    goto again;
125
                }
126
                qesd_logerr (errno, "write failed\n");
127
                return NULL;
128
            }
129

    
130
            if (written != chunk << hw->info.shift) {
131
                int wsamples = written >> hw->info.shift;
132
                int wbytes = wsamples << hw->info.shift;
133
                if (wbytes != written) {
134
                    dolog ("warning: Misaligned write %d (requested %zd), "
135
                           "alignment %d\n",
136
                           wbytes, written, hw->info.align + 1);
137
                }
138
                to_mix -= wsamples;
139
                rpos = (rpos + wsamples) % hw->samples;
140
                break;
141
            }
142

    
143
            rpos = (rpos + chunk) % hw->samples;
144
            to_mix -= chunk;
145
        }
146

    
147
        if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
148
            return NULL;
149
        }
150

    
151
        esd->rpos = rpos;
152
        esd->live -= decr;
153
        esd->decr += decr;
154
    }
155

    
156
 exit:
157
    audio_pt_unlock (&esd->pt, AUDIO_FUNC);
158
    return NULL;
159
}
160

    
161
static int qesd_run_out (HWVoiceOut *hw, int live)
162
{
163
    int decr;
164
    ESDVoiceOut *esd = (ESDVoiceOut *) hw;
165

    
166
    if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
167
        return 0;
168
    }
169

    
170
    decr = audio_MIN (live, esd->decr);
171
    esd->decr -= decr;
172
    esd->live = live - decr;
173
    hw->rpos = esd->rpos;
174
    if (esd->live > 0) {
175
        audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
176
    }
177
    else {
178
        audio_pt_unlock (&esd->pt, AUDIO_FUNC);
179
    }
180
    return decr;
181
}
182

    
183
static int qesd_write (SWVoiceOut *sw, void *buf, int len)
184
{
185
    return audio_pcm_sw_write (sw, buf, len);
186
}
187

    
188
static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
189
{
190
    ESDVoiceOut *esd = (ESDVoiceOut *) hw;
191
    struct audsettings obt_as = *as;
192
    int esdfmt = ESD_STREAM | ESD_PLAY;
193
    int err;
194
    sigset_t set, old_set;
195

    
196
    sigfillset (&set);
197

    
198
    esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
199
    switch (as->fmt) {
200
    case AUD_FMT_S8:
201
    case AUD_FMT_U8:
202
        esdfmt |= ESD_BITS8;
203
        obt_as.fmt = AUD_FMT_U8;
204
        break;
205

    
206
    case AUD_FMT_S32:
207
    case AUD_FMT_U32:
208
        dolog ("Will use 16 instead of 32 bit samples\n");
209

    
210
    case AUD_FMT_S16:
211
    case AUD_FMT_U16:
212
    deffmt:
213
        esdfmt |= ESD_BITS16;
214
        obt_as.fmt = AUD_FMT_S16;
215
        break;
216

    
217
    default:
218
        dolog ("Internal logic error: Bad audio format %d\n", as->fmt);
219
        goto deffmt;
220

    
221
    }
222
    obt_as.endianness = AUDIO_HOST_ENDIANNESS;
223

    
224
    audio_pcm_init_info (&hw->info, &obt_as);
225

    
226
    hw->samples = conf.samples;
227
    esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
228
    if (!esd->pcm_buf) {
229
        dolog ("Could not allocate buffer (%d bytes)\n",
230
               hw->samples << hw->info.shift);
231
        return -1;
232
    }
233

    
234
    esd->fd = -1;
235
    err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
236
    if (err) {
237
        qesd_logerr (err, "pthread_sigmask failed\n");
238
        goto fail1;
239
    }
240

    
241
    esd->fd = esd_play_stream (esdfmt, as->freq, conf.dac_host, NULL);
242
    if (esd->fd < 0) {
243
        qesd_logerr (errno, "esd_play_stream failed\n");
244
        goto fail2;
245
    }
246

    
247
    if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) {
248
        goto fail3;
249
    }
250

    
251
    err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
252
    if (err) {
253
        qesd_logerr (err, "pthread_sigmask(restore) failed\n");
254
    }
255

    
256
    return 0;
257

    
258
 fail3:
259
    if (close (esd->fd)) {
260
        qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
261
                     AUDIO_FUNC, esd->fd);
262
    }
263
    esd->fd = -1;
264

    
265
 fail2:
266
    err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
267
    if (err) {
268
        qesd_logerr (err, "pthread_sigmask(restore) failed\n");
269
    }
270

    
271
 fail1:
272
    qemu_free (esd->pcm_buf);
273
    esd->pcm_buf = NULL;
274
    return -1;
275
}
276

    
277
static void qesd_fini_out (HWVoiceOut *hw)
278
{
279
    void *ret;
280
    ESDVoiceOut *esd = (ESDVoiceOut *) hw;
281

    
282
    audio_pt_lock (&esd->pt, AUDIO_FUNC);
283
    esd->done = 1;
284
    audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
285
    audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
286

    
287
    if (esd->fd >= 0) {
288
        if (close (esd->fd)) {
289
            qesd_logerr (errno, "failed to close esd socket\n");
290
        }
291
        esd->fd = -1;
292
    }
293

    
294
    audio_pt_fini (&esd->pt, AUDIO_FUNC);
295

    
296
    qemu_free (esd->pcm_buf);
297
    esd->pcm_buf = NULL;
298
}
299

    
300
static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...)
301
{
302
    (void) hw;
303
    (void) cmd;
304
    return 0;
305
}
306

    
307
/* capture */
308
static void *qesd_thread_in (void *arg)
309
{
310
    ESDVoiceIn *esd = arg;
311
    HWVoiceIn *hw = &esd->hw;
312
    int threshold;
313

    
314
    threshold = conf.divisor ? hw->samples / conf.divisor : 0;
315

    
316
    if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
317
        return NULL;
318
    }
319

    
320
    for (;;) {
321
        int incr, to_grab, wpos;
322

    
323
        for (;;) {
324
            if (esd->done) {
325
                goto exit;
326
            }
327

    
328
            if (esd->dead > threshold) {
329
                break;
330
            }
331

    
332
            if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
333
                goto exit;
334
            }
335
        }
336

    
337
        incr = to_grab = esd->dead;
338
        wpos = hw->wpos;
339

    
340
        if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
341
            return NULL;
342
        }
343

    
344
        while (to_grab) {
345
            ssize_t nread;
346
            int chunk = audio_MIN (to_grab, hw->samples - wpos);
347
            void *buf = advance (esd->pcm_buf, wpos);
348

    
349
        again:
350
            nread = read (esd->fd, buf, chunk << hw->info.shift);
351
            if (nread == -1) {
352
                if (errno == EINTR || errno == EAGAIN) {
353
                    goto again;
354
                }
355
                qesd_logerr (errno, "read failed\n");
356
                return NULL;
357
            }
358

    
359
            if (nread != chunk << hw->info.shift) {
360
                int rsamples = nread >> hw->info.shift;
361
                int rbytes = rsamples << hw->info.shift;
362
                if (rbytes != nread) {
363
                    dolog ("warning: Misaligned write %d (requested %zd), "
364
                           "alignment %d\n",
365
                           rbytes, nread, hw->info.align + 1);
366
                }
367
                to_grab -= rsamples;
368
                wpos = (wpos + rsamples) % hw->samples;
369
                break;
370
            }
371

    
372
            hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift,
373
                      &nominal_volume);
374
            wpos = (wpos + chunk) % hw->samples;
375
            to_grab -= chunk;
376
        }
377

    
378
        if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
379
            return NULL;
380
        }
381

    
382
        esd->wpos = wpos;
383
        esd->dead -= incr;
384
        esd->incr += incr;
385
    }
386

    
387
 exit:
388
    audio_pt_unlock (&esd->pt, AUDIO_FUNC);
389
    return NULL;
390
}
391

    
392
static int qesd_run_in (HWVoiceIn *hw)
393
{
394
    int live, incr, dead;
395
    ESDVoiceIn *esd = (ESDVoiceIn *) hw;
396

    
397
    if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
398
        return 0;
399
    }
400

    
401
    live = audio_pcm_hw_get_live_in (hw);
402
    dead = hw->samples - live;
403
    incr = audio_MIN (dead, esd->incr);
404
    esd->incr -= incr;
405
    esd->dead = dead - incr;
406
    hw->wpos = esd->wpos;
407
    if (esd->dead > 0) {
408
        audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
409
    }
410
    else {
411
        audio_pt_unlock (&esd->pt, AUDIO_FUNC);
412
    }
413
    return incr;
414
}
415

    
416
static int qesd_read (SWVoiceIn *sw, void *buf, int len)
417
{
418
    return audio_pcm_sw_read (sw, buf, len);
419
}
420

    
421
static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as)
422
{
423
    ESDVoiceIn *esd = (ESDVoiceIn *) hw;
424
    struct audsettings obt_as = *as;
425
    int esdfmt = ESD_STREAM | ESD_RECORD;
426
    int err;
427
    sigset_t set, old_set;
428

    
429
    sigfillset (&set);
430

    
431
    esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
432
    switch (as->fmt) {
433
    case AUD_FMT_S8:
434
    case AUD_FMT_U8:
435
        esdfmt |= ESD_BITS8;
436
        obt_as.fmt = AUD_FMT_U8;
437
        break;
438

    
439
    case AUD_FMT_S16:
440
    case AUD_FMT_U16:
441
        esdfmt |= ESD_BITS16;
442
        obt_as.fmt = AUD_FMT_S16;
443
        break;
444

    
445
    case AUD_FMT_S32:
446
    case AUD_FMT_U32:
447
        dolog ("Will use 16 instead of 32 bit samples\n");
448
        esdfmt |= ESD_BITS16;
449
        obt_as.fmt = AUD_FMT_S16;
450
        break;
451
    }
452
    obt_as.endianness = AUDIO_HOST_ENDIANNESS;
453

    
454
    audio_pcm_init_info (&hw->info, &obt_as);
455

    
456
    hw->samples = conf.samples;
457
    esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
458
    if (!esd->pcm_buf) {
459
        dolog ("Could not allocate buffer (%d bytes)\n",
460
               hw->samples << hw->info.shift);
461
        return -1;
462
    }
463

    
464
    esd->fd = -1;
465

    
466
    err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
467
    if (err) {
468
        qesd_logerr (err, "pthread_sigmask failed\n");
469
        goto fail1;
470
    }
471

    
472
    esd->fd = esd_record_stream (esdfmt, as->freq, conf.adc_host, NULL);
473
    if (esd->fd < 0) {
474
        qesd_logerr (errno, "esd_record_stream failed\n");
475
        goto fail2;
476
    }
477

    
478
    if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) {
479
        goto fail3;
480
    }
481

    
482
    err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
483
    if (err) {
484
        qesd_logerr (err, "pthread_sigmask(restore) failed\n");
485
    }
486

    
487
    return 0;
488

    
489
 fail3:
490
    if (close (esd->fd)) {
491
        qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
492
                     AUDIO_FUNC, esd->fd);
493
    }
494
    esd->fd = -1;
495

    
496
 fail2:
497
    err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
498
    if (err) {
499
        qesd_logerr (err, "pthread_sigmask(restore) failed\n");
500
    }
501

    
502
 fail1:
503
    qemu_free (esd->pcm_buf);
504
    esd->pcm_buf = NULL;
505
    return -1;
506
}
507

    
508
static void qesd_fini_in (HWVoiceIn *hw)
509
{
510
    void *ret;
511
    ESDVoiceIn *esd = (ESDVoiceIn *) hw;
512

    
513
    audio_pt_lock (&esd->pt, AUDIO_FUNC);
514
    esd->done = 1;
515
    audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
516
    audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
517

    
518
    if (esd->fd >= 0) {
519
        if (close (esd->fd)) {
520
            qesd_logerr (errno, "failed to close esd socket\n");
521
        }
522
        esd->fd = -1;
523
    }
524

    
525
    audio_pt_fini (&esd->pt, AUDIO_FUNC);
526

    
527
    qemu_free (esd->pcm_buf);
528
    esd->pcm_buf = NULL;
529
}
530

    
531
static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...)
532
{
533
    (void) hw;
534
    (void) cmd;
535
    return 0;
536
}
537

    
538
/* common */
539
static void *qesd_audio_init (void)
540
{
541
    return &conf;
542
}
543

    
544
static void qesd_audio_fini (void *opaque)
545
{
546
    (void) opaque;
547
    ldebug ("esd_fini");
548
}
549

    
550
struct audio_option qesd_options[] = {
551
    {
552
        .name  = "SAMPLES",
553
        .tag   = AUD_OPT_INT,
554
        .valp  = &conf.samples,
555
        .descr = "buffer size in samples"
556
    },
557
    {
558
        .name  = "DIVISOR",
559
        .tag   = AUD_OPT_INT,
560
        .valp  = &conf.divisor,
561
        .descr = "threshold divisor"
562
    },
563
    {
564
        .name  = "DAC_HOST",
565
        .tag   = AUD_OPT_STR,
566
        .valp  = &conf.dac_host,
567
        .descr = "playback host"
568
    },
569
    {
570
        .name  = "ADC_HOST",
571
        .tag   = AUD_OPT_STR,
572
        .valp  = &conf.adc_host,
573
        .descr = "capture host"
574
    },
575
    { /* End of list */ }
576
};
577

    
578
static struct audio_pcm_ops qesd_pcm_ops = {
579
    .init_out = qesd_init_out,
580
    .fini_out = qesd_fini_out,
581
    .run_out  = qesd_run_out,
582
    .write    = qesd_write,
583
    .ctl_out  = qesd_ctl_out,
584

    
585
    .init_in  = qesd_init_in,
586
    .fini_in  = qesd_fini_in,
587
    .run_in   = qesd_run_in,
588
    .read     = qesd_read,
589
    .ctl_in   = qesd_ctl_in,
590
};
591

    
592
struct audio_driver esd_audio_driver = {
593
    .name           = "esd",
594
    .descr          = "http://en.wikipedia.org/wiki/Esound",
595
    .options        = qesd_options,
596
    .init           = qesd_audio_init,
597
    .fini           = qesd_audio_fini,
598
    .pcm_ops        = &qesd_pcm_ops,
599
    .can_be_default = 0,
600
    .max_voices_out = INT_MAX,
601
    .max_voices_in  = INT_MAX,
602
    .voice_size_out = sizeof (ESDVoiceOut),
603
    .voice_size_in  = sizeof (ESDVoiceIn)
604
};