discovery: add loopback support for sinks
[profile/ivi/pulseaudio-module-murphy-ivi.git] / murphy / loopback.c
1 /*
2  * module-murphy-ivi -- PulseAudio module for providing audio routing support
3  * Copyright (c) 2012, Intel Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU Lesser General Public License,
7  * version 2.1, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.
12  * See the GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston,
17  * MA 02110-1301 USA.
18  *
19  */
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <strings.h>
23
24 #include <pulsecore/pulsecore-config.h>
25
26 #include <pulse/def.h>
27 #include <pulsecore/thread.h>
28 #include <pulsecore/strlist.h>
29 #include <pulsecore/time-smoother.h>
30 #include <pulsecore/sink.h>
31 #include <pulsecore/sink-input.h>
32
33 #include "userdata.h"
34
35 #include "loopback.h"
36 #include "utils.h"
37
38
39 pa_loopback *pa_loopback_init(void)
40 {
41     pa_loopback *loopback = pa_xnew0(pa_loopback, 1);
42
43     return loopback;
44 }
45
46
47 void pa_loopback_done(pa_loopback *loopback, pa_core *core)
48 {
49     pa_loopnode *loop, *n;
50
51     PA_LLIST_FOREACH_SAFE(loop,n, loopback->loopnodes) {
52         pa_module_unload_by_index(core, loop->module_index, FALSE);
53     }
54 }
55
56
57
58 pa_loopnode *pa_loopback_create(pa_loopback   *loopback,
59                                 pa_core       *core,
60                                 uint32_t       node_index,
61                                 uint32_t       source_index,
62                                 uint32_t       sink_index,
63                                 const char    *media_role)
64 {
65     static char *modnam = "module-loopback";
66
67     pa_loopnode      *loop;
68     pa_source        *source;
69     pa_sink          *sink;
70     pa_module        *module;
71     pa_sink_input    *sink_input;
72     pa_source_output *source_output;
73     char              args[512];
74     uint32_t          idx;
75
76     pa_assert(core);
77
78     if (!(source = pa_idxset_get_by_index(core->sources, source_index))) {
79         pa_log_debug("can't find source (index %u) for loopback",source_index);
80         return NULL;
81     }
82
83     if (!(sink = pa_idxset_get_by_index(core->sinks, sink_index))) {
84         pa_log_debug("can't find the primary sink (index %u) for loopback",
85                      sink_index);
86         return NULL;
87     }
88
89     if (!media_role)
90         media_role = "music";
91
92     snprintf(args, sizeof(args), "source=\"%s\" sink=\"%s\" "
93              "sink_input_properties=\"%s=%s %s=%u\" "
94              "source_output_properties=\"%s=%s %s=%u\"",
95              source->name, sink->name,
96              PA_PROP_MEDIA_ROLE, media_role,
97              PA_PROP_NODE_INDEX, node_index,
98              PA_PROP_MEDIA_ROLE, media_role,
99              PA_PROP_NODE_INDEX, node_index);
100
101     pa_log_debug("loading %s %s", modnam, args);
102
103     if (!(module = pa_module_load(core, modnam, args))) {
104         pa_log("failed to load module '%s %s'. can't loopback", modnam, args);
105         return NULL;
106     }
107
108     PA_IDXSET_FOREACH(sink_input, core->sink_inputs, idx) {
109         if (sink_input->module == module)
110             break;
111     }
112
113     PA_IDXSET_FOREACH(source_output, core->source_outputs, idx) {
114         if (source_output->module == module)
115             break;
116     }
117
118     if (!sink_input || !source_output) {
119         if (!sink_input) {
120             pa_log("can't find output stream of loopback module (index %u)",
121                    module->index);
122         }
123         if (!source_output) {
124             pa_log("can't find input stream of loopback module (index %u)",
125                    module->index);
126         }
127         pa_module_unload(core, module, FALSE);
128         return NULL;
129     }
130
131     pa_assert(sink_input->index != PA_IDXSET_INVALID);
132     pa_assert(source_output->index != PA_IDXSET_INVALID);
133
134     loop = pa_xnew0(pa_loopnode, 1);
135     loop->module_index = module->index;
136     loop->node_index = node_index;
137     loop->sink_input_index = sink_input->index;
138     loop->source_output_index = source_output->index;
139
140     PA_LLIST_PREPEND(pa_loopnode, loopback->loopnodes, loop);
141
142     pa_log_debug("loopback succesfully loaded. Module index %u",module->index);
143
144     return loop;
145 }
146
147
148 void pa_loopback_destroy(pa_loopback *loopback,
149                          pa_core     *core,
150                          pa_loopnode *loop)
151 {
152     pa_assert(loopback);
153     pa_assert(core);
154
155     if (loop) {
156         PA_LLIST_REMOVE(pa_loopnode, loopback->loopnodes, loop);
157         pa_module_unload_by_index(core, loop->module_index, FALSE);
158         pa_xfree(loop);
159     }
160 }
161
162 uint32_t pa_loopback_get_sink_index(pa_core *core, pa_loopnode *loop)
163 {
164     pa_sink_input *sink_input;
165     pa_sink *sink;
166
167     pa_assert(core);
168     pa_assert(loop);
169
170     sink_input = pa_idxset_get_by_index(core->sink_inputs,
171                                         loop->sink_input_index);
172
173     if (sink_input && (sink = sink_input->sink))
174         return sink->index;
175
176     return PA_IDXSET_INVALID;
177 }
178
179 int pa_loopback_print(pa_loopnode *loop, char *buf, int len)
180 {
181     char *p, *e;
182
183     pa_assert(buf);
184     pa_assert(len > 0);
185
186     e = (p = buf) + len;
187
188     if (!loop)
189         p += snprintf(p, e-p, "<not set>");
190     else {
191         p += snprintf(p, e-p, "module %u, sink_input %u",
192                       loop->module_index, loop->sink_input_index);
193     }
194     
195     return p - buf;
196 }
197
198
199 /*
200  * Local Variables:
201  * c-basic-offset: 4
202  * indent-tabs-mode: nil
203  * End:
204  *
205  */
206