Statistics
| Branch: | Revision:

root / audio / paaudio.c @ 414f0dab

History | View | Annotate | Download (11.2 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
    1024,
42
    2,
43
    NULL,
44
    NULL,
45
    NULL
46
};
47

    
48
static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
49
{
50
    va_list ap;
51

    
52
    va_start (ap, fmt);
53
    AUD_vlog (AUDIO_CAP, fmt, ap);
54
    va_end (ap);
55

    
56
    AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err));
57
}
58

    
59
static void *qpa_thread_out (void *arg)
60
{
61
    PAVoiceOut *pa = arg;
62
    HWVoiceOut *hw = &pa->hw;
63
    int threshold;
64

    
65
    threshold = conf.divisor ? hw->samples / conf.divisor : 0;
66

    
67
    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
68
        return NULL;
69
    }
70

    
71
    for (;;) {
72
        int decr, to_mix, rpos;
73

    
74
        for (;;) {
75
            if (pa->done) {
76
                goto exit;
77
            }
78

    
79
            if (pa->live > threshold) {
80
                break;
81
            }
82

    
83
            if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
84
                goto exit;
85
            }
86
        }
87

    
88
        decr = to_mix = pa->live;
89
        rpos = hw->rpos;
90

    
91
        if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
92
            return NULL;
93
        }
94

    
95
        while (to_mix) {
96
            int error;
97
            int chunk = audio_MIN (to_mix, hw->samples - rpos);
98
            st_sample_t *src = hw->mix_buf + rpos;
99

    
100
            hw->clip (pa->pcm_buf, src, chunk);
101

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

    
108
            rpos = (rpos + chunk) % hw->samples;
109
            to_mix -= chunk;
110
        }
111

    
112
        if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
113
            return NULL;
114
        }
115

    
116
        pa->rpos = rpos;
117
        pa->live -= decr;
118
        pa->decr += decr;
119
    }
120

    
121
 exit:
122
    audio_pt_unlock (&pa->pt, AUDIO_FUNC);
123
    return NULL;
124
}
125

    
126
static int qpa_run_out (HWVoiceOut *hw)
127
{
128
    int live, decr;
129
    PAVoiceOut *pa = (PAVoiceOut *) hw;
130

    
131
    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
132
        return 0;
133
    }
134

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

    
149
static int qpa_write (SWVoiceOut *sw, void *buf, int len)
150
{
151
    return audio_pcm_sw_write (sw, buf, len);
152
}
153

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

    
161
    threshold = conf.divisor ? hw->samples / conf.divisor : 0;
162

    
163
    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
164
        return NULL;
165
    }
166

    
167
    for (;;) {
168
        int incr, to_grab, wpos;
169

    
170
        for (;;) {
171
            if (pa->done) {
172
                goto exit;
173
            }
174

    
175
            if (pa->dead > threshold) {
176
                break;
177
            }
178

    
179
            if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
180
                goto exit;
181
            }
182
        }
183

    
184
        incr = to_grab = pa->dead;
185
        wpos = hw->wpos;
186

    
187
        if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
188
            return NULL;
189
        }
190

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

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

    
202
            hw->conv (hw->conv_buf + wpos, buf, chunk, &nominal_volume);
203
            wpos = (wpos + chunk) % hw->samples;
204
            to_grab -= chunk;
205
        }
206

    
207
        if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
208
            return NULL;
209
        }
210

    
211
        pa->wpos = wpos;
212
        pa->dead -= incr;
213
        pa->incr += incr;
214
    }
215

    
216
 exit:
217
    audio_pt_unlock (&pa->pt, AUDIO_FUNC);
218
    return NULL;
219
}
220

    
221
static int qpa_run_in (HWVoiceIn *hw)
222
{
223
    int live, incr, dead;
224
    PAVoiceIn *pa = (PAVoiceIn *) hw;
225

    
226
    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
227
        return 0;
228
    }
229

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

    
245
static int qpa_read (SWVoiceIn *sw, void *buf, int len)
246
{
247
    return audio_pcm_sw_read (sw, buf, len);
248
}
249

    
250
static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness)
251
{
252
    int format;
253

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

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

    
298
static int qpa_init_out (HWVoiceOut *hw, audsettings_t *as)
299
{
300
    int error;
301
    static pa_sample_spec ss;
302
    audsettings_t obt_as = *as;
303
    PAVoiceOut *pa = (PAVoiceOut *) hw;
304

    
305
    ss.format = audfmt_to_pa (as->fmt, as->endianness);
306
    ss.channels = as->nchannels;
307
    ss.rate = as->freq;
308

    
309
    obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
310

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

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

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

    
340
    return 0;
341

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

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

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

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

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

    
381
    audio_pcm_init_info (&hw->info, &obt_as);
382
    hw->samples = conf.samples;
383
    pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
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
    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
    qemu_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
    qemu_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
    {"SAMPLES", AUD_OPT_INT, &conf.samples,
473
     "buffer size in samples", NULL, 0},
474

    
475
    {"DIVISOR", AUD_OPT_INT, &conf.divisor,
476
     "threshold divisor", NULL, 0},
477

    
478
    {"SERVER", AUD_OPT_STR, &conf.server,
479
     "server address", NULL, 0},
480

    
481
    {"SINK", AUD_OPT_STR, &conf.sink,
482
     "sink device name", NULL, 0},
483

    
484
    {"SOURCE", AUD_OPT_STR, &conf.source,
485
     "source device name", NULL, 0},
486

    
487
    {NULL, 0, NULL, NULL, NULL, 0}
488
};
489

    
490
struct audio_pcm_ops qpa_pcm_ops = {
491
    qpa_init_out,
492
    qpa_fini_out,
493
    qpa_run_out,
494
    qpa_write,
495
    qpa_ctl_out,
496
    qpa_init_in,
497
    qpa_fini_in,
498
    qpa_run_in,
499
    qpa_read,
500
    qpa_ctl_in
501
};
502

    
503
struct audio_driver pa_audio_driver = {
504
    INIT_FIELD (name           = ) "pa",
505
    INIT_FIELD (descr          = ) "http://www.pulseaudio.org/",
506
    INIT_FIELD (options        = ) qpa_options,
507
    INIT_FIELD (init           = ) qpa_audio_init,
508
    INIT_FIELD (fini           = ) qpa_audio_fini,
509
    INIT_FIELD (pcm_ops        = ) &qpa_pcm_ops,
510
    INIT_FIELD (can_be_default = ) 0,
511
    INIT_FIELD (max_voices_out = ) INT_MAX,
512
    INIT_FIELD (max_voices_in  = ) INT_MAX,
513
    INIT_FIELD (voice_size_out = ) sizeof (PAVoiceOut),
514
    INIT_FIELD (voice_size_in  = ) sizeof (PAVoiceIn)
515
};