char *pa_sink_list_to_string(pa_core *c) { pa_strbuf *s; pa_sink *sink; uint32_t idx = PA_IDXSET_INVALID; static const char* const state_table[] = { [PA_SINK_RUNNING] = "RUNNING", [PA_SINK_SUSPENDED] = "SUSPENDED", [PA_SINK_IDLE] = "IDLE", [PA_SINK_UNLINKED] = "UNLINKED" }; pa_assert(c); s = pa_strbuf_new(); pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_size(c->sinks)); for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_strbuf_printf( s, " %c index: %u\n" "\tname: <%s>\n" "\tdriver: <%s>\n" "\tflags: %s%s%s%s\n" "\tstate: %s\n" "\tvolume: <%s>\n" "\tmute: <%i>\n" "\tlatency: <%0.0f usec>\n" "\tmonitor source: <%u>\n" "\tsample spec: <%s>\n" "\tchannel map: <%s>\n" "\tused by: <%u>\n" "\tlinked by: <%u>\n", c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ', sink->index, sink->name, sink->driver, sink->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "", sink->flags & PA_SINK_LATENCY ? "LATENCY " : "", sink->flags & PA_SINK_HARDWARE ? "HARDWARE " : "", sink->flags & PA_SINK_NETWORK ? "NETWORK " : "", state_table[pa_sink_get_state(sink)], pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink)), !!pa_sink_get_mute(sink), (double) pa_sink_get_latency(sink), sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX, pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec), pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map), pa_sink_used_by(sink), pa_sink_linked_by(sink)); if (sink->module) pa_strbuf_printf(s, "\tmodule: <%u>\n", sink->module->index); if (sink->description) pa_strbuf_printf(s, "\tdescription: <%s>\n", sink->description); } return pa_strbuf_tostring_free(s); }
int pa__get_n_used(pa_module *m) { struct userdata *u; pa_assert(m); pa_assert_se(u = m->userdata); return pa_sink_linked_by(u->sink); }
int pa__get_n_used(pa_module *m) { pa_sink *sink; pa_assert(m); pa_assert_se(sink = m->userdata); return pa_sink_linked_by(sink); }
int pa__get_n_used(pa_module *module) { struct context *context; pa_assert(module); pa_assert_se(context = module->userdata); return pa_sink_linked_by(context->sink); }
int pa__init(pa_module*m) { struct userdata *u = NULL; pa_sample_spec ss; pa_channel_map map; pa_modargs *ma = NULL; pa_sink_new_data data; size_t nbytes; pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("Failed to parse module arguments."); goto fail; } ss = m->core->default_sample_spec; map = m->core->default_channel_map; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { pa_log("Invalid sample format specification or channel map"); goto fail; } m->userdata = u = pa_xnew0(struct userdata, 1); u->core = m->core; u->module = m; u->rtpoll = pa_rtpoll_new(); pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); pa_sink_new_data_init(&data); data.driver = __FILE__; data.module = m; pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME)); pa_sink_new_data_set_sample_spec(&data, &ss); pa_sink_new_data_set_channel_map(&data, &map); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "xrdp sink"); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract"); if (pa_modargs_get_proplist(ma, "sink_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { pa_log("Invalid properties"); pa_sink_new_data_done(&data); goto fail; } u->sink = pa_sink_new(m->core, &data, PA_SINK_LATENCY | PA_SINK_DYNAMIC_LATENCY); pa_sink_new_data_done(&data); if (!u->sink) { pa_log("Failed to create sink object."); goto fail; } u->sink->parent.process_msg = sink_process_msg; u->sink->update_requested_latency = sink_update_requested_latency_cb; u->sink->userdata = u; pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); pa_sink_set_rtpoll(u->sink, u->rtpoll); u->block_usec = BLOCK_USEC; pa_log_debug("3 block_usec %d", u->block_usec); nbytes = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec); pa_sink_set_max_rewind(u->sink, nbytes); pa_sink_set_max_request(u->sink, nbytes); u->display_num = get_display_num_from_display(getenv("DISPLAY")); #if defined(PA_CHECK_VERSION) #if PA_CHECK_VERSION(0, 9, 22) if (!(u->thread = pa_thread_new("xrdp-sink", thread_func, u))) { #else if (!(u->thread = pa_thread_new(thread_func, u))) { #endif #else if (!(u->thread = pa_thread_new(thread_func, u))) { #endif pa_log("Failed to create thread."); goto fail; } pa_sink_put(u->sink); pa_modargs_free(ma); return 0; fail: if (ma) { pa_modargs_free(ma); } pa__done(m); return -1; } int pa__get_n_used(pa_module *m) { struct userdata *u; pa_assert(m); pa_assert_se(u = m->userdata); return pa_sink_linked_by(u->sink); } void pa__done(pa_module*m) { struct userdata *u; pa_assert(m); if (!(u = m->userdata)) { return; } if (u->sink) { pa_sink_unlink(u->sink); } if (u->thread) { pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); pa_thread_free(u->thread); } pa_thread_mq_done(&u->thread_mq); if (u->sink) { pa_sink_unref(u->sink); } if (u->rtpoll) { pa_rtpoll_free(u->rtpoll); } pa_xfree(u); }
int pa__init(pa_module * m) { struct userdata *u; pa_sample_spec ss; pa_channel_map map; pa_modargs *ma; struct pollfd *pollfd; pa_sink_new_data data_sink; pa_source_new_data data_source; pa_assert(m); pa_log("vchan module loading"); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("Failed to parse module arguments."); goto fail; } ss = m->core->default_sample_spec; map = m->core->default_channel_map; if (pa_modargs_get_sample_spec_and_channel_map (ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { pa_log ("Invalid sample format specification or channel map"); goto fail; } u = pa_xnew0(struct userdata, 1); u->core = m->core; u->module = m; m->userdata = u; pa_memchunk_reset(&u->memchunk_sink); pa_memchunk_reset(&u->memchunk_source); u->rtpoll = pa_rtpoll_new(); pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); if ((do_conn(u)) < 0) { pa_log("get_early_allocated_vchan: %s", pa_cstrerror(errno)); goto fail; } /* SINK preparation */ pa_sink_new_data_init(&data_sink); data_sink.driver = __FILE__; data_sink.module = m; pa_sink_new_data_set_name(&data_sink, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME)); pa_proplist_sets(data_sink.proplist, PA_PROP_DEVICE_STRING, DEFAULT_SINK_NAME); pa_proplist_setf(data_sink.proplist, PA_PROP_DEVICE_DESCRIPTION, "Qubes VCHAN sink"); pa_sink_new_data_set_sample_spec(&data_sink, &ss); pa_sink_new_data_set_channel_map(&data_sink, &map); if (pa_modargs_get_proplist (ma, "sink_properties", data_sink.proplist, PA_UPDATE_REPLACE) < 0) { pa_log("Invalid properties"); pa_sink_new_data_done(&data_sink); goto fail; } u->sink = pa_sink_new(m->core, &data_sink, PA_SINK_LATENCY); pa_sink_new_data_done(&data_sink); if (!u->sink) { pa_log("Failed to create sink."); goto fail; } u->sink->parent.process_msg = sink_process_msg; u->sink->userdata = u; pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); pa_sink_set_rtpoll(u->sink, u->rtpoll); pa_sink_set_max_request(u->sink, VCHAN_BUF); pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec (VCHAN_BUF, &u->sink->sample_spec)); u->play_rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); pollfd = pa_rtpoll_item_get_pollfd(u->play_rtpoll_item, NULL); pollfd->fd = libvchan_fd_for_select(u->play_ctrl); pollfd->events = POLLIN; pollfd->revents = 0; /* SOURCE preparation */ pa_source_new_data_init(&data_source); data_source.driver = __FILE__; data_source.module = m; pa_source_new_data_set_name(&data_source, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME)); pa_proplist_sets(data_source.proplist, PA_PROP_DEVICE_STRING, DEFAULT_SOURCE_NAME); pa_proplist_setf(data_source.proplist, PA_PROP_DEVICE_DESCRIPTION, "Qubes VCHAN source"); pa_source_new_data_set_sample_spec(&data_source, &ss); pa_source_new_data_set_channel_map(&data_source, &map); if (pa_modargs_get_proplist(ma, "source_properties", data_source.proplist, PA_UPDATE_REPLACE) < 0) { pa_log("Invalid properties"); pa_source_new_data_done(&data_source); goto fail; } u->source = pa_source_new(m->core, &data_source, PA_SOURCE_LATENCY); pa_source_new_data_done(&data_source); if (!u->source) { pa_log("Failed to create source."); goto fail; } u->source->parent.process_msg = source_process_msg; u->source->userdata = u; pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); pa_source_set_rtpoll(u->source, u->rtpoll); pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(PIPE_BUF, &u->source->sample_spec)); u->rec_rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); pollfd = pa_rtpoll_item_get_pollfd(u->rec_rtpoll_item, NULL); pollfd->fd = libvchan_fd_for_select(u->rec_ctrl); pollfd->events = POLLIN; pollfd->revents = 0; #if PA_CHECK_VERSION(0,9,22) if (!(u->thread = pa_thread_new("vchan-sink", thread_func, u))) { #else if (!(u->thread = pa_thread_new(thread_func, u))) { #endif pa_log("Failed to create thread."); goto fail; } pa_sink_put(u->sink); pa_source_put(u->source); pa_modargs_free(ma); return 0; fail: if (ma) pa_modargs_free(ma); pa__done(m); return -1; } int pa__get_n_used(pa_module * m) { struct userdata *u; pa_assert(m); pa_assert_se(u = m->userdata); return pa_sink_linked_by(u->sink); } void pa__done(pa_module * m) { struct userdata *u; pa_assert(m); if (!(u = m->userdata)) return; if (u->sink) pa_sink_unlink(u->sink); if (u->source) pa_source_unlink(u->source); if (u->thread) { pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); pa_thread_free(u->thread); } pa_thread_mq_done(&u->thread_mq); if (u->sink) pa_sink_unref(u->sink); if (u->source) pa_source_unref(u->source); if (u->memchunk_sink.memblock) pa_memblock_unref(u->memchunk_sink.memblock); if (u->memchunk_source.memblock) pa_memblock_unref(u->memchunk_source.memblock); if (u->play_rtpoll_item) pa_rtpoll_item_free(u->play_rtpoll_item); if (u->rec_rtpoll_item) pa_rtpoll_item_free(u->rec_rtpoll_item); if (u->rtpoll) pa_rtpoll_free(u->rtpoll); if (u->play_ctrl) libvchan_close(u->play_ctrl); if (u->rec_ctrl) libvchan_close(u->rec_ctrl); pa_xfree(u); }
char *pa_sink_list_to_string(pa_core *c) { pa_strbuf *s; pa_sink *sink; uint32_t idx = PA_IDXSET_INVALID; pa_assert(c); s = pa_strbuf_new(); pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_size(c->sinks)); for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX], v[PA_VOLUME_SNPRINT_MAX], vdb[PA_SW_VOLUME_SNPRINT_DB_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t; const char *cmn; cmn = pa_channel_map_to_pretty_name(&sink->channel_map); pa_strbuf_printf( s, " %c index: %u\n" "\tname: <%s>\n" "\tdriver: <%s>\n" "\tflags: %s%s%s%s%s%s%s%s\n" "\tstate: %s\n" "\tsuspend cause: %s%s%s%s\n" "\tpriority: %u\n" "\tvolume: %s%s%s\n" "\t balance %0.2f\n" "\tbase volume: %s%s%s\n" "\tvolume steps: %u\n" "\tmuted: %s\n" "\tcurrent latency: %0.2f ms\n" "\tmax request: %lu KiB\n" "\tmax rewind: %lu KiB\n" "\tmonitor source: %u\n" "\tsample spec: %s\n" "\tchannel map: %s%s%s\n" "\tused by: %u\n" "\tlinked by: %u\n", sink == c->default_sink ? '*' : ' ', sink->index, sink->name, sink->driver, sink->flags & PA_SINK_HARDWARE ? "HARDWARE " : "", sink->flags & PA_SINK_NETWORK ? "NETWORK " : "", sink->flags & PA_SINK_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "", sink->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "", sink->flags & PA_SINK_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "", sink->flags & PA_SINK_LATENCY ? "LATENCY " : "", sink->flags & PA_SINK_FLAT_VOLUME ? "FLAT_VOLUME " : "", sink->flags & PA_SINK_DYNAMIC_LATENCY ? "DYNAMIC_LATENCY" : "", sink_state_to_string(pa_sink_get_state(sink)), sink->suspend_cause & PA_SUSPEND_USER ? "USER " : "", sink->suspend_cause & PA_SUSPEND_APPLICATION ? "APPLICATION " : "", sink->suspend_cause & PA_SUSPEND_IDLE ? "IDLE " : "", sink->suspend_cause & PA_SUSPEND_SESSION ? "SESSION" : "", sink->priority, pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, FALSE)), sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "", sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_sink_get_volume(sink, FALSE)) : "", pa_cvolume_get_balance(pa_sink_get_volume(sink, FALSE), &sink->channel_map), pa_volume_snprint(v, sizeof(v), sink->base_volume), sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "", sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), sink->base_volume) : "", sink->n_volume_steps, pa_yes_no(pa_sink_get_mute(sink, FALSE)), (double) pa_sink_get_latency(sink) / (double) PA_USEC_PER_MSEC, (unsigned long) pa_sink_get_max_request(sink) / 1024, (unsigned long) pa_sink_get_max_rewind(sink) / 1024, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX, pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec), pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map), cmn ? "\n\t " : "", cmn ? cmn : "", pa_sink_used_by(sink), pa_sink_linked_by(sink)); if (sink->flags & PA_SINK_DYNAMIC_LATENCY) { pa_usec_t min_latency, max_latency; pa_sink_get_latency_range(sink, &min_latency, &max_latency); pa_strbuf_printf( s, "\tconfigured latency: %0.2f ms; range is %0.2f .. %0.2f ms\n", (double) pa_sink_get_requested_latency(sink) / (double) PA_USEC_PER_MSEC, (double) min_latency / PA_USEC_PER_MSEC, (double) max_latency / PA_USEC_PER_MSEC); } else pa_strbuf_printf( s, "\tfixed latency: %0.2f ms\n", (double) pa_sink_get_fixed_latency(sink) / PA_USEC_PER_MSEC); if (sink->card) pa_strbuf_printf(s, "\tcard: %u <%s>\n", sink->card->index, sink->card->name); if (sink->module) pa_strbuf_printf(s, "\tmodule: %u\n", sink->module->index); t = pa_proplist_to_string_sep(sink->proplist, "\n\t\t"); pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t); pa_xfree(t); append_port_list(s, sink->ports); if (sink->active_port) pa_strbuf_printf( s, "\tactive port: <%s>\n", sink->active_port->name); } return pa_strbuf_tostring_free(s); }