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