Statistics
| Branch: | Revision:

root / audio / paaudio.c @ 7267c094

History | View | Annotate | Download (11.5 kB)

1
/* public domain */
2
#include "qemu-common.h"
3
#include "audio.h"
4

    
5
#include <pulse/simple.h>
6
#include <pulse/error.h>
7

    
8
#define AUDIO_CAP "pulseaudio"
9
#include "audio_int.h"
10
#include "audio_pt_int.h"
11

    
12
typedef struct {
13
    HWVoiceOut hw;
14
    int done;
15
    int live;
16
    int decr;
17
    int rpos;
18
    pa_simple *s;
19
    void *pcm_buf;
20
    struct audio_pt pt;
21
} PAVoiceOut;
22

    
23
typedef struct {
24
    HWVoiceIn hw;
25
    int done;
26
    int dead;
27
    int incr;
28
    int wpos;
29
    pa_simple *s;
30
    void *pcm_buf;
31
    struct audio_pt pt;
32
} PAVoiceIn;
33

    
34
static struct {
35
    int samples;
36
    char *server;
37
    char *sink;
38
    char *source;
39
} conf = {
40
    .samples = 4096,
41
};
42

    
43
static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
44
{
45
    va_list ap;
46

    
47
    va_start (ap, fmt);
48
    AUD_vlog (AUDIO_CAP, fmt, ap);
49
    va_end (ap);
50

    
51
    AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err));
52
}
53

    
54
static void *qpa_thread_out (void *arg)
55
{
56
    PAVoiceOut *pa = arg;
57
    HWVoiceOut *hw = &pa->hw;
58

    
59
    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
60
        return NULL;
61
    }
62

    
63
    for (;;) {
64
        int decr, to_mix, rpos;
65

    
66
        for (;;) {
67
            if (pa->done) {
68
                goto exit;
69
            }
70

    
71
            if (pa->live > 0) {
72
                break;
73
            }
74

    
75
            if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
76
                goto exit;
77
            }
78
        }
79

    
80
        decr = to_mix = audio_MIN (pa->live, conf.samples >> 2);
81
        rpos = pa->rpos;
82

    
83
        if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
84
            return NULL;
85
        }
86

    
87
        while (to_mix) {
88
            int error;
89
            int chunk = audio_MIN (to_mix, hw->samples - rpos);
90
            struct st_sample *src = hw->mix_buf + rpos;
91

    
92
            hw->clip (pa->pcm_buf, src, chunk);
93

    
94
            if (pa_simple_write (pa->s, pa->pcm_buf,
95
                                 chunk << hw->info.shift, &error) < 0) {
96
                qpa_logerr (error, "pa_simple_write failed\n");
97
                return NULL;
98
            }
99

    
100
            rpos = (rpos + chunk) % hw->samples;
101
            to_mix -= chunk;
102
        }
103

    
104
        if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
105
            return NULL;
106
        }
107

    
108
        pa->rpos = rpos;
109
        pa->live -= decr;
110
        pa->decr += decr;
111
    }
112

    
113
 exit:
114
    audio_pt_unlock (&pa->pt, AUDIO_FUNC);
115
    return NULL;
116
}
117

    
118
static int qpa_run_out (HWVoiceOut *hw, int live)
119
{
120
    int decr;
121
    PAVoiceOut *pa = (PAVoiceOut *) hw;
122

    
123
    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
124
        return 0;
125
    }
126

    
127
    decr = audio_MIN (live, pa->decr);
128
    pa->decr -= decr;
129
    pa->live = live - decr;
130
    hw->rpos = pa->rpos;
131
    if (pa->live > 0) {
132
        audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
133
    }
134
    else {
135
        audio_pt_unlock (&pa->pt, AUDIO_FUNC);
136
    }
137
    return decr;
