1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
/*
* module-agl-audio -- PulseAudio module for providing audio routing support
* (forked from "module-murphy-ivi" - https://github.com/otcshare )
* Copyright (c) 2012, Intel Corporation.
* Copyright (c) 2016, IoT.bzh
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston,
* MA 02110-1301 USA.
*
*/
#include "loopback.h"
#include "utils.h"
#include "list.h"
agl_loopback *agl_loopback_init (void)
{
agl_loopback *loopback = pa_xnew0 (agl_loopback, 1);
return loopback;
}
void agl_loopback_done (struct userdata *u, agl_loopback *loopback)
{
agl_loopnode *loop, *n;
pa_core *core;
pa_assert_se (core = u->core);
PA_LLIST_FOREACH_SAFE(loop, n, loopback->loopnodes) {
pa_module_unload_by_index (core, loop->module_index, false);
}
}
agl_loopnode *agl_loopnode_create (struct userdata *u, agl_loopnode_type type,
uint32_t node_index, uint32_t source_index, uint32_t sink_index)
{
pa_core *core;
pa_module *module;
pa_source *source;
pa_sink *sink;
const char *sonam;
const char *sinam;
pa_source_output *sout;
pa_sink_input *sinp;
agl_loopnode *loopnode;
int idx;
char args[256];
pa_assert (u);
pa_assert_se (core = u->core);
source = pa_idxset_get_by_index (core->sources, source_index);
sink = pa_idxset_get_by_index (core->sinks, sink_index);
sonam = agl_utils_get_source_name (source);
sinam = agl_utils_get_sink_name (sink);
snprintf (args, sizeof(args), "source=\"%s\" sink=\"%s\"", sonam, sinam);
module = pa_module_load (core, "module-loopback", args);
if (!module) {
pa_log ("failed to load loopback for source '%s' & sink '%s'", sonam, sinam);
return NULL;
}
/* find the sink_input/source_output couple generated but the module we just loaded */
PA_IDXSET_FOREACH(sout, core->source_outputs, idx) {
if (sout->module && sout->module == module)
break;
sout = NULL;
}
PA_IDXSET_FOREACH(sinp, core->sink_inputs, idx) {
if (sinp->module && sinp->module == module)
break;
sinp = NULL;
}
if (!sout || !sinp) {
pa_module_unload (module, false);
return NULL;
}
loopnode = pa_xnew0 (agl_loopnode, 1);
loopnode->module_index = module->index;
loopnode->source_output_index = sout->index;
loopnode->sink_input_index = sinp->index;
return loopnode;
}
void agl_loopnode_destroy (struct userdata *u, agl_loopnode *loopnode)
{
pa_core *core;
pa_module *module;
if (u && (core = u->core)) {
if ((module = pa_idxset_get_by_index (core->modules, loopnode->module_index))){
pa_log_info ("unloading loopback");
pa_module_unload (module, false);
}
pa_xfree (loopnode);
}
}
|