"Fossies" - the Fresh Open Source Software Archive

Member "pulseaudio-13.0/src/modules/module-switch-on-connect.c" (13 Sep 2019, 8404 Bytes) of package /linux/misc/pulseaudio-13.0.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "module-switch-on-connect.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 12.2_vs_13.0.

    1 /***
    2   This file is part of PulseAudio.
    3 
    4   Copyright 2006 Lennart Poettering
    5   Copyright 2009 Canonical Ltd
    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 <pulse/xmalloc.h>
   26 
   27 #include <pulsecore/core.h>
   28 #include <pulsecore/sink-input.h>
   29 #include <pulsecore/source-output.h>
   30 #include <pulsecore/source.h>
   31 #include <pulsecore/modargs.h>
   32 #include <pulsecore/log.h>
   33 #include <pulsecore/namereg.h>
   34 #include <pulsecore/core-util.h>
   35 
   36 PA_MODULE_AUTHOR("Michael Terry");
   37 PA_MODULE_DESCRIPTION("When a sink/source is added, switch to it or conditionally switch to it");
   38 PA_MODULE_VERSION(PACKAGE_VERSION);
   39 PA_MODULE_LOAD_ONCE(true);
   40 PA_MODULE_USAGE(
   41         "only_from_unavailable=<boolean, only switch from unavailable ports> "
   42         "ignore_virtual=<boolean, ignore new virtual sinks and sources, defaults to true> "
   43 );
   44 
   45 static const char* const valid_modargs[] = {
   46     "only_from_unavailable",
   47     "ignore_virtual",
   48     NULL,
   49 };
   50 
   51 struct userdata {
   52     bool only_from_unavailable;
   53     bool ignore_virtual;
   54 };
   55 
   56 static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* userdata) {
   57     pa_sink_input *i;
   58     uint32_t idx;
   59     pa_sink *old_default_sink;
   60     const char *s;
   61     struct userdata *u = userdata;
   62 
   63     pa_assert(c);
   64     pa_assert(sink);
   65     pa_assert(userdata);
   66 
   67     /* Don't want to run during startup or shutdown */
   68     if (c->state != PA_CORE_RUNNING)
   69         return PA_HOOK_OK;
   70 
   71     pa_log_debug("Trying to switch to new sink %s", sink->name);
   72 
   73     /* Don't switch to any internal devices except HDMI */
   74     s = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_STRING);
   75     if (s && !pa_startswith(s, "hdmi")) {
   76         s = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_BUS);
   77         if (pa_safe_streq(s, "pci") || pa_safe_streq(s, "isa")) {
   78             pa_log_debug("Refusing to switch to sink on %s bus", s);
   79             return PA_HOOK_OK;
   80         }
   81     }
   82 
   83     /* Ignore virtual sinks if not configured otherwise on the command line */
   84     if (u->ignore_virtual && !(sink->flags & PA_SINK_HARDWARE)) {
   85         pa_log_debug("Refusing to switch to virtual sink");
   86         return PA_HOOK_OK;
   87     }
   88 
   89     /* No default sink, nothing to move away, just set the new default */
   90     if (!c->default_sink) {
   91         pa_core_set_configured_default_sink(c, sink->name);
   92         return PA_HOOK_OK;
   93     }
   94 
   95     if (c->default_sink == sink) {
   96         pa_log_debug("%s already is the default sink", sink->name);
   97         return PA_HOOK_OK;
   98     }
   99 
  100     if (u->only_from_unavailable)
  101         if (!c->default_sink->active_port || c->default_sink->active_port->available != PA_AVAILABLE_NO) {
  102             pa_log_debug("Current default sink is available and module argument only_from_unavailable was set");
  103             return PA_HOOK_OK;
  104         }
  105 
  106     old_default_sink = c->default_sink;
  107 
  108     /* Actually do the switch to the new sink */
  109     pa_core_set_configured_default_sink(c, sink->name);
  110 
  111     /* Now move all old inputs over */
  112     if (pa_idxset_size(old_default_sink->inputs) <= 0) {
  113         pa_log_debug("No sink inputs to move away.");
  114         return PA_HOOK_OK;
  115     }
  116 
  117     PA_IDXSET_FOREACH(i, old_default_sink->inputs, idx) {
  118         if (i->save_sink || !PA_SINK_INPUT_IS_LINKED(i->state))
  119             continue;
  120 
  121         if (pa_sink_input_move_to(i, sink, false) < 0)
  122             pa_log_info("Failed to move sink input %u \"%s\" to %s.", i->index,
  123                         pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), sink->name);
  124         else
  125             pa_log_info("Successfully moved sink input %u \"%s\" to %s.", i->index,
  126                         pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), sink->name);
  127     }
  128 
  129     return PA_HOOK_OK;
  130 }
  131 
  132 static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, void* userdata) {
  133     pa_source_output *o;
  134     uint32_t idx;
  135     pa_source *old_default_source;
  136     const char *s;
  137     struct userdata *u = userdata;
  138 
  139     pa_assert(c);
  140     pa_assert(source);
  141     pa_assert(userdata);
  142 
  143     /* Don't want to run during startup or shutdown */
  144     if (c->state != PA_CORE_RUNNING)
  145         return PA_HOOK_OK;
  146 
  147     /* Don't switch to a monitoring source */
  148     if (source->monitor_of)
  149         return PA_HOOK_OK;
  150 
  151     pa_log_debug("Trying to switch to new source %s", source->name);
  152 
  153     /* Don't switch to any internal devices */
  154     s = pa_proplist_gets(source->proplist, PA_PROP_DEVICE_BUS);
  155     if (pa_safe_streq(s, "pci") || pa_safe_streq(s, "isa")) {
  156         pa_log_debug("Refusing to switch to source on %s bus", s);
  157         return PA_HOOK_OK;
  158     }
  159 
  160     /* Ignore virtual sources if not configured otherwise on the command line */
  161     if (u->ignore_virtual && !(source->flags & PA_SOURCE_HARDWARE)) {
  162         pa_log_debug("Refusing to switch to virtual source");
  163         return PA_HOOK_OK;
  164     }
  165 
  166     /* No default source, nothing to move away, just set the new default */
  167     if (!c->default_source) {
  168         pa_core_set_configured_default_source(c, source->name);
  169         return PA_HOOK_OK;
  170     }
  171 
  172     if (c->default_source == source) {
  173         pa_log_debug("%s already is the default source", source->name);
  174         return PA_HOOK_OK;
  175     }
  176 
  177     if (u->only_from_unavailable)
  178         if (!c->default_source->active_port || c->default_source->active_port->available != PA_AVAILABLE_NO) {
  179             pa_log_debug("Current default source is available and module argument only_from_unavailable was set");
  180             return PA_HOOK_OK;
  181         }
  182 
  183     old_default_source = c->default_source;
  184 
  185     /* Actually do the switch to the new source */
  186     pa_core_set_configured_default_source(c, source->name);
  187 
  188     /* Now move all old outputs over */
  189     if (pa_idxset_size(old_default_source->outputs) <= 0) {
  190         pa_log_debug("No source outputs to move away.");
  191         return PA_HOOK_OK;
  192     }
  193 
  194     PA_IDXSET_FOREACH(o, old_default_source->outputs, idx) {
  195         if (o->save_source || !PA_SOURCE_OUTPUT_IS_LINKED(o->state))
  196             continue;
  197 
  198         if (pa_source_output_move_to(o, source, false) < 0)
  199             pa_log_info("Failed to move source output %u \"%s\" to %s.", o->index,
  200                         pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_APPLICATION_NAME)), source->name);
  201         else
  202             pa_log_info("Successfully moved source output %u \"%s\" to %s.", o->index,
  203                         pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_APPLICATION_NAME)), source->name);
  204     }
  205 
  206     return PA_HOOK_OK;
  207 }
  208 
  209 int pa__init(pa_module*m) {
  210     pa_modargs *ma;
  211     struct userdata *u;
  212 
  213     pa_assert(m);
  214 
  215     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
  216         pa_log("Failed to parse module arguments");
  217         return -1;
  218     }
  219 
  220     m->userdata = u = pa_xnew0(struct userdata, 1);
  221 
  222     /* A little bit later than module-rescue-streams... */
  223     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE+30, (pa_hook_cb_t) sink_put_hook_callback, u);
  224     pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE+20, (pa_hook_cb_t) source_put_hook_callback, u);
  225 
  226     if (pa_modargs_get_value_boolean(ma, "only_from_unavailable", &u->only_from_unavailable) < 0) {
  227         pa_log("Failed to get a boolean value for only_from_unavailable.");
  228         goto fail;
  229     }
  230 
  231     u->ignore_virtual = true;
  232     if (pa_modargs_get_value_boolean(ma, "ignore_virtual", &u->ignore_virtual) < 0) {
  233         pa_log("Failed to get a boolean value for ignore_virtual.");
  234         goto fail;
  235     }
  236 
  237     pa_modargs_free(ma);
  238     return 0;
  239 
  240 fail:
  241     if (ma)
  242         pa_modargs_free(ma);
  243 
  244     pa__done(m);
  245 
  246     return -1;
  247 }
  248 
  249 void pa__done(pa_module*m) {
  250     struct userdata *u;
  251 
  252     pa_assert(m);
  253 
  254     if (!(u = m->userdata))
  255         return;
  256 
  257     pa_xfree(u);
  258 }