138
}
139

    
140
static int qpa_write (SWVoiceOut *sw, void *buf, int len)
141
{
142
    return audio_pcm_sw_write (sw, buf, len);
143
}
144

    
145
/* capture */
146
static void *qpa_thread_in (void *arg)
147
{
148
    PAVoiceIn *pa = arg;
149
    HWVoiceIn *hw = &pa->hw;
150

    
151
    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
152
        return NULL;
153
    }
154

    
155
    for (;;) {
156
        int incr, to_grab, wpos;
157

    
158
        for (;;) {
159
            if (pa->done) {
160
                goto exit;
161
            }
162

    
163
            if (pa->dead > 0) {
164
                break;
165
            }
166

    
167
            if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
168
                goto exit;
169
            }
170
        }
171

    
172
        incr = to_grab = audio_MIN (pa->dead, conf.samples >> 2);
173
        wpos = pa->wpos;
174

    
175
        if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
176
            return NULL;
177
        }
178

    
179
        while (to_grab) {
180
            int error;
181
            int chunk = audio_MIN (to_grab, hw->samples - wpos);
182
            void *buf = advance (pa->pcm_buf, wpos);
183

    
184
            if (pa_simple_read (pa->s, buf,
185
                                chunk << hw->info.shift, &error) < 0) {
186
                qpa_logerr (error, "pa_simple_read failed\n");
187
                return NULL;
188
            }
189

    
190
            hw->conv (hw->conv_buf + wpos, buf, chunk);
191
            wpos = (wpos + chunk) % hw->samples;
192
            to_grab -= chunk;
193
        }
194

    
195
        if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
196
            return NULL;
197
        }
198

    
199
        pa->wpos = wpos;
200
        pa->dead -= incr;
201
        pa->incr += incr;
202
    }
203

    
204
 exit:
205
    audio_pt_unlock (&pa->pt, AUDIO_FUNC);
206
    return NULL;
207
}
208

    
209
static int qpa_run_in (HWVoiceIn *hw)
210
{
211
    int live, incr, dead;
212
    PAVoiceIn *pa = (PAVoiceIn *) hw;
213

    
214
    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
215
        return 0;
216
    }
217

    
218
    live = audio_pcm_hw_get_live_in (hw);
219
    dead = hw->samples - live;
220
    incr = audio_MIN (dead, pa->incr);
221
    pa->incr -= incr;
222
    pa->dead = dead - incr;
223
    hw->wpos = pa->wpos;
224
    if (pa->dead > 0) {
225
        audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
226
    }
227
    else {
228
        audio_pt_unlock (&pa->pt, AUDIO_FUNC);
229
    }
230
    return incr;
