Statistics
| Branch: | Revision:

root / audio / paaudio.c @ eedfac6f

History | View | Annotate | Download (23.6 kB)

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

    
5
#include <pulse/pulseaudio.h>
6

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

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

    
22
typedef struct {
23
    HWVoiceIn hw;
24
    int done;
25
    int dead;
26
    int incr;
27
    int wpos;
28
    pa_stream *stream;
29
    void *pcm_buf;
30
    struct audio_pt pt;
31
    const void *read_data;
32
    size_t read_index, read_length;
33
} PAVoiceIn;
34

    
35
typedef struct {
36
    int samples;
37
    char *server;
38
    char *sink;
39
    char *source;
40
    pa_threaded_mainloop *mainloop;
41
    pa_context *context;
42
} paaudio;
43

    
44
static paaudio glob_paaudio = {
45
    .samples = 4096,
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
#ifndef PA_CONTEXT_IS_GOOD
60
static inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x)
61
{
62
    return
63
        x == PA_CONTEXT_CONNECTING ||
64
        x == PA_CONTEXT_AUTHORIZING ||
65
        x == PA_CONTEXT_SETTING_NAME ||
66
        x == PA_CONTEXT_READY;
67
}
68
#endif
69

    
70
#ifndef PA_STREAM_IS_GOOD
71
static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
72
{
73
    return
74
        x == PA_STREAM_CREATING ||
75
        x == PA_STREAM_READY;
76
}
77
#endif
78

    
79
#define CHECK_SUCCESS_GOTO(c, rerror, expression, label)        \
80
    do {                                                        \
81
        if (!(expression)) {                                    \
82
            if (rerror) {                                       \
83
                *(rerror) = pa_context_errno ((c)->context);    \
84
            }                                                   \
85
            goto label;                                         \
86
        }                                                       \
87
    } while (0);
88

    
89
#define CHECK_DEAD_GOTO(c, stream, rerror, label)                       \
90
    do {                                                                \
91
        if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \
92
            !(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream)))) { \
93
            if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \
94
                ((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \
95
                if (rerror) {                                           \
96
                    *(rerror) = pa_context_errno ((c)->context);        \
97
                }                                                       \
98
            } else {                                                    \
99
                if (rerror) {                                           \
100
                    *(rerror) = PA_ERR_BADSTATE;                        \
101
                }                                                       \
102
            }                                                           \
103
            goto label;                                                 \
104
        }                                                               \
105
    } while (0);
