]> Git Repo - qemu.git/blob - audio/paaudio.c
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
[qemu.git] / audio / paaudio.c
1 /* public domain */
2 #include "qemu/osdep.h"
3 #include "qemu-common.h"
4 #include "audio.h"
5 #include "qapi/opts-visitor.h"
6
7 #include <pulse/pulseaudio.h>
8
9 #define AUDIO_CAP "pulseaudio"
10 #include "audio_int.h"
11 #include "audio_pt_int.h"
12
13 typedef struct {
14     Audiodev *dev;
15     pa_threaded_mainloop *mainloop;
16     pa_context *context;
17 } paaudio;
18
19 typedef struct {
20     HWVoiceOut hw;
21     int done;
22     int live;
23     int decr;
24     int rpos;
25     pa_stream *stream;
26     void *pcm_buf;
27     struct audio_pt pt;
28     paaudio *g;
29     int samples;
30 } PAVoiceOut;
31
32 typedef struct {
33     HWVoiceIn hw;
34     int done;
35     int dead;
36     int incr;
37     int wpos;
38     pa_stream *stream;
39     void *pcm_buf;
40     struct audio_pt pt;
41     const void *read_data;
42     size_t read_index, read_length;
43     paaudio *g;
44     int samples;
45 } PAVoiceIn;
46
47 static void qpa_audio_fini(void *opaque);
48
49 static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
50 {
51     va_list ap;
52
53     va_start (ap, fmt);
54     AUD_vlog (AUDIO_CAP, fmt, ap);
55     va_end (ap);
56
57     AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err));
58 }
59
60 #ifndef PA_CONTEXT_IS_GOOD
61 static inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x)
62 {
63     return
64         x == PA_CONTEXT_CONNECTING ||
65         x == PA_CONTEXT_AUTHORIZING ||
66         x == PA_CONTEXT_SETTING_NAME ||
67         x == PA_CONTEXT_READY;
68 }
69 #endif
70
71 #ifndef PA_STREAM_IS_GOOD
72 static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
73 {
74     return
75         x == PA_STREAM_CREATING ||
76         x == PA_STREAM_READY;
77 }
78 #endif
79
80 #define CHECK_SUCCESS_GOTO(c, rerror, expression, label)        \
81     do {                                                        \
82         if (!(expression)) {                                    \
83             if (rerror) {                                       \
84                 *(rerror) = pa_context_errno ((c)->context);    \
85             }                                                   \
86             goto label;                                         \
87         }                                                       \
88     } while (0)
89
90 #define CHECK_DEAD_GOTO(c, stream, rerror, label)                       \
91     do {                                                                \
92         if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \
93             !(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream)))) { \
94             if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \
95                 ((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \
96                 if (rerror) {                                           \
97                     *(rerror) = pa_context_errno ((c)->context);        \
98                 }                                                       \
99             } else {                                                    \
100                 if (rerror) {                                           \
101                     *(rerror) = PA_ERR_BADSTATE;                        \
102                 }                                                       \
103             }                                                           \
104             goto label;                                                 \
105         }                                                               \
106     } while (0)
107
108 static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror)
109 {
110     paaudio *g = p->g;
111
112     pa_threaded_mainloop_lock (g->mainloop);
113
114     CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
115
116     while (length > 0) {
117         size_t l;
118
119         while (!p->read_data) {
120             int r;
121
122             r = pa_stream_peek (p->stream, &p->read_data, &p->read_length);
123             CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
124
125             if (!p->read_data) {
126                 pa_threaded_mainloop_wait (g->mainloop);
127                 CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
128             } else {
129                 p->read_index = 0;
130             }
131         }
132
133         l = p->read_length < length ? p->read_length : length;
134         memcpy (data, (const uint8_t *) p->read_data+p->read_index, l);
135
136         data = (uint8_t *) data + l;
137         length -= l;
138
139         p->read_index += l;
140         p->read_length -= l;
141
142         if (!p->read_length) {
143             int r;
144
145             r = pa_stream_drop (p->stream);
146             p->read_data = NULL;
147             p->read_length = 0;
148             p->read_index = 0;
149
150             CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
151         }
152     }
153
154     pa_threaded_mainloop_unlock (g->mainloop);
155     return 0;
156
157 unlock_and_fail:
158     pa_threaded_mainloop_unlock (g->mainloop);
159     return -1;
160 }
161
162 static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror)
163 {
164     paaudio *g = p->g;
165
166     pa_threaded_mainloop_lock (g->mainloop);
167
168     CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
169
170     while (length > 0) {
171         size_t l;
172         int r;
173
174         while (!(l = pa_stream_writable_size (p->stream))) {
175             pa_threaded_mainloop_wait (g->mainloop);
176             CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
177         }
178
179         CHECK_SUCCESS_GOTO (g, rerror, l != (size_t) -1, unlock_and_fail);
180
181         if (l > length) {
182             l = length;
183         }
184
185         r = pa_stream_write (p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
186         CHECK_SUCCESS_GOTO (g, rerror, r >= 0, unlock_and_fail);
187
188         data = (const uint8_t *) data + l;
189         length -= l;
190     }
191
192     pa_threaded_mainloop_unlock (g->mainloop);
193     return 0;
194
195 unlock_and_fail:
196     pa_threaded_mainloop_unlock (g->mainloop);
197     return -1;
198 }
199
200 static void *qpa_thread_out (void *arg)
201 {
202     PAVoiceOut *pa = arg;
203     HWVoiceOut *hw = &pa->hw;
204
205     if (audio_pt_lock(&pa->pt, __func__)) {
206         return NULL;
207     }
208
209     for (;;) {
210         int decr, to_mix, rpos;
211
212         for (;;) {
213             if (pa->done) {
214                 goto exit;
215             }
216
217             if (pa->live > 0) {
218                 break;
219             }
220
221             if (audio_pt_wait(&pa->pt, __func__)) {
222                 goto exit;
223             }
224         }
225
226         decr = to_mix = audio_MIN(pa->live, pa->samples >> 5);
227         rpos = pa->rpos;
228
229         if (audio_pt_unlock(&pa->pt, __func__)) {
230             return NULL;
231         }
232
233         while (to_mix) {
234             int error;
235             int chunk = audio_MIN (to_mix, hw->samples - rpos);
236             struct st_sample *src = hw->mix_buf + rpos;
237
238             hw->clip (pa->pcm_buf, src, chunk);
239
240             if (qpa_simple_write (pa, pa->pcm_buf,
241                                   chunk << hw->info.shift, &error) < 0) {
242                 qpa_logerr (error, "pa_simple_write failed\n");
243                 return NULL;
244             }
245
246             rpos = (rpos + chunk) % hw->samples;
247             to_mix -= chunk;
248         }
249
250         if (audio_pt_lock(&pa->pt, __func__)) {
251             return NULL;
252         }
253
254         pa->rpos = rpos;
255         pa->live -= decr;
256         pa->decr += decr;
257     }
258
259  exit:
260     audio_pt_unlock(&pa->pt, __func__);
261     return NULL;
262 }
263
264 static int qpa_run_out (HWVoiceOut *hw, int live)
265 {
266     int decr;
267     PAVoiceOut *pa = (PAVoiceOut *) hw;
268
269     if (audio_pt_lock(&pa->pt, __func__)) {
270         return 0;
271     }
272
273     decr = audio_MIN (live, pa->decr);
274     pa->decr -= decr;
275     pa->live = live - decr;
276     hw->rpos = pa->rpos;
277     if (pa->live > 0) {
278         audio_pt_unlock_and_signal(&pa->pt, __func__);
279     }
280     else {
281         audio_pt_unlock(&pa->pt, __func__);
282     }
283     return decr;
284 }
285
286 static int qpa_write (SWVoiceOut *sw, void *buf, int len)
287 {
288     return audio_pcm_sw_write (sw, buf, len);
289 }
290
291 /* capture */
292 static void *qpa_thread_in (void *arg)
293 {
294     PAVoiceIn *pa = arg;
295     HWVoiceIn *hw = &pa->hw;
296
297     if (audio_pt_lock(&pa->pt, __func__)) {
298         return NULL;
299     }
300
301     for (;;) {
302         int incr, to_grab, wpos;
303
304         for (;;) {
305             if (pa->done) {
306                 goto exit;
307             }
308
309             if (pa->dead > 0) {
310                 break;
311             }
312
313             if (audio_pt_wait(&pa->pt, __func__)) {
314                 goto exit;
315             }
316         }
317
318         incr = to_grab = audio_MIN(pa->dead, pa->samples >> 5);
319         wpos = pa->wpos;
320
321         if (audio_pt_unlock(&pa->pt, __func__)) {
322             return NULL;
323         }
324
325         while (to_grab) {
326             int error;
327             int chunk = audio_MIN (to_grab, hw->samples - wpos);
328             void *buf = advance (pa->pcm_buf, wpos);
329
330             if (qpa_simple_read (pa, buf,
331                                  chunk << hw->info.shift, &error) < 0) {
332                 qpa_logerr (error, "pa_simple_read failed\n");
333                 return NULL;
334             }
335
336             hw->conv (hw->conv_buf + wpos, buf, chunk);
337             wpos = (wpos + chunk) % hw->samples;
338             to_grab -= chunk;
339         }
340
341         if (audio_pt_lock(&pa->pt, __func__)) {
342             return NULL;
343         }
344
345         pa->wpos = wpos;
346         pa->dead -= incr;
347         pa->incr += incr;
348     }
349
350  exit:
351     audio_pt_unlock(&pa->pt, __func__);
352     return NULL;
353 }
354
355 static int qpa_run_in (HWVoiceIn *hw)
356 {
357     int live, incr, dead;
358     PAVoiceIn *pa = (PAVoiceIn *) hw;
359
360     if (audio_pt_lock(&pa->pt, __func__)) {
361         return 0;
362     }
363
364     live = audio_pcm_hw_get_live_in (hw);
365     dead = hw->samples - live;
366     incr = audio_MIN (dead, pa->incr);
367     pa->incr -= incr;
368     pa->dead = dead - incr;
369     hw->wpos = pa->wpos;
370     if (pa->dead > 0) {
371         audio_pt_unlock_and_signal(&pa->pt, __func__);
372     }
373     else {
374         audio_pt_unlock(&pa->pt, __func__);
375     }
376     return incr;
377 }
378
379 static int qpa_read (SWVoiceIn *sw, void *buf, int len)
380 {
381     return audio_pcm_sw_read (sw, buf, len);
382 }
383
384 static pa_sample_format_t audfmt_to_pa (AudioFormat afmt, int endianness)
385 {
386     int format;
387
388     switch (afmt) {
389     case AUDIO_FORMAT_S8:
390     case AUDIO_FORMAT_U8:
391         format = PA_SAMPLE_U8;
392         break;
393     case AUDIO_FORMAT_S16:
394     case AUDIO_FORMAT_U16:
395         format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
396         break;
397     case AUDIO_FORMAT_S32:
398     case AUDIO_FORMAT_U32:
399         format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
400         break;
401     default:
402         dolog ("Internal logic error: Bad audio format %d\n", afmt);
403         format = PA_SAMPLE_U8;
404         break;
405     }
406     return format;
407 }
408
409 static AudioFormat pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
410 {
411     switch (fmt) {
412     case PA_SAMPLE_U8:
413         return AUDIO_FORMAT_U8;
414     case PA_SAMPLE_S16BE:
415         *endianness = 1;
416         return AUDIO_FORMAT_S16;
417     case PA_SAMPLE_S16LE:
418         *endianness = 0;
419         return AUDIO_FORMAT_S16;
420     case PA_SAMPLE_S32BE:
421         *endianness = 1;
422         return AUDIO_FORMAT_S32;
423     case PA_SAMPLE_S32LE:
424         *endianness = 0;
425         return AUDIO_FORMAT_S32;
426     default:
427         dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
428         return AUDIO_FORMAT_U8;
429     }
430 }
431
432 static void context_state_cb (pa_context *c, void *userdata)
433 {
434     paaudio *g = userdata;
435
436     switch (pa_context_get_state(c)) {
437     case PA_CONTEXT_READY:
438     case PA_CONTEXT_TERMINATED:
439     case PA_CONTEXT_FAILED:
440         pa_threaded_mainloop_signal (g->mainloop, 0);
441         break;
442
443     case PA_CONTEXT_UNCONNECTED:
444     case PA_CONTEXT_CONNECTING:
445     case PA_CONTEXT_AUTHORIZING:
446     case PA_CONTEXT_SETTING_NAME:
447         break;
448     }
449 }
450
451 static void stream_state_cb (pa_stream *s, void * userdata)
452 {
453     paaudio *g = userdata;
454
455     switch (pa_stream_get_state (s)) {
456
457     case PA_STREAM_READY:
458     case PA_STREAM_FAILED:
459     case PA_STREAM_TERMINATED:
460         pa_threaded_mainloop_signal (g->mainloop, 0);
461         break;
462
463     case PA_STREAM_UNCONNECTED:
464     case PA_STREAM_CREATING:
465         break;
466     }
467 }
468
469 static void stream_request_cb (pa_stream *s, size_t length, void *userdata)
470 {
471     paaudio *g = userdata;
472
473     pa_threaded_mainloop_signal (g->mainloop, 0);
474 }
475
476 static pa_stream *qpa_simple_new (
477         paaudio *g,
478         const char *name,
479         pa_stream_direction_t dir,
480         const char *dev,
481         const pa_sample_spec *ss,
482         const pa_channel_map *map,
483         const pa_buffer_attr *attr,
484         int *rerror)
485 {
486     int r;
487     pa_stream *stream;
488
489     pa_threaded_mainloop_lock (g->mainloop);
490
491     stream = pa_stream_new (g->context, name, ss, map);
492     if (!stream) {
493         goto fail;
494     }
495
496     pa_stream_set_state_callback (stream, stream_state_cb, g);
497     pa_stream_set_read_callback (stream, stream_request_cb, g);
498     pa_stream_set_write_callback (stream, stream_request_cb, g);
499
500     if (dir == PA_STREAM_PLAYBACK) {
501         r = pa_stream_connect_playback (stream, dev, attr,
502                                         PA_STREAM_INTERPOLATE_TIMING
503 #ifdef PA_STREAM_ADJUST_LATENCY
504                                         |PA_STREAM_ADJUST_LATENCY
505 #endif
506                                         |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
507     } else {
508         r = pa_stream_connect_record (stream, dev, attr,
509                                       PA_STREAM_INTERPOLATE_TIMING
510 #ifdef PA_STREAM_ADJUST_LATENCY
511                                       |PA_STREAM_ADJUST_LATENCY
512 #endif
513                                       |PA_STREAM_AUTO_TIMING_UPDATE);
514     }
515
516     if (r < 0) {
517       goto fail;
518     }
519
520     pa_threaded_mainloop_unlock (g->mainloop);
521
522     return stream;
523
524 fail:
525     pa_threaded_mainloop_unlock (g->mainloop);
526
527     if (stream) {
528         pa_stream_unref (stream);
529     }
530
531     *rerror = pa_context_errno (g->context);
532
533     return NULL;
534 }
535
536 static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
537                         void *drv_opaque)
538 {
539     int error;
540     pa_sample_spec ss;
541     pa_buffer_attr ba;
542     struct audsettings obt_as = *as;
543     PAVoiceOut *pa = (PAVoiceOut *) hw;
544     paaudio *g = pa->g = drv_opaque;
545     AudiodevPaOptions *popts = &g->dev->u.pa;
546     AudiodevPaPerDirectionOptions *ppdo = popts->out;
547
548     ss.format = audfmt_to_pa (as->fmt, as->endianness);
549     ss.channels = as->nchannels;
550     ss.rate = as->freq;
551
552     /*
553      * qemu audio tick runs at 100 Hz (by default), so processing
554      * data chunks worth 10 ms of sound should be a good fit.
555      */
556     ba.tlength = pa_usec_to_bytes (10 * 1000, &ss);
557     ba.minreq = pa_usec_to_bytes (5 * 1000, &ss);
558     ba.maxlength = -1;
559     ba.prebuf = -1;
560
561     obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
562
563     pa->stream = qpa_simple_new (
564         g,
565         "qemu",
566         PA_STREAM_PLAYBACK,
567         ppdo->has_name ? ppdo->name : NULL,
568         &ss,
569         NULL,                   /* channel map */
570         &ba,                    /* buffering attributes */
571         &error
572         );
573     if (!pa->stream) {
574         qpa_logerr (error, "pa_simple_new for playback failed\n");
575         goto fail1;
576     }
577
578     audio_pcm_init_info (&hw->info, &obt_as);
579     hw->samples = pa->samples = audio_buffer_samples(
580         qapi_AudiodevPaPerDirectionOptions_base(ppdo), &obt_as, 46440);
581     pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
582     pa->rpos = hw->rpos;
583     if (!pa->pcm_buf) {
584         dolog ("Could not allocate buffer (%d bytes)\n",
585                hw->samples << hw->info.shift);
586         goto fail2;
587     }
588
589     if (audio_pt_init(&pa->pt, qpa_thread_out, hw, AUDIO_CAP, __func__)) {
590         goto fail3;
591     }
592
593     return 0;
594
595  fail3:
596     g_free (pa->pcm_buf);
597     pa->pcm_buf = NULL;
598  fail2:
599     if (pa->stream) {
600         pa_stream_unref (pa->stream);
601         pa->stream = NULL;
602     }
603  fail1:
604     return -1;
605 }
606
607 static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
608 {
609     int error;
610     pa_sample_spec ss;
611     struct audsettings obt_as = *as;
612     PAVoiceIn *pa = (PAVoiceIn *) hw;
613     paaudio *g = pa->g = drv_opaque;
614     AudiodevPaOptions *popts = &g->dev->u.pa;
615     AudiodevPaPerDirectionOptions *ppdo = popts->in;
616
617     ss.format = audfmt_to_pa (as->fmt, as->endianness);
618     ss.channels = as->nchannels;
619     ss.rate = as->freq;
620
621     obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
622
623     pa->stream = qpa_simple_new (
624         g,
625         "qemu",
626         PA_STREAM_RECORD,
627         ppdo->has_name ? ppdo->name : NULL,
628         &ss,
629         NULL,                   /* channel map */
630         NULL,                   /* buffering attributes */
631         &error
632         );
633     if (!pa->stream) {
634         qpa_logerr (error, "pa_simple_new for capture failed\n");
635         goto fail1;
636     }
637
638     audio_pcm_init_info (&hw->info, &obt_as);
639     hw->samples = pa->samples = audio_buffer_samples(
640         qapi_AudiodevPaPerDirectionOptions_base(ppdo), &obt_as, 46440);
641     pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
642     pa->wpos = hw->wpos;
643     if (!pa->pcm_buf) {
644         dolog ("Could not allocate buffer (%d bytes)\n",
645                hw->samples << hw->info.shift);
646         goto fail2;
647     }
648
649     if (audio_pt_init(&pa->pt, qpa_thread_in, hw, AUDIO_CAP, __func__)) {
650         goto fail3;
651     }
652
653     return 0;
654
655  fail3:
656     g_free (pa->pcm_buf);
657     pa->pcm_buf = NULL;
658  fail2:
659     if (pa->stream) {
660         pa_stream_unref (pa->stream);
661         pa->stream = NULL;
662     }
663  fail1:
664     return -1;
665 }
666
667 static void qpa_fini_out (HWVoiceOut *hw)
668 {
669     void *ret;
670     PAVoiceOut *pa = (PAVoiceOut *) hw;
671
672     audio_pt_lock(&pa->pt, __func__);
673     pa->done = 1;
674     audio_pt_unlock_and_signal(&pa->pt, __func__);
675     audio_pt_join(&pa->pt, &ret, __func__);
676
677     if (pa->stream) {
678         pa_stream_unref (pa->stream);
679         pa->stream = NULL;
680     }
681
682     audio_pt_fini(&pa->pt, __func__);
683     g_free (pa->pcm_buf);
684     pa->pcm_buf = NULL;
685 }
686
687 static void qpa_fini_in (HWVoiceIn *hw)
688 {
689     void *ret;
690     PAVoiceIn *pa = (PAVoiceIn *) hw;
691
692     audio_pt_lock(&pa->pt, __func__);
693     pa->done = 1;
694     audio_pt_unlock_and_signal(&pa->pt, __func__);
695     audio_pt_join(&pa->pt, &ret, __func__);
696
697     if (pa->stream) {
698         pa_stream_unref (pa->stream);
699         pa->stream = NULL;
700     }
701
702     audio_pt_fini(&pa->pt, __func__);
703     g_free (pa->pcm_buf);
704     pa->pcm_buf = NULL;
705 }
706
707 static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
708 {
709     PAVoiceOut *pa = (PAVoiceOut *) hw;
710     pa_operation *op;
711     pa_cvolume v;
712     paaudio *g = pa->g;
713
714 #ifdef PA_CHECK_VERSION    /* macro is present in 0.9.16+ */
715     pa_cvolume_init (&v);  /* function is present in 0.9.13+ */
716 #endif
717
718     switch (cmd) {
719     case VOICE_VOLUME:
720         {
721             SWVoiceOut *sw;
722             va_list ap;
723
724             va_start (ap, cmd);
725             sw = va_arg (ap, SWVoiceOut *);
726             va_end (ap);
727
728             v.channels = 2;
729             v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
730             v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
731
732             pa_threaded_mainloop_lock (g->mainloop);
733
734             op = pa_context_set_sink_input_volume (g->context,
735                 pa_stream_get_index (pa->stream),
736                 &v, NULL, NULL);
737             if (!op)
738                 qpa_logerr (pa_context_errno (g->context),
739                             "set_sink_input_volume() failed\n");
740             else
741                 pa_operation_unref (op);
742
743             op = pa_context_set_sink_input_mute (g->context,
744                 pa_stream_get_index (pa->stream),
745                sw->vol.mute, NULL, NULL);
746             if (!op) {
747                 qpa_logerr (pa_context_errno (g->context),
748                             "set_sink_input_mute() failed\n");
749             } else {
750                 pa_operation_unref (op);
751             }
752
753             pa_threaded_mainloop_unlock (g->mainloop);
754         }
755     }
756     return 0;
757 }
758
759 static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
760 {
761     PAVoiceIn *pa = (PAVoiceIn *) hw;
762     pa_operation *op;
763     pa_cvolume v;
764     paaudio *g = pa->g;
765
766 #ifdef PA_CHECK_VERSION
767     pa_cvolume_init (&v);
768 #endif
769
770     switch (cmd) {
771     case VOICE_VOLUME:
772         {
773             SWVoiceIn *sw;
774             va_list ap;
775
776             va_start (ap, cmd);
777             sw = va_arg (ap, SWVoiceIn *);
778             va_end (ap);
779
780             v.channels = 2;
781             v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
782             v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
783
784             pa_threaded_mainloop_lock (g->mainloop);
785
786             op = pa_context_set_source_output_volume (g->context,
787                 pa_stream_get_index (pa->stream),
788                 &v, NULL, NULL);
789             if (!op) {
790                 qpa_logerr (pa_context_errno (g->context),
791                             "set_source_output_volume() failed\n");
792             } else {
793                 pa_operation_unref(op);
794             }
795
796             op = pa_context_set_source_output_mute (g->context,
797                 pa_stream_get_index (pa->stream),
798                 sw->vol.mute, NULL, NULL);
799             if (!op) {
800                 qpa_logerr (pa_context_errno (g->context),
801                             "set_source_output_mute() failed\n");
802             } else {
803                 pa_operation_unref (op);
804             }
805
806             pa_threaded_mainloop_unlock (g->mainloop);
807         }
808     }
809     return 0;
810 }
811
812 /* common */
813 static void *qpa_audio_init(Audiodev *dev)
814 {
815     paaudio *g;
816     AudiodevPaOptions *popts = &dev->u.pa;
817     const char *server;
818
819     if (!popts->has_server) {
820         char pidfile[64];
821         char *runtime;
822         struct stat st;
823
824         runtime = getenv("XDG_RUNTIME_DIR");
825         if (!runtime) {
826             return NULL;
827         }
828         snprintf(pidfile, sizeof(pidfile), "%s/pulse/pid", runtime);
829         if (stat(pidfile, &st) != 0) {
830             return NULL;
831         }
832     }
833
834     assert(dev->driver == AUDIODEV_DRIVER_PA);
835
836     g = g_malloc(sizeof(paaudio));
837     server = popts->has_server ? popts->server : NULL;
838
839     g->dev = dev;
840     g->mainloop = NULL;
841     g->context = NULL;
842
843     g->mainloop = pa_threaded_mainloop_new ();
844     if (!g->mainloop) {
845         goto fail;
846     }
847
848     g->context = pa_context_new (pa_threaded_mainloop_get_api (g->mainloop),
849                                  server);
850     if (!g->context) {
851         goto fail;
852     }
853
854     pa_context_set_state_callback (g->context, context_state_cb, g);
855
856     if (pa_context_connect(g->context, server, 0, NULL) < 0) {
857         qpa_logerr (pa_context_errno (g->context),
858                     "pa_context_connect() failed\n");
859         goto fail;
860     }
861
862     pa_threaded_mainloop_lock (g->mainloop);
863
864     if (pa_threaded_mainloop_start (g->mainloop) < 0) {
865         goto unlock_and_fail;
866     }
867
868     for (;;) {
869         pa_context_state_t state;
870
871         state = pa_context_get_state (g->context);
872
873         if (state == PA_CONTEXT_READY) {
874             break;
875         }
876
877         if (!PA_CONTEXT_IS_GOOD (state)) {
878             qpa_logerr (pa_context_errno (g->context),
879                         "Wrong context state\n");
880             goto unlock_and_fail;
881         }
882
883         /* Wait until the context is ready */
884         pa_threaded_mainloop_wait (g->mainloop);
885     }
886
887     pa_threaded_mainloop_unlock (g->mainloop);
888
889     return g;
890
891 unlock_and_fail:
892     pa_threaded_mainloop_unlock (g->mainloop);
893 fail:
894     AUD_log (AUDIO_CAP, "Failed to initialize PA context");
895     qpa_audio_fini(g);
896     return NULL;
897 }
898
899 static void qpa_audio_fini (void *opaque)
900 {
901     paaudio *g = opaque;
902
903     if (g->mainloop) {
904         pa_threaded_mainloop_stop (g->mainloop);
905     }
906
907     if (g->context) {
908         pa_context_disconnect (g->context);
909         pa_context_unref (g->context);
910     }
911
912     if (g->mainloop) {
913         pa_threaded_mainloop_free (g->mainloop);
914     }
915
916     g_free(g);
917 }
918
919 static struct audio_pcm_ops qpa_pcm_ops = {
920     .init_out = qpa_init_out,
921     .fini_out = qpa_fini_out,
922     .run_out  = qpa_run_out,
923     .write    = qpa_write,
924     .ctl_out  = qpa_ctl_out,
925
926     .init_in  = qpa_init_in,
927     .fini_in  = qpa_fini_in,
928     .run_in   = qpa_run_in,
929     .read     = qpa_read,
930     .ctl_in   = qpa_ctl_in
931 };
932
933 static struct audio_driver pa_audio_driver = {
934     .name           = "pa",
935     .descr          = "http://www.pulseaudio.org/",
936     .init           = qpa_audio_init,
937     .fini           = qpa_audio_fini,
938     .pcm_ops        = &qpa_pcm_ops,
939     .can_be_default = 1,
940     .max_voices_out = INT_MAX,
941     .max_voices_in  = INT_MAX,
942     .voice_size_out = sizeof (PAVoiceOut),
943     .voice_size_in  = sizeof (PAVoiceIn),
944     .ctl_caps       = VOICE_VOLUME_CAP
945 };
946
947 static void register_audio_pa(void)
948 {
949     audio_driver_register(&pa_audio_driver);
950 }
951 type_init(register_audio_pa);
This page took 0.076463 seconds and 4 git commands to generate.