Browse code

rtp_media_server: adding call bridging

- forward in dialog messages using RMS bridge in B2BUA manner
- move all code related to rms_session_info to dedicated source file
- session_list refactoring to always include all dialog information
needed
- suspend transaction to have non blocking bridging
- random rtp port
- stop using shared memory for MS2 and oRTP, manage all the allocation
from one dedicated process

Julien Chavanton authored on 26/11/2018 05:57:23
Showing 13 changed files
1 1
old mode 100644
2 2
new mode 100755
... ...
@@ -48,9 +48,8 @@ route {
48 48
 			exit;
49 49
 		}
50 50
 	}
51
-	if (is_method("BYE")){
52
-		rms_media_stop();
53
-	}
51
+	if(rms_session_check())
52
+		rms_sip_request();
54 53
 	exit;
55 54
 }
56 55
 
57 56
new file mode 100644
... ...
@@ -0,0 +1,38 @@
1
+
2
+
3
+
4
+|rms_bridge_f| >> create a_leg and b_leg
5
+               >> link them and add them to the sessions
6
+               >> suspend a_leg connection
7
+               ---------------------------
8
+               | caller-leg | callee-leg |
9
+               ---------------------------
10
+               |offer|answer|offer|answer|
11
+               ---------------------------
12
+               |  x  |      |  x  |      | // create a resulting offer depending on codecs etc.
13
+               ---------------------------
14
+               >> BRIDING
15
+
16
+|BRIDGING|     >> INVITE b_leg using the callee-leg offer's
17
+               >> wait for transaction response/timeout
18
+               ---------------------------
19
+               | caller-leg | callee-leg |
20
+               ---------------------------
21
+               |offer|answer|offer|answer|
22
+               ---------------------------
23
+               |  x  |  x   |  x  |  x   | // create a resulting answer depending on codecs etc.
24
+               ---------------------------
25
+               >> BRIDGED
26
+
27
+|BRIDGED|      >> continue a_leg considering the state of b_leg
28
+
29
+
30
+
31
+TODO:
32
+- Implement and test a_leg received CANCEL handling
33
+- Implement and test in-dialog message FAILURE.
34
+- Implement RE-INVITE with and without codec modification.
35
+- Verify and enforce state control when receiving re-transmission of multiple INITIAL INVITEs / BYEs
36
+- The B2BUA logic must be able to handle multiple b_leg Dialogs responses that could be created because of upstream call forking,
37
+  when receiving multiple connections https://tools.ietf.org/html/rfc3261#section-15)
38
+  a soon as one Dialog connect, we need to terminate / cancel all other Dialogs if any.
... ...
@@ -140,11 +140,7 @@ route {
140 140
 			t_reply("503", "server error");
141 141
 		}
142 142
 	}
143
-
144
-	if (is_method("BYE")){
145
-		xnotice("BYE RECEIVED [$ci]\n");
146
-		rms_media_stop();
147
-	}
143
+	rms_sip_request();
148 144
 ...
149 145
 		</programlisting></example>
150 146
 	</section>
... ...
@@ -166,12 +162,34 @@ route {
166 162
 		</programlisting></example>
167 163
 	</section>
168 164
 
169
-	<section id="rtp_media_server.f.rms_media_stop">
170
-		<title><varname>rms_media_stop</varname> ()</title>
165
+	<section id="rtp_media_server.f.rms_session_check">
166
+		<title><varname>rms_session_check</varname> ()</title>
167
+		<para>
168
+		Returns true if the current SIP message it handled/known by
169
+		the RMS module, else it may be handle in any other way by
170
+		Kamailio.
171
+		</para>
172
+		<para>
173
+		This function can be used from REQUEST_ROUTE, REPLY_ROUTE and FAILURE_ROUTE.
174
+		</para>
175
+		<example>
176
+		<title>usage example</title>
177
+		<programlisting format="linespecific">
178
+...
179
+	if (rms_session_check()) {
180
+		xnotice("This session is handled by the RMS module\n");
181
+		rms_sip_request();
182
+	}
183
+...
184
+		</programlisting></example>
185
+	</section>
186
+
187
+	<section id="rtp_media_server.f.rms_sip_request">
188
+		<title><varname>rms_sip_request</varname> ()</title>
171 189
 		<para>
172
-		This should be called on reception of a BYE, this will
173
-		delete the RTP session and the media ressources.
174
-		and reply "200 OK".
190
+		This should be called for every in-dialog SIP request,
191
+		it will be forwarded behaving as a B2BUA, the transaction
192
+		will be suspended until the second leg replies.
175 193
 		</para>
176 194
 		<para>
177 195
 		If the SIP session is not found "481 Call/Transaction Does Not Exist"
... ...
@@ -184,8 +202,8 @@ route {
184 202
 		<title>usage example</title>
185 203
 		<programlisting format="linespecific">
186 204
 ...
187
-	if (is_method("BYE")){
188
-		rms_media_stop();
205
+	if (rms_session_check()) {
206
+		rms_sip_request();
189 207
 	}
190 208
 ...
191 209
 		</programlisting></example>
... ...
@@ -68,11 +68,11 @@ static MSFactory *rms_create_factory()
68 68
 
69 69
 int rms_media_init()
70 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);
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 76
 	ortp_init();
77 77
 	return 1;
78 78
 }
... ...
@@ -82,18 +82,17 @@ static MSTicker *rms_create_ticker(char *name)
82 82
 	MSTickerParams params;
83 83
 	params.name = name;
84 84
 	params.prio = MS_TICKER_PRIO_NORMAL;
85
+	LM_DBG("\n");
85 86
 	return ms_ticker_new_with_params(&params);
86 87
 }
87 88
 
88 89
 void rms_media_destroy(call_leg_media_t *m)
89 90
 {
90
-	LM_INFO("rtp_session_destroy[%p]\n", m->rtps);
91
+	LM_DBG("rtp_session_destroy[%p]\n", m->rtps);
91 92
 	rtp_session_destroy(m->rtps);
92 93
 	m->rtps = NULL;
93
-	LM_INFO("ms_ticker[%p]\n", m->ms_ticker);
94 94
 	ms_ticker_destroy(m->ms_ticker);
95 95
 	m->ms_ticker = NULL;
96
-	LM_INFO("ms_factory_destroy[%p]\n", m->ms_factory);
97 96
 	ms_factory_destroy(m->ms_factory);
98 97
 	m->ms_factory = NULL;
99 98
 }
... ...
@@ -114,7 +113,8 @@ int create_call_leg_media(call_leg_media_t *m)
114 113
 	m->ms_rtprecv = ms_factory_create_filter(m->ms_factory, MS_RTP_RECV_ID);
115 114
 	m->ms_rtpsend = ms_factory_create_filter(m->ms_factory, MS_RTP_SEND_ID);
116 115
 
117
-	LM_INFO("codec[%s]\n", m->pt->mime_type);
116
+	LM_INFO("codec[%s] rtprecv[%p] rtpsend[%p]\n", m->pt->mime_type,
117
+			m->ms_rtprecv, m->ms_rtpsend);
118 118
 	m->ms_encoder = ms_factory_create_encoder(m->ms_factory, m->pt->mime_type);
119 119
 	if(!m->ms_encoder) {
120 120
 		LM_ERR("creating encoder failed.\n");
... ...
@@ -128,26 +128,6 @@ int create_call_leg_media(call_leg_media_t *m)
128 128
 	return 1;
129 129
 }
130 130
 
131
-int rms_bridge(call_leg_media_t *m1, call_leg_media_t *m2)
132
-{
133
-	MSConnectionHelper h;
134
-	m1->ms_ticker = rms_create_ticker(NULL);
135
-
136
-	// direction 1
137
-	ms_connection_helper_start(&h);
138
-	ms_connection_helper_link(&h, m1->ms_rtprecv, -1, 0);
139
-	ms_connection_helper_link(&h, m2->ms_rtpsend, 0, -1);
140
-
141
-	// direction 2
142
-	ms_connection_helper_start(&h);
143
-	ms_connection_helper_link(&h, m2->ms_rtprecv, -1, 0);
144
-	ms_connection_helper_link(&h, m1->ms_rtpsend, 0, -1);
145
-
146
-	ms_ticker_attach_multiple(
147
-			m1->ms_ticker, m1->ms_rtprecv, m2->ms_rtprecv, NULL);
148
-
149
-	return 1;
150
-}
151 131
 
