Statistics
| Branch: | Revision:

root / audio / esdaudio.c @ 23fb600b

History | View | Annotate | Download (14.3 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
    1024,
62
    2,
63
    NULL,
64
    NULL
65
};
66

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

    
71
    va_start (ap, fmt);
72
    AUD_vlog (AUDIO_CAP, fmt, ap);
73
    va_end (ap);
74

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

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

    
85
    threshold = conf.divisor ? hw->samples / conf.divisor : 0;
86

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

    
91
    for (;;) {
92
        int decr, to_mix, rpos;
93

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

    
99
            if (esd->live > threshold) {
100
                break;
101
            }
102

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

    
108
        decr = to_mix = esd->live;
109
        rpos = hw->rpos;
110

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

    
115
        while (to_mix) {
116
            ssize_t written;
117
            int chunk = audio_MIN (to_mix, hw->samples - rpos);
118
            st_sample_t *src = hw->mix_buf + rpos;
119

    
120
            hw->clip (esd->pcm_buf, src, chunk);
121

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

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

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

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

    
153
        esd->rpos = rpos;
154
        esd->live -= decr;
155
        esd->decr += decr;
156
    }
157

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

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

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

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

    
186
static int qesd_write (SWVoiceOut *sw, void *buf, int len)
187
{
188
    return audio_pcm_sw_write (sw, buf, len);
189
}
190

    
191
static int qesd_init_out (HWVoiceOut *hw, audsettings_t *as)
192
{
193
    ESDVoiceOut *esd = (ESDVoiceOut *) hw;
194
    audsettings_t obt_as = *as;
195
    int esdfmt = ESD_STREAM | ESD_PLAY;
196
    int err;
197
    sigset_t set, old_set;
198

    
199
    sigfillset (&set);
200

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

    
209
    case AUD_FMT_S32:
210
    case AUD_FMT_U32:
211
        dolog ("Will use 16 instead of 32 bit samples\n");
212

    
213
    case AUD_FMT_S16:
214
    case AUD_FMT_U16:
215
    deffmt:
216
        esdfmt |= ESD_BITS16;
217
        obt_as.fmt = AUD_FMT_S16;
218
        break;
219

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

    
224
    }
225
    obt_as.endianness = AUDIO_HOST_ENDIANNESS;
226

    
227
    audio_pcm_init_info (&hw->info, &obt_as);
228

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

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

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

    
250
    if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) {
251
        goto fail3;
252
    }
253

    
254
    err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
255
    if (err) {
256
        qesd_logerr (err, "pthread_sigmask(restore) failed\n");
257
    }
258

    
259
    return 0;
260

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

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

    
274
 fail1:
275
    qemu_free (esd->pcm_buf);
276
    esd->pcm_buf = NULL;
277
    return -1;
278
}
279

    
280
static void qesd_fini_out (HWVoiceOut *hw)
281
{
282
    void *ret;
283
    ESDVoiceOut *esd = (ESDVoiceOut *) hw;
284

    
285
    audio_pt_lock (&esd->pt, AUDIO_FUNC);
286
    esd->done = 1;
287
    audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
288
    audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
289

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

    
297
    audio_pt_fini (&esd->pt, AUDIO_FUNC);
298

    
299
    qemu_free (esd->pcm_buf);
300
    esd->pcm_buf = NULL;
301
}
302

    
303
static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...)
304
{
305
    (void) hw;
306
    (void) cmd;
307
    return 0;
308
}
309

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

    
317
    threshold = conf.divisor ? hw->samples / conf.divisor : 0;
318

    
319
    if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
320
        return NULL;
321
    }
322

    
323
    for (;;) {
324
        int incr, to_grab, wpos;
325

    
326
        for (;;) {
327
            if (esd->done) {
328
                goto exit;
329
            }
330

    
331
            if (esd->dead > threshold) {
332
                break;
333
            }
334

    
335
            if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
336
                goto exit;
337
            }
338
        }
339

    
340
        incr = to_grab = esd->dead;
341
        wpos = hw->wpos;
342

    
343
        if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
344
            return NULL;
345
        }
346

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

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

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

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

    
381
        if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
382
            return NULL;
383
        }
384

    
385
        esd->wpos = wpos;
386
        esd->dead -= incr;
387
        esd->incr += incr;
388
    }
389

    
390
 exit:
391
    audio_pt_unlock (&esd->pt, AUDIO_FUNC);
392
    return NULL;
