1 /*
2 * Copyright (C) 2017-2018 Julien Chavanton jchavanton@gmail.com
3 *
4 * This file is part of Kamailio, a free SIP server.
5 *
6 * Kamailio is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version
10 *
11 * Kamailio is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "../../core/mem/shm.h"
22 #include "../../core/sr_module.h"
23 #include "rtp_media_server.h"
24
ptr_shm_malloc(size_t size)25 inline static void *ptr_shm_malloc(size_t size)
26 {
27 return shm_malloc(size);
28 }
ptr_shm_realloc(void * ptr,size_t size)29 inline static void *ptr_shm_realloc(void *ptr, size_t size)
30 {
31 return shm_realloc(ptr, size);
32 }
ptr_shm_free(void * ptr)33 inline static void ptr_shm_free(void *ptr)
34 {
35 shm_free(ptr);
36 }
37
38 typedef struct shared_global_vars
39 {
40 MSFactory *ms_factory;
41 gen_lock_t lock;
42 } shared_global_vars_t;
43
44
45 MSFilterDesc *rms_ms_filter_descs[] = {&ms_alaw_dec_desc, &ms_alaw_enc_desc,
46 &ms_ulaw_dec_desc, &ms_ulaw_enc_desc, &ms_rtp_send_desc,
47 &ms_rtp_recv_desc, &ms_dtmf_gen_desc, &ms_volume_desc,
48 &ms_equalizer_desc, &ms_channel_adapter_desc, &ms_audio_mixer_desc,
49 &ms_tone_detector_desc, &ms_speex_dec_desc, &ms_speex_enc_desc,
50 &ms_speex_ec_desc, &ms_file_player_desc, &ms_file_rec_desc,
51 &ms_resample_desc,
52 &ms_opus_dec_desc,
53 &ms_opus_enc_desc,
54 NULL};
55
rms_create_factory()56 static MSFactory *rms_create_factory()
57 {
58 MSFactory *f = ms_factory_new();
59 int i;
60 for(i = 0; rms_ms_filter_descs[i] != NULL; i++) {
61 ms_factory_register_filter(f, rms_ms_filter_descs[i]);
62 }
63 ms_factory_init_plugins(f);
64 ms_factory_enable_statistics(f, TRUE);
65 ms_factory_reset_statistics(f);
66 return f;
67 }
68
rms_media_init()69 int rms_media_init()
70 {
71 // OrtpMemoryFunctions ortp_memory_functions;
72 // ortp_memory_functions.malloc_fun = ptr_shm_malloc;
73 // ortp_memory_functions.realloc_fun = ptr_shm_realloc;
74 // ortp_memory_functions.free_fun = ptr_shm_free;
75 // ortp_set_memory_functions(&ortp_memory_functions);
76 ortp_init();
77 return 1;
78 }
79
rms_create_ticker(char * name)80 static MSTicker *rms_create_ticker(char *name)
81 {
82 MSTickerParams params;
83 params.name = name;
84 params.prio = MS_TICKER_PRIO_NORMAL;
85 LM_DBG("\n");
86 return ms_ticker_new_with_params(¶ms);
87 }
88
rms_media_destroy(call_leg_media_t * m)89 void rms_media_destroy(call_leg_media_t *m)
90 {
91 LM_DBG("rtp_session_destroy[%p]\n", m->rtps);
92 rtp_session_destroy(m->rtps);
93 m->rtps = NULL;
94 ms_ticker_destroy(m->ms_ticker);
95 m->ms_ticker = NULL;
96 ms_factory_destroy(m->ms_factory);
97 m->ms_factory = NULL;
98 }
99
create_session_payload(call_leg_media_t * m)100 int create_session_payload(call_leg_media_t *m) {
101 LM_INFO("RTP [%p][%d]\n", m->pt, m->pt->type);
102 m->rtp_profile=rtp_profile_new("Call profile");
103 if(!m->rtp_profile) return 0;
104 rtp_profile_set_payload(m->rtp_profile, m->pt->type, m->pt);
105 rtp_session_set_profile(m->rtps, m->rtp_profile);
106 rtp_session_set_payload_type(m->rtps, m->pt->type);
107 return 1;
108 }
109
create_call_leg_media(call_leg_media_t * m)110 int create_call_leg_media(call_leg_media_t *m)
111 {
112 if (m) rms_stop_media(m);
113 m->ms_factory = rms_create_factory();
114 // Create caller RTP session
115 LM_INFO("RTP session [%s:%d]<>[%s:%d]\n", m->local_ip.s, m->local_port,
116 m->remote_ip.s, m->remote_port);
117 m->rtps = ms_create_duplex_rtp_session(m->local_ip.s, m->local_port,
118 m->local_port + 1, ms_factory_get_mtu(m->ms_factory));
119
120 create_session_payload(m);
121
122 rtp_session_set_remote_addr_full(m->rtps, m->remote_ip.s, m->remote_port,
123 m->remote_ip.s, m->remote_port + 1);
124
125 rtp_session_enable_rtcp(m->rtps, FALSE);
126 // create caller filters : rtprecv1/rtpsend1/encoder1/decoder1
127 m->ms_rtprecv = ms_factory_create_filter(m->ms_factory, MS_RTP_RECV_ID);
128 m->ms_rtpsend = ms_factory_create_filter(m->ms_factory, MS_RTP_SEND_ID);
129
130 LM_INFO("codec[%s] rtprecv[%p] rtpsend[%p] rate[%dHz]\n", m->pt->mime_type,
131 m->ms_rtprecv, m->ms_rtpsend, m->pt->clock_rate);
132 m->ms_encoder = ms_factory_create_encoder(m->ms_factory, m->pt->mime_type);
133 if(!m->ms_encoder) {
134 LM_ERR("creating encoder failed.\n");
135 return 0;
136 }
137 m->ms_decoder = ms_factory_create_decoder(m->ms_factory, m->pt->mime_type);
138
139 /* set filter params */
140 ms_filter_call_method(m->ms_rtpsend, MS_RTP_SEND_SET_SESSION, m->rtps);
141 ms_filter_call_method(m->ms_rtprecv, MS_RTP_RECV_SET_SESSION, m->rtps);
142 return 1;
143 }
144
145
rms_player_eof(void * user_data,MSFilter * f,unsigned int event,void * event_data)146 static void rms_player_eof(
147 void *user_data, MSFilter *f, unsigned int event, void *event_data)
148 {
149 if(event == MS_FILE_PLAYER_EOF) {
150 rms_action_t *a = (rms_action_t *)user_data;
151 a->type = RMS_DONE;
152 }
153 MS_UNUSED(f), MS_UNUSED(event_data);
154 }
155
156
rms_get_dtmf(call_leg_media_t * m,char dtmf)157 int rms_get_dtmf(call_leg_media_t *m, char dtmf)
158 {
159 // static void tone_detected_cb(void *data, MSFilter *f, unsigned int event_id, MSToneDetectorEvent *ev) {
160 // MS_UNUSED(data), MS_UNUSED(f), MS_UNUSED(event_id), MS_UNUSED(ev);
161 // ms_tester_tone_detected = TRUE;
162 // }
163 return 1;
164 }
165
rms_playfile(call_leg_media_t * m,rms_action_t * a)166 int rms_playfile(call_leg_media_t *m, rms_action_t *a)
167 {
168 int channels = 1;
169 int file_sample_rate = 8000;
170 if(!m->ms_player)
171 return 0;
172 ms_filter_add_notify_callback(m->ms_player, rms_player_eof, a, TRUE);
173 ms_filter_call_method(
174 m->ms_player, MS_FILE_PLAYER_OPEN, (void *)a->param.s);
175 ms_filter_call_method(m->ms_player, MS_FILE_PLAYER_START, NULL);
176 ms_filter_call_method(m->ms_player, MS_FILTER_GET_SAMPLE_RATE, &file_sample_rate);
177 ms_filter_call_method(m->ms_player, MS_FILTER_GET_NCHANNELS, &channels);
178
179 if (m->ms_resampler) {
180 ms_filter_call_method(m->ms_resampler, MS_FILTER_SET_SAMPLE_RATE, &file_sample_rate);
181 LM_INFO("clock[%d]file[%d]\n", m->pt->clock_rate, file_sample_rate);
182 ms_filter_call_method(m->ms_resampler, MS_FILTER_SET_OUTPUT_SAMPLE_RATE, &m->pt->clock_rate);
183 ms_filter_call_method(m->ms_resampler, MS_FILTER_SET_OUTPUT_NCHANNELS, &m->pt->channels);
184 }
185 LM_INFO("[%s]clock[%d][%d]\n", m->pt->mime_type, m->pt->clock_rate, file_sample_rate);
186 return 1;
187 }
188
rms_start_media(call_leg_media_t * m,char * file_name)189 int rms_start_media(call_leg_media_t *m, char *file_name)
190 {
191 MSConnectionHelper h;
192 int channels = 1;
193 int file_sample_rate = 8000;
194
195 if (m) rms_stop_media(m);
196
197 m->ms_ticker = rms_create_ticker(NULL);
198 if(!m->ms_ticker)
199 goto error;
200 m->ms_player = ms_factory_create_filter(m->ms_factory, MS_FILE_PLAYER_ID);
201 if(!m->ms_player)
202 goto error;
203
204
205 // m->ms_recorder = ms_factory_create_filter(m->ms_factory, MS_FILE_PLAYER_ID);
206 m->ms_voidsink = ms_factory_create_filter(m->ms_factory, MS_VOID_SINK_ID);
207 if(!m->ms_voidsink)
208 goto error;
209 LM_INFO("m[%p]call-id[%p]pt[%s]\n", m, m->di->callid.s, m->pt->mime_type);
210
211 ms_filter_call_method(m->ms_player, MS_FILTER_SET_OUTPUT_NCHANNELS, &channels);
212 ms_filter_call_method_noarg(m->ms_player, MS_FILE_PLAYER_START);
213 ms_filter_call_method(m->ms_player, MS_FILTER_GET_SAMPLE_RATE, &file_sample_rate);
214 if (strcasecmp(m->pt->mime_type,"opus") == 0) {
215 ms_filter_call_method(m->ms_encoder, MS_FILTER_SET_SAMPLE_RATE, &file_sample_rate);
216 ms_filter_call_method(m->ms_encoder, MS_FILTER_SET_NCHANNELS, &channels);
217 } else {
218 m->ms_resampler = ms_factory_create_filter(m->ms_factory, MS_RESAMPLE_ID);
219 if (!m->ms_resampler) goto error;
220 }
221
222 if (m->ms_resampler) {
223 ms_filter_call_method(m->ms_resampler, MS_FILTER_SET_SAMPLE_RATE, &file_sample_rate);
224 ms_filter_call_method(m->ms_resampler, MS_FILTER_SET_OUTPUT_SAMPLE_RATE, &m->pt->clock_rate);
225 }
226
227 // sending graph
228 ms_connection_helper_start(&h);
229 ms_connection_helper_link(&h, m->ms_player, -1, 0);
230 if (m->ms_resampler)
231 ms_connection_helper_link(&h, m->ms_resampler, 0, 0);
232 ms_connection_helper_link(&h, m->ms_encoder, 0, 0);
233 ms_connection_helper_link(&h, m->ms_rtpsend, 0, -1);
234
235 // receiving graph
236 ms_connection_helper_start(&h);
237 ms_connection_helper_link(&h, m->ms_rtprecv, -1, 0);
238 // ms_connection_helper_link(&h, m->ms_decoder, 0, 0);
239 ms_connection_helper_link(&h, m->ms_voidsink, 0, -1);
240
241 ms_ticker_attach_multiple(m->ms_ticker, m->ms_player, m->ms_rtprecv, NULL);
242 return 1;
243 error:
244 LM_ERR(" can not start media!\n");
245 return 0;
246 }
247
rms_stop_media(call_leg_media_t * m)248 int rms_stop_media(call_leg_media_t *m)
249 {
250 MSConnectionHelper h;
251 if(!m->ms_ticker) {
252 LM_ERR("RMS STOP MEDIA\n");
253 return -1;
254 }
255 if(m->ms_player)
256 ms_ticker_detach(m->ms_ticker, m->ms_player);
257 if(m->ms_rtprecv)
258 ms_ticker_detach(m->ms_ticker, m->ms_rtprecv);
259
260 rtp_stats_display(
261 rtp_session_get_stats(m->rtps), " AUDIO SESSION'S RTP STATISTICS ");
262 ms_factory_log_statistics(m->ms_factory);
263
264 /*dismantle the sending graph*/
265 ms_connection_helper_start(&h);
266 if(m->ms_player)
267 ms_connection_helper_unlink(&h, m->ms_player, -1, 0);
268 if(m->ms_resampler)
269 ms_connection_helper_unlink(&h, m->ms_resampler, 0, 0);
270 if(m->ms_encoder)
271 ms_connection_helper_unlink(&h, m->ms_encoder, 0, 0);
272 if(m->ms_rtpsend)
273 ms_connection_helper_unlink(&h, m->ms_rtpsend, 0, -1);
274 /*dismantle the receiving graph*/
275 ms_connection_helper_start(&h);
276 if(m->ms_rtprecv)
277 ms_connection_helper_unlink(&h, m->ms_rtprecv, -1, 0);
278 if(m->ms_voidsink)
279 ms_connection_helper_unlink(&h, m->ms_voidsink, 0, -1);
280
281 if(m->ms_player)
282 ms_filter_destroy(m->ms_player);
283 if(m->ms_resampler)
284 ms_filter_destroy(m->ms_resampler);
285 if(m->ms_encoder)
286 ms_filter_destroy(m->ms_encoder);
287 if(m->ms_rtpsend) {
288 LM_ERR("detroy rtpsend\n");
289 ms_filter_destroy(m->ms_rtpsend);
290 } else {
291 LM_ERR("no rtpsend\n");
292 }
293 if(m->ms_rtprecv)
294 ms_filter_destroy(m->ms_rtprecv);
295 if(m->ms_voidsink)
296 ms_filter_destroy(m->ms_voidsink);
297
298 rms_media_destroy(m);
299 return 1;
300 }
301
rms_bridge(call_leg_media_t * m1,call_leg_media_t * m2)302 int rms_bridge(call_leg_media_t *m1, call_leg_media_t *m2)
303 {
304 MSConnectionHelper h;
305 m1->ms_ticker = rms_create_ticker(NULL);
306 LM_NOTICE("[%p][%p][%p][%p]\n", m1->ms_rtprecv, m1->ms_rtpsend,
307 m2->ms_rtprecv, m2->ms_rtpsend);
308 // direction 1
309 ms_connection_helper_start(&h);
310 ms_connection_helper_link(&h, m1->ms_rtprecv, -1, 0);
311 ms_connection_helper_link(&h, m2->ms_rtpsend, 0, -1);
312
313 LM_NOTICE("[%p][%p][%p][%p]2\n", m1->ms_rtprecv, m1->ms_rtpsend,
314 m2->ms_rtprecv, m2->ms_rtpsend);
315 // direction 2
316 ms_connection_helper_start(&h);
317 ms_connection_helper_link(&h, m2->ms_rtprecv, -1, 0);
318 ms_connection_helper_link(&h, m1->ms_rtpsend, 0, -1);
319
320 ms_ticker_attach_multiple(
321 m1->ms_ticker, m1->ms_rtprecv, m2->ms_rtprecv, NULL);
322
323 return 1;
324 }
325
rms_stop_bridge(call_leg_media_t * m1,call_leg_media_t * m2)326 int rms_stop_bridge(call_leg_media_t *m1, call_leg_media_t *m2)
327 {
328 MSConnectionHelper h;
329 MSTicker *ticker = NULL;
330
331 if(m1->ms_ticker) {
332 ticker = m1->ms_ticker;
333 }
334 if(m2->ms_ticker) {
335 ticker = m2->ms_ticker;
336 }
337 if(!ticker)
338 return -1;
339
340 if(m1->ms_rtprecv)
341 ms_ticker_detach(ticker, m1->ms_rtprecv);
342 if(m1->ms_rtpsend)
343 ms_ticker_detach(ticker, m1->ms_rtpsend);
344 if(m2->ms_rtprecv)
345 ms_ticker_detach(ticker, m2->ms_rtprecv);
346 if(m2->ms_rtpsend)
347 ms_ticker_detach(ticker, m2->ms_rtpsend);
348
349 ms_connection_helper_start(&h);
350 if(m1->ms_rtprecv)
351 ms_connection_helper_unlink(&h, m1->ms_rtprecv, -1, 0);
352 if(m2->ms_rtpsend)
353 ms_connection_helper_unlink(&h, m2->ms_rtpsend, 0, -1);
354
355 ms_connection_helper_start(&h);
356 if(m2->ms_rtprecv)
357 ms_connection_helper_unlink(&h, m2->ms_rtprecv, -1, 0);
358 if(m1->ms_rtpsend)
359 ms_connection_helper_unlink(&h, m1->ms_rtpsend, 0, -1);
360
361 rtp_stats_display(rtp_session_get_stats(m1->rtps),
362 " AUDIO BRIDGE offer RTP STATISTICS ");
363
364 rtp_stats_display(rtp_session_get_stats(m2->rtps),
365 " AUDIO BRIDGE answer RTP STATISTICS ");
366
367 if(m1->ms_rtpsend)
368 ms_filter_destroy(m1->ms_rtpsend);
369 if(m1->ms_rtprecv)
370 ms_filter_destroy(m1->ms_rtprecv);
371 if(m2->ms_rtpsend)
372 ms_filter_destroy(m2->ms_rtpsend);
373 if(m2->ms_rtprecv)
374 ms_filter_destroy(m2->ms_rtprecv);
375
376 rtp_session_destroy(m1->rtps);
377 rtp_session_destroy(m2->rtps);
378 if(m1->ms_ticker)
379 ms_ticker_destroy(m1->ms_ticker);
380 if(m2->ms_ticker)
381 ms_ticker_destroy(m2->ms_ticker);
382 m1->ms_ticker = NULL;
383 m2->ms_ticker = NULL;
384 ms_factory_log_statistics(m1->ms_factory);
385 return 1;
386 }
387