152 132
 static void rms_player_eof(
153 133
 		void *user_data, MSFilter *f, unsigned int event, void *event_data)
... ...
@@ -159,54 +139,13 @@ static void rms_player_eof(
159 139
 	MS_UNUSED(f), MS_UNUSED(event_data);
160 140
 }
161 141
 
162
-int rms_stop_bridge(call_leg_media_t *m1, call_leg_media_t *m2)
163
-{
164
-	MSConnectionHelper h;
165
-	if(!m1->ms_ticker)
166
-		return -1;
167
-	if(m1->ms_rtpsend)
168
-		ms_ticker_detach(m1->ms_ticker, m1->ms_rtpsend);
169
-	if(m1->ms_rtprecv)
170
-		ms_ticker_detach(m1->ms_ticker, m1->ms_rtprecv);
171
-	if(m2->ms_rtpsend)
172
-		ms_ticker_detach(m1->ms_ticker, m2->ms_rtpsend);
173
-	if(m2->ms_rtprecv)
174
-		ms_ticker_detach(m1->ms_ticker, m2->ms_rtprecv);
175
-	rtp_stats_display(rtp_session_get_stats(m1->rtps),
176
-			" AUDIO BRIDGE offer RTP STATISTICS ");
177
-	rtp_stats_display(rtp_session_get_stats(m2->rtps),
178
-			" AUDIO BRIDGE answer RTP STATISTICS ");
179
-	ms_factory_log_statistics(m1->ms_factory);
180 142
 
181
-	ms_connection_helper_start(&h);
182
-	if(m1->ms_rtprecv)
183
-		ms_connection_helper_unlink(&h, m1->ms_rtprecv, -1, 0);
184
-	if(m2->ms_rtpsend)
185
-		ms_connection_helper_unlink(&h, m2->ms_rtpsend, 0, -1);
186
-
187
-	ms_connection_helper_start(&h);
188
-	if(m2->ms_rtprecv)
189
-		ms_connection_helper_unlink(&h, m2->ms_rtprecv, -1, 0);
190
-	if(m1->ms_rtpsend)
191
-		ms_connection_helper_unlink(&h, m1->ms_rtpsend, 0, -1);
192
-
193
-	if(m1->ms_rtpsend)
194
-		ms_filter_destroy(m1->ms_rtpsend);
195
-	if(m1->ms_rtprecv)
196
-		ms_filter_destroy(m1->ms_rtprecv);
197
-	if(m2->ms_rtpsend)
198
-		ms_filter_destroy(m2->ms_rtpsend);
199
-	if(m2->ms_rtprecv)
200
-		ms_filter_destroy(m2->ms_rtprecv);
201
-	return 1;
202
-}
203
-
204
-
205
-int rms_get_dtmf(call_leg_media_t *m, char dtmf) {
206
-//	static void tone_detected_cb(void *data, MSFilter *f, unsigned int event_id, MSToneDetectorEvent *ev) {
207
-//			MS_UNUSED(data), MS_UNUSED(f), MS_UNUSED(event_id), MS_UNUSED(ev);
208
-//				ms_tester_tone_detected = TRUE;
209
-//	}
143
+int rms_get_dtmf(call_leg_media_t *m, char dtmf)
144
+{
145
+	//	static void tone_detected_cb(void *data, MSFilter *f, unsigned int event_id, MSToneDetectorEvent *ev) {
146
+	//			MS_UNUSED(data), MS_UNUSED(f), MS_UNUSED(event_id), MS_UNUSED(ev);
147
+	//				ms_tester_tone_detected = TRUE;
148
+	//	}
210 149
 	return 1;
211 150
 }
212 151
 
... ...
@@ -216,12 +155,17 @@ int rms_playfile(call_leg_media_t *m, rms_action_t *a)
216 155
 	if(!m->ms_player)
217 156
 		return 0;
218 157
 	ms_filter_add_notify_callback(m->ms_player, rms_player_eof, a, TRUE);
219
-	ms_filter_call_method(m->ms_player, MS_FILE_PLAYER_OPEN, (void *)a->param.s);
158
+	ms_filter_call_method(
159
+			m->ms_player, MS_FILE_PLAYER_OPEN, (void *)a->param.s);
220 160
 	ms_filter_call_method(m->ms_player, MS_FILE_PLAYER_START, NULL);
221
-	ms_filter_call_method(m->ms_player, MS_FILTER_GET_SAMPLE_RATE, &file_sample_rate);
222
-	ms_filter_call_method(m->ms_resampler, MS_FILTER_SET_SAMPLE_RATE, &file_sample_rate);
223
-	ms_filter_call_method(m->ms_resampler, MS_FILTER_SET_OUTPUT_SAMPLE_RATE, &m->pt->clock_rate);
224
-	ms_filter_call_method(m->ms_resampler, MS_FILTER_SET_OUTPUT_NCHANNELS, &m->pt->channels);
161
+	ms_filter_call_method(
162
+			m->ms_player, MS_FILTER_GET_SAMPLE_RATE, &file_sample_rate);
163
+	ms_filter_call_method(
164
+			m->ms_resampler, MS_FILTER_SET_SAMPLE_RATE, &file_sample_rate);
165
+	ms_filter_call_method(m->ms_resampler, MS_FILTER_SET_OUTPUT_SAMPLE_RATE,
166
+			&m->pt->clock_rate);
167
+	ms_filter_call_method(
168
+			m->ms_resampler, MS_FILTER_SET_OUTPUT_NCHANNELS, &m->pt->channels);
225 169
 	LM_INFO("clock[%d][%d]\n", m->pt->clock_rate, file_sample_rate);
226 170
 	return 1;
227 171
 }
... ...
@@ -232,23 +176,30 @@ int rms_start_media(call_leg_media_t *m, char *file_name)
232 176
 	int channels = 1;
233 177
 	int file_sample_rate = 8000;
234 178
 	m->ms_ticker = rms_create_ticker(NULL);
235
-	if(!m->ms_ticker) goto error;
179
+	if(!m->ms_ticker)
180
+		goto error;
236 181
 	m->ms_player = ms_factory_create_filter(m->ms_factory, MS_FILE_PLAYER_ID);
237
-	if(!m->ms_player) goto error;
182
+	if(!m->ms_player)
183
+		goto error;
238 184
 	m->ms_resampler = ms_factory_create_filter(m->ms_factory, MS_RESAMPLE_ID);
239
-	if(!m->ms_resampler) goto error;
185
+	if(!m->ms_resampler)
186
+		goto error;
240 187
 	// m->ms_recorder = ms_factory_create_filter(m->ms_factory,
241 188
 	// MS_FILE_PLAYER_ID);
242 189
 	m->ms_voidsink = ms_factory_create_filter(m->ms_factory, MS_VOID_SINK_ID);
243
-	if(!m->ms_voidsink) goto error;
190
+	if(!m->ms_voidsink)
191
+		goto error;
244 192
 	LM_INFO("m[%p]call-id[%p]\n", m, m->si->callid.s);
245 193
 
246 194
 	ms_filter_call_method(
247 195
 			m->ms_player, MS_FILTER_SET_OUTPUT_NCHANNELS, &channels);
248 196
 	ms_filter_call_method_noarg(m->ms_player, MS_FILE_PLAYER_START);
249
-	ms_filter_call_method(m->ms_player, MS_FILTER_GET_SAMPLE_RATE, &file_sample_rate);
250
-	ms_filter_call_method(m->ms_resampler, MS_FILTER_SET_SAMPLE_RATE, &file_sample_rate);
251
-	ms_filter_call_method(m->ms_resampler, MS_FILTER_SET_OUTPUT_SAMPLE_RATE, &m->pt->clock_rate);
197
+	ms_filter_call_method(
198
+			m->ms_player, MS_FILTER_GET_SAMPLE_RATE, &file_sample_rate);
199
+	ms_filter_call_method(
200
+			m->ms_resampler, MS_FILTER_SET_SAMPLE_RATE, &file_sample_rate);
201
+	ms_filter_call_method(m->ms_resampler, MS_FILTER_SET_OUTPUT_SAMPLE_RATE,
202
+			&m->pt->clock_rate);
252 203
 
