1 /* public domain */ 2 3 #include "qemu/osdep.h" 4 #include "qemu/module.h" 5 #include "qemu-common.h" 6 #include "audio.h" 7 #include "qapi/opts-visitor.h" 8 9 #include <pulse/pulseaudio.h> 10 11 #define AUDIO_CAP "pulseaudio" 12 #include "audio_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 pa_stream *stream; 34 paaudio *g; 35 size_t samples; 36 } PAVoiceOut; 37 38 typedef struct { 39 HWVoiceIn hw; 40 pa_stream *stream; 41 const void *read_data; 42 size_t read_length; 43 paaudio *g; 44 size_t samples; 45 } PAVoiceIn; 46 47 static void qpa_conn_fini(PAConnection *c); 48 49 static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...) 50 { 51 va_list ap; 52 53 va_start (ap, fmt); 54 AUD_vlog (AUDIO_CAP, fmt, ap); 55 va_end (ap); 56 57 AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err)); 58 } 59 60 #ifndef PA_CONTEXT_IS_GOOD 61 static inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x) 62 { 63 return 64 x == PA_CONTEXT_CONNECTING || 65 x == PA_CONTEXT_AUTHORIZING || 66 x == PA_CONTEXT_SETTING_NAME || 67 x == PA_CONTEXT_READY; 68 } 69 #endif 70 71 #ifndef PA_STREAM_IS_GOOD 72 static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x) 73 { 74 return 75 x == PA_STREAM_CREATING || 76 x == PA_STREAM_READY; 77 } 78 #endif 79 80 #define CHECK_SUCCESS_GOTO(c, expression, label, msg) \ 81 do { \ 82 if (!(expression)) { \ 83 qpa_logerr(pa_context_errno((c)->context), msg); \ 84 goto label; \ 85 } \ 86 } while (0) 87 88 #define CHECK_DEAD_GOTO(c, stream, label, msg) \ 89 do { \ 90 if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \ 91 !(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream)))) { \ 92 if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \ 93 ((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \ 94 qpa_logerr(pa_context_errno((c)->context), msg); \ 95 } else { \ 96 qpa_logerr(PA_ERR_BADSTATE, msg); \ 97 } \ 98 goto label; \ 99 } \ 100 } while (0) 101 102 static void *qpa_get_buffer_in(HWVoiceIn *hw, size_t *size) 103 { 104 PAVoiceIn *p = (PAVoiceIn *) hw; 105 PAConnection *c = p->g->conn; 106 int r; 107 108 pa_threaded_mainloop_lock(c->mainloop); 109 110 CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail, 111 "pa_threaded_mainloop_lock failed\n"); 112 113 if (!p->read_length) { 114 r = pa_stream_peek(p->stream, &p->read_data, &p->read_length); 115 CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail, 116 "pa_stream_peek failed\n"); 117 } 118 119 *size = MIN(p->read_length, *size); 120 121 pa_threaded_mainloop_unlock(c->mainloop); 122 return (void *) p->read_data; 123 124 unlock_and_fail: 125 pa_threaded_mainloop_unlock(c->mainloop); 126 *size = 0; 127 return NULL; 128 } 129 130 static void qpa_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size) 131 { 132 PAVoiceIn *p = (PAVoiceIn *) hw; 133 PAConnection *c = p->g->conn; 134 int r; 135 136 pa_threaded_mainloop_lock(c->mainloop); 137 138 CHECK_DEAD_GOTO(c, p->stream, unlock, 139 "pa_threaded_mainloop_lock failed\n"); 140 141 assert(buf == p->read_data && size <= p->read_length); 142 143 p->read_data += size; 144 p->read_length -= size; 145 146 if (size && !p->read_length) { 147 r = pa_stream_drop(p->stream); 148 CHECK_SUCCESS_GOTO(c, r == 0, unlock, "pa_stream_drop failed\n"); 149 } 150 151 unlock: 152 pa_threaded_mainloop_unlock(c->mainloop); 153 } 154 155 static size_t qpa_read(HWVoiceIn *hw, void *data, size_t length) 156 { 157 PAVoiceIn *p = (PAVoiceIn *) hw; 158 PAConnection *c = p->g->conn; 159 size_t total = 0; 160 161 pa_threaded_mainloop_lock(c->mainloop); 162 163 CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail, 164 "pa_threaded_mainloop_lock failed\n"); 165 if (pa_stream_get_state(p->stream) != PA_STREAM_READY) { 166 /* wait for stream to become ready */ 167 goto unlock; 168 } 169 170 while (total < length) { 171 size_t l; 172 int r; 173 174 if (!p->read_length) { 175 r = pa_stream_peek(p->stream, &p->read_data, &p->read_length); 176 CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail, 177 "pa_stream_peek failed\n"); 178 if (!p->read_length) { 179 /* buffer is empty */ 180 break; 181 } 182 } 183 184 l = MIN(p->read_length, length - total); 185 memcpy((char *)data + total, p->read_data, l); 186 187 p->read_data += l; 188 p->read_length -= l; 189 total += l; 190 191 if (!p->read_length) { 192 r = pa_stream_drop(p->stream); 193 CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail, 194 "pa_stream_drop failed\n"); 195 } 196 } 197 198 unlock: 199 pa_threaded_mainloop_unlock(c->mainloop); 200 return total; 201 202 unlock_and_fail: 203 pa_threaded_mainloop_unlock(c->mainloop); 204 return 0; 205 } 206 207 static void *qpa_get_buffer_out(HWVoiceOut *hw, size_t *size) 208 { 209 PAVoiceOut *p = (PAVoiceOut *) hw; 210 PAConnection *c = p->g->conn; 211 void *ret; 212 int r; 213 214 pa_threaded_mainloop_lock(c->mainloop); 215 216 CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail, 217 "pa_threaded_mainloop_lock failed\n"); 218 219 *size = -1; 220 r = pa_stream_begin_write(p->stream, &ret, size); 221 CHECK_SUCCESS_GOTO(c, r >= 0, unlock_and_fail, 222 "pa_stream_begin_write failed\n"); 223 224 pa_threaded_mainloop_unlock(c->mainloop); 225 return ret; 226 227 unlock_and_fail: 228 pa_threaded_mainloop_unlock(c->mainloop); 229 *size = 0; 230 return NULL; 231 } 232 233 static size_t qpa_write(HWVoiceOut *hw, void *data, size_t length) 234 { 235 PAVoiceOut *p = (PAVoiceOut *) hw; 236 PAConnection *c = p->g->conn; 237 size_t l; 238 int r; 239 240 pa_threaded_mainloop_lock(c->mainloop); 241 242 CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail, 243 "pa_threaded_mainloop_lock failed\n"); 244 245 l = pa_stream_writable_size(p->stream); 246 247 CHECK_SUCCESS_GOTO(c, l != (size_t) -1, unlock_and_fail, 248 "pa_stream_writable_size failed\n"); 249 250 if (l > length) { 251 l = length; 252 } 253 254 r = pa_stream_write(p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE); 255 CHECK_SUCCESS_GOTO(c, r >= 0, unlock_and_fail, "pa_stream_write failed\n"); 256 257 pa_threaded_mainloop_unlock(c->mainloop); 258 return l; 259 260 unlock_and_fail: 261 pa_threaded_mainloop_unlock(c->mainloop); 262 return 0; 263 } 264 265 static pa_sample_format_t audfmt_to_pa (AudioFormat afmt, int endianness) 266 { 267 int format; 268 269 switch (afmt) { 270 case AUDIO_FORMAT_S8: 271 case AUDIO_FORMAT_U8: 272 format = PA_SAMPLE_U8; 273 break; 274 case AUDIO_FORMAT_S16: 275 case AUDIO_FORMAT_U16: 276 format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE; 277 break; 278 case AUDIO_FORMAT_S32: 279 case AUDIO_FORMAT_U32: 280 format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE; 281 break; 282 default: 283 dolog ("Internal logic error: Bad audio format %d\n", afmt); 284 format = PA_SAMPLE_U8; 285 break; 286 } 287 return format; 288 } 289 290 static AudioFormat pa_to_audfmt (pa_sample_format_t fmt, int *endianness) 291 { 292 switch (fmt) { 293 case PA_SAMPLE_U8: 294 return AUDIO_FORMAT_U8; 295 case PA_SAMPLE_S16BE: 296 *endianness = 1; 297 return AUDIO_FORMAT_S16; 298 case PA_SAMPLE_S16LE: 299 *endianness = 0; 300 return AUDIO_FORMAT_S16; 301 case PA_SAMPLE_S32BE: 302 *endianness = 1; 303 return AUDIO_FORMAT_S32; 304 case PA_SAMPLE_S32LE: 305 *endianness = 0; 306 return AUDIO_FORMAT_S32; 307 default: 308 dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt); 309 return AUDIO_FORMAT_U8; 310 } 311 } 312 313 static void context_state_cb (pa_context *c, void *userdata) 314 { 315 PAConnection *conn = userdata; 316 317 switch (pa_context_get_state(c)) { 318 case PA_CONTEXT_READY: 319 case PA_CONTEXT_TERMINATED: 320 case PA_CONTEXT_FAILED: 321 pa_threaded_mainloop_signal(conn->mainloop, 0); 322 break; 323 324 case PA_CONTEXT_UNCONNECTED: 325 case PA_CONTEXT_CONNECTING: 326 case PA_CONTEXT_AUTHORIZING: 327 case PA_CONTEXT_SETTING_NAME: 328 break; 329 } 330 } 331 332 static void stream_state_cb (pa_stream *s, void * userdata) 333 { 334 PAConnection *c = userdata; 335 336 switch (pa_stream_get_state (s)) { 337 338 case PA_STREAM_READY: 339 case PA_STREAM_FAILED: 340 case PA_STREAM_TERMINATED: 341 pa_threaded_mainloop_signal(c->mainloop, 0); 342 break; 343 344 case PA_STREAM_UNCONNECTED: 345 case PA_STREAM_CREATING: 346 break; 347 } 348 } 349 350 static pa_stream *qpa_simple_new ( 351 PAConnection *c, 352 const char *name, 353 pa_stream_direction_t dir, 354 const char *dev, 355 const pa_sample_spec *ss, 356 const pa_buffer_attr *attr, 357 int *rerror) 358 { 359 int r; 360 pa_stream *stream = NULL; 361 pa_stream_flags_t flags; 362 pa_channel_map map; 363 364 pa_threaded_mainloop_lock(c->mainloop); 365 366 pa_channel_map_init(&map); 367 map.channels = ss->channels; 368 369 /* 370 * TODO: This currently expects the only frontend supporting more than 2 371 * channels is the usb-audio. We will need some means to set channel 372 * order when a new frontend gains multi-channel support. 373 */ 374 switch (ss->channels) { 375 case 1: 376 map.map[0] = PA_CHANNEL_POSITION_MONO; 377 break; 378 379 case 2: 380 map.map[0] = PA_CHANNEL_POSITION_LEFT; 381 map.map[1] = PA_CHANNEL_POSITION_RIGHT; 382 break; 383 384 case 6: 385 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; 386 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; 387 map.map[2] = PA_CHANNEL_POSITION_CENTER; 388 map.map[3] = PA_CHANNEL_POSITION_LFE; 389 map.map[4] = PA_CHANNEL_POSITION_REAR_LEFT; 390 map.map[5] = PA_CHANNEL_POSITION_REAR_RIGHT; 391 break; 392 393 case 8: 394 map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; 395 map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; 396 map.map[2] = PA_CHANNEL_POSITION_CENTER; 397 map.map[3] = PA_CHANNEL_POSITION_LFE; 398 map.map[4] = PA_CHANNEL_POSITION_REAR_LEFT; 399 map.map[5] = PA_CHANNEL_POSITION_REAR_RIGHT; 400 map.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; 401 map.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; 402 break; 403 404 default: 405 dolog("Internal error: unsupported channel count %d\n", ss->channels); 406 goto fail; 407 } 408 409 stream = pa_stream_new(c->context, name, ss, &map); 410 if (!stream) { 411 goto fail; 412 } 413 414 pa_stream_set_state_callback(stream, stream_state_cb, c); 415 416 flags = 417 PA_STREAM_INTERPOLATE_TIMING 418 | PA_STREAM_AUTO_TIMING_UPDATE 419 | PA_STREAM_EARLY_REQUESTS; 420 421 if (dev) { 422 /* don't move the stream if the user specified a sink/source */ 423 flags |= PA_STREAM_DONT_MOVE; 424 } 425 426 if (dir == PA_STREAM_PLAYBACK) { 427 r = pa_stream_connect_playback(stream, dev, attr, flags, NULL, NULL); 428 } else { 429 r = pa_stream_connect_record(stream, dev, attr, flags); 430 } 431 432 if (r < 0) { 433 goto fail; 434 } 435 436 pa_threaded_mainloop_unlock(c->mainloop); 437 438 return stream; 439 440 fail: 441 pa_threaded_mainloop_unlock(c->mainloop); 442 443 if (stream) { 444 pa_stream_unref (stream); 445 } 446 447 *rerror = pa_context_errno(c->context); 448 449 return NULL; 450 } 451 452 static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, 453 void *drv_opaque) 454 { 455 int error; 456 pa_sample_spec ss; 457 pa_buffer_attr ba; 458 struct audsettings obt_as = *as; 459 PAVoiceOut *pa = (PAVoiceOut *) hw; 460 paaudio *g = pa->g = drv_opaque; 461 AudiodevPaOptions *popts = &g->dev->u.pa; 462 AudiodevPaPerDirectionOptions *ppdo = popts->out; 463 PAConnection *c = g->conn; 464 465 ss.format = audfmt_to_pa (as->fmt, as->endianness); 466 ss.channels = as->nchannels; 467 ss.rate = as->freq; 468 469 ba.tlength = pa_usec_to_bytes(ppdo->latency, &ss); 470 ba.minreq = -1; 471 ba.maxlength = -1; 472 ba.prebuf = -1; 473 474 obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness); 475 476 pa->stream = qpa_simple_new ( 477 c, 478 ppdo->has_stream_name ? ppdo->stream_name : g->dev->id, 479 PA_STREAM_PLAYBACK, 480 ppdo->has_name ? ppdo->name : NULL, 481 &ss, 482 &ba, /* buffering attributes */ 483 &error 484 ); 485 if (!pa->stream) { 486 qpa_logerr (error, "pa_simple_new for playback failed\n"); 487 goto fail1; 488 } 489 490 audio_pcm_init_info (&hw->info, &obt_as); 491 hw->samples = pa->samples = audio_buffer_samples( 492 qapi_AudiodevPaPerDirectionOptions_base(ppdo), 493 &obt_as, ppdo->buffer_length); 494 495 return 0; 496 497 fail1: 498 return -1; 499 } 500 501 static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) 502 { 503 int error; 504 pa_sample_spec ss; 505 pa_buffer_attr ba; 506 struct audsettings obt_as = *as; 507 PAVoiceIn *pa = (PAVoiceIn *) hw; 508 paaudio *g = pa->g = drv_opaque; 509 AudiodevPaOptions *popts = &g->dev->u.pa; 510 AudiodevPaPerDirectionOptions *ppdo = popts->in; 511 PAConnection *c = g->conn; 512 513 ss.format = audfmt_to_pa (as->fmt, as->endianness); 514 ss.channels = as->nchannels; 515 ss.rate = as->freq; 516 517 ba.fragsize = pa_usec_to_bytes(ppdo->latency, &ss); 518 ba.maxlength = pa_usec_to_bytes(ppdo->latency * 2, &ss); 519 ba.minreq = -1; 520 ba.prebuf = -1; 521 522 obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness); 523 524 pa->stream = qpa_simple_new ( 525 c, 526 ppdo->has_stream_name ? ppdo->stream_name : g->dev->id, 527 PA_STREAM_RECORD, 528 ppdo->has_name ? ppdo->name : NULL, 529 &ss, 530 &ba, /* buffering attributes */ 531 &error 532 ); 533 if (!pa->stream) { 534 qpa_logerr (error, "pa_simple_new for capture failed\n"); 535 goto fail1; 536 } 537 538 audio_pcm_init_info (&hw->info, &obt_as); 539 hw->samples = pa->samples = audio_buffer_samples( 540 qapi_AudiodevPaPerDirectionOptions_base(ppdo), 541 &obt_as, ppdo->buffer_length); 542 543 return 0; 544 545 fail1: 546 return -1; 547 } 548 549 static void qpa_simple_disconnect(PAConnection *c, pa_stream *stream) 550 { 551 int err; 552 553 /* 554 * wait until actually connects. workaround pa bug #247 555 * https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/247 556 */ 557 while (pa_stream_get_state(stream) == PA_STREAM_CREATING) { 558 pa_threaded_mainloop_wait(c->mainloop); 559 } 560 561 err = pa_stream_disconnect(stream); 562 if (err != 0) { 563 dolog("Failed to disconnect! err=%d\n", err); 564 } 565 pa_stream_unref(stream); 566 } 567 568 static void qpa_fini_out (HWVoiceOut *hw) 569 { 570 PAVoiceOut *pa = (PAVoiceOut *) hw; 571 572 if (pa->stream) { 573 PAConnection *c = pa->g->conn; 574 575 pa_threaded_mainloop_lock(c->mainloop); 576 qpa_simple_disconnect(c, pa->stream); 577 pa->stream = NULL; 578 pa_threaded_mainloop_unlock(c->mainloop); 579 } 580 } 581 582 static void qpa_fini_in (HWVoiceIn *hw) 583 { 584 PAVoiceIn *pa = (PAVoiceIn *) hw; 585 586 if (pa->stream) { 587 PAConnection *c = pa->g->conn; 588 589 pa_threaded_mainloop_lock(c->mainloop); 590 if (pa->read_length) { 591 int r = pa_stream_drop(pa->stream); 592 if (r) { 593 qpa_logerr(pa_context_errno(c->context), 594 "pa_stream_drop failed\n"); 595 } 596 pa->read_length = 0; 597 } 598 qpa_simple_disconnect(c, pa->stream); 599 pa->stream = NULL; 600 pa_threaded_mainloop_unlock(c->mainloop); 601 } 602 } 603 604 static void qpa_volume_out(HWVoiceOut *hw, Volume *vol) 605 { 606 PAVoiceOut *pa = (PAVoiceOut *) hw; 607 pa_operation *op; 608 pa_cvolume v; 609 PAConnection *c = pa->g->conn; 610 int i; 611 612 #ifdef PA_CHECK_VERSION /* macro is present in 0.9.16+ */ 613 pa_cvolume_init (&v); /* function is present in 0.9.13+ */ 614 #endif 615 616 v.channels = vol->channels; 617 for (i = 0; i < vol->channels; ++i) { 618 v.values[i] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * vol->vol[i]) / 255; 619 } 620 621 pa_threaded_mainloop_lock(c->mainloop); 622 623 op = pa_context_set_sink_input_volume(c->context, 624 pa_stream_get_index(pa->stream), 625 &v, NULL, NULL); 626 if (!op) { 627 qpa_logerr(pa_context_errno(c->context), 628 "set_sink_input_volume() failed\n"); 629 } else { 630 pa_operation_unref(op); 631 } 632 633 op = pa_context_set_sink_input_mute(c->context, 634 pa_stream_get_index(pa->stream), 635 vol->mute, NULL, NULL); 636 if (!op) { 637 qpa_logerr(pa_context_errno(c->context), 638 "set_sink_input_mute() failed\n"); 639 } else { 640 pa_operation_unref(op); 641 } 642 643 pa_threaded_mainloop_unlock(c->mainloop); 644 } 645 646 static void qpa_volume_in(HWVoiceIn *hw, Volume *vol) 647 { 648 PAVoiceIn *pa = (PAVoiceIn *) hw; 649 pa_operation *op; 650 pa_cvolume v; 651 PAConnection *c = pa->g->conn; 652 int i; 653 654 #ifdef PA_CHECK_VERSION 655 pa_cvolume_init (&v); 656 #endif 657 658 v.channels = vol->channels; 659 for (i = 0; i < vol->channels; ++i) { 660 v.values[i] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * vol->vol[i]) / 255; 661 } 662 663 pa_threaded_mainloop_lock(c->mainloop); 664 665 op = pa_context_set_source_output_volume(c->context, 666 pa_stream_get_index(pa->stream), 667 &v, NULL, NULL); 668 if (!op) { 669 qpa_logerr(pa_context_errno(c->context), 670 "set_source_output_volume() failed\n"); 671 } else { 672 pa_operation_unref(op); 673 } 674 675 op = pa_context_set_source_output_mute(c->context, 676 pa_stream_get_index(pa->stream), 677 vol->mute, NULL, NULL); 678 if (!op) { 679 qpa_logerr(pa_context_errno(c->context), 680 "set_source_output_mute() failed\n"); 681 } else { 682 pa_operation_unref(op); 683 } 684 685 pa_threaded_mainloop_unlock(c->mainloop); 686 } 687 688 static int qpa_validate_per_direction_opts(Audiodev *dev, 689 AudiodevPaPerDirectionOptions *pdo) 690 { 691 if (!pdo->has_buffer_length) { 692 pdo->has_buffer_length = true; 693 pdo->buffer_length = 46440; 694 } 695 if (!pdo->has_latency) { 696 pdo->has_latency = true; 697 pdo->latency = 15000; 698 } 699 return 1; 700 } 701 702 /* common */ 703 static void *qpa_conn_init(const char *server) 704 { 705 const char *vm_name; 706 PAConnection *c = g_malloc0(sizeof(PAConnection)); 707 QTAILQ_INSERT_TAIL(&pa_conns, c, list); 708 709 c->mainloop = pa_threaded_mainloop_new(); 710 if (!c->mainloop) { 711 goto fail; 712 } 713 714 vm_name = qemu_get_vm_name(); 715 c->context = pa_context_new(pa_threaded_mainloop_get_api(c->mainloop), 716 vm_name ? vm_name : "qemu"); 717 if (!c->context) { 718 goto fail; 719 } 720 721 pa_context_set_state_callback(c->context, context_state_cb, c); 722 723 if (pa_context_connect(c->context, server, 0, NULL) < 0) { 724 qpa_logerr(pa_context_errno(c->context), 725 "pa_context_connect() failed\n"); 726 goto fail; 727 } 728 729 pa_threaded_mainloop_lock(c->mainloop); 730 731 if (pa_threaded_mainloop_start(c->mainloop) < 0) { 732 goto unlock_and_fail; 733 } 734 735 for (;;) { 736 pa_context_state_t state; 737 738 state = pa_context_get_state(c->context); 739 740 if (state == PA_CONTEXT_READY) { 741 break; 742 } 743 744 if (!PA_CONTEXT_IS_GOOD(state)) { 745 qpa_logerr(pa_context_errno(c->context), 746 "Wrong context state\n"); 747 goto unlock_and_fail; 748 } 749 750 /* Wait until the context is ready */ 751 pa_threaded_mainloop_wait(c->mainloop); 752 } 753 754 pa_threaded_mainloop_unlock(c->mainloop); 755 return c; 756 757 unlock_and_fail: 758 pa_threaded_mainloop_unlock(c->mainloop); 759 fail: 760 AUD_log (AUDIO_CAP, "Failed to initialize PA context"); 761 qpa_conn_fini(c); 762 return NULL; 763 } 764 765 static void *qpa_audio_init(Audiodev *dev) 766 { 767 paaudio *g; 768 AudiodevPaOptions *popts = &dev->u.pa; 769 const char *server; 770 PAConnection *c; 771 772 assert(dev->driver == AUDIODEV_DRIVER_PA); 773 774 if (!popts->has_server) { 775 char pidfile[64]; 776 char *runtime; 777 struct stat st; 778 779 runtime = getenv("XDG_RUNTIME_DIR"); 780 if (!runtime) { 781 return NULL; 782 } 783 snprintf(pidfile, sizeof(pidfile), "%s/pulse/pid", runtime); 784 if (stat(pidfile, &st) != 0) { 785 return NULL; 786 } 787 } 788 789 if (!qpa_validate_per_direction_opts(dev, popts->in)) { 790 return NULL; 791 } 792 if (!qpa_validate_per_direction_opts(dev, popts->out)) { 793 return NULL; 794 } 795 796 g = g_malloc0(sizeof(paaudio)); 797 server = popts->has_server ? popts->server : NULL; 798 799 g->dev = dev; 800 801 QTAILQ_FOREACH(c, &pa_conns, list) { 802 if (server == NULL || c->server == NULL ? 803 server == c->server : 804 strcmp(server, c->server) == 0) { 805 g->conn = c; 806 break; 807 } 808 } 809 if (!g->conn) { 810 g->conn = qpa_conn_init(server); 811 } 812 if (!g->conn) { 813 g_free(g); 814 return NULL; 815 } 816 817 ++g->conn->refcount; 818 return g; 819 } 820 821 static void qpa_conn_fini(PAConnection *c) 822 { 823 if (c->mainloop) { 824 pa_threaded_mainloop_stop(c->mainloop); 825 } 826 827 if (c->context) { 828 pa_context_disconnect(c->context); 829 pa_context_unref(c->context); 830 } 831 832 if (c->mainloop) { 833 pa_threaded_mainloop_free(c->mainloop); 834 } 835 836 QTAILQ_REMOVE(&pa_conns, c, list); 837 g_free(c); 838 } 839 840 static void qpa_audio_fini (void *opaque) 841 { 842 paaudio *g = opaque; 843 PAConnection *c = g->conn; 844 845 if (--c->refcount == 0) { 846 qpa_conn_fini(c); 847 } 848 849 g_free(g); 850 } 851 852 static struct audio_pcm_ops qpa_pcm_ops = { 853 .init_out = qpa_init_out, 854 .fini_out = qpa_fini_out, 855 .write = qpa_write, 856 .get_buffer_out = qpa_get_buffer_out, 857 .put_buffer_out = qpa_write, /* pa handles it */ 858 .volume_out = qpa_volume_out, 859 860 .init_in = qpa_init_in, 861 .fini_in = qpa_fini_in, 862 .read = qpa_read, 863 .get_buffer_in = qpa_get_buffer_in, 864 .put_buffer_in = qpa_put_buffer_in, 865 .volume_in = qpa_volume_in 866 }; 867 868 static struct audio_driver pa_audio_driver = { 869 .name = "pa", 870 .descr = "http://www.pulseaudio.org/", 871 .init = qpa_audio_init, 872 .fini = qpa_audio_fini, 873 .pcm_ops = &qpa_pcm_ops, 874 .can_be_default = 1, 875 .max_voices_out = INT_MAX, 876 .max_voices_in = INT_MAX, 877 .voice_size_out = sizeof (PAVoiceOut), 878 .voice_size_in = sizeof (PAVoiceIn), 879 }; 880 881 static void register_audio_pa(void) 882 { 883 audio_driver_register(&pa_audio_driver); 884 } 885 type_init(register_audio_pa); 886