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