scripting: support for zone based routing in application classes
[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 typedef struct {
39     const char *media_role;
40     int         time;
41 } latency_def;
42
43
44 static int get_latency(const char *);
45
46
47 pa_loopback *pa_loopback_init(void)
48 {
49     pa_loopback *loopback = pa_xnew0(pa_loopback, 1);
50
51     return loopback;
52 }
53
54
55 void pa_loopback_done(pa_loopback *loopback, pa_core *core)
56 {
57     pa_loopnode *loop, *n;
58
59     PA_LLIST_FOREACH_SAFE(loop,n, loopback->loopnodes) {
60         pa_module_unload_by_index(core, loop->module_index, FALSE);
61     }
62 }
63
64
65
66 pa_loopnode *pa_loopback_create(pa_loopback      *loopback,
67                                 pa_core          *core,
68                                 pa_loopback_type  type,
69                                 uint32_t          node_index,
70                                 uint32_t          source_index,
71                                 uint32_t          sink_index,
72                                 const char       *media_role,
73                                 uint32_t          resource_priority,
74                                 uint32_t          resource_set_flags,
75                                 uint32_t          resource_audio_flags)
76 {
77     static char *modnam = "module-loopback";
78
79     pa_loopnode       *loop;
80     pa_source         *source;
81     pa_sink           *sink;
82     pa_module         *module;
83     pa_sink_input     *sink_input;
84     pa_source_output  *source_output;
85     char               args[512];
86     uint32_t           idx;
87
88     pa_assert(core);
89     pa_assert(media_role);
90     pa_assert(type == PA_LOOPBACK_SOURCE || type == PA_LOOPBACK_SINK);
91
92     if (!(source = pa_idxset_get_by_index(core->sources, source_index))) {
93         pa_log_debug("can't find source (index %u) for loopback",source_index);
94         return NULL;
95     }
96
97     if (!(sink = pa_idxset_get_by_index(core->sinks, sink_index))) {
98         pa_log_debug("can't find the primary sink (index %u) for loopback",
99                      sink_index);
100         return NULL;
101     }
102             
103
104     if (type == PA_LOOPBACK_SOURCE) {
105         snprintf(args, sizeof(args), "source=\"%s\" sink=\"%s\" "
106                  "latency_msec=%d "
107                  "sink_input_properties=\"%s=%s %s=%u %s=%u %s=%u %s=%u\" "
108                  "source_output_properties=\"%s=%s %s=%u\"",
109                  source->name, sink->name,
110                  get_latency(media_role),
111                  PA_PROP_MEDIA_ROLE, media_role,
112                  PA_PROP_NODE_INDEX, node_index,
113                  PA_PROP_RESOURCE_PRIORITY, resource_priority,
114                  PA_PROP_RESOURCE_SET_FLAGS, resource_set_flags, 
115                  PA_PROP_RESOURCE_AUDIO_FLAGS, resource_audio_flags,
116                  PA_PROP_MEDIA_ROLE, media_role,
117                  PA_PROP_NODE_INDEX, node_index);
118     }
119     else {
120         snprintf(args, sizeof(args), "source=\"%s\" sink=\"%s\" "
121                  "latency_msec=%d "
122                  "sink_input_properties=\"%s=%s %s=%u\" "
123                  "source_output_properties=\"%s=%s %s=%u %s=%u %s=%u %s=%u\"",
124                  source->name, sink->name,
125                  get_latency(media_role),
126                  PA_PROP_MEDIA_ROLE, media_role,
127                  PA_PROP_NODE_INDEX, node_index,
128                  PA_PROP_MEDIA_ROLE, media_role,
129                  PA_PROP_NODE_INDEX, node_index,
130                  PA_PROP_RESOURCE_PRIORITY, resource_priority,
131                  PA_PROP_RESOURCE_SET_FLAGS, resource_set_flags, 
132                  PA_PROP_RESOURCE_AUDIO_FLAGS, resource_audio_flags);
133     }
134
135     pa_log_debug("loading %s %s", modnam, args);
136
137     if (!(module = pa_module_load(core, modnam, args))) {
138         pa_log("failed to load module '%s %s'. can't loopback", modnam, args);
139         return NULL;
140     }
141
142     PA_IDXSET_FOREACH(sink_input, core->sink_inputs, idx) {
143         if (sink_input->module == module)
144             break;
145     }
146
147     PA_IDXSET_FOREACH(source_output, core->source_outputs, idx) {
148         if (source_output->module == module)
149             break;
150     }
151
152     if (!sink_input || !source_output) {
153         if (!sink_input) {
154             pa_log("can't find output stream of loopback module (index %u)",
155                    module->index);
156         }
157         if (!source_output) {
158             pa_log("can't find input stream of loopback module (index %u)",
159                    module->index);
160         }
161         pa_module_unload(core, module, FALSE);
162         return NULL;
163     }
164
165     pa_assert(sink_input->index != PA_IDXSET_INVALID);
166     pa_assert(source_output->index != PA_IDXSET_INVALID);
167
168     loop = pa_xnew0(pa_loopnode, 1);
169     loop->module_index = module->index;
170     loop->node_index = node_index;
171     loop->sink_input_index = sink_input->index;
172     loop->source_output_index = source_output->index;
173
174     PA_LLIST_PREPEND(pa_loopnode, loopback->loopnodes, loop);
175
176     pa_log_debug("loopback succesfully loaded. Module index %u",module->index);
177
178     return loop;
179 }
180
181
182 void pa_loopback_destroy(pa_loopback *loopback,
183                          pa_core     *core,
184                          pa_loopnode *loop)
185 {
186     pa_assert(loopback);
187     pa_assert(core);
188
189     if (loop) {
190         PA_LLIST_REMOVE(pa_loopnode, loopback->loopnodes, loop);
191         pa_module_unload_by_index(core, loop->module_index, FALSE);
192         pa_xfree(loop);
193     }
194 }
195
196 uint32_t pa_loopback_get_sink_index(pa_core *core, pa_loopnode *loop)
197 {
198     pa_sink_input *sink_input;
199     pa_sink *sink;
200
201     pa_assert(core);
202     pa_assert(loop);
203
204     sink_input = pa_idxset_get_by_index(core->sink_inputs,
205                                         loop->sink_input_index);
206
207     if (sink_input && (sink = sink_input->sink))
208         return sink->index;
209
210     return PA_IDXSET_INVALID;
211 }
212
213 int pa_loopback_print(pa_loopnode *loop, char *buf, int len)
214 {
215     char *p, *e;
216
217     pa_assert(buf);
218     pa_assert(len > 0);
219
220     e = (p = buf) + len;
221
222     if (!loop)
223         p += snprintf(p, e-p, "<not set>");
224     else {
225         p += snprintf(p, e-p, "module %u, sink_input %u",
226                       loop->module_index, loop->sink_input_index);
227     }
228     
229     return p - buf;
230 }
231
232 static int get_latency(const char *media_role)
233 {
234     static latency_def  latencies[] = {
235         { "phone"   , 50 },
236         { "ringtone", 50 },
237         {    NULL   , 0  }
238     };
239
240     latency_def *l;
241
242     pa_assert(media_role);
243
244     for (l = latencies;  l->media_role;  l++) {
245         if (pa_streq(media_role, l->media_role))
246             return l->time;
247     }
248
249     return 200;
250 }
251
252
253 /*
254  * Local Variables:
255  * c-basic-offset: 4
256  * indent-tabs-mode: nil
257  * End:
258  *
259  */
260