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 389 default: 390 dolog("Internal error: unsupported channel count %d\n", ss->channels); 391 goto fail; 392 } 393 394 stream = pa_stream_new(c->context, name, ss, &map); 395 if (!stream) { 396 goto fail; 397 } 398 399 pa_stream_set_state_callback(stream, stream_state_cb, c); 400 401 flags = 402 PA_STREAM_INTERPOLATE_TIMING 403 | PA_STREAM_AUTO_TIMING_UPDATE 404 | PA_STREAM_EARLY_REQUESTS; 405 406 if (dev) { 407 /* don't move the stream if the user specified a sink/source */ 408 flags |= PA_STREAM_DONT_MOVE; 409 } 410 411 if (dir == PA_STREAM_PLAYBACK) { 412 r = pa_stream_connect_playback(stream, dev, attr, flags, NULL, NULL); 413 } else { 414 r = pa_stream_connect_record(stream, dev, attr, flags); 415 } 416 417 if (r < 0) { 418 goto fail; 419 } 420 421 pa_threaded_mainloop_unlock(c->mainloop); 422 423 return stream; 424 425 fail: 426 pa_threaded_mainloop_unlock(c->mainloop); 427 428 if (stream) { 429 pa_stream_unref (stream); 430 } 431 432 *rerror = pa_context_errno(c->context); 433 434 return NULL; 435 } 436 437 static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, 438 void *drv_opaque) 439 { 440 int error; 441 pa_sample_spec ss; 442 pa_buffer_attr ba; 443 struct audsettings obt_as = *as; 444 PAVoiceOut *pa = (PAVoiceOut *) hw; 445 paaudio *g = pa->g = drv_opaque; 446 AudiodevPaOptions *popts = &g->dev->u.pa; 447 AudiodevPaPerDirectionOptions *ppdo = popts->out; 448 PAConnection *c = g->conn; 449 450 ss.format = audfmt_to_pa (as->fmt, as->endianness); 451 ss.channels = as->nchannels; 452 ss.rate = as->freq; 453 454 ba.tlength = pa_usec_to_bytes(ppdo->latency, &ss); 455 ba.minreq = -1; 456 ba.maxlength = -1; 457 ba.prebuf = -1; 458 459 obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness); 460 461 pa->stream = qpa_simple_new ( 462 c, 463 ppdo->has_stream_name ? ppdo->stream_name : g->dev->id, 464 PA_STREAM_PLAYBACK, 465 ppdo->has_name ? ppdo->name : NULL, 466 &ss, 467 &ba, /* buffering attributes */ 468 &error 469 ); 470 if (!pa->stream) { 471 qpa_logerr (error, "pa_simple_new for playback failed\n"); 472 goto fail1; 473 } 474 475 audio_pcm_init_info (&hw->info, &obt_as); 476 hw->samples = pa->samples = audio_buffer_samples( 477 qapi_AudiodevPaPerDirectionOptions_base(ppdo), 478 &obt_as, ppdo->buffer_length); 479 480 return 0; 481 482 fail1: 483 return -1; 484 } 485 486 static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) 487 { 488 int error; 489 pa_sample_spec ss; 490 pa_buffer_attr ba; 491 struct audsettings obt_as = *as; 492 PAVoiceIn *pa = (PAVoiceIn *) hw; 493 paaudio *g = pa->g = drv_opaque; 494 AudiodevPaOptions *popts = &g->dev->u.pa; 495 AudiodevPaPerDirectionOptions *ppdo = popts->in; 496 PAConnection *c = g->conn; 497 498 ss.format = audfmt_to_pa (as->fmt, as->endianness); 499 ss.channels = as->nchannels; 500 ss.rate = as->freq; 501 502 ba.fragsize = pa_usec_to_bytes(ppdo->latency, &ss); 503 ba.maxlength = pa_usec_to_bytes(ppdo->latency * 2, &ss); 504 ba.minreq = -1; 505 ba.prebuf = -1; 506 507 obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness); 508 509 pa->stream = qpa_simple_new ( 510 c, 511 ppdo->has_stream_name ? ppdo->stream_name : g->dev->id, 512 PA_STREAM_RECORD, 513 ppdo->has_name ? ppdo->name : NULL, 514 &ss, 515 &ba, /* buffering attributes */ 516 &error 517 ); 518 if (!pa->stream) { 519 qpa_logerr (error, "pa_simple_new for capture failed\n"); 520 goto fail1; 521 } 522 523 audio_pcm_init_info (&hw->info, &obt_as); 524 hw->samples = pa->samples = audio_buffer_samples( 525 qapi_AudiodevPaPerDirectionOptions_base(ppdo), 526 &obt_as, ppdo->buffer_length); 527 528 return 0; 529 530 fail1: 531 return -1; 532 } 533 534 static void qpa_simple_disconnect(PAConnection *c, pa_stream *stream) 535 { 536 int err; 537 538 pa_threaded_mainloop_lock(c->mainloop); 539 /* 540 * wait until actually connects. workaround pa bug #247 541 * https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/247 542 */ 543 while (pa_stream_get_state(stream) == PA_STREAM_CREATING) { 544 pa_threaded_mainloop_wait(c->mainloop); 545 } 546 547 err = pa_stream_disconnect(stream); 548 if (err != 0) { 549 dolog("Failed to disconnect! err=%d\n", err); 550 } 551 pa_stream_unref(stream); 552 pa_threaded_mainloop_unlock(c->mainloop); 553 } 554 555 static void qpa_fini_out (HWVoiceOut *hw) 556 { 557 PAVoiceOut *pa = (PAVoiceOut *) hw; 558 559 if (pa->stream) { 560 qpa_simple_disconnect(pa->g->conn, pa->stream); 561 pa->stream = NULL; 562 } 563 } 564 565 static void qpa_fini_in (HWVoiceIn *hw) 566 { 567 PAVoiceIn *pa = (PAVoiceIn *) hw; 568 569 if (pa->stream) { 570 qpa_simple_disconnect(pa->g->conn, pa->stream); 571 pa->stream = NULL; 572 } 573 } 574 575 static void qpa_volume_out(HWVoiceOut *hw, Volume *vol) 576 { 577 PAVoiceOut *pa = (PAVoiceOut *) hw; 578 pa_operation *op; 579 pa_cvolume v; 580 PAConnection *c = pa->g->conn; 581 int i; 582 583 #ifdef PA_CHECK_VERSION /* macro is present in 0.9.16+ */ 584 pa_cvolume_init (&v); /* function is present in 0.9.13+ */ 585 #endif 586 587 v.channels = vol->channels; 588 for (i = 0; i < vol->channels; ++i) { 589 v.values[i] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * vol->vol[i]) / 255; 590 } 591 592 pa_threaded_mainloop_lock(c->mainloop); 593 594 op = pa_context_set_sink_input_volume(c->context, 595 pa_stream_get_index(pa->stream), 596 &v, NULL, NULL); 597 if (!op) { 598 qpa_logerr(pa_context_errno(c->context), 599 "set_sink_input_volume() failed\n"); 600 } else { 601 pa_operation_unref(op); 602 } 603 604 op = pa_context_set_sink_input_mute(c->context, 605 pa_stream_get_index(pa->stream), 606 vol->mute, NULL, NULL); 607 if (!op) { 608 qpa_logerr(pa_context_errno(c->context), 609 "set_sink_input_mute() failed\n"); 610 } else { 611 pa_operation_unref(op); 612 } 613 614 pa_threaded_mainloop_unlock(c->mainloop); 615 } 616 617 static void qpa_volume_in(HWVoiceIn *hw, Volume *vol) 618 { 619 PAVoiceIn *pa = (PAVoiceIn *) hw; 620 pa_operation *op; 621 pa_cvolume v; 622 PAConnection *c = pa->g->conn; 623 int i; 624 625 #ifdef PA_CHECK_VERSION 626 pa_cvolume_init (&v); 627 #endif 628 629 v.channels = vol->channels; 630 for (i = 0; i < vol->channels; ++i) { 631 v.values[i] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * vol->vol[i]) / 255; 632 } 633 634 pa_threaded_mainloop_lock(c->mainloop); 635 636 op = pa_context_set_source_output_volume(c->context, 637 pa_stream_get_index(pa->stream), 638 &v, NULL, NULL); 639 if (!op) { 640 qpa_logerr(pa_context_errno(c->context), 641 "set_source_output_volume() failed\n"); 642 } else { 643 pa_operation_unref(op); 644 } 645 646 op = pa_context_set_source_output_mute(c->context, 647 pa_stream_get_index(pa->stream), 648 vol->mute, NULL, NULL); 649 if (!op) { 650 qpa_logerr(pa_context_errno(c->context), 651 "set_source_output_mute() failed\n"); 652 } else { 653 pa_operation_unref(op); 654 } 655 656 pa_threaded_mainloop_unlock(c->mainloop); 657 } 658 659 static int qpa_validate_per_direction_opts(Audiodev *dev, 660 AudiodevPaPerDirectionOptions *pdo) 661 { 662 if (!pdo->has_buffer_length) { 663 pdo->has_buffer_length = true; 664 pdo->buffer_length = 46440; 665 } 666 if (!pdo->has_latency) { 667 pdo->has_latency = true; 668 pdo->latency = 15000; 669 } 670 return 1; 671 } 672 673 /* common */ 674 static void *qpa_conn_init(const char *server) 675 { 676 const char *vm_name; 677 PAConnection *c = g_malloc0(sizeof(PAConnection)); 678 QTAILQ_INSERT_TAIL(&pa_conns, c, list); 679 680 c->mainloop = pa_threaded_mainloop_new(); 681 if (!c->mainloop) { 682 goto fail; 683 } 684 685 vm_name = qemu_get_vm_name(); 686 c->context = pa_context_new(pa_threaded_mainloop_get_api(c->mainloop), 687 vm_name ? vm_name : "qemu"); 688 if (!c->context) { 689 goto fail; 690 } 691 692 pa_context_set_state_callback(c->context, context_state_cb, c); 693 694 if (pa_context_connect(c->context, server, 0, NULL) < 0) { 695 qpa_logerr(pa_context_errno(c->context), 696 "pa_context_connect() failed\n"); 697 goto fail; 698 } 699 700 pa_threaded_mainloop_lock(c->mainloop); 701 702 if (pa_threaded_mainloop_start(c->mainloop) < 0) { 703 goto unlock_and_fail; 704 } 705 706 for (;;) { 707 pa_context_state_t state; 708 709 state = pa_context_get_state(c->context); 710 711 if (state == PA_CONTEXT_READY) { 712 break; 713 } 714 715 if (!PA_CONTEXT_IS_GOOD(state)) { 716 qpa_logerr(pa_context_errno(c->context), 717 "Wrong context state\n"); 718 goto unlock_and_fail; 719 } 720 721 /* Wait until the context is ready */ 722 pa_threaded_mainloop_wait(c->mainloop); 723 } 724 725 pa_threaded_mainloop_unlock(c->mainloop); 726 return c; 727 728 unlock_and_fail: 729 pa_threaded_mainloop_unlock(c->mainloop); 730 fail: 731 AUD_log (AUDIO_CAP, "Failed to initialize PA context"); 732 qpa_conn_fini(c); 733 return NULL; 734 } 735 736 static void *qpa_audio_init(Audiodev *dev) 737 { 738 paaudio *g; 739 AudiodevPaOptions *popts = &dev->u.pa; 740 const char *server; 741 PAConnection *c; 742 743 assert(dev->driver == AUDIODEV_DRIVER_PA); 744 745 if (!popts->has_server) { 746 char pidfile[64]; 747 char *runtime; 748 struct stat st; 749 750 runtime = getenv("XDG_RUNTIME_DIR"); 751 if (!runtime) { 752 return NULL; 753 } 754 snprintf(pidfile, sizeof(pidfile), "%s/pulse/pid", runtime); 755 if (stat(pidfile, &st) != 0) { 756 return NULL; 757 } 758 } 759 760 if (!qpa_validate_per_direction_opts(dev, popts->in)) { 761 return NULL; 762 } 763 if (!qpa_validate_per_direction_opts(dev, popts->out)) { 764 return NULL; 765 } 766 767 g = g_malloc0(sizeof(paaudio)); 768 server = popts->has_server ? popts->server : NULL; 769 770 g->dev = dev; 771 772 QTAILQ_FOREACH(c, &pa_conns, list) { 773 if (server == NULL || c->server == NULL ? 774 server == c->server : 775 strcmp(server, c->server) == 0) { 776 g->conn = c; 777 break; 778 } 779 } 780 if (!g->conn) { 781 g->conn = qpa_conn_init(server); 782 } 783 if (!g->conn) { 784 g_free(g); 785 return NULL; 786 } 787 788 ++g->conn->refcount; 789 return g; 790 } 791 792 static void qpa_conn_fini(PAConnection *c) 793 { 794 if (c->mainloop) { 795 pa_threaded_mainloop_stop(c->mainloop); 796 } 797 798 if (c->context) { 799 pa_context_disconnect(c->context); 800 pa_context_unref(c->context); 801 } 802 803 if (c->mainloop) { 804 pa_threaded_mainloop_free(c->mainloop); 805 } 806 807 QTAILQ_REMOVE(&pa_conns, c, list); 808 g_free(c); 809 } 810 811 static void qpa_audio_fini (void *opaque) 812 { 813 paaudio *g = opaque; 814 PAConnection *c = g->conn; 815 816 if (--c->refcount == 0) { 817 qpa_conn_fini(c); 818 } 819 820 g_free(g); 821 } 822 823 static struct audio_pcm_ops qpa_pcm_ops = { 824 .init_out = qpa_init_out, 825 .fini_out = qpa_fini_out, 826 .write = qpa_write, 827 .get_buffer_out = qpa_get_buffer_out, 828 .put_buffer_out = qpa_write, /* pa handles it */ 829 .volume_out = qpa_volume_out, 830 831 .init_in = qpa_init_in, 832 .fini_in = qpa_fini_in, 833 .read = qpa_read, 834 .get_buffer_in = qpa_get_buffer_in, 835 .put_buffer_in = qpa_put_buffer_in, 836 .volume_in = qpa_volume_in 837 }; 838 839 static struct audio_driver pa_audio_driver = { 840 .name = "pa", 841 .descr = "http://www.pulseaudio.org/", 842 .init = qpa_audio_init, 843 .fini = qpa_audio_fini, 844 .pcm_ops = &qpa_pcm_ops, 845 .can_be_default = 1, 846 .max_voices_out = INT_MAX, 847 .max_voices_in = INT_MAX, 848 .voice_size_out = sizeof (PAVoiceOut), 849 .voice_size_in = sizeof (PAVoiceIn), 850 }; 851 852 static void register_audio_pa(void) 853 { 854 audio_driver_register(&pa_audio_driver); 855 } 856 type_init(register_audio_pa); 857