253 204
 	// sending graph
254 205
 	ms_connection_helper_start(&h);
... ...
@@ -324,3 +275,89 @@ int rms_stop_media(call_leg_media_t *m)
324 275
 	rms_media_destroy(m);
325 276
 	return 1;
326 277
 }
278
+
279
+int rms_bridge(call_leg_media_t *m1, call_leg_media_t *m2)
280
+{
281
+	MSConnectionHelper h;
282
+	m1->ms_ticker = rms_create_ticker(NULL);
283
+	LM_NOTICE("[%p][%p][%p][%p]\n", m1->ms_rtprecv, m1->ms_rtpsend,
284
+			m2->ms_rtprecv, m2->ms_rtpsend);
285
+	// direction 1
286
+	ms_connection_helper_start(&h);
287
+	ms_connection_helper_link(&h, m1->ms_rtprecv, -1, 0);
288
+	ms_connection_helper_link(&h, m2->ms_rtpsend, 0, -1);
289
+
290
+	LM_NOTICE("[%p][%p][%p][%p]2\n", m1->ms_rtprecv, m1->ms_rtpsend,
291
+			m2->ms_rtprecv, m2->ms_rtpsend);
292
+	// direction 2
293
+	ms_connection_helper_start(&h);
294
+	ms_connection_helper_link(&h, m2->ms_rtprecv, -1, 0);
295
+	ms_connection_helper_link(&h, m1->ms_rtpsend, 0, -1);
296
+
297
+	ms_ticker_attach_multiple(
298
+			m1->ms_ticker, m1->ms_rtprecv, m2->ms_rtprecv, NULL);
299
+
300
+	return 1;
301
+}
302
+
303
+int rms_stop_bridge(call_leg_media_t *m1, call_leg_media_t *m2)
304
+{
305
+	MSConnectionHelper h;
306
+	MSTicker *ticker = NULL;
307
+
308
+	if(m1->ms_ticker) {
309
+		ticker = m1->ms_ticker;
310
+	}
311
+	if(m2->ms_ticker) {
312
+		ticker = m2->ms_ticker;
313
+	}
314
+	if(!ticker)
315
+		return -1;
316
+
317
+	if(m1->ms_rtprecv)
318
+		ms_ticker_detach(ticker, m1->ms_rtprecv);
319
+	if(m1->ms_rtpsend)
320
+		ms_ticker_detach(ticker, m1->ms_rtpsend);
321
+	if(m2->ms_rtprecv)
322
+		ms_ticker_detach(ticker, m2->ms_rtprecv);
323
+	if(m2->ms_rtpsend)
324
+		ms_ticker_detach(ticker, m2->ms_rtpsend);
325
+
326
+	ms_connection_helper_start(&h);
327
+	if(m1->ms_rtprecv)
328
+		ms_connection_helper_unlink(&h, m1->ms_rtprecv, -1, 0);
329
+	if(m2->ms_rtpsend)
330
+		ms_connection_helper_unlink(&h, m2->ms_rtpsend, 0, -1);
331
+
332
+	ms_connection_helper_start(&h);
333
+	if(m2->ms_rtprecv)
334
+		ms_connection_helper_unlink(&h, m2->ms_rtprecv, -1, 0);
335
+	if(m1->ms_rtpsend)
336
+		ms_connection_helper_unlink(&h, m1->ms_rtpsend, 0, -1);
337
+
338
+	rtp_stats_display(rtp_session_get_stats(m1->rtps),
339
+			" AUDIO BRIDGE offer RTP STATISTICS ");
340
+
341
+	rtp_stats_display(rtp_session_get_stats(m2->rtps),
342
+			" AUDIO BRIDGE answer RTP STATISTICS ");
343
+
344
+	if(m1->ms_rtpsend)
345
+		ms_filter_destroy(m1->ms_rtpsend);
346
+	if(m1->ms_rtprecv)
347
+		ms_filter_destroy(m1->ms_rtprecv);
348
+	if(m2->ms_rtpsend)
349
+		ms_filter_destroy(m2->ms_rtpsend);
350
+	if(m2->ms_rtprecv)
351
+		ms_filter_destroy(m2->ms_rtprecv);
352
+
353
+	rtp_session_destroy(m1->rtps);
354
+	rtp_session_destroy(m2->rtps);
355
+	if(m1->ms_ticker)
356
+		ms_ticker_destroy(m1->ms_ticker);
357
+	if(m2->ms_ticker)
358
+		ms_ticker_destroy(m2->ms_ticker);
359
+	m1->ms_ticker = NULL;
360
+	m2->ms_ticker = NULL;
361
+	ms_factory_log_statistics(m1->ms_factory);
362
+	return 1;
363
+}
327 364
old mode 100644
328 365
new mode 100755
... ...
@@ -34,9 +34,12 @@
34 34
 #include <ortp/ortp.h>
35 35
 #include <ortp/port.h>
36 36
 
37
-struct rms_session_info;
37
+#include "rtp_media_server.h"
38
+// #include "rms_session_info.h"
39
+// struct rms_session_info;
38 40
 typedef struct rms_action rms_action_t;
39 41
 
42
+
40 43
 typedef struct call_leg_media
41 44
 {
42 45
 	MSFactory *ms_factory;
... ...
@@ -58,7 +61,7 @@ typedef struct call_leg_media
58 61
 	int local_port;
59 62
 	str remote_ip;
60 63
 	int remote_port;
61
-	struct rms_session_info *si;
64
+	const struct rms_session_info *si;
62 65
 } call_leg_media_t;
63 66
 
64 67
 int create_call_leg_media(call_leg_media_t *m);
... ...
@@ -22,6 +22,7 @@
22 22
 #include "rms_util.h"
23 23
 #include "../../core/data_lump.h"
24 24
 #include "../../core/parser/parse_content.h"
25
+#include "../../core/parser/sdp/sdp.h"
25 26
 
26 27
 // https://tools.ietf.org/html/rfc4566
27 28
 // (protocol version)
... ...
@@ -37,28 +38,98 @@ const char *sdp_t = "t=0 0\r\n";
37 38
 //"a=rtpmap:96 opus/48000/2\r\n"
38 39
 //"a=fmtp:96 useinbandfec=1\r\n";
39 40
 
