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