Statistics
| Branch: | Revision:

root / audio / paaudio.c @ 98f9f48c

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
    int divisor;
37
    char *server;
38
    char *sink;
39
    char *source;
40
} conf = {
41
    .samples = 1024,
42
    .divisor = 2,
43
};
44

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

    
49
    va_start (ap, fmt);
50
    AUD_vlog (AUDIO_CAP, fmt, ap);
51
    va_end (ap);
52

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

    
56
static void *qpa_thread_out (void *arg)
57
{
58
    PAVoiceOut *pa = arg;
59
    HWVoiceOut *hw = &pa->hw;
60
    int threshold;
61

    
62
    threshold = conf.divisor ? hw->samples / conf.divisor : 0;
63

    
64
    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
65
        return NULL;
66
    }
67

    
68
    for (;;) {
69
        int decr, to_mix, rpos;
70

    
71
        for (;;) {
72
            if (pa->done) {
73
                goto exit;
74
            }
75

    
76
            if (pa->live > threshold) {
77
                break;
78
            }
79

    
80
            if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
81
                goto exit;
82
            }
83
        }
84

    
85
        decr = to_mix = pa->live;
86
        rpos = hw->rpos;
87

    
88
        if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
89
            return NULL;
90
        }
91

    
92
        while (to_mix) {
93
            int error;
94
            int chunk = audio_MIN (to_mix, hw->samples - rpos);
95
            struct st_sample *src = hw->mix_buf + rpos;
96

    
97
            hw->clip (pa->pcm_buf, src, chunk);
98

    
99
            if (pa_simple_write (pa->s, pa->pcm_buf,
100
                                 chunk << hw->info.shift, &error) < 0) {
101
                qpa_logerr (error, "pa_simple_write failed\n");
102
                return NULL;
103
            }
104

    
105
            rpos = (rpos + chunk) % hw->samples;
106
            to_mix -= chunk;
107
        }
108

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

    
113
        pa->rpos = rpos;
114
        pa->live -= decr;
115
        pa->decr += decr;
116
    }
117

    
118
 exit:
119
    audio_pt_unlock (&pa->pt, AUDIO_FUNC);
120
    return NULL;
121
}
122

    
123
static int qpa_run_out (HWVoiceOut *hw)
124
{
125
    int live, decr;
126
    PAVoiceOut *pa = (PAVoiceOut *) hw;
127

    
128
    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
129
        return 0;
130
    }
131

    
132
    live = audio_pcm_hw_get_live_out (hw);
133
    decr = audio_MIN (live, pa->decr);
134
    pa->decr -= decr;
135
    pa->live = live - decr;
136
    hw->rpos = pa->rpos;
137
    if (pa->live > 0) {
138
        audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
139
    }
140
    else {
141
        audio_pt_unlock (&pa->pt, AUDIO_FUNC);
142
    }
143
    return decr;
144
}
145

    
146
static int qpa_write (SWVoiceOut *sw, void *buf, int len)
147
{
148
    return audio_pcm_sw_write (sw, buf, len);
149
}
150

    
151
/* capture */
152
static void *qpa_thread_in (void *arg)
153
{
154
    PAVoiceIn *pa = arg;
155
    HWVoiceIn *hw = &pa->hw;
156
    int threshold;
157

    
158
    threshold = conf.divisor ? hw->samples / conf.divisor : 0;
159

    
160
    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
161
        return NULL;
162
    }
163

    
164
    for (;;) {
165
        int incr, to_grab, wpos;
166

    
167
        for (;;) {
168
            if (pa->done) {
169
                goto exit;
170
            }
171

    
172
            if (pa->dead > threshold) {
173
                break;
174
            }
175

    
176
            if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
177
                goto exit;
178
            }
179
        }
180

    
181
        incr = to_grab = pa->dead;
182
        wpos = hw->wpos;
183

    
184
        if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
185
            return NULL;
186
        }
187

    
188
        while (to_grab) {
189
            int error;
190
            int chunk = audio_MIN (to_grab, hw->samples - wpos);
191
            void *buf = advance (pa->pcm_buf, wpos);
192

    
193
            if (pa_simple_read (pa->s, buf,
194
                                chunk << hw->info.shift, &error) < 0) {
195
                qpa_logerr (error, "pa_simple_read failed\n");
196
                return NULL;
197
            }
198

    
199
            hw->conv (hw->conv_buf + wpos, buf, chunk, &nominal_volume);
200
            wpos = (wpos + chunk) % hw->samples;
201
            to_grab -= chunk;
202
        }
203

    
204
        if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
205
            return NULL;
206
        }
207

    
208
        pa->wpos = wpos;
209
        pa->dead -= incr;
210
        pa->incr += incr;
211
    }
212

    
213
 exit:
214
    audio_pt_unlock (&pa->pt, AUDIO_FUNC);
215
    return NULL;
216
}
217

    
218
static int qpa_run_in (HWVoiceIn *hw)
219
{
220
    int live, incr, dead;
221
    PAVoiceIn *pa = (PAVoiceIn *) hw;
222

    
223
    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
224
        return 0;
225
    }
226

    
227
    live = audio_pcm_hw_get_live_in (hw);
228
    dead = hw->samples - live;