106

    
107
static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror)
108
{
109
    paaudio *g = &glob_paaudio;
110

    
111
    pa_threaded_mainloop_lock (g->mainloop);
112

    
113
    CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
114

    
115
    while (length > 0) {
116
        size_t l;
117

    
118
        while (!p->read_data) {
119
            int r;
120

    
121
            r = pa_stream_peek (p->stream, &p->read_data, &p->read_length);
122
            CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
123

    
124
            if (!p->read_data) {
125
                pa_threaded_mainloop_wait (g->mainloop);
126
                CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
127
            } else {
128
                p->read_index = 0;
129
            }
130
        }
131

    
132
        l = p->read_length < length ? p->read_length : length;
133
        memcpy (data, (const uint8_t *) p->read_data+p->read_index, l);
134

    
135
        data = (uint8_t *) data + l;
136
        length -= l;
137

    
138
        p->read_index += l;
139
        p->read_length -= l;
140

    
141
        if (!p->read_length) {
142
            int r;
143

    
144
            r = pa_stream_drop (p->stream);
145
            p->read_data = NULL;
146
            p->read_length = 0;
147
            p->read_index = 0;
148

    
149
            CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
150
        }
151
    }
152

    
153
    pa_threaded_mainloop_unlock (g->mainloop);
154
    return 0;
155

    
156
unlock_and_fail:
157
    pa_threaded_mainloop_unlock (g->mainloop);
158
    return -1;
159
}
160

    
161
static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror)
162
{
163
    paaudio *g = &glob_paaudio;
164

    
165
    pa_threaded_mainloop_lock (g->mainloop);
166

    
167
    CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
168

    
169
    while (length > 0) {
170
        size_t l;
171
        int r;
172

    
173
        while (!(l = pa_stream_writable_size (p->stream))) {
174
            pa_threaded_mainloop_wait (g->mainloop);
175
            CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
176
        }
177

    
178
        CHECK_SUCCESS_GOTO (g, rerror, l != (size_t) -1, unlock_and_fail);
179

    
180
        if (l > length) {
181
            l = length;
182
        }
183

    
184
        r = pa_stream_write (p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
185
        CHECK_SUCCESS_GOTO (g, rerror, r >= 0, unlock_and_fail);
186

    
187
        data = (const uint8_t *) data + l;
188
        length -= l;
189
    }
190

    
191
    pa_threaded_mainloop_unlock (g->mainloop);
192
    return 0;
193

    
194
unlock_and_fail:
195
    pa_threaded_mainloop_unlock (g->mainloop);
196
    return -1;
197
}
198

    
199
static void *qpa_thread_out (void *arg)
200
{
201
    PAVoiceOut *pa = arg;
202
    HWVoiceOut *hw = &pa->hw;
203

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

    
208
    for (;;) {
209
        int decr, to_mix, rpos;
210

    
211
        for (;;) {
212
            if (pa->done) {
213
                goto exit;
214
            }
215

    
216
            if (pa->live > 0) {
217
                break;
218
            }
219

    
220
            if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
221
                goto exit;
222
            }
223
        }
224

    
225
        decr = to_mix = audio_MIN (pa->live, glob_paaudio.samples >> 2);
226
        rpos = pa->rpos;
227

    
228
        if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
229
            return NULL;
230
        }
231

    
232
        while (to_mix) {
233
            int error;
234
            int chunk = audio_MIN (to_mix, hw->samples - rpos);
235
            struct st_sample *src = hw->mix_buf + rpos;
236

    
237
            hw->clip (pa->pcm_buf, src, chunk);
238

    
239
            if (qpa_simple_write (pa, pa->pcm_buf,
240
                                  chunk << hw->info.shift, &error) < 0) {
241
                qpa_logerr (error, "pa_simple_write failed\n");
242
                return NULL;
243
            }
244

    
245
            rpos = (rpos + chunk) % hw->samples;
246
            to_mix -= chunk;
247
        }
248

    
249
        if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
250
            return NULL;
251
        }
252

    
253
        pa->rpos = rpos;
254
        pa->live -= decr;
255
        pa->decr += decr;
256
    }
257

    
258
 exit:
259
    audio_pt_unlock (&pa->pt, AUDIO_FUNC);
260
    return NULL;
261
}
262

    
263
static int qpa_run_out (HWVoiceOut *hw, int live)
264
{
265
    int decr;
266
    PAVoiceOut *pa = (PAVoiceOut *) hw;
267

    
268
    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
269
        return 0;
270
    }
271

    
272
    decr = audio_MIN (live, pa->decr);
273
    pa->decr -= decr;
274
    pa->live = live - decr;
275
    hw->rpos = pa->rpos;
276
    if (pa->live > 0) {
277
        audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
278
    }
279
    else {
280
        audio_pt_unlock (&pa->pt, AUDIO_FUNC);
281
    }
282
    return decr;
283
}
284

    
285
static int qpa_write (SWVoiceOut *sw, void *buf, int len)
286
{
287
    return audio_pcm_sw_write (sw, buf, len);
288
}
289

    
290
/* capture */
291
static void *qpa_thread_in (void *arg)
292
{
293
    PAVoiceIn *pa = arg;
294
    HWVoiceIn *hw = &pa->hw;
295

    
296
    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
297
        return NULL;
298
    }
299

    
300
    for (;;) {
301
        int incr, to_grab, wpos;
302

    
303
        for (;;) {
304
            if (pa->done) {
305
                goto exit;
306
            }
307

    
308
            if (pa->dead > 0) {
309
                break;
310
            }
311

    
312
            if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
313
                goto exit;
314
            }
315
        }
316

    
317
        incr = to_grab = audio_MIN (pa->dead, glob_paaudio.samples >> 2);
318
        wpos = pa->wpos;
319

    
320
        if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
