alsa: skip eld initialization if hctl_handle is NULL
[platform/upstream/pulseaudio.git] / src / modules / module-switch-on-connect.c
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, write to the Free Software
19   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20   USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <pulse/xmalloc.h>
28
29 #include <pulsecore/core.h>
30 #include <pulsecore/sink-input.h>
31 #include <pulsecore/source-output.h>
32 #include <pulsecore/source.h>
33 #include <pulsecore/modargs.h>
34 #include <pulsecore/log.h>
35 #include <pulsecore/namereg.h>
36 #include <pulsecore/core-util.h>
37
38 #include "module-switch-on-connect-symdef.h"
39
40 PA_MODULE_AUTHOR("Michael Terry");
41 PA_MODULE_DESCRIPTION("When a sink/source is added, switch to it");
42 PA_MODULE_VERSION(PACKAGE_VERSION);
43 PA_MODULE_LOAD_ONCE(TRUE);
44
45 static const char* const valid_modargs[] = {
46     NULL,
47 };
48
49 struct userdata {
50     pa_hook_slot
51         *sink_put_slot,
52         *source_put_slot;
53 };
54
55 static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* userdata) {
56     pa_sink_input *i;
57     uint32_t idx;
58     pa_sink *def;
59     const char *s;
60
61     pa_assert(c);
62     pa_assert(sink);
63
64     /* Don't want to run during startup or shutdown */
65     if (c->state != PA_CORE_RUNNING)
66         return PA_HOOK_OK;
67
68     /* Don't switch to any internal devices */
69     if ((s = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_BUS))) {
70         if (pa_streq(s, "pci"))
71             return PA_HOOK_OK;
72         else if (pa_streq(s, "isa"))
73             return PA_HOOK_OK;
74     }
75
76     def = pa_namereg_get_default_sink(c);
77     if (def == sink)
78         return PA_HOOK_OK;
79
80     /* Actually do the switch to the new sink */
81     pa_namereg_set_default_sink(c, sink);
82
83     /* Now move all old inputs over */
84     if (pa_idxset_size(def->inputs) <= 0) {
85         pa_log_debug("No sink inputs to move away.");
86         return PA_HOOK_OK;
87     }
88
89     PA_IDXSET_FOREACH(i, def->inputs, idx) {
90         if (i->save_sink || !PA_SINK_INPUT_IS_LINKED(i->state))
91             continue;
92
93         if (pa_sink_input_move_to(i, sink, FALSE) < 0)
94             pa_log_info("Failed to move sink input %u \"%s\" to %s.", i->index,
95                         pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), sink->name);
96         else
97             pa_log_info("Successfully moved sink input %u \"%s\" to %s.", i->index,
98                         pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), sink->name);
99     }
100
101     return PA_HOOK_OK;
102 }
103
104 static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, void* userdata) {
105     pa_source_output *o;
106     uint32_t idx;
107     pa_source *def;
108     const char *s;
109
110     pa_assert(c);
111     pa_assert(source);
112
113     /* Don't want to run during startup or shutdown */
114     if (c->state != PA_CORE_RUNNING)
115         return PA_HOOK_OK;
116
117     /* Don't switch to a monitoring source */
118     if (source->monitor_of)
119         return PA_HOOK_OK;
120
121     /* Don't switch to any internal devices */
122     if ((s = pa_proplist_gets(source->proplist, PA_PROP_DEVICE_BUS))) {
123         if (pa_streq(s, "pci"))
124             return PA_HOOK_OK;
125         else if (pa_streq(s, "isa"))
126             return PA_HOOK_OK;
127     }
128
129     def = pa_namereg_get_default_source(c);
130     if (def == source)
131         return PA_HOOK_OK;
132
133     /* Actually do the switch to the new source */
134     pa_namereg_set_default_source(c, source);
135
136     /* Now move all old outputs over */
137     if (pa_idxset_size(def->outputs) <= 0) {
138         pa_log_debug("No source outputs to move away.");
139         return PA_HOOK_OK;
140     }
141
142     PA_IDXSET_FOREACH(o, def->outputs, idx) {
143         if (o->save_source || !PA_SOURCE_OUTPUT_IS_LINKED(o->state))
144             continue;
145
146         if (pa_source_output_move_to(o, source, FALSE) < 0)
147             pa_log_info("Failed to move source output %u \"%s\" to %s.", o->index,
148                         pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_APPLICATION_NAME)), source->name);
149         else
150             pa_log_info("Successfully moved source output %u \"%s\" to %s.", o->index,
151                         pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_APPLICATION_NAME)), source->name);
152     }
153
154     return PA_HOOK_OK;
155 }
156
157 int pa__init(pa_module*m) {
158     pa_modargs *ma;
159     struct userdata *u;
160
161     pa_assert(m);
162
163     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
164         pa_log("Failed to parse module arguments");
165         return -1;
166     }
167
168     m->userdata = u = pa_xnew(struct userdata, 1);
169
170     /* A little bit later than module-rescue-streams... */
171     u->sink_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE+30, (pa_hook_cb_t) sink_put_hook_callback, u);
172     u->source_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE+20, (pa_hook_cb_t) source_put_hook_callback, u);
173
174     pa_modargs_free(ma);
175     return 0;
176 }
177
178 void pa__done(pa_module*m) {
179     struct userdata *u;
180
181     pa_assert(m);
182
183     if (!(u = m->userdata))
184         return;
185
186     if (u->sink_put_slot)
187         pa_hook_slot_free(u->sink_put_slot);
188     if (u->source_put_slot)
189         pa_hook_slot_free(u->source_put_slot);
190
191     pa_xfree(u);
192 }