1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2010 Intel Corporation 5 Contributor: Pierre-Louis Bossart <pierre-louis.bossart@intel.com> 6 7 PulseAudio is free software; you can redistribute it and/or modify 8 it under the terms of the GNU Lesser General Public License as published 9 by the Free Software Foundation; either version 2.1 of the License, 10 or (at your option) any later version. 11 12 PulseAudio is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public License for more details. 16 17 You should have received a copy of the GNU Lesser General Public License 18 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 19***/ 20 21#ifdef HAVE_CONFIG_H 22#include <config.h> 23#endif 24 25#include <stdio.h> 26 27#include <pulse/xmalloc.h> 28 29#include <pulsecore/i18n.h> 30#include <pulsecore/macro.h> 31#include <pulsecore/namereg.h> 32#include <pulsecore/sink.h> 33#include <pulsecore/module.h> 34#include <pulsecore/core-util.h> 35#include <pulsecore/modargs.h> 36#include <pulsecore/log.h> 37#include <pulsecore/rtpoll.h> 38#include <pulsecore/sample-util.h> 39#include <pulsecore/ltdl-helper.h> 40#include <pulsecore/mix.h> 41#include <pulsecore/rtpoll.h> 42 43PA_MODULE_AUTHOR("Pierre-Louis Bossart"); 44PA_MODULE_DESCRIPTION("Virtual source"); 45PA_MODULE_VERSION(PACKAGE_VERSION); 46PA_MODULE_LOAD_ONCE(false); 47PA_MODULE_USAGE( 48 _("source_name=<name for the source> " 49 "source_properties=<properties for the source> " 50 "master=<name of source to filter> " 51 "uplink_sink=<name> (optional)" 52 "format=<sample format> " 53 "rate=<sample rate> " 54 "channels=<number of channels> " 55 "channel_map=<channel map> " 56 "use_volume_sharing=<yes or no> " 57 "force_flat_volume=<yes or no> " 58 )); 59 60#define MEMBLOCKQ_MAXLENGTH (16*1024*1024) 61#define BLOCK_USEC 1000 /* FIXME */ 62 63struct userdata { 64 pa_module *module; 65 66 /* FIXME: Uncomment this and take "autoloaded" as a modarg if this is a filter */ 67 /* bool autoloaded; */ 68 69 pa_source *source; 70 pa_source_output *source_output; 71 72 pa_memblockq *memblockq; 73 74 bool auto_desc; 75 unsigned channels; 76 77 /* optional fields for uplink sink */ 78 pa_sink *sink; 79 pa_usec_t block_usec; 80 pa_memblockq *sink_memblockq; 81 pa_rtpoll *rtpoll; 82 83}; 84 85static const char* const valid_modargs[] = { 86 "source_name", 87 "source_properties", 88 "master", 89 "uplink_sink", 90 "format", 91 "rate", 92 "channels", 93 "channel_map", 94 "use_volume_sharing", 95 "force_flat_volume", 96 NULL 97}; 98 99/* Called from I/O thread context */ 100static int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { 101 102 switch (code) { 103 104 case PA_SINK_MESSAGE_GET_LATENCY: 105 106 /* there's no real latency here */ 107 *((int64_t*) data) = 0; 108 109 return 0; 110 } 111 112 return pa_sink_process_msg(o, code, data, offset, chunk); 113} 114 115/* Called from main context */ 116static int sink_set_state_in_main_thread_cb(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t suspend_cause) { 117 struct userdata *u; 118 119 pa_sink_assert_ref(s); 120 pa_assert_se(u = s->userdata); 121 122 if (!PA_SINK_IS_LINKED(state)) { 123 return 0; 124 } 125 126 if (state == PA_SINK_RUNNING) { 127 /* need to wake-up source if it was suspended */ 128 pa_log_debug("Resuming source %s, because its uplink sink became active.", u->source->name); 129 pa_source_suspend(u->source, false, PA_SUSPEND_ALL); 130 131 /* FIXME: if there's no client connected, the source will suspend 132 and playback will be stuck. You'd want to prevent the source from 133 sleeping when the uplink sink is active; even if the audio is 134 discarded at least the app isn't stuck */ 135 136 } else { 137 /* nothing to do, if the sink becomes idle or suspended let 138 module-suspend-idle handle the sources later */ 139 } 140 141 return 0; 142} 143 144static void sink_update_requested_latency_cb(pa_sink *s) { 145 struct userdata *u; 146 147 pa_sink_assert_ref(s); 148 pa_assert_se(u = s->userdata); 149 150 /* FIXME: there's no latency support */ 151 152} 153 154/* Called from I/O thread context */ 155static int source_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { 156 struct userdata *u = PA_SOURCE(o)->userdata; 157 158 switch (code) { 159 160 case PA_SOURCE_MESSAGE_GET_LATENCY: 161 162 /* The source is _put() before the source output is, so let's 163 * make sure we don't access it in that time. Also, the 164 * source output is first shut down, the source second. */ 165 if (!PA_SOURCE_IS_LINKED(u->source->thread_info.state) || 166 !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state)) { 167 *((pa_usec_t*) data) = 0; 168 return 0; 169 } 170 171 *((pa_usec_t*) data) = 172 173 /* Get the latency of the master source */ 174 pa_source_get_latency_within_thread(u->source_output->source, true) + 175 176 /* Add the latency internal to our source output on top */ 177 /* FIXME, no idea what I am doing here */ 178 pa_bytes_to_usec(pa_memblockq_get_length(u->source_output->thread_info.delay_memblockq), &u->source_output->source->sample_spec); 179 180 /* Add resampler delay */ 181 *((int64_t*) data) += pa_resampler_get_delay_usec(u->source_output->thread_info.resampler); 182 183 return 0; 184 } 185 186 return pa_source_process_msg(o, code, data, offset, chunk); 187} 188 189/* Called from main context */ 190static int source_set_state_in_main_thread_cb(pa_source *s, pa_source_state_t state, pa_suspend_cause_t suspend_cause) { 191 struct userdata *u; 192 193 pa_source_assert_ref(s); 194 pa_assert_se(u = s->userdata); 195 196 if (!PA_SOURCE_IS_LINKED(state) || 197 !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->state)) 198 return 0; 199 200 pa_source_output_cork(u->source_output, state == PA_SOURCE_SUSPENDED); 201 return 0; 202} 203 204/* Called from I/O thread context */ 205static void source_update_requested_latency_cb(pa_source *s) { 206 struct userdata *u; 207 208 pa_source_assert_ref(s); 209 pa_assert_se(u = s->userdata); 210 211 if (!PA_SOURCE_IS_LINKED(u->source->thread_info.state) || 212 !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state)) 213 return; 214 215 /* Just hand this one over to the master source */ 216 pa_source_output_set_requested_latency_within_thread( 217 u->source_output, 218 pa_source_get_requested_latency_within_thread(s)); 219} 220 221/* Called from main context */ 222static void source_set_volume_cb(pa_source *s) { 223 struct userdata *u; 224 225 pa_source_assert_ref(s); 226 pa_assert_se(u = s->userdata); 227 228 if (!PA_SOURCE_IS_LINKED(s->state) || 229 !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->state)) 230 return; 231 232 pa_source_output_set_volume(u->source_output, &s->real_volume, s->save_volume, true); 233} 234 235/* Called from main context */ 236static void source_set_mute_cb(pa_source *s) { 237 struct userdata *u; 238 239 pa_source_assert_ref(s); 240 pa_assert_se(u = s->userdata); 241 242 if (!PA_SOURCE_IS_LINKED(s->state) || 243 !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->state)) 244 return; 245 246 pa_source_output_set_mute(u->source_output, s->muted, s->save_muted); 247} 248 249/* Called from input thread context */ 250static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { 251 struct userdata *u; 252 253 pa_source_output_assert_ref(o); 254 pa_source_output_assert_io_context(o); 255 pa_assert_se(u = o->userdata); 256 257 if (!PA_SOURCE_IS_LINKED(u->source->thread_info.state)) 258 return; 259 260 if (!PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state)) { 261 pa_log("push when no link?"); 262 return; 263 } 264 265 /* PUT YOUR CODE HERE TO DO SOMETHING WITH THE SOURCE DATA */ 266 267 /* if uplink sink exists, pull data from there; simplify by using 268 same length as chunk provided by source */ 269 if (u->sink && (u->sink->thread_info.state == PA_SINK_RUNNING)) { 270 pa_memchunk tchunk; 271 size_t nbytes = chunk->length; 272 pa_mix_info streams[2]; 273 pa_memchunk target_chunk; 274 void *target; 275 int ch; 276 277 /* Hmm, process any rewind request that might be queued up */ 278 pa_sink_process_rewind(u->sink, 0); 279 280 /* get data from the sink */ 281 while (pa_memblockq_peek(u->sink_memblockq, &tchunk) < 0) { 282 pa_memchunk nchunk; 283 284 /* make sure we get nbytes from the sink with render_full, 285 otherwise we cannot mix with the uplink */ 286 pa_sink_render_full(u->sink, nbytes, &nchunk); 287 pa_memblockq_push(u->sink_memblockq, &nchunk); 288 pa_memblock_unref(nchunk.memblock); 289 } 290 pa_assert(tchunk.length == chunk->length); 291 292 /* move the read pointer for sink memblockq */ 293 pa_memblockq_drop(u->sink_memblockq, tchunk.length); 294 295 /* allocate target chunk */ 296 /* this could probably be done in-place, but having chunk as both 297 the input and output creates issues with reference counts */ 298 target_chunk.index = 0; 299 target_chunk.length = chunk->length; 300 pa_assert(target_chunk.length == chunk->length); 301 302 target_chunk.memblock = pa_memblock_new(o->source->core->mempool, 303 target_chunk.length); 304 pa_assert( target_chunk.memblock ); 305 306 /* get target pointer */ 307 target = pa_memblock_acquire_chunk(&target_chunk); 308 309 /* set-up mixing structure 310 volume was taken care of in sink and source already */ 311 streams[0].chunk = *chunk; 312 for(ch=0;ch<o->sample_spec.channels;ch++) 313 streams[0].volume.values[ch] = PA_VOLUME_NORM; /* FIXME */ 314 streams[0].volume.channels = o->sample_spec.channels; 315 316 streams[1].chunk = tchunk; 317 for(ch=0;ch<o->sample_spec.channels;ch++) 318 streams[1].volume.values[ch] = PA_VOLUME_NORM; /* FIXME */ 319 streams[1].volume.channels = o->sample_spec.channels; 320 321 /* do mixing */ 322 pa_mix(streams, /* 2 streams to be mixed */ 323 2, 324 target, /* put result in target chunk */ 325 chunk->length, /* same length as input */ 326 (const pa_sample_spec *)&o->sample_spec, /* same sample spec for input and output */ 327 NULL, /* no volume information */ 328 false); /* no mute */ 329 330 pa_memblock_release(target_chunk.memblock); 331 pa_memblock_unref(tchunk.memblock); /* clean-up */ 332 333 /* forward the data to the virtual source */ 334 pa_source_post(u->source, &target_chunk); 335 336 pa_memblock_unref(target_chunk.memblock); /* clean-up */ 337 338 } else { 339 /* forward the data to the virtual source */ 340 pa_source_post(u->source, chunk); 341 } 342 343} 344 345/* Called from input thread context */ 346static void source_output_process_rewind_cb(pa_source_output *o, size_t nbytes) { 347 struct userdata *u; 348 349 pa_source_output_assert_ref(o); 350 pa_source_output_assert_io_context(o); 351 pa_assert_se(u = o->userdata); 352 353 /* If the source is not yet linked, there is nothing to rewind */ 354 if (PA_SOURCE_IS_LINKED(u->source->thread_info.state)) 355 pa_source_process_rewind(u->source, nbytes); 356 357 /* FIXME, no idea what I am doing here */ 358#if 0 359 pa_asyncmsgq_post(u->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_REWIND, NULL, (int64_t) nbytes, NULL, NULL); 360 u->send_counter -= (int64_t) nbytes; 361#endif 362} 363 364/* Called from output thread context */ 365static void source_output_update_max_rewind_cb(pa_source_output *o, size_t nbytes) { 366 struct userdata *u; 367 368 pa_source_output_assert_ref(o); 369 pa_source_output_assert_io_context(o); 370 pa_assert_se(u = o->userdata); 371 372 pa_source_set_max_rewind_within_thread(u->source, nbytes); 373} 374 375/* Called from output thread context */ 376static void source_output_attach_cb(pa_source_output *o) { 377 struct userdata *u; 378 379 pa_source_output_assert_ref(o); 380 pa_source_output_assert_io_context(o); 381 pa_assert_se(u = o->userdata); 382 383 pa_source_set_rtpoll(u->source, o->source->thread_info.rtpoll); 384 pa_source_set_latency_range_within_thread(u->source, o->source->thread_info.min_latency, o->source->thread_info.max_latency); 385 pa_source_set_fixed_latency_within_thread(u->source, o->source->thread_info.fixed_latency); 386 pa_source_set_max_rewind_within_thread(u->source, pa_source_output_get_max_rewind(o)); 387 388 if (PA_SOURCE_IS_LINKED(u->source->thread_info.state)) 389 pa_source_attach_within_thread(u->source); 390} 391 392/* Called from output thread context */ 393static void source_output_detach_cb(pa_source_output *o) { 394 struct userdata *u; 395 396 pa_source_output_assert_ref(o); 397 pa_source_output_assert_io_context(o); 398 pa_assert_se(u = o->userdata); 399 400 if (PA_SOURCE_IS_LINKED(u->source->thread_info.state)) 401 pa_source_detach_within_thread(u->source); 402 pa_source_set_rtpoll(u->source, NULL); 403} 404 405/* Called from output thread context except when cork() is called without valid source.*/ 406static void source_output_state_change_cb(pa_source_output *o, pa_source_output_state_t state) { 407 struct userdata *u; 408 409 pa_source_output_assert_ref(o); 410 pa_assert_se(u = o->userdata); 411 412 /* FIXME */ 413#if 0 414 if (PA_SOURCE_OUTPUT_IS_LINKED(state) && o->thread_info.state == PA_SOURCE_OUTPUT_INIT && o->source) { 415 416 u->skip = pa_usec_to_bytes(PA_CLIP_SUB(pa_source_get_latency_within_thread(o->source, false), 417 u->latency), 418 &o->sample_spec); 419 420 pa_log_info("Skipping %lu bytes", (unsigned long) u->skip); 421 } 422#endif 423} 424 425/* Called from main thread */ 426static void source_output_kill_cb(pa_source_output *o) { 427 struct userdata *u; 428 429 pa_source_output_assert_ref(o); 430 pa_assert_ctl_context(); 431 pa_assert_se(u = o->userdata); 432 433 /* The order here matters! We first kill the source so that streams 434 * can properly be moved away while the source output is still connected 435 * to the master. */ 436 pa_source_output_cork(u->source_output, true); 437 pa_source_unlink(u->source); 438 pa_source_output_unlink(u->source_output); 439 440 pa_source_output_unref(u->source_output); 441 u->source_output = NULL; 442 443 pa_source_unref(u->source); 444 u->source = NULL; 445 446 pa_module_unload_request(u->module, true); 447} 448 449/* Called from main thread */ 450static void source_output_moving_cb(pa_source_output *o, pa_source *dest) { 451 struct userdata *u; 452 uint32_t idx; 453 pa_source_output *output; 454 455 pa_source_output_assert_ref(o); 456 pa_assert_ctl_context(); 457 pa_assert_se(u = o->userdata); 458 459 if (dest) { 460 pa_source_set_asyncmsgq(u->source, dest->asyncmsgq); 461 pa_source_update_flags(u->source, PA_SOURCE_LATENCY|PA_SOURCE_DYNAMIC_LATENCY, dest->flags); 462 } else 463 pa_source_set_asyncmsgq(u->source, NULL); 464 465 /* Propagate asyncmsq change to attached virtual sources */ 466 PA_IDXSET_FOREACH(output, u->source->outputs, idx) { 467 if (output->destination_source && output->moving) 468 output->moving(output, u->source); 469 } 470 471 if (u->auto_desc && dest) { 472 const char *z; 473 pa_proplist *pl; 474 475 pl = pa_proplist_new(); 476 z = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION); 477 pa_proplist_setf(pl, PA_PROP_DEVICE_DESCRIPTION, "Virtual Source %s on %s", 478 pa_proplist_gets(u->source->proplist, "device.vsource.name"), z ? z : dest->name); 479 480 pa_source_update_proplist(u->source, PA_UPDATE_REPLACE, pl); 481 pa_proplist_free(pl); 482 } 483} 484 485int pa__init(pa_module*m) { 486 struct userdata *u; 487 pa_sample_spec ss; 488 pa_channel_map map; 489 pa_modargs *ma; 490 pa_source *master=NULL; 491 pa_source_output_new_data source_output_data; 492 pa_source_new_data source_data; 493 bool use_volume_sharing = true; 494 bool force_flat_volume = false; 495 496 /* optional for uplink_sink */ 497 pa_sink_new_data sink_data; 498 size_t nbytes; 499 500 pa_assert(m); 501 502 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { 503 pa_log("Failed to parse module arguments."); 504 goto fail; 505 } 506 507 if (!(master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "master", NULL), PA_NAMEREG_SOURCE))) { 508 pa_log("Master source not found"); 509 goto fail; 510 } 511 512 pa_assert(master); 513 514 ss = master->sample_spec; 515 ss.format = PA_SAMPLE_FLOAT32; 516 map = master->channel_map; 517 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { 518 pa_log("Invalid sample format specification or channel map"); 519 goto fail; 520 } 521 522 if (pa_modargs_get_value_boolean(ma, "use_volume_sharing", &use_volume_sharing) < 0) { 523 pa_log("use_volume_sharing= expects a boolean argument"); 524 goto fail; 525 } 526 527 if (pa_modargs_get_value_boolean(ma, "force_flat_volume", &force_flat_volume) < 0) { 528 pa_log("force_flat_volume= expects a boolean argument"); 529 goto fail; 530 } 531 532 if (use_volume_sharing && force_flat_volume) { 533 pa_log("Flat volume can't be forced when using volume sharing."); 534 goto fail; 535 } 536 537 u = pa_xnew0(struct userdata, 1); 538 u->module = m; 539 m->userdata = u; 540 u->memblockq = pa_memblockq_new("module-virtual-source memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, NULL); 541 if (!u->memblockq) { 542 pa_log("Failed to create source memblockq."); 543 goto fail; 544 } 545 u->channels = ss.channels; 546 547 /* The rtpoll created here is never run. It is only necessary to avoid crashes 548 * when module-virtual-source is used together with module-loopback or 549 * module-combine-sink. Both modules base their asyncmsq on the rtpoll provided 550 * by the sink. module-loopback and combine-sink only work because they 551 * call pa_asyncmsq_process_one() themselves. */ 552 u->rtpoll = pa_rtpoll_new(); 553 554 /* Create source */ 555 pa_source_new_data_init(&source_data); 556 source_data.driver = __FILE__; 557 source_data.module = m; 558 if (!(source_data.name = pa_xstrdup(pa_modargs_get_value(ma, "source_name", NULL)))) 559 source_data.name = pa_sprintf_malloc("%s.vsource", master->name); 560 pa_source_new_data_set_sample_spec(&source_data, &ss); 561 pa_source_new_data_set_channel_map(&source_data, &map); 562 pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name); 563 pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_CLASS, "filter"); 564 pa_proplist_sets(source_data.proplist, "device.vsource.name", source_data.name); 565 566 if (pa_modargs_get_proplist(ma, "source_properties", source_data.proplist, PA_UPDATE_REPLACE) < 0) { 567 pa_log("Invalid properties"); 568 pa_source_new_data_done(&source_data); 569 goto fail; 570 } 571 572 if ((u->auto_desc = !pa_proplist_contains(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) { 573 const char *z; 574 575 z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION); 576 pa_proplist_setf(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Virtual Source %s on %s", source_data.name, z ? z : master->name); 577 } 578 579 u->source = pa_source_new(m->core, &source_data, (master->flags & (PA_SOURCE_LATENCY|PA_SOURCE_DYNAMIC_LATENCY)) 580 | (use_volume_sharing ? PA_SOURCE_SHARE_VOLUME_WITH_MASTER : 0)); 581 582 pa_source_new_data_done(&source_data); 583 584 if (!u->source) { 585 pa_log("Failed to create source."); 586 goto fail; 587 } 588 589 u->source->parent.process_msg = source_process_msg_cb; 590 u->source->set_state_in_main_thread = source_set_state_in_main_thread_cb; 591 u->source->update_requested_latency = source_update_requested_latency_cb; 592 pa_source_set_set_mute_callback(u->source, source_set_mute_cb); 593 if (!use_volume_sharing) { 594 pa_source_set_set_volume_callback(u->source, source_set_volume_cb); 595 pa_source_enable_decibel_volume(u->source, true); 596 } 597 /* Normally this flag would be enabled automatically be we can force it. */ 598 if (force_flat_volume) 599 u->source->flags |= PA_SOURCE_FLAT_VOLUME; 600 u->source->userdata = u; 601 602 pa_source_set_asyncmsgq(u->source, master->asyncmsgq); 603 604 /* Create source output */ 605 pa_source_output_new_data_init(&source_output_data); 606 source_output_data.driver = __FILE__; 607 source_output_data.module = m; 608 pa_source_output_new_data_set_source(&source_output_data, master, false, true); 609 source_output_data.destination_source = u->source; 610 611 pa_proplist_setf(source_output_data.proplist, PA_PROP_MEDIA_NAME, "Virtual Source Stream of %s", pa_proplist_gets(u->source->proplist, PA_PROP_DEVICE_DESCRIPTION)); 612 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "filter"); 613 pa_source_output_new_data_set_sample_spec(&source_output_data, &ss); 614 pa_source_output_new_data_set_channel_map(&source_output_data, &map); 615 source_output_data.flags |= PA_SOURCE_OUTPUT_START_CORKED; 616 617 pa_source_output_new(&u->source_output, m->core, &source_output_data); 618 pa_source_output_new_data_done(&source_output_data); 619 620 if (!u->source_output) 621 goto fail; 622 623 u->source_output->push = source_output_push_cb; 624 u->source_output->process_rewind = source_output_process_rewind_cb; 625 u->source_output->update_max_rewind = source_output_update_max_rewind_cb; 626 u->source_output->kill = source_output_kill_cb; 627 u->source_output->attach = source_output_attach_cb; 628 u->source_output->detach = source_output_detach_cb; 629 u->source_output->state_change = source_output_state_change_cb; 630 u->source_output->moving = source_output_moving_cb; 631 u->source_output->userdata = u; 632 633 u->source->output_from_master = u->source_output; 634 635 /* The order here is important. The output must be put first, 636 * otherwise streams might attach to the source before the 637 * source output is attached to the master. */ 638 pa_source_output_put(u->source_output); 639 pa_source_put(u->source); 640 pa_source_output_cork(u->source_output, false); 641 642 /* Create optional uplink sink */ 643 pa_sink_new_data_init(&sink_data); 644 sink_data.driver = __FILE__; 645 sink_data.module = m; 646 if ((sink_data.name = pa_xstrdup(pa_modargs_get_value(ma, "uplink_sink", NULL)))) { 647 pa_sink_new_data_set_sample_spec(&sink_data, &ss); 648 pa_sink_new_data_set_channel_map(&sink_data, &map); 649 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name); 650 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "uplink sink"); 651 pa_proplist_sets(sink_data.proplist, "device.uplink_sink.name", sink_data.name); 652 653 if ((u->auto_desc = !pa_proplist_contains(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) { 654 const char *z; 655 656 z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION); 657 pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Uplink Sink %s on %s", sink_data.name, z ? z : master->name); 658 } 659 660 u->sink_memblockq = pa_memblockq_new("module-virtual-source sink_memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, NULL); 661 if (!u->sink_memblockq) { 662 pa_sink_new_data_done(&sink_data); 663 pa_log("Failed to create sink memblockq."); 664 goto fail; 665 } 666 667 u->sink = pa_sink_new(m->core, &sink_data, 0); /* FIXME, sink has no capabilities */ 668 pa_sink_new_data_done(&sink_data); 669 670 if (!u->sink) { 671 pa_log("Failed to create sink."); 672 goto fail; 673 } 674 675 u->sink->parent.process_msg = sink_process_msg_cb; 676 u->sink->update_requested_latency = sink_update_requested_latency_cb; 677 u->sink->set_state_in_main_thread = sink_set_state_in_main_thread_cb; 678 u->sink->userdata = u; 679 680 pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq); 681 pa_sink_set_rtpoll(u->sink, u->rtpoll); 682 683 /* FIXME: no idea what I am doing here */ 684 u->block_usec = BLOCK_USEC; 685 nbytes = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec); 686 pa_sink_set_max_rewind(u->sink, 0); 687 pa_sink_set_max_request(u->sink, nbytes); 688 689 pa_sink_put(u->sink); 690 } else { 691 pa_sink_new_data_done(&sink_data); 692 /* optional uplink sink not enabled */ 693 u->sink = NULL; 694 } 695 696 pa_modargs_free(ma); 697 698 return 0; 699 700fail: 701 if (ma) 702 pa_modargs_free(ma); 703 704 pa__done(m); 705 706 return -1; 707} 708 709int pa__get_n_used(pa_module *m) { 710 struct userdata *u; 711 712 pa_assert(m); 713 pa_assert_se(u = m->userdata); 714 715 return pa_source_linked_by(u->source); 716} 717 718void pa__done(pa_module*m) { 719 struct userdata *u; 720 721 pa_assert(m); 722 723 if (!(u = m->userdata)) 724 return; 725 726 /* See comments in source_output_kill_cb() above regarding 727 * destruction order! */ 728 729 if (u->source_output) 730 pa_source_output_cork(u->source_output, true); 731 732 if (u->source) 733 pa_source_unlink(u->source); 734 735 if (u->source_output) { 736 pa_source_output_unlink(u->source_output); 737 pa_source_output_unref(u->source_output); 738 } 739 740 if (u->source) 741 pa_source_unref(u->source); 742 743 if (u->sink) { 744 pa_sink_unlink(u->sink); 745 pa_sink_unref(u->sink); 746 } 747 748 if (u->memblockq) 749 pa_memblockq_free(u->memblockq); 750 751 if (u->sink_memblockq) 752 pa_memblockq_free(u->sink_memblockq); 753 754 if (u->rtpoll) 755 pa_rtpoll_free(u->rtpoll); 756 757 pa_xfree(u); 758} 759