321
            return NULL;
322
        }
323

    
324
        while (to_grab) {
325
            int error;
326
            int chunk = audio_MIN (to_grab, hw->samples - wpos);
327
            void *buf = advance (pa->pcm_buf, wpos);
328

    
329
            if (qpa_simple_read (pa, buf,
330
                                 chunk << hw->info.shift, &error) < 0) {
331
                qpa_logerr (error, "pa_simple_read failed\n");
332
                return NULL;
333
            }
334

    
335
            hw->conv (hw->conv_buf + wpos, buf, chunk);
336
            wpos = (wpos + chunk) % hw->samples;
337
            to_grab -= chunk;
338
        }
339

    
340
        if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
341
            return NULL;
342
        }
343

    
344
        pa->wpos = wpos;
345
        pa->dead -= incr;
346
        pa->incr += incr;
347
    }
348

    
349
 exit:
350
    audio_pt_unlock (&pa->pt, AUDIO_FUNC);
351
    return NULL;
352
}
353

    
354
static int qpa_run_in (HWVoiceIn *hw)
355
{
356
    int live, incr, dead;
357
    PAVoiceIn *pa = (PAVoiceIn *) hw;
358

    
359
    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
360
        return 0;
361
    }
362

    
363
    live = audio_pcm_hw_get_live_in (hw);
364
    dead = hw->samples - live;
365
    incr = audio_MIN (dead, pa->incr);
366
    pa->incr -= incr;
367
    pa->dead = dead - incr;
368
    hw->wpos = pa->wpos;
369
    if (pa->dead > 0) {
370
        audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
371
    }
372
    else {
373
        audio_pt_unlock (&pa->pt, AUDIO_FUNC);
374
    }
375
    return incr;
376
}
377

    
378
static int qpa_read (SWVoiceIn *sw, void *buf, int len)
379
{
380
    return audio_pcm_sw_read (sw, buf, len);
381
}
382

    
383
static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness)
384
{
385
    int format;
386

    
387
    switch (afmt) {
388
    case AUD_FMT_S8:
389
    case AUD_FMT_U8:
390
        format = PA_SAMPLE_U8;
391
        break;
392
    case AUD_FMT_S16:
393
    case AUD_FMT_U16:
394
        format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
395
        break;
396
    case AUD_FMT_S32:
397
    case AUD_FMT_U32:
398
        format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
399
        break;
400
    default:
401
        dolog ("Internal logic error: Bad audio format %d\n", afmt);
402
        format = PA_SAMPLE_U8;
403
        break;
404
    }
405
    return format;
406
}
407

    
408
static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
409
{
410
    switch (fmt) {
411
    case PA_SAMPLE_U8:
412
        return AUD_FMT_U8;
413
    case PA_SAMPLE_S16BE:
414
        *endianness = 1;
415
        return AUD_FMT_S16;
416
    case PA_SAMPLE_S16LE:
417
        *endianness = 0;
418
        return AUD_FMT_S16;
419
    case PA_SAMPLE_S32BE:
420
        *endianness = 1;
421
        return AUD_FMT_S32;
422
    case PA_SAMPLE_S32LE:
423
        *endianness = 0;
424
        return AUD_FMT_S32;
425
    default:
426
        dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
427
        return AUD_FMT_U8;
428
    }
429
}
430

    
431
static void context_state_cb (pa_context *c, void *userdata)
432
{
433
    paaudio *g = &glob_paaudio;
434

    
435
    switch (pa_context_get_state(c)) {
436
    case PA_CONTEXT_READY:
437
    case PA_CONTEXT_TERMINATED:
438
    case PA_CONTEXT_FAILED:
439
        pa_threaded_mainloop_signal (g->mainloop, 0);
440
        break;
441

    
442
    case PA_CONTEXT_UNCONNECTED:
443
    case PA_CONTEXT_CONNECTING:
444
    case PA_CONTEXT_AUTHORIZING:
445
    case PA_CONTEXT_SETTING_NAME:
446
        break;
447
    }
448
}
449

    
450
static void stream_state_cb (pa_stream *s, void * userdata)
451
{
452
    paaudio *g = &glob_paaudio;
453

    
454
    switch (pa_stream_get_state (s)) {
455

    
456
    case PA_STREAM_READY:
457
    case PA_STREAM_FAILED:
458
    case PA_STREAM_TERMINATED:
459
        pa_threaded_mainloop_signal (g->mainloop, 0);
460
        break;
461

    
462
    case PA_STREAM_UNCONNECTED:
463
    case PA_STREAM_CREATING:
464
        break;
465
    }
466
}
467

    
468
static void stream_request_cb (pa_stream *s, size_t length, void *userdata)
469
{
470
    paaudio *g = &glob_paaudio;
471

    
472
    pa_threaded_mainloop_signal (g->mainloop, 0);
473
}
474

    
475
static pa_stream *qpa_simple_new (
476
        const char *server,
477
        const char *name,
478
        pa_stream_direction_t dir,
479
        const char *dev,
480
        const char *stream_name,
481
        const pa_sample_spec *ss,
482
        const pa_channel_map *map,
483
        const pa_buffer_attr *attr,
484
        int *rerror)
