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