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 int done; 34 int live; 35 int decr; 36 int rpos; 37 pa_stream *stream; 38 void *pcm_buf; 39 struct audio_pt pt; 40 paaudio *g; 41 int samples; 42 } PAVoiceOut; 43 44 typedef struct { 45 HWVoiceIn hw; 46 int done; 47 int dead; 48 int incr; 49 int 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 int 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 int 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 = audio_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 int chunk = audio_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 int qpa_run_out (HWVoiceOut *hw, int live) 277 { 278 int decr; 279 PAVoiceOut *pa = (PAVoiceOut *) hw; 280 281 if (audio_pt_lock(&pa->pt, __func__)) { 282 return 0; 283 } 284 285 decr = audio_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 static int qpa_write (SWVoiceOut *sw, void *buf, int len) 299 { 300 return audio_pcm_sw_write (sw, buf, len); 301 } 302 303 /* capture */ 304 static void *qpa_thread_in (void *arg) 305 { 306 PAVoiceIn *pa = arg; 307 HWVoiceIn *hw = &pa->hw; 308 309 if (audio_pt_lock(&pa->pt, __func__)) { 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 321 if (pa->dead > 0) { 322 break; 323 } 324 325 if (audio_pt_wait(&pa->pt, __func__)) { 326 goto exit; 327 } 328 } 329 330 incr = to_grab = audio_MIN(pa->dead, pa->samples >> 5); 331 wpos = pa->wpos; 332 333 if (audio_pt_unlock(&pa->pt, __func__)) { 334 return NULL; 335 } 336 337 while (to_grab) { 338 int error; 339 int chunk = audio_MIN (to_grab, hw->samples - wpos); 340 void *buf = advance (pa->pcm_buf, wpos); 341 342 if (qpa_simple_read (pa, buf, 343 chunk << hw->info.shift, &error) < 0) { 344 qpa_logerr (error, "pa_simple_read failed\n"); 345 return NULL; 346 } 347 348 hw->conv (hw->conv_buf + wpos, buf, chunk); 349 wpos = (wpos + chunk) % hw->samples; 350 to_grab -= chunk; 351 } 352 353 if (audio_pt_lock(&pa->pt, __func__)) { 354 return NULL; 355 } 356 357 pa->wpos = wpos; 358 pa->dead -= incr; 359 pa->incr += incr; 360 } 361 362 exit: 363 audio_pt_unlock(&pa->pt, __func__); 364 return NULL; 365 } 366 367 static int qpa_run_in (HWVoiceIn *hw) 368 { 369 int live, incr, dead; 370 PAVoiceIn *pa = (PAVoiceIn *) hw; 371 372 if (audio_pt_lock(&pa->pt, __func__)) { 373 return 0; 374 } 375 376 live = audio_pcm_hw_get_live_in (hw); 377 dead = hw->samples - live; 378 incr = audio_MIN (dead, pa->incr); 379 pa->incr -= incr; 380 pa->dead = dead - incr; 381 hw->wpos = pa->wpos; 382 if (pa->dead > 0) { 383 audio_pt_unlock_and_signal(&pa->pt, __func__); 384 } 385 else { 386 audio_pt_unlock(&pa->pt, __func__); 387 } 388 return incr; 389 } 390 391 static int qpa_read (SWVoiceIn *sw, void *buf, int len) 392 { 393 return audio_pcm_sw_read (sw, buf, len); 394 } 395 396 static pa_sample_format_t audfmt_to_pa (AudioFormat afmt, int endianness) 397 { 398 int format; 399 400 switch (afmt) { 401 case AUDIO_FORMAT_S8: 402 case AUDIO_FORMAT_U8: 403 format = PA_SAMPLE_U8; 404 break; 405 case AUDIO_FORMAT_S16: 406 case AUDIO_FORMAT_U16: 407 format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE; 408 break; 409 case AUDIO_FORMAT_S32: 410 case AUDIO_FORMAT_U32: 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 421 static AudioFormat pa_to_audfmt (pa_sample_format_t fmt, int *endianness) 422 { 423 switch (fmt) { 424 case PA_SAMPLE_U8: 425 return AUDIO_FORMAT_U8; 426 case PA_SAMPLE_S16BE: 427 *endianness = 1; 428 return AUDIO_FORMAT_S16; 429 case PA_SAMPLE_S16LE: 430 *endianness = 0; 431 return AUDIO_FORMAT_S16; 432 case PA_SAMPLE_S32BE: 433 *endianness = 1; 434 return AUDIO_FORMAT_S32; 435 case PA_SAMPLE_S32LE: 436 *endianness = 0; 437 return AUDIO_FORMAT_S32; 438 default: 439 dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt); 440 return AUDIO_FORMAT_U8; 441 } 442 } 443 444 static void context_state_cb (pa_context *c, void *userdata) 445 { 446 PAConnection *conn = userdata; 447 448 switch (pa_context_get_state(c)) { 449 case PA_CONTEXT_READY: 450 case PA_CONTEXT_TERMINATED: 451 case PA_CONTEXT_FAILED: 452 pa_threaded_mainloop_signal(conn->mainloop, 0); 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 463 static void stream_state_cb (pa_stream *s, void * userdata) 464 { 465 PAConnection *c = userdata; 466 467 switch (pa_stream_get_state (s)) { 468 469 case PA_STREAM_READY: 470 case PA_STREAM_FAILED: 471 case PA_STREAM_TERMINATED: 472 pa_threaded_mainloop_signal(c->mainloop, 0); 473 break; 474 475 case PA_STREAM_UNCONNECTED: 476 case PA_STREAM_CREATING: 477 break; 478 } 479 } 480 481 static void stream_request_cb (pa_stream *s, size_t length, void *userdata) 482 { 483 PAConnection *c = userdata; 484 485 pa_threaded_mainloop_signal(c->mainloop, 0); 486 } 487 488 static pa_stream *qpa_simple_new ( 489 PAConnection *c, 490 const char *name, 491 pa_stream_direction_t dir, 492 const char *dev, 493 const pa_sample_spec *ss, 494 const pa_channel_map *map, 495 const pa_buffer_attr *attr, 496 int *rerror) 497 { 498 int r; 499 pa_stream *stream; 500 pa_stream_flags_t flags; 501 502 pa_threaded_mainloop_lock(c->mainloop); 503 504 stream = pa_stream_new(c->context, name, ss, map); 505 if (!stream) { 506 goto fail; 507 } 508 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); 512 513 flags = 514 PA_STREAM_INTERPOLATE_TIMING 515 #ifdef PA_STREAM_ADJUST_LATENCY 516 | PA_STREAM_ADJUST_LATENCY 517 #endif 518 | PA_STREAM_AUTO_TIMING_UPDATE; 519 520 if (dir == PA_STREAM_PLAYBACK) { 521 r = pa_stream_connect_playback(stream, dev, attr, flags, NULL, NULL); 522 } else { 523 r = pa_stream_connect_record(stream, dev, attr, flags); 524 } 525 526 if (r < 0) { 527 goto fail; 528 } 529 530 pa_threaded_mainloop_unlock(c->mainloop); 531 532 return stream; 533 534 fail: 535 pa_threaded_mainloop_unlock(c->mainloop); 536 537 if (stream) { 538 pa_stream_unref (stream); 539 } 540 541 *rerror = pa_context_errno(c->context); 542 543 return NULL; 544 } 545 546 static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, 547 void *drv_opaque) 548 { 549 int error; 550 pa_sample_spec ss; 551 pa_buffer_attr ba; 552 struct audsettings obt_as = *as; 553 PAVoiceOut *pa = (PAVoiceOut *) hw; 554 paaudio *g = pa->g = drv_opaque; 555 AudiodevPaOptions *popts = &g->dev->u.pa; 556 AudiodevPaPerDirectionOptions *ppdo = popts->out; 557 PAConnection *c = g->conn; 558 559 ss.format = audfmt_to_pa (as->fmt, as->endianness); 560 ss.channels = as->nchannels; 561 ss.rate = as->freq; 562 563 ba.tlength = pa_usec_to_bytes(ppdo->latency, &ss); 564 ba.minreq = -1; 565 ba.maxlength = -1; 566 ba.prebuf = -1; 567 568 obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness); 569 570 pa->stream = qpa_simple_new ( 571 c, 572 "qemu", 573 PA_STREAM_PLAYBACK, 574 ppdo->has_name ? ppdo->name : NULL, 575 &ss, 576 NULL, /* channel map */ 577 &ba, /* buffering attributes */ 578 &error 579 ); 580 if (!pa->stream) { 581 qpa_logerr (error, "pa_simple_new for playback failed\n"); 582 goto fail1; 583 } 584 585 audio_pcm_init_info (&hw->info, &obt_as); 586 hw->samples = pa->samples = audio_buffer_samples( 587 qapi_AudiodevPaPerDirectionOptions_base(ppdo), 588 &obt_as, ppdo->buffer_length); 589 pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift); 590 pa->rpos = hw->rpos; 591 if (!pa->pcm_buf) { 592 dolog ("Could not allocate buffer (%d bytes)\n", 593 hw->samples << hw->info.shift); 594 goto fail2; 595 } 596 597 if (audio_pt_init(&pa->pt, qpa_thread_out, hw, AUDIO_CAP, __func__)) { 598 goto fail3; 599 } 600 601 return 0; 602 603 fail3: 604 g_free (pa->pcm_buf); 605 pa->pcm_buf = NULL; 606 fail2: 607 if (pa->stream) { 608 pa_stream_unref (pa->stream); 609 pa->stream = NULL; 610 } 611 fail1: 612 return -1; 613 } 614 615 static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) 616 { 617 int error; 618 pa_sample_spec ss; 619 pa_buffer_attr ba; 620 struct audsettings obt_as = *as; 621 PAVoiceIn *pa = (PAVoiceIn *) hw; 622 paaudio *g = pa->g = drv_opaque; 623 AudiodevPaOptions *popts = &g->dev->u.pa; 624 AudiodevPaPerDirectionOptions *ppdo = popts->in; 625 PAConnection *c = g->conn; 626 627 ss.format = audfmt_to_pa (as->fmt, as->endianness); 628 ss.channels = as->nchannels; 629 ss.rate = as->freq; 630 631 ba.fragsize = pa_usec_to_bytes(ppdo->latency, &ss); 632 ba.maxlength = pa_usec_to_bytes(ppdo->latency * 2, &ss); 633 ba.minreq = -1; 634 ba.prebuf = -1; 635 636 obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness); 637 638 pa->stream = qpa_simple_new ( 639 c, 640 "qemu", 641 PA_STREAM_RECORD, 642 ppdo->has_name ? ppdo->name : NULL, 643 &ss, 644 NULL, /* channel map */ 645 &ba, /* buffering attributes */ 646 &error 647 ); 648 if (!pa->stream) { 649 qpa_logerr (error, "pa_simple_new for capture failed\n"); 650 goto fail1; 651 } 652 653 audio_pcm_init_info (&hw->info, &obt_as); 654 hw->samples = pa->samples = audio_buffer_samples( 655 qapi_AudiodevPaPerDirectionOptions_base(ppdo), 656 &obt_as, ppdo->buffer_length); 657 pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift); 658 pa->wpos = hw->wpos; 659 if (!pa->pcm_buf) { 660 dolog ("Could not allocate buffer (%d bytes)\n", 661 hw->samples << hw->info.shift); 662 goto fail2; 663 } 664 665 if (audio_pt_init(&pa->pt, qpa_thread_in, hw, AUDIO_CAP, __func__)) { 666 goto fail3; 667 } 668 669 return 0; 670 671 fail3: 672 g_free (pa->pcm_buf); 673 pa->pcm_buf = NULL; 674 fail2: 675 if (pa->stream) { 676 pa_stream_unref (pa->stream); 677 pa->stream = NULL; 678 } 679 fail1: 680 return -1; 681 } 682 683 static void qpa_fini_out (HWVoiceOut *hw) 684 { 685 void *ret; 686 PAVoiceOut *pa = (PAVoiceOut *) hw; 687 688 audio_pt_lock(&pa->pt, __func__); 689 pa->done = 1; 690 audio_pt_unlock_and_signal(&pa->pt, __func__); 691 audio_pt_join(&pa->pt, &ret, __func__); 692 693 if (pa->stream) { 694 pa_stream_unref (pa->stream); 695 pa->stream = NULL; 696 } 697 698 audio_pt_fini(&pa->pt, __func__); 699 g_free (pa->pcm_buf); 700 pa->pcm_buf = NULL; 701 } 702 703 static void qpa_fini_in (HWVoiceIn *hw) 704 { 705 void *ret; 706 PAVoiceIn *pa = (PAVoiceIn *) hw; 707 708 audio_pt_lock(&pa->pt, __func__); 709 pa->done = 1; 710 audio_pt_unlock_and_signal(&pa->pt, __func__); 711 audio_pt_join(&pa->pt, &ret, __func__); 712 713 if (pa->stream) { 714 pa_stream_unref (pa->stream); 715 pa->stream = NULL; 716 } 717 718 audio_pt_fini(&pa->pt, __func__); 719 g_free (pa->pcm_buf); 720 pa->pcm_buf = NULL; 721 } 722 723 static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) 724 { 725 PAVoiceOut *pa = (PAVoiceOut *) hw; 726 pa_operation *op; 727 pa_cvolume v; 728 PAConnection *c = pa->g->conn; 729 730 #ifdef PA_CHECK_VERSION /* macro is present in 0.9.16+ */ 731 pa_cvolume_init (&v); /* function is present in 0.9.13+ */ 732 #endif 733 734 switch (cmd) { 735 case VOICE_VOLUME: 736 { 737 SWVoiceOut *sw; 738 va_list ap; 739 740 va_start (ap, cmd); 741 sw = va_arg (ap, SWVoiceOut *); 742 va_end (ap); 743 744 v.channels = 2; 745 v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; 746 v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; 747 748 pa_threaded_mainloop_lock(c->mainloop); 749 750 op = pa_context_set_sink_input_volume(c->context, 751 pa_stream_get_index (pa->stream), 752 &v, NULL, NULL); 753 if (!op) { 754 qpa_logerr(pa_context_errno(c->context), 755 "set_sink_input_volume() failed\n"); 756 } else { 757 pa_operation_unref(op); 758 } 759 760 op = pa_context_set_sink_input_mute(c->context, 761 pa_stream_get_index (pa->stream), 762 sw->vol.mute, NULL, NULL); 763 if (!op) { 764 qpa_logerr(pa_context_errno(c->context), 765 "set_sink_input_mute() failed\n"); 766 } else { 767 pa_operation_unref(op); 768 } 769 770 pa_threaded_mainloop_unlock(c->mainloop); 771 } 772 } 773 return 0; 774 } 775 776 static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) 777 { 778 PAVoiceIn *pa = (PAVoiceIn *) hw; 779 pa_operation *op; 780 pa_cvolume v; 781 PAConnection *c = pa->g->conn; 782 783 #ifdef PA_CHECK_VERSION 784 pa_cvolume_init (&v); 785 #endif 786 787 switch (cmd) { 788 case VOICE_VOLUME: 789 { 790 SWVoiceIn *sw; 791 va_list ap; 792 793 va_start (ap, cmd); 794 sw = va_arg (ap, SWVoiceIn *); 795 va_end (ap); 796 797 v.channels = 2; 798 v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; 799 v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; 800 801 pa_threaded_mainloop_lock(c->mainloop); 802 803 op = pa_context_set_source_output_volume(c->context, 804 pa_stream_get_index(pa->stream), 805 &v, NULL, NULL); 806 if (!op) { 807 qpa_logerr(pa_context_errno(c->context), 808 "set_source_output_volume() failed\n"); 809 } else { 810 pa_operation_unref(op); 811 } 812 813 op = pa_context_set_source_output_mute(c->context, 814 pa_stream_get_index (pa->stream), 815 sw->vol.mute, NULL, NULL); 816 if (!op) { 817 qpa_logerr(pa_context_errno(c->context), 818 "set_source_output_mute() failed\n"); 819 } else { 820 pa_operation_unref (op); 821 } 822 823 pa_threaded_mainloop_unlock(c->mainloop); 824 } 825 } 826 return 0; 827 } 828 829 static int qpa_validate_per_direction_opts(Audiodev *dev, 830 AudiodevPaPerDirectionOptions *pdo) 831 { 832 if (!pdo->has_buffer_length) { 833 pdo->has_buffer_length = true; 834 pdo->buffer_length = 46440; 835 } 836 if (!pdo->has_latency) { 837 pdo->has_latency = true; 838 pdo->latency = 15000; 839 } 840 return 1; 841 } 842 843 /* common */ 844 static void *qpa_conn_init(const char *server) 845 { 846 PAConnection *c = g_malloc0(sizeof(PAConnection)); 847 QTAILQ_INSERT_TAIL(&pa_conns, c, list); 848 849 c->mainloop = pa_threaded_mainloop_new(); 850 if (!c->mainloop) { 851 goto fail; 852 } 853 854 c->context = pa_context_new(pa_threaded_mainloop_get_api(c->mainloop), 855 server); 856 if (!c->context) { 857 goto fail; 858 } 859 860 pa_context_set_state_callback(c->context, context_state_cb, c); 861 862 if (pa_context_connect(c->context, server, 0, NULL) < 0) { 863 qpa_logerr(pa_context_errno(c->context), 864 "pa_context_connect() failed\n"); 865 goto fail; 866 } 867 868 pa_threaded_mainloop_lock(c->mainloop); 869 870 if (pa_threaded_mainloop_start(c->mainloop) < 0) { 871 goto unlock_and_fail; 872 } 873 874 for (;;) { 875 pa_context_state_t state; 876 877 state = pa_context_get_state(c->context); 878 879 if (state == PA_CONTEXT_READY) { 880 break; 881 } 882 883 if (!PA_CONTEXT_IS_GOOD(state)) { 884 qpa_logerr(pa_context_errno(c->context), 885 "Wrong context state\n"); 886 goto unlock_and_fail; 887 } 888 889 /* Wait until the context is ready */ 890 pa_threaded_mainloop_wait(c->mainloop); 891 } 892 893 pa_threaded_mainloop_unlock(c->mainloop); 894 return c; 895 896 unlock_and_fail: 897 pa_threaded_mainloop_unlock(c->mainloop); 898 fail: 899 AUD_log (AUDIO_CAP, "Failed to initialize PA context"); 900 qpa_conn_fini(c); 901 return NULL; 902 } 903 904 static void *qpa_audio_init(Audiodev *dev) 905 { 906 paaudio *g; 907 AudiodevPaOptions *popts = &dev->u.pa; 908 const char *server; 909 PAConnection *c; 910 911 assert(dev->driver == AUDIODEV_DRIVER_PA); 912 913 if (!popts->has_server) { 914 char pidfile[64]; 915 char *runtime; 916 struct stat st; 917 918 runtime = getenv("XDG_RUNTIME_DIR"); 919 if (!runtime) { 920 return NULL; 921 } 922 snprintf(pidfile, sizeof(pidfile), "%s/pulse/pid", runtime); 923 if (stat(pidfile, &st) != 0) { 924 return NULL; 925 } 926 } 927 928 if (!qpa_validate_per_direction_opts(dev, popts->in)) { 929 return NULL; 930 } 931 if (!qpa_validate_per_direction_opts(dev, popts->out)) { 932 return NULL; 933 } 934 935 g = g_malloc0(sizeof(paaudio)); 936 server = popts->has_server ? popts->server : NULL; 937 938 g->dev = dev; 939 940 QTAILQ_FOREACH(c, &pa_conns, list) { 941 if (server == NULL || c->server == NULL ? 942 server == c->server : 943 strcmp(server, c->server) == 0) { 944 g->conn = c; 945 break; 946 } 947 } 948 if (!g->conn) { 949 g->conn = qpa_conn_init(server); 950 } 951 if (!g->conn) { 952 g_free(g); 953 return NULL; 954 } 955 956 ++g->conn->refcount; 957 return g; 958 } 959 960 static void qpa_conn_fini(PAConnection *c) 961 { 962 if (c->mainloop) { 963 pa_threaded_mainloop_stop(c->mainloop); 964 } 965 966 if (c->context) { 967 pa_context_disconnect(c->context); 968 pa_context_unref(c->context); 969 } 970 971 if (c->mainloop) { 972 pa_threaded_mainloop_free(c->mainloop); 973 } 974 975 QTAILQ_REMOVE(&pa_conns, c, list); 976 g_free(c); 977 } 978 979 static void qpa_audio_fini (void *opaque) 980 { 981 paaudio *g = opaque; 982 PAConnection *c = g->conn; 983 984 if (--c->refcount == 0) { 985 qpa_conn_fini(c); 986 } 987 988 g_free(g); 989 } 990 991 static struct audio_pcm_ops qpa_pcm_ops = { 992 .init_out = qpa_init_out, 993 .fini_out = qpa_fini_out, 994 .run_out = qpa_run_out, 995 .write = qpa_write, 996 .ctl_out = qpa_ctl_out, 997 998 .init_in = qpa_init_in, 999 .fini_in = qpa_fini_in, 1000 .run_in = qpa_run_in, 1001 .read = qpa_read, 1002 .ctl_in = qpa_ctl_in 1003 }; 1004 1005 static struct audio_driver pa_audio_driver = { 1006 .name = "pa", 1007 .descr = "http://www.pulseaudio.org/", 1008 .init = qpa_audio_init, 1009 .fini = qpa_audio_fini, 1010 .pcm_ops = &qpa_pcm_ops, 1011 .can_be_default = 1, 1012 .max_voices_out = INT_MAX, 1013 .max_voices_in = INT_MAX, 1014 .voice_size_out = sizeof (PAVoiceOut), 1015 .voice_size_in = sizeof (PAVoiceIn), 1016 .ctl_caps = VOICE_VOLUME_CAP 1017 }; 1018 1019 static void register_audio_pa(void) 1020 { 1021 audio_driver_register(&pa_audio_driver); 1022 } 1023 type_init(register_audio_pa); 1024