393
}
394

    
395
static int qesd_run_in (HWVoiceIn *hw)
396
{
397
    int live, incr, dead;
398
    ESDVoiceIn *esd = (ESDVoiceIn *) hw;
399

    
400
    if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
401
        return 0;
402
    }
403

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

    
419
static int qesd_read (SWVoiceIn *sw, void *buf, int len)
420
{
421
    return audio_pcm_sw_read (sw, buf, len);
422
}
423

    
424
static int qesd_init_in (HWVoiceIn *hw, audsettings_t *as)
425
{
426
    ESDVoiceIn *esd = (ESDVoiceIn *) hw;
427
    audsettings_t obt_as = *as;
428
    int esdfmt = ESD_STREAM | ESD_RECORD;
429
    int err;
430
    sigset_t set, old_set;
431

    
432
    sigfillset (&set);
433

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

    
442
    case AUD_FMT_S16:
443
    case AUD_FMT_U16:
444
        esdfmt |= ESD_BITS16;
445
        obt_as.fmt = AUD_FMT_S16;
446
        break;
447

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

    
457
    audio_pcm_init_info (&hw->info, &obt_as);
458

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

    
467
    esd->fd = -1;
468

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

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

    
481
    if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) {
482
        goto fail3;
483
    }
484

    
485
    err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
486
    if (err) {
487
        qesd_logerr (err, "pthread_sigmask(restore) failed\n");
488
    }
489

    
490
    return 0;
491

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

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

    
505
 fail1:
506
    qemu_free (esd->pcm_buf);
507
    esd->pcm_buf = NULL;
508
    return -1;
509
}
510

    
511
static void qesd_fini_in (HWVoiceIn *hw)
512
{
513
    void *ret;
514
    ESDVoiceIn *esd = (ESDVoiceIn *) hw;
515

    
516
    audio_pt_lock (&esd->pt, AUDIO_FUNC);
517
    esd->done = 1;
518
    audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
519
    audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
520

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

    
528
    audio_pt_fini (&esd->pt, AUDIO_FUNC);
529

    
530
    qemu_free (esd->pcm_buf);
531
    esd->pcm_buf = NULL;
532
}
533

    
534
static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...)
535
{
536
    (void) hw;
537
    (void) cmd;
538
    return 0;
539
}
540

    
541
/* common */
542
static void *qesd_audio_init (void)
543
{
544
    return &conf;
545
}
546

    
547
static void qesd_audio_fini (void *opaque)
548
{
549
    (void) opaque;
550
    ldebug ("esd_fini");
551
}
552

    
553
struct audio_option qesd_options[] = {
554
    {"SAMPLES", AUD_OPT_INT, &conf.samples,
555
     "buffer size in samples", NULL, 0},
556

    
557
    {"DIVISOR", AUD_OPT_INT, &conf.divisor,
558
     "threshold divisor", NULL, 0},
559

    
560
    {"DAC_HOST", AUD_OPT_STR, &conf.dac_host,
561
     "playback host", NULL, 0},
562

    
563
    {"ADC_HOST", AUD_OPT_STR, &conf.adc_host,
564
     "capture host", NULL, 0},
565

    
566
    {NULL, 0, NULL, NULL, NULL, 0}
567
};
568

    
569
struct audio_pcm_ops qesd_pcm_ops = {
570
    qesd_init_out,
571
    qesd_fini_out,
572
    qesd_run_out,
573
    qesd_write,
574
    qesd_ctl_out,
575

    
576
    qesd_init_in,
577
    qesd_fini_in,
578
    qesd_run_in,
579
    qesd_read,
580
    qesd_ctl_in,
581
};
582

    
583
struct audio_driver esd_audio_driver = {
584
    INIT_FIELD (name           = ) "esd",
585
    INIT_FIELD (descr          = )
586
    "http://en.wikipedia.org/wiki/Esound",
587
    INIT_FIELD (options        = ) qesd_options,
588
    INIT_FIELD (init           = ) qesd_audio_init,
589
    INIT_FIELD (fini           = ) qesd_audio_fini,
590
    INIT_FIELD (pcm_ops        = ) &qesd_pcm_ops,
591
    INIT_FIELD (can_be_default = ) 0,
592
    INIT_FIELD (max_voices_out = ) INT_MAX,
593
    INIT_FIELD (max_voices_in  = ) INT_MAX,
594
    INIT_FIELD (voice_size_out = ) sizeof (ESDVoiceOut),
595
    INIT_FIELD (voice_size_in  = ) sizeof (ESDVoiceIn)
596
};