Statistics
| Branch: | Revision:

root / audio / paaudio.c @ cf2c1839

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->live = 0;
114
        pa->rpos = rpos;
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, int live)
124
{
125
    int decr;
126
    PAVoiceOut *pa = (PAVoiceOut *) hw;
127

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
336
    return 0;
337

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

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

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

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

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

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

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

    
390
    return 0;
391

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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