1 /**
2  * @file echo.c Echo module
3  */
4 #include <re.h>
5 #include <baresip.h>
6 
7 /**
8  *
9  * Multi Call Echo module
10  *
11  * REQUIRES: aubridge
12  * NOTE: This module is experimental.
13  *
14  */
15 
16 struct session {
17 	struct le le;
18 	struct call *call_in;
19 };
20 
21 
22 static struct list sessionl;
23 
24 
destructor(void * arg)25 static void destructor(void *arg)
26 {
27 	struct session *sess = arg;
28 
29 	debug("echo: session destroyed (in=%p)\n",
30 			sess->call_in);
31 
32 	list_unlink(&sess->le);
33 	mem_deref(sess->call_in);
34 }
35 
36 
call_event_handler(struct call * call,enum call_event ev,const char * str,void * arg)37 static void call_event_handler(struct call *call, enum call_event ev,
38 			       const char *str, void *arg)
39 {
40 	struct session *sess = arg;
41 	(void)call;
42 
43 	switch (ev) {
44 
45 		case CALL_EVENT_CLOSED:
46 			debug("echo: CALL_CLOSED: %s\n", str);
47 			mem_deref(sess);
48 			break;
49 
50 		default:
51 			break;
52 	}
53 }
54 
55 
call_dtmf_handler(struct call * call,char key,void * arg)56 static void call_dtmf_handler(struct call *call, char key, void *arg)
57 {
58 	(void)arg;
59 
60 	debug("echo: relaying DTMF event: key = '%c'\n", key ? key : '.');
61 
62 	call_send_digit(call, key);
63 }
64 
65 
new_session(struct call * call)66 static int new_session(struct call *call)
67 {
68 	struct session *sess;
69 	char a[64];
70 	int err = 0;
71 
72 	sess = mem_zalloc(sizeof(*sess), destructor);
73 	if (!sess)
74 		return ENOMEM;
75 
76 	sess->call_in = call;
77 
78 	re_snprintf(a, sizeof(a), "A-%x", sess);
79 
80 	audio_set_devicename(call_audio(sess->call_in), a, a);
81 
82 	call_set_handlers(sess->call_in, call_event_handler,
83 			call_dtmf_handler, sess);
84 
85 	list_append(&sessionl, &sess->le, sess);
86 	ua_answer(uag_current(), NULL);
87 
88 	if (err)
89 		mem_deref(sess);
90 
91 	return err;
92 }
93 
94 
ua_event_handler(struct ua * ua,enum ua_event ev,struct call * call,const char * prm,void * arg)95 static void ua_event_handler(struct ua *ua, enum ua_event ev,
96 		struct call *call, const char *prm, void *arg)
97 {
98 	int err;
99 	(void)prm;
100 	(void)arg;
101 
102 	switch (ev) {
103 
104 		case UA_EVENT_CALL_INCOMING:
105 			debug("echo: CALL_INCOMING: peer=%s  -->  local=%s\n",
106 					call_peeruri(call),
107 					call_localuri(call));
108 
109 			err = new_session(call);
110 			if (err) {
111 				ua_hangup(ua, call, 500, "Server Error");
112 			}
113 			break;
114 
115 		default:
116 			break;
117 	}
118 }
119 
120 
module_init(void)121 static int module_init(void)
122 {
123 	int err;
124 
125 	list_init(&sessionl);
126 
127 	err = uag_event_register(ua_event_handler, 0);
128 	if (err)
129 		return err;
130 
131 	debug("echo: module loaded\n");
132 
133 	return 0;
134 }
135 
136 
module_close(void)137 static int module_close(void)
138 {
139 	debug("echo: module closing..\n");
140 
141 	if (!list_isempty(&sessionl)) {
142 
143 		info("echo: flushing %u sessions\n", list_count(&sessionl));
144 		list_flush(&sessionl);
145 	}
146 
147 	uag_event_unregister(ua_event_handler);
148 
149 	return 0;
150 }
151 
152 
153 const struct mod_export DECL_EXPORTS(echo) = {
154 	"echo",
155 	"application",
156 	module_init,
157 	module_close
158 };
159