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