summaryrefslogtreecommitdiffstats
path: root/loopback.c
blob: 0c955672a2b4997e80b182acd7630d7e6f32e0c9 (plain)
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);
	}
}