231
}
232

    
233
static int qpa_read (SWVoiceIn *sw, void *buf, int len)
234
{
235
    return audio_pcm_sw_read (sw, buf, len);
236
}
237

    
238
static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness)
239
{
240
    int format;
241

    
242
    switch (afmt) {
243
    case AUD_FMT_S8:
244
    case AUD_FMT_U8:
245
        format = PA_SAMPLE_U8;
246
        break;
247
    case AUD_FMT_S16:
248
    case AUD_FMT_U16:
249
        format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
250
        break;
251
    case AUD_FMT_S32:
252
    case AUD_FMT_U32:
253
        format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
254
        break;
255
    default:
256
        dolog ("Internal logic error: Bad audio format %d\n", afmt);
257
        format = PA_SAMPLE_U8;
258
        break;
259
    }
260
    return format;
261
}
262

    
263
static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
264
{
265
    switch (fmt) {
266
    case PA_SAMPLE_U8:
267
        return AUD_FMT_U8;
268
    case PA_SAMPLE_S16BE:
269
        *endianness = 1;
270
        return AUD_FMT_S16;
271
    case PA_SAMPLE_S16LE:
272
        *endianness = 0;
273
        return AUD_FMT_S16;
274
    case PA_SAMPLE_S32BE:
275
        *endianness = 1;
276
        return AUD_FMT_S32;
277
    case PA_SAMPLE_S32LE:
278
        *endianness = 0;
279
        return AUD_FMT_S32;
280
    default:
281
        dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
282
        return AUD_FMT_U8;
283
    }
284
}
285

    
286
static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
287
{
288
    int error;
289
    static pa_sample_spec ss;
290
    static pa_buffer_attr ba;
291
    struct audsettings obt_as = *as;
292
    PAVoiceOut *pa = (PAVoiceOut *) hw;
293

    
294
    ss.format = audfmt_to_pa (as->fmt, as->endianness);
295
    ss.channels = as->nchannels;
296
    ss.rate = as->freq;
297

    
298
    /*
299
     * qemu audio tick runs at 250 Hz (by default), so processing
300
     * data chunks worth 4 ms of sound should be a good fit.
301
     */
302
    ba.tlength = pa_usec_to_bytes (4 * 1000, &ss);
303
    ba.minreq = pa_usec_to_bytes (2 * 1000, &ss);
304
    ba.maxlength = -1;
305
    ba.prebuf = -1;
306

    
307
    obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
308

    
309
    pa->s = pa_simple_new (
310
        conf.server,
311
        "qemu",
312
        PA_STREAM_PLAYBACK,
313
        conf.sink,
314
        "pcm.playback",
315
        &ss,
316
        NULL,                   /* channel map */
317
        &ba,                    /* buffering attributes */
318
        &error
319
        );
320
    if (!pa->s) {
321
        qpa_logerr (error, "pa_simple_new for playback failed\n");
322
        goto fail1;
323
    }
324

    
325
    audio_pcm_init_info (&hw->info, &obt_as);
326
    hw->samples = conf.samples;
327
    pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
328
    pa->rpos = hw->rpos;
329
    if (!pa->pcm_buf) {
330
        dolog ("Could not allocate buffer (%d bytes)\n",
331
               hw->samples << hw->info.shift);
332
        goto fail2;
333
    }
334

    
335
    if (audio_pt_init (&pa->pt, qpa_thread_out, hw, AUDIO_CAP, AUDIO_FUNC)) {
336
        goto fail3;
337
    }
338

    
339
    return 0;
340

    
341
 fail3:
342
    g_free (pa->pcm_buf);
343
    pa->pcm_buf = NULL;
344
 fail2:
345
    pa_simple_free (pa->s);
346
    pa->s = NULL;
347
 fail1:
348
    return -1;
349
}
350

    
351
static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
352
{
353
    int error;
354
    static pa_sample_spec ss;
355
    struct audsettings obt_as = *as;
356
    PAVoiceIn *pa = (PAVoiceIn *) hw;
357

    
358
    ss.format = audfmt_to_pa (as->fmt, as->endianness);
359
    ss.channels = as->nchannels;
360
    ss.rate = as->freq;
361

    
362
    obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
363

    
364
    pa->s = pa_simple_new (
365
        conf.server,
366
        "qemu",
367
        PA_STREAM_RECORD,
368
        conf.source,
369
        "pcm.capture",
370
        &ss,
371
        NULL,                   /* channel map */
372
        NULL,                   /* buffering attributes */
373
        &error
374
        );
375
    if (!pa->s) {
376
        qpa_logerr (error, "pa_simple_new for capture failed\n");
377
        goto fail1;
378
    }
379

    
380
    audio_pcm_init_info (&hw->info, &obt_as);
381
    hw->samples = conf.samples;
382
    pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
383
    pa->wpos = hw->wpos;
384
    if (!pa->pcm_buf) {
385
        dolog ("Could not allocate buffer (%d bytes)\n",
386
               hw->samples << hw->info.shift);
387
        goto fail2;
388
    }
389

    
390
    if (audio_pt_init (&pa->pt, qpa_thread_in, hw, AUDIO_CAP, AUDIO_FUNC)) {
391
        goto fail3;
392
    }
393

    
394
    return 0;
395

    
396
 fail3:
397
    g_free (pa->pcm_buf);
398
    pa->pcm_buf = NULL;
399
 fail2:
400
    pa_simple_free (pa->s);
401
    pa->s = NULL;
402
 fail1:
403
    return -1;
404
}
405

    
406
static void qpa_fini_out (HWVoiceOut *hw)
407
{
408
    void *ret;
409
    PAVoiceOut *pa = (PAVoiceOut *) hw;
410

    
411
    audio_pt_lock (&pa->pt, AUDIO_FUNC);
412
    pa->done = 1;
413
    audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
414
    audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
415

    
416
    if (pa->s) {
417
        pa_simple_free (pa->s);
418
        pa->s = NULL;
419
    }
420

    
421
    audio_pt_fini (&pa->pt, AUDIO_FUNC);
422
    g_free (pa->pcm_buf);
423
    pa->pcm_buf = NULL;
424
}
425

    
426
static void qpa_fini_in (HWVoiceIn *hw)
427
{
428
    void *ret;
429
    PAVoiceIn *pa = (PAVoiceIn *) hw;
430

    
431
    audio_pt_lock (&pa->pt, AUDIO_FUNC);
432
    pa->done = 1;
433
    audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
434
    audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
435

    
436
    if (pa->s) {
437
        pa_simple_free (pa->s);
438
        pa->s = NULL;
439
    }
440

    
441
    audio_pt_fini (&pa->pt, AUDIO_FUNC);
442
    g_free (pa->pcm_buf);
443
    pa->pcm_buf = NULL;
444
}
445

    
446
static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
447
{
448
    (void) hw;
449
    (void) cmd;
450
    return 0;
451
}
452

    
453
static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
454
{
455
    (void) hw;
456
    (void) cmd;
457
    return 0;
458
}
459

    
460
/* common */
461
static void *qpa_audio_init (void)
462
{
463
    return &conf;
464
}
465

    
466
static void qpa_audio_fini (void *opaque)
467
{
468
    (void) opaque;
469
}
470

    
471
struct audio_option qpa_options[] = {
472
    {
473
        .name  = "SAMPLES",
474
        .tag   = AUD_OPT_INT,
475
        .valp  = &conf.samples,
476
        .descr = "buffer size in samples"
477
    },
478
    {
479
        .name  = "SERVER",
480
        .tag   = AUD_OPT_STR,
481
        .valp  = &conf.server,
482
        .descr = "server address"
483
    },
484
    {
485
        .name  = "SINK",
486
        .tag   = AUD_OPT_STR,
487
        .valp  = &conf.sink,
488
        .descr = "sink device name"
489
    },
490
    {
491
        .name  = "SOURCE",
492
        .tag   = AUD_OPT_STR,
493
        .valp  = &conf.source,
494
        .descr = "source device name"
495
    },
496
    { /* End of list */ }
497
};
498

    
499
static struct audio_pcm_ops qpa_pcm_ops = {
500
    .init_out = qpa_init_out,
501
    .fini_out = qpa_fini_out,
502
    .run_out  = qpa_run_out,
503
    .write    = qpa_write,
504
    .ctl_out  = qpa_ctl_out,
505

    
506
    .init_in  = qpa_init_in,
507
    .fini_in  = qpa_fini_in,
508
    .run_in   = qpa_run_in,
509
    .read     = qpa_read,
510
    .ctl_in   = qpa_ctl_in
511
};
512

    
513
struct audio_driver pa_audio_driver = {
514
    .name           = "pa",
515
    .descr          = "http://www.pulseaudio.org/",
516
    .options        = qpa_options,
517
    .init           = qpa_audio_init,
518
    .fini           = qpa_audio_fini,
519
    .pcm_ops        = &qpa_pcm_ops,
520
    .can_be_default = 1,
521
    .max_voices_out = INT_MAX,
522
    .max_voices_in  = INT_MAX,
523
    .voice_size_out = sizeof (PAVoiceOut),
524
    .voice_size_in  = sizeof (PAVoiceIn)
525
};