40
-static char *rms_sdp_get_rtpmap(str body, int type_number)
41
+int rms_get_sdp_info(rms_sdp_info_t *sdp_info, struct sip_msg *msg)
41 42
 {
42
-	char *pos = body.s;
43
-	while((pos = strstr(pos, "a=rtpmap:"))) {
44
-		int id;
45
-		int sampling_rate;
46
-		char codec[64];
47
-		sscanf(pos, "a=rtpmap:%d %s/%d", &id, codec, &sampling_rate);
48
-		if(id == type_number) {
49
-			LM_INFO("[%d][%s/%d]\n", id, codec, sampling_rate);
50
-			return rms_char_dup(codec, 1);
43
+	sdp_session_cell_t *sdp_session;
44
+	sdp_stream_cell_t *sdp_stream;
45
+	str media_ip, media_port;
46
+	int sdp_session_num = 0;
47
+	int sdp_stream_num = get_sdp_stream_num(msg);
48
+	if(parse_sdp(msg) < 0) {
49
+		LM_INFO("can not parse sdp\n");
50
+		return 0;
51
+	}
52
+	sdp_info_t *sdp = (sdp_info_t *)msg->body;
53
+	if(!sdp) {
54
+		LM_INFO("sdp null\n");
55
+		return 0;
56
+	}
57
+	rms_str_dup(&sdp_info->recv_body, &sdp->text, 1);
58
+	if(!sdp_info->recv_body.s)
59
+		goto error;
60
+	LM_INFO("sdp body - type[%d]\n", sdp->type);
61
+	if(sdp_stream_num > 1 || !sdp_stream_num) {
62
+		LM_INFO("only support one stream[%d]\n", sdp_stream_num);
63
+	}
64
+	sdp_stream_num = 0;
65
+	sdp_session = get_sdp_session(msg, sdp_session_num);
66
+	if(!sdp_session) {
67
+		return 0;
68
+	} else {
69
+		int sdp_stream_num = 0;
70
+		sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num);
71
+		if(!sdp_stream) {
72
+			LM_INFO("can not get the sdp stream\n");
73
+			return 0;
74
+		} else {
75
+			rms_str_dup(&sdp_info->payloads, &sdp_stream->payloads, 1);
76
+			if(!sdp_info->payloads.s)
77
+				goto error;
51 78
 		}
52
-		pos++;
53 79
 	}
54
-	return NULL;
80
+	if(sdp_stream->ip_addr.s && sdp_stream->ip_addr.len > 0) {
81
+		media_ip = sdp_stream->ip_addr;
82
+	} else {
83
+		media_ip = sdp_session->ip_addr;
84
+	}
85
+	rms_str_dup(&sdp_info->remote_ip, &media_ip, 1);
86
+	if(!sdp_info->remote_ip.s)
87
+		goto error;
88
+	rms_str_dup(&media_port, &sdp_stream->port, 0);
89
+	if(!media_port.s)
90
+		goto error;
91
+	sdp_info->remote_port = atoi(media_port.s);
92
+	pkg_free(media_port.s);
93
+	return 1;
94
+error:
95
+	rms_sdp_info_free(sdp_info);
96
+	return 0;
55 97
 }
56 98
 
99
+//static char *rms_sdp_get_rtpmap(str body, int type_number)
100
+//{
101
+//	char *pos = body.s;
102
+//	while((pos = strstr(pos, "a=rtpmap:"))) {
103
+//		int id;
104
+//		int sampling_rate;
105
+//		char codec[64];
106
+//		sscanf(pos, "a=rtpmap:%d %s/%d", &id, codec, &sampling_rate);
107
+//		if(id == type_number) {
108
+//			LM_INFO("[%d][%s/%d]\n", id, codec, sampling_rate);
109
+//			return rms_char_dup(codec, 1);
110
+//		}
111
+//		pos++;
112
+//	}
113
+//	return NULL;
114
+//}
115
+
57 116
 void rms_sdp_info_init(rms_sdp_info_t *sdp_info)
58 117
 {
59 118
 	memset(sdp_info, 0, sizeof(rms_sdp_info_t));
60 119
 }
61 120
 
121
+int rms_sdp_info_clone(rms_sdp_info_t *dst, rms_sdp_info_t *src)
122
+{
123
+	rms_sdp_info_init(dst);
124
+	if(!rms_str_dup(&dst->remote_ip, &src->remote_ip, 1))
125
+		return 0;
126
+	if(!rms_str_dup(&dst->payloads, &src->payloads, 1))
127
+		return 0;
128
+	if(!rms_str_dup(&dst->new_body, &src->new_body, 1))
129
+		return 0;
130
+	return 1;
131
+}
132
+
62 133
 void rms_sdp_info_free(rms_sdp_info_t *sdp_info)
63 134
 {
64 135
 	if(sdp_info->remote_ip.s) {
... ...
@@ -99,8 +170,9 @@ int rms_sdp_prepare_new_body(rms_sdp_info_t *sdp_info, int payload_type_number)
99 170
 			payload_type_number);
100 171
 	body->len += strlen(sdp_m);
101 172
 
102
-	body->s = pkg_malloc(body->len + 1);
103
-	if (!body->s) return 0;
173
+	body->s = shm_malloc(body->len + 1);
174
+	if(!body->s)
175
+		return 0;
104 176
 	strcpy(body->s, sdp_v);
105 177
 	strcat(body->s, sdp_o);
106 178
 	strcat(body->s, sdp_s);
... ...
@@ -110,11 +182,19 @@ int rms_sdp_prepare_new_body(rms_sdp_info_t *sdp_info, int payload_type_number)
110 182
 	return 1;
111 183
 }
112 184
 
185
+PayloadType *
186
+rms_payload_type_new() // TODO: convert at the last minute from the MS manager process instead.
187
+{
188
+	PayloadType *newpayload = (PayloadType *)shm_malloc(sizeof(PayloadType));
189
+	newpayload->flags |= PAYLOAD_TYPE_ALLOCATED;
190
+	return newpayload;
191
+}
192
+
113 193
 PayloadType *rms_sdp_check_payload(rms_sdp_info_t *sdp)
114 194
 {
115 195
 	// https://tools.ietf.org/html/rfc3551
116 196
 	LM_INFO("payloads[%s]\n", sdp->payloads.s); // 0 8
117
-	PayloadType *pt = payload_type_new();
197
+	PayloadType *pt = rms_payload_type_new();
118 198
 	char *payloads = sdp->payloads.s;
119 199
 	char *payload_type_number = strtok(payloads, " ");
120 200
 	if(!payload_type_number) {
... ...
@@ -168,7 +248,6 @@ PayloadType *rms_sdp_check_payload(rms_sdp_info_t *sdp)
168 248
 }
169 249
 
170 250
 
171
-
172 251
 int rms_sdp_set_body(struct sip_msg *msg, str *new_body)
173 252
 {
174 253
 	struct lump *anchor;
175 254
old mode 100644
176 255
new mode 100755
... ...
@@ -36,9 +36,11 @@ typedef struct rms_sdp_info
36 36
 	int udp_local_port;
37 37
 } rms_sdp_info_t;
38 38
 
39
+int rms_get_sdp_info(rms_sdp_info_t *sdp_info, struct sip_msg *msg);
39 40
 int rms_sdp_set_body(struct sip_msg *msg, str *new_body);
40 41
 int rms_sdp_prepare_new_body(rms_sdp_info_t *, int payload_type_number);
41 42
 void rms_sdp_info_init(rms_sdp_info_t *sdp_info);
43
+int rms_sdp_info_clone(rms_sdp_info_t *dst, rms_sdp_info_t *src);
42 44
 void rms_sdp_info_free(rms_sdp_info_t *sdp_info);
43 45
 PayloadType *rms_sdp_check_payload(rms_sdp_info_t *);
44 46
 
45 47
new file mode 100644
... ...
@@ -0,0 +1,217 @@
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 "rtp_media_server.h"
22
+extern rms_session_info_t *rms_session_list;
23
+
24
+
25
+static void rms_action_free(rms_session_info_t *si)
26
+{
27
+	rms_action_t *a, *tmp;
28
+	clist_foreach(&si->action, a, next)
29
+	{
30
+		tmp = a;
31
+		a = a->prev;
32
+		clist_rm(tmp, next, prev);
33
+		shm_free(tmp);
34
+	}
35
+}
36
+
37
+rms_action_t *rms_action_new(rms_action_type_t t)
38
+{
39
+	rms_action_t *a = shm_malloc(sizeof(rms_action_t));
40
+	if(!a)
41
+		return NULL;
42
+	memset(a, 0, sizeof(rms_action_t));
43
+	a->type = t;
44
+	return a;
45
+}
46
+
47
+int init_rms_session_list()
48
+{
49
+	rms_session_list = shm_malloc(sizeof(rms_session_info_t));
50
+	if(!rms_session_list)
51
+		return 0;
52
+	clist_init(rms_session_list, next, prev);
53
+	return 1;
54
+}
55
+
56
+rms_session_info_t *rms_session_search(struct sip_msg *msg) // str *from_tag)
57
+{
58
+	rms_session_info_t *si;
59
+	str callid = msg->callid->body;
60
+	if(parse_from_header(msg) < 0) {
61
+		LM_ERR("can not parse from header!\n");
62
+		return NULL;
63
+	}
64
+	struct to_body *from = get_from(msg);
65
+	clist_foreach(rms_session_list, si, next)
66
+	{
67
+		if(strncmp(callid.s, si->callid.s, callid.len) == 0) {
68
+			LM_NOTICE("call-id[%s]tag[%s][%s]\n", si->callid.s, si->local_tag.s,
69
+					si->remote_tag.s);
70
+			if(si->remote_tag.s
71
+					&& strncmp(from->tag_value.s, si->remote_tag.s,
72
+							   from->tag_value.len)
73
+							   == 0)
74
+				return si;
75
+			if(si->local_tag.s
76
+					&& strncmp(from->tag_value.s, si->local_tag.s,
77
+							   from->tag_value.len)
78
+							   == 0)
79
+				return si;
80
+			LM_NOTICE("call-id found but tag not matching ? [%s][%.*s]\n",
81
+					si->callid.s, from->tag_value.len, from->tag_value.s);
82
+		}
83
+	}
84
+	return NULL;
85
+}
86
+
87
+rms_session_info_t *rms_session_search_sync(struct sip_msg *msg)
88
+{
89
+	lock(&session_list_mutex);
90
+	rms_session_info_t *si = rms_session_search(msg);
91
+	unlock(&session_list_mutex);
92
+	return si;
93
+}
94
+
95
+void rms_session_add(rms_session_info_t *si)
96
+{
97
+	lock(&session_list_mutex);
98
+	clist_append(rms_session_list, si, next, prev);
99
+	unlock(&session_list_mutex);
100
+}
101
+
102
+void rms_session_rm(rms_session_info_t *si)
103
+{
104
+	lock(&session_list_mutex);
105
+	clist_rm(si, next, prev);
106
+	unlock(&session_list_mutex);
107
+}
108
+
109
+int rms_session_free(rms_session_info_t *si)
110
+{
111
+	rms_action_free(si);
112
+	rms_sdp_info_free(&si->sdp_info_offer);
113
+	rms_sdp_info_free(&si->sdp_info_answer);
114
+	if(si->media.pt) {
115
+		// payload_type_destroy(si->media.pt);
116
+		shm_free(
117
+				si->media
118
+						.pt); // TODO: should be destroyed in  compatible way from MS manager process
119
+		si->media.pt = NULL;
120
+	}
121
+	if(si->callid.s) {
122
+		shm_free(si->callid.s);
123
+		si->callid.s = NULL;
124
+	}
125
+	if(si->contact_uri.s) {
126
+		shm_free(si->contact_uri.s);
127
+		si->contact_uri.s = NULL;
128
+	}
129
+	if(si->local_ip.s) {
130
+		shm_free(si->local_ip.s);
131
+		si->local_ip.s = NULL;
132
+	}
133
+	if(si->remote_uri.s) {
134
+		shm_free(si->remote_uri.s);
135
+		si->remote_uri.s = NULL;
136
+	}
137
+	if(si->local_uri.s) {
138
+		shm_free(si->local_uri.s);
139
+		si->local_uri.s = NULL;
140
+	}
141
+	shm_free(si);
142
+	si = NULL;
143
+	return 1;
144
+}
145
+
146
+int rms_check_msg(struct sip_msg *msg)
147
+{
148
+	if(!msg || !msg->callid || !msg->callid->body.s) {
149
+		LM_INFO("no callid ?\n");
150
+		return -1;
151
+	}
152
+	return 1;
153
+}
154
+
155
+rms_session_info_t *rms_session_new(struct sip_msg *msg)
156
+{
157
+	struct hdr_field *hdr = NULL;
158
+
159
+	if(!rms_check_msg(msg))
160
+		return NULL;
161
+	rms_session_info_t *si = shm_malloc(sizeof(rms_session_info_t));
162
+	if(!si) {
163
+		LM_ERR("can not allocate session info !\n");
164
+		goto error;
165
+	}
166
+	memset(si, 0, sizeof(rms_session_info_t));
167
+
168
+	if(!rms_str_dup(&si->callid, &msg->callid->body, 1)) {
169
+		LM_ERR("can not get callid .\n");
170
+		goto error;
171
+	}
172
+	if(!rms_str_dup(&si->remote_uri, &msg->from->body, 1))
173
+		goto error;
174
+	if(!rms_str_dup(&si->local_uri, &msg->to->body, 1))
175
+		goto error;
176
+	str ip;
177
+	ip.s = ip_addr2a(&msg->rcv.dst_ip);
178
+	ip.len = strlen(ip.s);
179
+	if(!rms_str_dup(&si->local_ip, &ip, 1))
180
+		goto error;
181
+	hdr = msg->contact;
182
+	if(parse_contact(hdr) < 0)
183
+		goto error;
184
+	contact_body_t *contact = hdr->parsed;
185
+	if(!rms_str_dup(&si->contact_uri, &contact->contacts->uri, 1))
186
+		goto error;
187
+	LM_INFO("[contact offer] [%.*s]\n", si->contact_uri.len, si->contact_uri.s);
188
+	si->cseq = atoi(msg->cseq->body.s);
189
+
190
+	rms_sdp_info_t *sdp_info = &si->sdp_info_offer;
191
+	if(!rms_get_sdp_info(sdp_info, msg))
192
+		goto error;
193
+	si->media.pt = rms_sdp_check_payload(sdp_info);
194
+	if(!si->media.pt) {
195
+		tmb.t_reply(msg, 488, "incompatible media format");
196
+		goto error;
197
+	}
198
+	clist_init(&si->action, next, prev);
199
+	return si;
200
+error:
201
+	LM_ERR("can not create session.\n");
202
+	rms_session_free(si);
203
+	return NULL;
204
+}
205
+
206
+int rms_sessions_dump_f(struct sip_msg *msg, char *param1, char *param2)
207
+{
208
+	int x = 1;
209
+	rms_session_info_t *si;
210
+	clist_foreach(rms_session_list, si, next)
211
+	{
212
+		LM_INFO("[%d]callid[%s]remote_tag[%s]local_tag[%s]cseq[%d]\n", x,
213
+				si->callid.s, si->remote_tag.s, si->local_tag.s, si->cseq);
214
+		x++;
215
+	}
216
+	return 1;
217
+}
0 218
new file mode 100644
... ...
@@ -0,0 +1,107 @@
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
+#ifndef rms_session_info_h
22
+#define rms_session_info_h
23
+// #include "rtp_media_server.h"
24
+#include "rms_media.h"
25
+//typedef struct rms_action rms_action_t;
26
+typedef struct rms_session_info rms_session_info_t;
27
+// struct call_leg_media;
28
+// typedef struct call_leg_media call_leg_media_t;
29
+
30
+typedef enum rms_action_type {
31
+	RMS_NONE,
32
+	RMS_START,
33
+	RMS_STOP,
34
+	RMS_HANGUP,
35
+	RMS_PLAY,
36
+	RMS_BRIDGING,
37
+	RMS_BRIDGED,
38
+	RMS_DONE,
39
+} rms_action_type_t;
40
+
41
+typedef struct rms_tm_info
42
+{
43
+	unsigned int hash_index;
44
+	unsigned int label;
45
+} rms_tm_info_t;
46
+
47
+typedef struct rms_action
48
+{
49
+	struct rms_action *next;
50
+	struct rms_action *prev;
51
+	str param;
52
+	str route;
53
+	rms_action_type_t type;
54
+	rms_tm_info_t tm_info;
55
+	struct rms_session_info *si;
56
+	struct cell *cell;
57
+} rms_action_t;
58
+
59
+int rms_check_msg(struct sip_msg *msg);
60
+rms_action_t *rms_action_new(rms_action_type_t t);
61
+int init_rms_session_list();
62
+rms_session_info_t *rms_session_search(struct sip_msg *msg);
63
+rms_session_info_t *rms_session_search_sync(struct sip_msg *msg);
64
+void rms_session_add(rms_session_info_t *si);
65
+void rms_session_rm(rms_session_info_t *si);
66
+int rms_session_free(rms_session_info_t *si);
67
+rms_session_info_t *rms_session_new(struct sip_msg *msg);
68
+int rms_sessions_dump_f(struct sip_msg *msg, char *param1, char *param2);
69
+rms_session_info_t *rms_get_session_list(void);
70
+
71
+typedef struct ms_res
72
+{
73
+	AudioStream *audio_stream;
74
+	RtpProfile *rtp_profile;
75
+} ms_res_t;
76
+
77
+typedef enum rms_session_state {
78
+	RMS_ST_DEFAULT,
79
+	RMS_ST_CONNECTING,
80
+	RMS_ST_CONNECTED,
81
+	RMS_ST_DISCONNECTING,
82
+	RMS_ST_DISCONNECTED,
83
+} rms_session_state_t;
84
+
85
+typedef struct rms_session_info
86
+{
87
+	struct rms_session_info *next;
88
+	struct rms_session_info *prev;
89
+	rms_sdp_info_t sdp_info_offer;
90
+	rms_sdp_info_t sdp_info_answer;
91
+	str callid;
92
+	str local_ip;
93
+	int local_port;
94
+	str local_uri;
95
+	str local_tag;
96
+	str remote_uri;
97
+	str remote_tag;
98
+	str contact_uri;
99
+	int cseq;
100
+	ms_res_t ms;
101
+	call_leg_media_t media;
102
+	rms_action_t action;
103
+	rms_session_info_t *bridged_si;
104
+	rms_session_state_t state;
105
+} rms_session_info_t;
106
+
107
+#endif
... ...
@@ -33,7 +33,7 @@ static inline int rms_str_dup(str *dst, str *src, int shared)
33 33
 {
34 34
 	if(!dst) {
35 35
 		LM_ERR("dst null\n");
36
-		return -1;
36
+		return 0;
37 37
 	}
38 38
 	dst->len = 0;
39 39
 	dst->s = NULL;
... ...
@@ -45,21 +45,21 @@ static inline int rms_str_dup(str *dst, str *src, int shared)
45 45
 		return 1;
46 46
 	dst->len = src->len;
47 47
 	if(shared) {
48
-		dst->s = shm_malloc(dst->len+1);
48
+		dst->s = shm_malloc(dst->len + 1);
49 49
 	} else {
50
-		dst->s = pkg_malloc(dst->len+1);
50
+		dst->s = pkg_malloc(dst->len + 1);
51 51
 	}
52 52
 	if(!dst->s) {
53 53
 		LM_ERR("%s_malloc: can't allocate memory (%d bytes)\n",
54 54
 				shared ? "shm" : "pkg", src->len);
55
-		return -1;
55
+		return 0;
56 56
 	}
57 57
 	memcpy(dst->s, src->s, src->len);
58 58
 	dst->s[dst->len] = '\0';
59 59
 	return 1;
60 60
 }
61 61
 
62
-static inline char* rms_char_dup(char *s, int shared)
62
+static inline char *rms_char_dup(char *s, int shared)
63 63
 {
64 64
 	str src;
65 65
 	str dst;
... ...
@@ -23,39 +23,44 @@
23 23
 
24 24
 MODULE_VERSION
25 25
 
26
+rms_session_info_t *rms_session_list;
26 27
 static int mod_init(void);
27 28
 static void mod_destroy(void);
28 29
 static int child_init(int);
29
-
30
-static rms_session_info_t *rms_session_list;
31 30
 str playback_fn = {0, 0};
32 31
 str log_fn = {0, 0};
33 32
 
34 33
 static rms_t rms;
35 34
 
36
-static int rms_session_free(rms_session_info_t *si);
37
-static rms_session_info_t *rms_session_search(char *callid, int len);
35
+static rms_session_info_t *rms_session_create_leg(rms_session_info_t *si);
38 36
 static int fixup_rms_action_play(void **param, int param_no);
37
+static int fixup_rms_bridge(void **param, int param_no);
39 38
 static int rms_hangup_call(rms_session_info_t *si);
39
+static int rms_bridging_call(rms_session_info_t *si, rms_action_t *a);
40
+static int rms_bridged_call(rms_session_info_t *si, rms_action_t *a);
40 41
 
41 42
 static int rms_answer_f(struct sip_msg *);
43
+static int rms_sip_request_f(struct sip_msg *);
42 44
 static int rms_action_play_f(struct sip_msg *, str *, str *);
43
-static int rms_sdp_offer_f(struct sip_msg *, char *, char *);
44
-static int rms_sdp_answer_f(struct sip_msg *, char *, char *);
45
-static int rms_media_stop_f(struct sip_msg *, char *, char *);
45
+static int rms_session_check_f(struct sip_msg *);
46 46
 static int rms_hangup_f(struct sip_msg *);
47
-static int rms_sessions_dump_f(struct sip_msg *, char *, char *);
47
+static int rms_bridge_f(struct sip_msg *, char *, str *);
48
+
49
+static int rms_update_call_sdp(struct sip_msg *msg,
50
+		const rms_session_info_t *si, call_leg_media_t *m,
51
+		rms_sdp_info_t *sdp_info);
48 52
 
49 53
 static cmd_export_t cmds[] = {
50 54
 		{"rms_answer", (cmd_function)rms_answer_f, 0, 0, 0, EVENT_ROUTE},
51
-		{"rms_play", (cmd_function)rms_action_play_f, 2, fixup_rms_action_play, 0,
52
-				ANY_ROUTE},
53
-		{"rms_sdp_offer", (cmd_function)rms_sdp_offer_f, 0, 0, 0, ANY_ROUTE},
54
-		{"rms_sdp_answer", (cmd_function)rms_sdp_answer_f, 0, 0, 0, REQUEST_ROUTE
55
-				| FAILURE_ROUTE | ONREPLY_ROUTE},
56
-		{"rms_media_stop", (cmd_function)rms_media_stop_f, 0, 0, 0, REQUEST_ROUTE
57
-				| FAILURE_ROUTE | ONREPLY_ROUTE},
55
+		{"rms_sip_request", (cmd_function)rms_sip_request_f, 0, 0, 0,
56
+				EVENT_ROUTE},
57
+		{"rms_play", (cmd_function)rms_action_play_f, 2, fixup_rms_action_play,
58
+				0, ANY_ROUTE},
59
+		{"rms_session_check", (cmd_function)rms_session_check_f, 0, 0, 0,
60
+				REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE},
58 61
 		{"rms_hangup", (cmd_function)rms_hangup_f, 0, 0, 0, EVENT_ROUTE},
62
+		{"rms_bridge", (cmd_function)rms_bridge_f, 2, fixup_rms_bridge, 0,
63
+				ANY_ROUTE},
59 64
 		{"rms_sessions_dump", (cmd_function)rms_sessions_dump_f, 0, 0, 0,
60 65
 				ANY_ROUTE},
61 66
 		{0, 0, 0, 0, 0, 0}};
... ...
@@ -89,12 +94,31 @@ static void run_action_route(rms_session_info_t *si, char *route)
89 94
 		LM_ERR("faked_msg_init() failed\n");
90 95
 		return;
91 96
 	}
97
+
92 98
 	fmsg = faked_msg_next();
93
-	struct hdr_field callid;
94
-	callid.body.s = si->callid.s;
95
-	callid.body.len = si->callid.len;
96 99
 
97
-	fmsg->callid = &callid;
100
+	{ // set the callid
101
+		struct hdr_field callid;
102
+		callid.body.s = si->callid.s;
103
+		callid.body.len = si->callid.len;
104
+		fmsg->callid = &callid;
105
+	}
106
+	{ // set the from tag
107
+		struct hdr_field from;
108
+		struct to_body from_parsed;
109
+		from.parsed = &from_parsed;
110
+		from_parsed.tag_value.len = si->remote_tag.len;
111
+		from_parsed.tag_value.s = si->remote_tag.s;
112
+		fmsg->from = &from;
113
+	}
114
+	//{ // set the to tag
115
+	//	struct hdr_field to;
116
+	//	struct to_body to_parsed;
117
+	//	to.parsed = &to_parsed;
118
+	//	to_parsed.tag_value.len = si->local_tag.len;
119
+	//	to_parsed.tag_value.s = si->local_tag.s;
120
+	//	fmsg->to = &to;
121
+	//}
98 122
 
99 123
 	backup_rt = get_route_type();
100 124
 	set_route_type(EVENT_ROUTE);
... ...
@@ -105,6 +129,17 @@ static void run_action_route(rms_session_info_t *si, char *route)
105 129
 	set_route_type(backup_rt);
106 130
 }
107 131
 
132
+
133
+static int fixup_rms_bridge(void **param, int param_no)
134
+{
135
+	if(param_no == 1)
136
+		return fixup_spve_null(param, 1);
137
+	if(param_no == 2)
138
+		return fixup_spve_null(param, 1);
139
+	LM_ERR("invalid parameter count [%d]\n", param_no);
140
+	return -1;
141
+}
142
+
108 143
 static int fixup_rms_action_play(void **param, int param_no)
109 144
 {
110 145
 	if(param_no == 1)
... ...
@@ -123,11 +158,15 @@ static int mod_init(void)
123 158
 {
124 159
 	LM_INFO("RTP media server module init\n");
125 160
 	rms.udp_start_port = 50000;
161
+	LM_INFO("RTP media server module init\n");
126 162
 	rms.udp_end_port = 60000;
127
-	rms.udp_last_port = 50000;
163
+	rms.udp_last_port = 50000 + rand() % 10000;
128 164
 	rms_media_init();
129
-	rms_session_list = shm_malloc(sizeof(rms_session_info_t));
130
-	clist_init(rms_session_list, next, prev);
165
+
166
+	if(!init_rms_session_list()) {
167
+		LM_ERR("can't initialize rms_session_list !\n");
168
+		return -1;
169
+	}
131 170
 
132 171
 	register_procs(1);
133 172
 	if(load_tm_api(&tmb) != 0) {
... ...
@@ -163,7 +202,26 @@ void rms_signal_handler(int signum)
163 202
 	LM_INFO("signal received [%d]\n", signum);
164 203
 }
165 204
 
166
-static rms_session_info_t* rms_session_action_check(rms_session_info_t *si)
205
+
206
+static rms_session_info_t *rms_stop(rms_session_info_t *si)
207
+{
208
+	LM_NOTICE("si[%p]\n", si);
209
+	if(si->bridged_si) {
210
+		rms_stop_bridge(&si->media, &si->bridged_si->media);
211
+	} else {
212
+		rms_stop_media(&si->media);
213
+	}
214
+
215
+	rms_session_info_t *tmp = si->prev;
216
+	si->state = RMS_ST_DISCONNECTED;
217
+	// keep it for a little while to deal with retransmissions ...
218
+	//clist_rm(si, next, prev);
219
+	//rms_session_free(si);
220
+	si = tmp;
221
+	return si;
222
+}
223
+
224
+static rms_session_info_t *rms_session_action_check(rms_session_info_t *si)
167 225
 {
168 226
 	rms_action_t *a;
169 227
 	clist_foreach(&si->action, a, next)
... ...
@@ -171,19 +229,35 @@ static rms_session_info_t* rms_session_action_check(rms_session_info_t *si)
171 229
 		if(a->type == RMS_HANGUP) {
172 230
 			LM_INFO("session action RMS_HANGUP [%s]\n", si->callid.s);
173 231
 			rms_hangup_call(si);
232
+			if(si->bridged_si)
233
+				rms_hangup_call(si->bridged_si);
174 234
 			a->type = RMS_STOP;
175 235
 			return si;
236
+		} else if(a->type == RMS_BRIDGING) {
237
+			LM_INFO("session action RMS_BRIDGING [%s][%p]\n", si->callid.s,
238
+					a->cell->uas.request);
239
+			rms_bridging_call(si, a);
240
+			a->type = RMS_NONE;
241
+			shm_free(a->param.s);
242
+			return si;
243
+		} else if(a->type == RMS_BRIDGED) {
244
+			LM_INFO("session action RMS_BRIDGED [%s]\n", si->callid.s);
245
+			LM_INFO("si_1[%p]si_2[%p]\n", si, si->bridged_si);
246
+			rms_bridged_call(si, a);
247
+			a->type = RMS_NONE;
248
+			return si;
176 249
 		} else if(a->type == RMS_STOP) {
177
-			LM_INFO("session action RMS_STOP [%s][%p|%p]\n", si->callid.s, si, si->prev);
178
-			rms_stop_media(&si->caller_media);
179
-			rms_session_info_t *tmp = si->prev;
180
-			clist_rm(si, next, prev);
181
-			rms_session_free(si);
182
-			si = tmp;
250
+			LM_INFO("session action RMS_STOP [%s][%p|%p]\n", si->callid.s, si,
251
+					si->prev);
252
+			//if (si->bridged_si)
253
+			//	rms_stop(si->bridged_si);
254
+			si = rms_stop(si);
255
+			a->type = RMS_NONE;
256
+			// si->state = RMS_SSTATE_DISCONNECTED;
183 257
 			return si;
184 258
 		} else if(a->type == RMS_PLAY) {
185 259
 			LM_INFO("session action RMS_PLAY [%s]\n", si->callid.s);
186
-			rms_playfile(&si->caller_media, a);
260
+			rms_playfile(&si->media, a);
187 261
 			a->type = RMS_NONE;
188 262
 		} else if(a->type == RMS_DONE) {
189 263
 			LM_INFO("session action RMS_DONE [%s][%s]\n", si->callid.s,
... ...
@@ -199,9 +273,9 @@ static rms_session_info_t* rms_session_action_check(rms_session_info_t *si)
199 273
 			}
200 274
 			return si;
201 275
 		} else if(a->type == RMS_START) {
202
-			create_call_leg_media(&si->caller_media);
276
+			create_call_leg_media(&si->media);
203 277
 			LM_INFO("session action RMS_START [%s]\n", si->callid.s);
204
-			rms_start_media(&si->caller_media, a->param.s);
278
+			rms_start_media(&si->media, a->param.s);
205 279
 			run_action_route(si, "rms:start");
206 280
 			a->type = RMS_NONE;
207 281
 			return si;
... ...
@@ -225,7 +299,7 @@ static void rms_session_manage_loop()
225 299
 			si = rms_session_action_check(si);
226 300
 		}
227 301
 		unlock(&session_list_mutex);
228
-		usleep(2000);
302
+		usleep(10000);
229 303
 	}
230 304
 }
231 305
 
... ...
@@ -259,130 +333,264 @@ static int child_init(int rank)
259 333
 	return (rtn);
260 334
 }
261 335
 
262
-static int rms_get_sdp_info(rms_sdp_info_t *sdp_info, struct sip_msg *msg)
336
+static int parse_from(struct sip_msg *msg, rms_session_info_t *si)
263 337
 {
264
-	sdp_session_cell_t *sdp_session;
265
-	sdp_stream_cell_t *sdp_stream;
266
-	str media_ip, media_port;
267
-	int sdp_session_num = 0;
268
-	int sdp_stream_num = get_sdp_stream_num(msg);
269
-	if(parse_sdp(msg) < 0) {
270
-		LM_INFO("can not parse sdp\n");
271
-		return 0;
272
-	}
273
-	sdp_info_t *sdp = (sdp_info_t *)msg->body;
274
-	if(!sdp) {
275
-		LM_INFO("sdp null\n");
338
+	struct to_body *from = get_from(msg);
339
+	LM_DBG("from[%.*s]tag[%.*s]\n", from->uri.len, from->uri.s,
340
+			from->tag_value.len, from->tag_value.s);
341
+	rms_str_dup(&si->remote_tag, &from->tag_value, 1);
342
+	return 1;
343
+}
344
+
345
+static int rms_sip_reply(
346
+		struct cell *cell, rms_session_info_t *si, int code, char *_reason)
347
+{
348
+	str reason = str_init(_reason);
349
+	if(si->remote_tag.len == 0) {
350
+		LM_ERR("can not find from tag\n");
276 351
 		return 0;
277 352
 	}
278
-	rms_str_dup(&sdp_info->recv_body, &sdp->text, 1);
279
-	if(!sdp_info->recv_body.s)
280
-		goto error;
281
-	LM_INFO("sdp body - type[%d]\n", sdp->type);
282
-	if(sdp_stream_num > 1 || !sdp_stream_num) {
283
-		LM_INFO("only support one stream[%d]\n", sdp_stream_num);
284
-	}
285
-	sdp_stream_num = 0;
286
-	sdp_session = get_sdp_session(msg, sdp_session_num);
287
-	if(!sdp_session) {
288
-		return 0;
289
-	} else {
290
-		int sdp_stream_num = 0;
291
-		sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num);
292
-		if(!sdp_stream) {
293
-			LM_INFO("can not get the sdp stream\n");
353
+
354
+	if(!cell)
355
+		cell = tmb.t_gett();
356
+
357
+	if(cell->uas.request) {
358
+		if(!tmb.t_reply_with_body(
359
+				   cell, code, &reason, NULL, NULL, &si->local_tag)) {
360
+			LM_ERR("t_reply error");
294 361
 			return 0;
295
-		} else {
296
-			rms_str_dup(&sdp_info->payloads, &sdp_stream->payloads, 1);
297
-			if(!sdp_info->payloads.s)
298
-				goto error;
299 362
 		}
300
-	}
301
-	if(sdp_stream->ip_addr.s && sdp_stream->ip_addr.len > 0) {
302
-		media_ip = sdp_stream->ip_addr;
303 363
 	} else {
304
-		media_ip = sdp_session->ip_addr;
364
+		LM_INFO("no request found\n");
305 365
 	}
306
-	rms_str_dup(&sdp_info->remote_ip, &media_ip, 1);
307
-	if(!sdp_info->remote_ip.s)
308
-		goto error;
309
-	rms_str_dup(&media_port, &sdp_stream->port, 0);
310
-	if(!media_port.s)
311
-		goto error;
312
-	sdp_info->remote_port = atoi(media_port.s);
313
-	pkg_free(media_port.s);
314 366
 	return 1;
315
-error:
316
-	rms_sdp_info_free(sdp_info);
317
-	return 0;
318 367
 }
319 368
 
320
-static int rms_relay_call(struct sip_msg *msg)
369
+static int rms_answer_call(
370
+		struct cell *cell, rms_session_info_t *si, rms_sdp_info_t *sdp_info)
321 371
 {
322
-	if(!tmb.t_relay(msg, NULL, NULL)) {
323
-		LM_INFO("t_ralay error\n");
324
-		return -1;
372
+	char buffer[128];
373
+	str reason = str_init("OK");
374
+	str contact_hdr;
375
+
376
+	LM_INFO("[%s][%d]\n", sdp_info->new_body.s, sdp_info->udp_local_port);
377
+
378
+	if(si->remote_tag.len == 0) {
379
+		LM_ERR("can not find from tag\n");
380
+		return 0;
381
+	}
382
+	LM_INFO("ip[%s]\n", si->local_ip.s);
383
+	sdp_info->local_ip.s = si->local_ip.s;
384
+	sdp_info->local_ip.len = si->local_ip.len;
385
+
386
+	snprintf(buffer, 128,
387
+			"Contact: <sip:rms@%s:%d>\r\nContent-Type: application/sdp\r\n",
388
+			si->local_ip.s, si->local_port);
389
+	contact_hdr.len = strlen(buffer);
390
+	contact_hdr.s = buffer;
391
+
392
+	if(!cell)
393
+		cell = tmb.t_gett();
394
+
395
+	if(cell->uas.request) {
396
+		if(!tmb.t_reply_with_body(cell, 200, &reason, &sdp_info->new_body,
397
+				   &contact_hdr, &si->local_tag)) {
398
+			LM_ERR("t_reply error");
399
+			return 0;
400
+		}
401
+		LM_INFO("answered\n");
402
+	} else {
403
+		LM_INFO("no request found\n");
325 404
 	}
326 405
 	return 1;
327 406
 }
328 407
 
329
-static int parse_from(struct sip_msg *msg, rms_session_info_t *si)
408
+// message originating leg is suspended, this is the callback function of the transaction with destination leg
409
+static void forward_cb(struct cell *ptrans, int ntype, struct tmcb_params *pcbp)
330 410
 {
331
-	struct to_body *from = get_from(msg);
332
-	LM_INFO("from[%.*s]tag[%.*s]\n", from->uri.len, from->uri.s,
333
-			from->tag_value.len, from->tag_value.s);
334
-	rms_str_dup(&si->remote_tag, &from->tag_value, 1);
335
-	return 1;
411
+	// struct sip_msg *msg = pcbp->rpl;
412
+	str *reason = &pcbp->rpl->first_line.u.reply.reason;
413
+	rms_action_t *a = (rms_action_t *)*pcbp->param;
414
+	if(ntype == TMCB_ON_FAILURE) {
415
+		LM_NOTICE("FAILURE [%d][%.*s]\n", pcbp->code, reason->len, reason->s);
416
+		return;
417
+	} else {
418
+		LM_NOTICE("COMPLETE [%d][%.*s] RE-INVITE/UPDATE - TODO SDP "
419
+				  "renegotiation ? \n",
420
+				pcbp->code, reason->len, reason->s);
421
+	}
422
+
423
+	// rms_answer_call(a->cell, si, sdp_info);
424
+	// if(!cell) cell = tmb.t_gett();
425
+	if(a->cell->uas.request) {
426
+		if(!tmb.t_reply_with_body(a->cell, pcbp->code, reason, NULL, NULL,
427
+				   &a->si->local_tag)) {
428
+			LM_ERR("t_reply error");
429
+			return;
430
+		}
431
+		LM_INFO("replied\n");
432
+	} else {
433
+		LM_INFO("no request found\n");
434
+	}
336 435
 }
337 436
 
338
-static int rms_answer_call(struct sip_msg *msg, rms_session_info_t *si)
339
-{
340
-	char buffer[128];
341
-	str to_tag;
342
-	str reason = str_init("OK");
343
-	str contact_hdr;
344 437
 
345
-	rms_sdp_info_t *sdp_info = &si->sdp_info_offer;
438
+// legA is suspended, this is the callback function of the transaction with legB (the callee)
439
+// response to legA will be not be done here but once the media negociation is completed by the RMS process.
440
+static void bridge_cb(struct cell *ptrans, int ntype, struct tmcb_params *pcbp)
441
+{
442
+	struct sip_msg *msg = pcbp->rpl;
443
+	if(ntype == TMCB_ON_FAILURE) {
444
+		LM_NOTICE("FAILURE [%d]\n", pcbp->code);
445
+		rms_action_t *a = (rms_action_t *)*pcbp->param;
446
+		a->si->state = RMS_ST_DISCONNECTED;
447
+		if(a->cell->uas.request) {
448
+			str *reason = &pcbp->rpl->first_line.u.reply.reason;
449
+			if(!tmb.t_reply_with_body(a->cell, pcbp->code, reason, NULL, NULL,
450
+					   &a->si->local_tag)) {
451
+				LM_ERR("t_reply error");
452
+				return;
453
+			}
454
+			LM_INFO("failure replied\n");
455
+			a->type = RMS_NONE;
456
+		} else {
457
+			LM_ERR("failure but no request found\n");
458
+		}
459
+		return;
460
+	} else if(ntype == TMCB_LOCAL_COMPLETED) {
461
+		LM_NOTICE("COMPLETED [%d]\n", pcbp->code);
462
+	} else {
463
+		LM_NOTICE("TMCB_TYPE[%d][%d]\n", ntype, pcbp->code);
464
+	}
346 465
 
347
-	if(msg->REQ_METHOD != METHOD_INVITE) {
348
-		LM_ERR("only invite is supported for offer \n");
349
-		return 0;
466
+	if(parse_to_header(msg) < 0) {
467
+		LM_ERR("can not parse To header!\n");
468
+		return;
350 469
 	}
470
+	struct to_body *to = get_to(msg);
471
+	if(parse_from_header(msg) < 0) {
472
+		LM_ERR("can not parse From header!\n");
473
+		return;
474
+	}
475
+	struct to_body *from = get_from(msg);
351 476
 
352
-	parse_from(msg, si);
477
+	rms_action_t *a = (rms_action_t *)*pcbp->param;
478
+	rms_session_info_t *bridged_si = a->si;
479
+	rms_session_info_t *si = bridged_si->bridged_si;
353 480
 
354
-	if(si->remote_tag.len == 0) {
355
-		LM_ERR("can not find from tag\n");
356
-		return 0;
481
+	if(to->tag_value.len == 0) {
482
+		LM_ERR("not to tag.\n");
483
+		goto error;