485
{
486
    paaudio *g = &glob_paaudio;
487
    int r;
488
    pa_stream *stream;
489

    
490
    pa_threaded_mainloop_lock (g->mainloop);
491

    
492
    stream = pa_stream_new (g->context, name, ss, map);
493
    if (!stream) {
494
        goto fail;
495
    }
496

    
497
    pa_stream_set_state_callback (stream, stream_state_cb, g);
498
    pa_stream_set_read_callback (stream, stream_request_cb, g);
499
    pa_stream_set_write_callback (stream, stream_request_cb, g);
500

    
501
    if (dir == PA_STREAM_PLAYBACK) {
502
        r = pa_stream_connect_playback (stream, dev, attr,
503
                                        PA_STREAM_INTERPOLATE_TIMING
504
#ifdef PA_STREAM_ADJUST_LATENCY
505
                                        |PA_STREAM_ADJUST_LATENCY
506
#endif
507
                                        |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
508
    } else {
509
        r = pa_stream_connect_record (stream, dev, attr,
510
                                      PA_STREAM_INTERPOLATE_TIMING
511
#ifdef PA_STREAM_ADJUST_LATENCY
512
                                      |PA_STREAM_ADJUST_LATENCY
513
#endif
514
                                      |PA_STREAM_AUTO_TIMING_UPDATE);
515
    }
516

    
517
    if (r < 0) {
518
      goto fail;
519
    }
520

    
521
    pa_threaded_mainloop_unlock (g->mainloop);
522

    
523
    return stream;
524

    
525
fail:
526
    pa_threaded_mainloop_unlock (g->mainloop);
527

    
528
    if (stream) {
529
        pa_stream_unref (stream);
530
    }
531

    
532
    *rerror = pa_context_errno (g->context);
533

    
534
    return NULL;
535
}
536

    
537
static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
538
{
539
    int error;
540
    static pa_sample_spec ss;
541
    static pa_buffer_attr ba;
542
    struct audsettings obt_as = *as;
543
    PAVoiceOut *pa = (PAVoiceOut *) hw;
544

    
545
    ss.format = audfmt_to_pa (as->fmt, as->endianness);
546
    ss.channels = as->nchannels;
547
    ss.rate = as->freq;
548

    
549
    /*
550
     * qemu audio tick runs at 250 Hz (by default), so processing
551
     * data chunks worth 4 ms of sound should be a good fit.
552
     */
553
    ba.tlength = pa_usec_to_bytes (4 * 1000, &ss);
554
    ba.minreq = pa_usec_to_bytes (2 * 1000, &ss);
555
    ba.maxlength = -1;
556
    ba.prebuf = -1;
557

    
558
    obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
559

    
560
    pa->stream = qpa_simple_new (
561
        glob_paaudio.server,
562
        "qemu",
563
        PA_STREAM_PLAYBACK,
564
        glob_paaudio.sink,
565
        "pcm.playback",
566
        &ss,
567
        NULL,                   /* channel map */
568
        &ba,                    /* buffering attributes */
569
        &error
570
        );
571
    if (!pa->stream) {
572
        qpa_logerr (error, "pa_simple_new for playback failed\n");
573
        goto fail1;
574
    }
575

    
576
    audio_pcm_init_info (&hw->info, &obt_as);
577
    hw->samples = glob_paaudio.samples;
578
    pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
579
    pa->rpos = hw->rpos;
580
    if (!pa->pcm_buf) {
581
        dolog ("Could not allocate buffer (%d bytes)\n",
582
               hw->samples << hw->info.shift);
583
        goto fail2;
584
    }
585

    
586
    if (audio_pt_init (&pa->pt, qpa_thread_out, hw, AUDIO_CAP, AUDIO_FUNC)) {
587
        goto fail3;
588
    }
589

    
590
    return 0;
591

    
592
 fail3:
593
    g_free (pa->pcm_buf);
594
    pa->pcm_buf = NULL;
595
 fail2:
596
    if (pa->stream) {
597
        pa_stream_unref (pa->stream);
598
        pa->stream = NULL;
599
    }
600
 fail1:
601
    return -1;
602
}
603

    
604
static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
605
{
606
    int error;
607
    static pa_sample_spec ss;
608
    struct audsettings obt_as = *as;
609
    PAVoiceIn *pa = (PAVoiceIn *) hw;
610

    
611
    ss.format = audfmt_to_pa (as->fmt, as->endianness);
612
    ss.channels = as->nchannels;
613
    ss.rate = as->freq;
614

    
615
    obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
616

    
617
    pa->stream = qpa_simple_new (
618
        glob_paaudio.server,
619
        "qemu",
620
        PA_STREAM_RECORD,
621
        glob_paaudio.source,
622
        "pcm.capture",
623
        &ss,
624
        NULL,                   /* channel map */
625
        NULL,                   /* buffering attributes */
626
        &error
627
        );
628
    if (!pa->stream) {
629
        qpa_logerr (error, "pa_simple_new for capture failed\n");
630
        goto fail1;
631
    }
632

    
633
    audio_pcm_init_info (&hw->info, &obt_as);
634
    hw->samples = glob_paaudio.samples;
635
    pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
636
    pa->wpos = hw->wpos;
637
    if (!pa->pcm_buf) {
638
        dolog ("Could not allocate buffer (%d bytes)\n",
639
               hw->samples << hw->info.shift);
640
        goto fail2;
641
    }
642

    
643
    if (audio_pt_init (&pa->pt, qpa_thread_in, hw, AUDIO_CAP, AUDIO_FUNC)) {
644
        goto fail3;
645
    }
646

    
647
    return 0;
648

    
649
 fail3:
650
    g_free (pa->pcm_buf);
651
    pa->pcm_buf = NULL;
652
 fail2:
653
    if (pa->stream) {
654
        pa_stream_unref (pa->stream);
655
        pa->stream = NULL;
656
    }
657
 fail1:
658
    return -1;
659
}
660

    
661
static void qpa_fini_out (HWVoiceOut *hw)
662
{
663
    void *ret;
664
    PAVoiceOut *pa = (PAVoiceOut *) hw;
665

    
666
    audio_pt_lock (&pa->pt, AUDIO_FUNC);
667
    pa->done = 1;
668
    audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
669
    audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
670

    
671
    if (pa->stream) {
672
        pa_stream_unref (pa->stream);
673
        pa->stream = NULL;
674
    }
675

    
676
    audio_pt_fini (&pa->pt, AUDIO_FUNC);
677
    g_free (pa->pcm_buf);
678
    pa->pcm_buf = NULL;
679
}
680

    
681
static void qpa_fini_in (HWVoiceIn *hw)
682
{
683
    void *ret;
684
    PAVoiceIn *pa = (PAVoiceIn *) hw;
685

    
686
    audio_pt_lock (&pa->pt, AUDIO_FUNC);
687
    pa->done = 1;
688
    audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
689
    audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
690

    
691
    if (pa->stream) {
692
        pa_stream_unref (pa->stream);
693
        pa->stream = NULL;
694
    }
695

    
696
    audio_pt_fini (&pa->pt, AUDIO_FUNC);
697
    g_free (pa->pcm_buf);
698
    pa->pcm_buf = NULL;
699
}
700

    
701
static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
702
{
703
    PAVoiceOut *pa = (PAVoiceOut *) hw;
704
    pa_operation *op;
705
    pa_cvolume v;
706
    paaudio *g = &glob_paaudio;
707

    
708
#ifdef PA_CHECK_VERSION    /* macro is present in 0.9.16+ */
709
    pa_cvolume_init (&v);  /* function is present in 0.9.13+ */
710
#endif
711

    
712
    switch (cmd) {
713
    case VOICE_VOLUME:
714
        {
715
            SWVoiceOut *sw;
716
            va_list ap;
717

    
718
            va_start (ap, cmd);
719
            sw = va_arg (ap, SWVoiceOut *);
720
            va_end (ap);
721

    
722
            v.channels = 2;
723
            v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
724
            v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
725

    
726
            pa_threaded_mainloop_lock (g->mainloop);
727

    
728
            op = pa_context_set_sink_input_volume (g->context,
729
                pa_stream_get_index (pa->stream),
730
                &v, NULL, NULL);
731
            if (!op)
732
                qpa_logerr (pa_context_errno (g->context),
733
                            "set_sink_input_volume() failed\n");
734
            else
735
                pa_operation_unref (op);
736

    
737
            op = pa_context_set_sink_input_mute (g->context,
738
                pa_stream_get_index (pa->stream),
739
               sw->vol.mute, NULL, NULL);
740
            if (!op) {
741
                qpa_logerr (pa_context_errno (g->context),
742
                            "set_sink_input_mute() failed\n");
743
            } else {
744
                pa_operation_unref (op);
745
            }
746

    
747
            pa_threaded_mainloop_unlock (g->mainloop);
748
        }
749
    }
750
    return 0;
751
}
752

    
753
static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
754
{
755
    PAVoiceIn *pa = (PAVoiceIn *) hw;
756
    pa_operation *op;
757
    pa_cvolume v;
758
    paaudio *g = &glob_paaudio;
759

    
760
#ifdef PA_CHECK_VERSION
761
    pa_cvolume_init (&v);
762
#endif
763

    
764
    switch (cmd) {
765
    case VOICE_VOLUME:
766
        {
767
            SWVoiceIn *sw;
768
            va_list ap;
769

    
770
            va_start (ap, cmd);
771
            sw = va_arg (ap, SWVoiceIn *);
772
            va_end (ap);
773

    
774
            v.channels = 2;
775
            v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
776
            v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
777

    
778
            pa_threaded_mainloop_lock (g->mainloop);
779

    
780
            /* FIXME: use the upcoming "set_source_output_{volume,mute}" */
781
            op = pa_context_set_source_volume_by_index (g->context,
782
                pa_stream_get_device_index (pa->stream),
783
                &v, NULL, NULL);
784
            if (!op) {
785
                qpa_logerr (pa_context_errno (g->context),
786
                            "set_source_volume() failed\n");
787
            } else {
788
                pa_operation_unref(op);
789
            }
790

    
791
            op = pa_context_set_source_mute_by_index (g->context,
792
                pa_stream_get_index (pa->stream),
793
                sw->vol.mute, NULL, NULL);
794
            if (!op) {
795
                qpa_logerr (pa_context_errno (g->context),
796
                            "set_source_mute() failed\n");
797
            } else {
798
                pa_operation_unref (op);
799
            }
800

    
801
            pa_threaded_mainloop_unlock (g->mainloop);
802
        }
803
    }
804
    return 0;
805
}
806

    
807
/* common */
808
static void *qpa_audio_init (void)
809
{
810
    paaudio *g = &glob_paaudio;
811

    
812
    g->mainloop = pa_threaded_mainloop_new ();
813
    if (!g->mainloop) {
814
        goto fail;
815
    }
816

    
817
    g->context = pa_context_new (pa_threaded_mainloop_get_api (g->mainloop), glob_paaudio.server);
818
    if (!g->context) {
819
        goto fail;
820
    }
821

    
822
    pa_context_set_state_callback (g->context, context_state_cb, g);
823

    
824
    if (pa_context_connect (g->context, glob_paaudio.server, 0, NULL) < 0) {
825
        qpa_logerr (pa_context_errno (g->context),
826
                    "pa_context_connect() failed\n");
827
        goto fail;
828
    }
829

    
830
    pa_threaded_mainloop_lock (g->mainloop);
831

    
832
    if (pa_threaded_mainloop_start (g->mainloop) < 0) {
833
        goto unlock_and_fail;
834
    }
835

    
836
    for (;;) {
837
        pa_context_state_t state;
838

    
839
        state = pa_context_get_state (g->context);
840

    
841
        if (state == PA_CONTEXT_READY) {
842
            break;
843
        }
844

    
845
        if (!PA_CONTEXT_IS_GOOD (state)) {
846
            qpa_logerr (pa_context_errno (g->context),
847
                        "Wrong context state\n");
848
            goto unlock_and_fail;
849
        }
850

    
851
        /* Wait until the context is ready */
852
        pa_threaded_mainloop_wait (g->mainloop);
853
    }
854

    
855
    pa_threaded_mainloop_unlock (g->mainloop);
856

    
857
    return &glob_paaudio;
858

    
859
unlock_and_fail:
860
    pa_threaded_mainloop_unlock (g->mainloop);
861
fail:
862
    AUD_log (AUDIO_CAP, "Failed to initialize PA context");
863
    return NULL;
864
}
865

    
866
static void qpa_audio_fini (void *opaque)
867
{
868
    paaudio *g = opaque;
869

    
870
    if (g->mainloop) {
871
        pa_threaded_mainloop_stop (g->mainloop);
872
    }
873

    
874
    if (g->context) {
875
        pa_context_disconnect (g->context);
876
        pa_context_unref (g->context);
877
        g->context = NULL;
878
    }
879

    
880
    if (g->mainloop) {
881
        pa_threaded_mainloop_free (g->mainloop);
882
    }
883

    
884
    g->mainloop = NULL;
885
}
886

    
887
struct audio_option qpa_options[] = {
888
    {
889
        .name  = "SAMPLES",
890
        .tag   = AUD_OPT_INT,
891
        .valp  = &glob_paaudio.samples,
892
        .descr = "buffer size in samples"
893
    },
894
    {
895
        .name  = "SERVER",
896
        .tag   = AUD_OPT_STR,
897
        .valp  = &glob_paaudio.server,
898
        .descr = "server address"
899
    },
900
    {
901
        .name  = "SINK",
902
        .tag   = AUD_OPT_STR,
903
        .valp  = &glob_paaudio.sink,
904
        .descr = "sink device name"
905
    },
906
    {
907
        .name  = "SOURCE",
908
        .tag   = AUD_OPT_STR,
909
        .valp  = &glob_paaudio.source,
910
        .descr = "source device name"
911
    },
912
    { /* End of list */ }
913
};
914

    
915
static struct audio_pcm_ops qpa_pcm_ops = {
916
    .init_out = qpa_init_out,
917
    .fini_out = qpa_fini_out,
918
    .run_out  = qpa_run_out,
919
    .write    = qpa_write,
920
    .ctl_out  = qpa_ctl_out,
921

    
922
    .init_in  = qpa_init_in,
923
    .fini_in  = qpa_fini_in,
924
    .run_in   = qpa_run_in,
925
    .read     = qpa_read,
926
    .ctl_in   = qpa_ctl_in
927
};
928

    
929
struct audio_driver pa_audio_driver = {
930
    .name           = "pa",
931
    .descr          = "http://www.pulseaudio.org/",
932
    .options        = qpa_options,
933
    .init           = qpa_audio_init,
934
    .fini           = qpa_audio_fini,
935
    .pcm_ops        = &qpa_pcm_ops,
936
    .can_be_default = 1,
937
    .max_voices_out = INT_MAX,
938
    .max_voices_in  = INT_MAX,
939
    .voice_size_out = sizeof (PAVoiceOut),
940
    .voice_size_in  = sizeof (PAVoiceIn),
941
    .ctl_caps       = VOICE_VOLUME_CAP
942
};