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