229
    incr = audio_MIN (dead, pa->incr);
230
    pa->incr -= incr;
231
    pa->dead = dead - incr;
232
    hw->wpos = pa->wpos;
233
    if (pa->dead > 0) {
234
        audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
235
    }
236
    else {
237
        audio_pt_unlock (&pa->pt, AUDIO_FUNC);
238
    }
239
    return incr;
240
}
241

    
242
static int qpa_read (SWVoiceIn *sw, void *buf, int len)
243
{
244
    return audio_pcm_sw_read (sw, buf, len);
245
}
246

    
247
static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness)
248
{
249
    int format;
250

    
251
    switch (afmt) {
252
    case AUD_FMT_S8:
253
    case AUD_FMT_U8:
254
        format = PA_SAMPLE_U8;
255
        break;
256
    case AUD_FMT_S16:
257
    case AUD_FMT_U16:
258
        format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
259
        break;
260
    case AUD_FMT_S32:
261
    case AUD_FMT_U32:
262
        format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
263
        break;
264
    default:
265
        dolog ("Internal logic error: Bad audio format %d\n", afmt);
266
        format = PA_SAMPLE_U8;
267
        break;
268
    }
269
    return format;
270
}
271

    
272
static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
273
{
274
    switch (fmt) {
275
    case PA_SAMPLE_U8:
276
        return AUD_FMT_U8;
277
    case PA_SAMPLE_S16BE:
278
        *endianness = 1;
279
        return AUD_FMT_S16;
280
    case PA_SAMPLE_S16LE:
281
        *endianness = 0;
282
        return AUD_FMT_S16;
283
    case PA_SAMPLE_S32BE:
284
        *endianness = 1;
285
        return AUD_FMT_S32;
286
    case PA_SAMPLE_S32LE:
287
        *endianness = 0;
288
        return AUD_FMT_S32;
289
    default:
290
        dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
291
        return AUD_FMT_U8;
292
    }
293
}
294

    
295
static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
296
{
297
    int error;
298
    static pa_sample_spec ss;
299
    struct audsettings obt_as = *as;
300
    PAVoiceOut *pa = (PAVoiceOut *) hw;
301

    
302
    ss.format = audfmt_to_pa (as->fmt, as->endianness);
303
    ss.channels = as->nchannels;
304
    ss.rate = as->freq;
305

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

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

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

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

    
337
    return 0;
338

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

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

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

    
360
    obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
361

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

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

    
387
    if (audio_pt_init (&pa->pt, qpa_thread_in, hw, AUDIO_CAP, AUDIO_FUNC)) {
388
        goto fail3;
389
    }
390

    
391
    return 0;
392

    
393
 fail3:
394
    qemu_free (pa->pcm_buf);
395
    pa->pcm_buf = NULL;
396
 fail2:
397
    pa_simple_free (pa->s);
398
    pa->s = NULL;
399
 fail1:
400
    return -1;
401
}
402

    
403
static void qpa_fini_out (HWVoiceOut *hw)
404
{
405
    void *ret;
406
    PAVoiceOut *pa = (PAVoiceOut *) hw;
407

    
408
    audio_pt_lock (&pa->pt, AUDIO_FUNC);
409
    pa->done = 1;
410
    audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
411
    audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
412

    
413
    if (pa->s) {
414
        pa_simple_free (pa->s);
415
        pa->s = NULL;
416
    }
417

    
418
    audio_pt_fini (&pa->pt, AUDIO_FUNC);
419
    qemu_free (pa->pcm_buf);
420
    pa->pcm_buf = NULL;
421
}
422

    
423
static void qpa_fini_in (HWVoiceIn *hw)
424
{
425
    void *ret;
426
    PAVoiceIn *pa = (PAVoiceIn *) hw;
427

    
428
    audio_pt_lock (&pa->pt, AUDIO_FUNC);
429
    pa->done = 1;
430
    audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
431
    audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
432

    
433
    if (pa->s) {
434
        pa_simple_free (pa->s);
435
        pa->s = NULL;
436
    }
437

    
438
    audio_pt_fini (&pa->pt, AUDIO_FUNC);
439
    qemu_free (pa->pcm_buf);
440
    pa->pcm_buf = NULL;
441
}
442

    
443
static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
444
{
445
    (void) hw;
446
    (void) cmd;
447
    return 0;
448
}
449

    
450
static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
451
{
452
    (void) hw;
453
    (void) cmd;
454
    return 0;
455
}
456

    
457
/* common */
458
static void *qpa_audio_init (void)
459
{
460
    return &conf;
461
}
462

    
463
static void qpa_audio_fini (void *opaque)
464
{
465
    (void) opaque;
466
}
467

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

    
502
static struct audio_pcm_ops qpa_pcm_ops = {
503
    .init_out = qpa_init_out,
504
    .fini_out = qpa_fini_out,
505
    .run_out  = qpa_run_out,
506
    .write    = qpa_write,
507
    .ctl_out  = qpa_ctl_out,
508

    
509
    .init_in  = qpa_init_in,
510
    .fini_in  = qpa_fini_in,
511
    .run_in   = qpa_run_in,
512
    .read     = qpa_read,
513
    .ctl_in   = qpa_ctl_in
514
};
515

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