... | ... |
@@ -207,6 +207,9 @@ mod_list_rabbitmq=rabbitmq |
207 | 207 |
# - modules depending on libphonenumber library |
208 | 208 |
mod_list_phonenum=phonenum |
209 | 209 |
|
210 |
+# - modules depending on oRTP and mediastreamer2 libraries |
|
211 |
+mod_list_rtp_media=rtp_media_server |
|
212 |
+ |
|
210 | 213 |
# - all modules |
211 | 214 |
mod_list_all=$(sort $(mod_list_basic) $(mod_list_extra) \ |
212 | 215 |
$(mod_list_db) $(mod_list_dbuid) \ |
... | ... |
@@ -239,7 +242,8 @@ mod_list_all=$(sort $(mod_list_basic) $(mod_list_extra) \ |
239 | 242 |
$(mod_list_erlang) $(mod_list_systemd) \ |
240 | 243 |
$(mod_list_http_async) $(mod_list_nsq) \ |
241 | 244 |
$(mod_list_rabbitmq) $(mod_list_jsdt)) \ |
242 |
- $(mod_list_phonenum) |
|
245 |
+ $(mod_list_phonenum) \ |
|
246 |
+ $(mod_list_rtp_media) |
|
243 | 247 |
|
244 | 248 |
|
245 | 249 |
|
246 | 250 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,13 @@ |
1 |
+include ../../Makefile.defs |
|
2 |
+auto_gen= |
|
3 |
+NAME=rtp_media_server.so |
|
4 |
+ |
|
5 |
+DEFS+=-I$(LOCALBASE)/lib |
|
6 |
+ |
|
7 |
+ORTPLIBS=-lortp |
|
8 |
+BCUNITLIBS=-lbcunit |
|
9 |
+MS2LIBS=-lmediastreamer_voip -lmediastreamer_base |
|
10 |
+ |
|
11 |
+LIBS=$(ORTPLIBS) $(BCUNITLIBS) $(MS2LIBS) |
|
12 |
+DEFS+=-DKAMAILIO_MOD_INTERFACE |
|
13 |
+include ../../Makefile.modules |
0 | 14 |
new file mode 100755 |
... | ... |
@@ -0,0 +1,56 @@ |
1 |
+ |
|
2 |
+debug=3 |
|
3 |
+log_stderror=yes |
|
4 |
+memdbg=5 |
|
5 |
+memlog=5 |
|
6 |
+ |
|
7 |
+# number of SIP routing processes |
|
8 |
+children=5 |
|
9 |
+ |
|
10 |
+loadmodule "ctl" |
|
11 |
+loadmodule "tm" |
|
12 |
+loadmodule "tmx" |
|
13 |
+loadmodule "sl" |
|
14 |
+loadmodule "rr" |
|
15 |
+loadmodule "pv" |
|
16 |
+loadmodule "textops" |
|
17 |
+loadmodule "siputils" |
|
18 |
+loadmodule "xlog" |
|
19 |
+loadmodule "nathelper" |
|
20 |
+loadmodule "rtp_media_server" |
|
21 |
+modparam("rtp_media_server", "log_file_name", "/tmp/rms_transfer.log") |
|
22 |
+modparam("tm", "wt_timer", 1000) |
|
23 |
+listen=udp:147.75.39.121:5090 |
|
24 |
+ |
|
25 |
+event_route[rms:start] { |
|
26 |
+ xnotice("[rms:start] play ...\n"); |
|
27 |
+ rms_play("./voice_file/Bach_10s_8000.wav", "rms:after_play"); |
|
28 |
+}; |
|
29 |
+ |
|
30 |
+event_route[rms:after_play] { |
|
31 |
+ xnotice("[rms:after_play] play done...\n"); |
|
32 |
+ rms_hangup(); |
|
33 |
+}; |
|
34 |
+ |
|
35 |
+route { |
|
36 |
+ if (t_precheck_trans()) { |
|
37 |
+ t_check_trans(); |
|
38 |
+ exit; |
|
39 |
+ } |
|
40 |
+ t_check_trans(); |
|
41 |
+ |
|
42 |
+ xnotice("[$rm][$ci]\n"); |
|
43 |
+ if (is_method("INVITE") && !has_totag()) { |
|
44 |
+ fix_nated_contact(); |
|
45 |
+ if (!rms_answer()) { |
|
46 |
+ t_reply("503", "server error"); |
|
47 |
+ xerr("rtp_media_server error!\n"); |
|
48 |
+ exit; |
|
49 |
+ } |
|
50 |
+ } |
|
51 |
+ if (is_method("BYE")){ |
|
52 |
+ rms_media_stop(); |
|
53 |
+ } |
|
54 |
+ exit; |
|
55 |
+} |
|
56 |
+ |
0 | 5 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,42 @@ |
1 |
+<?xml version="1.0" encoding='ISO-8859-1'?> |
|
2 |
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" |
|
3 |
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [ |
|
4 |
+ |
|
5 |
+<!-- Include general documentation entities --> |
|
6 |
+<!ENTITY % docentities SYSTEM "../../../../doc/docbook/entities.xml"> |
|
7 |
+%docentities; |
|
8 |
+ |
|
9 |
+]> |
|
10 |
+ |
|
11 |
+<book xmlns:xi="http://www.w3.org/2001/XInclude"> |
|
12 |
+ <bookinfo> |
|
13 |
+ <title>rtp_media_server Module</title> |
|
14 |
+ <productname class="trade">&kamailio;</productname> |
|
15 |
+ <authorgroup> |
|
16 |
+ <author> |
|
17 |
+ <firstname>Julien</firstname> |
|
18 |
+ <surname>Chavanton</surname> |
|
19 |
+ <email>jchavanton@gmail.com</email> |
|
20 |
+ </author> |
|
21 |
+ <author> |
|
22 |
+ <firstname>Julien</firstname> |
|
23 |
+ <surname>Chavanton</surname> |
|
24 |
+ <affiliation><orgname>flowroute.com</orgname></affiliation> |
|
25 |
+ <email>jchavanton@gmail.com</email> |
|
26 |
+ </author> |
|
27 |
+ <editor> |
|
28 |
+ <firstname>Julien</firstname> |
|
29 |
+ <surname>Chavanton</surname> |
|
30 |
+ <affiliation><orgname>flowroute.com</orgname></affiliation> |
|
31 |
+ <email>jchavanton@gmail.com</email> |
|
32 |
+ </editor> |
|
33 |
+ </authorgroup> |
|
34 |
+ <copyright> |
|
35 |
+ <year>2017-2018</year> |
|
36 |
+ <holder>Flowroute.com</holder> |
|
37 |
+ </copyright> |
|
38 |
+ </bookinfo> |
|
39 |
+ <toc></toc> |
|
40 |
+ |
|
41 |
+ <xi:include href="rtp_media_server_admin.xml"/> |
|
42 |
+</book> |
0 | 43 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,193 @@ |
1 |
+<?xml version="1.0" encoding='ISO-8859-1'?> |
|
2 |
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" |
|
3 |
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [ |
|
4 |
+ |
|
5 |
+<!-- Include general documentation entities --> |
|
6 |
+<!ENTITY % docentities SYSTEM "../../../../doc/docbook/entities.xml"> |
|
7 |
+%docentities; |
|
8 |
+ |
|
9 |
+]> |
|
10 |
+ |
|
11 |
+<chapter> |
|
12 |
+ <title>&adminguide;</title> |
|
13 |
+ |
|
14 |
+<section> |
|
15 |
+ <title>Overview</title> |
|
16 |
+ <para> |
|
17 |
+ rtp_media_server module is adding RTP and media processing functionalities to Kamailio |
|
18 |
+ </para> |
|
19 |
+ <para> |
|
20 |
+ Kamailio is providing SIP signaling including and enpoint with Dialog state, SDP parsing and scripting language |
|
21 |
+ </para><para> |
|
22 |
+ oRTP: is providing Real-time Transport Protocol (RFC 3550) |
|
23 |
+ </para><para> |
|
24 |
+ mediastreamer2: is providing mediaprocessing functionnalities using graphs and filters, many modules are available |
|
25 |
+ to support various features, it should be relatively simple to integrated them. |
|
26 |
+ </para><para> |
|
27 |
+ mediastreamer2 is also providing a framework to create custom mediaprocessing modules. |
|
28 |
+ </para> |
|
29 |
+</section> |
|
30 |
+ |
|
31 |
+<section> |
|
32 |
+ <title>Dependencies</title> |
|
33 |
+ <section> |
|
34 |
+ <title>&kamailio; Modules</title> |
|
35 |
+ <para> |
|
36 |
+ The module depends on the following modules (in the other words |
|
37 |
+ the listed modules must be loaded before this module): |
|
38 |
+ <itemizedlist> |
|
39 |
+ <listitem> |
|
40 |
+ <para><emphasis>tm</emphasis> - accounting module</para> |
|
41 |
+ </listitem> |
|
42 |
+ </itemizedlist> |
|
43 |
+ </para> |
|
44 |
+ </section> |
|
45 |
+ <section> |
|
46 |
+ <title>External Libraries or Applications</title> |
|
47 |
+ <para> |
|
48 |
+ The following libraries or applications must be installed |
|
49 |
+ before running &kamailio; with this module loaded: |
|
50 |
+ </para><para> |
|
51 |
+ If you want to build oRTP and mediastreamer from source, you can use the provided script for Debian "install_bc.sh". |
|
52 |
+ </para> |
|
53 |
+ <itemizedlist> |
|
54 |
+ <listitem> |
|
55 |
+ <para> |
|
56 |
+ <emphasis>oRTP</emphasis> git://git.linphone.org/ortp.git |
|
57 |
+ </para> |
|
58 |
+ <para> |
|
59 |
+ oRTP is a library implemeting Real-time Transport Protocol (RFC 3550), distributed under GNU GPLv2 or proprietary license. |
|
60 |
+ </para> |
|
61 |
+ </listitem> |
|
62 |
+ <listitem> |
|
63 |
+ <para> |
|
64 |
+ <emphasis>mediastreamer2</emphasis> git clone git://git.linphone.org/mediastreamer2.git |
|
65 |
+ </para> |
|
66 |
+ <para> |
|
67 |
+ Mediastreamer2 is a powerful and lightweight streaming engine specialized for voice/video telephony applications. |
|
68 |
+ </para> |
|
69 |
+ </listitem> |
|
70 |
+ </itemizedlist> |
|
71 |
+ </section> |
|
72 |
+</section> |
|
73 |
+ |
|
74 |
+<section> |
|
75 |
+ <title>Parameters</title> |
|
76 |
+ <section> |
|
77 |
+ <title><varname>log_file_name</varname> (string)</title> |
|
78 |
+ <para> |
|
79 |
+ oRTP and MediaStreamer2 log file settings |
|
80 |
+ the log mask is not configurable : |
|
81 |
+ MESSAGE | WARNING | ERROR | FATAL |
|
82 |
+ levels are activated. |
|
83 |
+ </para> |
|
84 |
+ <para> |
|
85 |
+ Default value is not-set (no logging to file). |
|
86 |
+ </para> |
|
87 |
+ <example> |
|
88 |
+ <title>log_file_name example</title> |
|
89 |
+ <programlisting format="linespecific"> |
|
90 |
+... |
|
91 |
+modparam("rtp_media_server", "log_file_name", "/var/log/rms/rms_ortp.log") |
|
92 |
+... |
|
93 |
+ </programlisting></example> |
|
94 |
+ </section> |
|
95 |
+</section> |
|
96 |
+ |
|
97 |
+<section> |
|
98 |
+ <title>Functions</title> |
|
99 |
+ |
|
100 |
+ <section id="rtp_media_server.f.rms_answer"> |
|
101 |
+ <title><varname>rms_answer</varname> ()</title> |
|
102 |
+ <para> |
|
103 |
+ Create a session and a call leg and call the event_route[rms:start] |
|
104 |
+ config example |
|
105 |
+ </para> |
|
106 |
+ <example> |
|
107 |
+ <title>usage example</title> |
|
108 |
+ <programlisting format="linespecific"> |
|
109 |
+... |
|
110 |
+event_route[rms:start] { |
|
111 |
+ xnotice("[rms:start] play ...\n"); |
|
112 |
+ rms_play("/tmp/reference_8000.wav", "rms:after_play"); |
|
113 |
+}; |
|
114 |
+ |
|
115 |
+event_route[rms:after_play] { |
|
116 |
+ xnotice("[rms:after_play] play done...\n"); |
|
117 |
+ rms_hangup(); |
|
118 |
+}; |
|
119 |
+ |
|
120 |
+route { |
|
121 |
+ if (t_precheck_trans()) { |
|
122 |
+ t_check_trans(); |
|
123 |
+ exit; |
|
124 |
+ } |
|
125 |
+ t_check_trans(); |
|
126 |
+ if (is_method("INVITE") && !has_totag()) { |
|
127 |
+ if (!rms_answer()) { |
|
128 |
+ t_reply("503", "server error"); |
|
129 |
+ } |
|
130 |
+ } |
|
131 |
+ |
|
132 |
+ if (is_method("BYE")){ |
|
133 |
+ xnotice("BYE RECEIVED [$ci]\n"); |
|
134 |
+ rms_media_stop(); |
|
135 |
+ } |
|
136 |
+... |
|
137 |
+ </programlisting></example> |
|
138 |
+ </section> |
|
139 |
+ |
|
140 |
+ <section id="rtp_media_server.f.rms_hangup"> |
|
141 |
+ <title><varname>rms_hangup</varname> ()</title> |
|
142 |
+ <para> |
|
143 |
+ Send a BYE, delete the RTP session and the media ressources. |
|
144 |
+ </para> |
|
145 |
+ <example> |
|
146 |
+ <title>usage example</title> |
|
147 |
+ <programlisting format="linespecific"> |
|
148 |
+... |
|
149 |
+ rms_hangup(); |
|
150 |
+... |
|
151 |
+ </programlisting></example> |
|
152 |
+ </section> |
|
153 |
+ |
|
154 |
+ <section id="rtp_media_server.f.rms_media_stop"> |
|
155 |
+ <title><varname>rms_media_stop</varname> ()</title> |
|
156 |
+ <para> |
|
157 |
+ This should be called on reception of a BYE, this will |
|
158 |
+ delete the RTP session and the media ressources. |
|
159 |
+ and reply "200 OK". |
|
160 |
+ </para> |
|
161 |
+ <para> |
|
162 |
+ If the SIP session is not found "481 Call/Transaction Does Not Exist" |
|
163 |
+ is returned. |
|
164 |
+ </para> |
|
165 |
+ <example> |
|
166 |
+ <title>usage example</title> |
|
167 |
+ <programlisting format="linespecific"> |
|
168 |
+... |
|
169 |
+ if (is_method("BYE")){ |
|
170 |
+ rms_media_stop(); |
|
171 |
+ } |
|
172 |
+... |
|
173 |
+ </programlisting></example> |
|
174 |
+ </section> |
|
175 |
+ |
|
176 |
+ <section id="rtp_media_server.f.rms_play"> |
|
177 |
+ <title><varname>rms_play</varname> ()</title> |
|
178 |
+ <para> |
|
179 |
+ Play a wav file, a resampler is automaticaly configured to resample |
|
180 |
+ and convert stereo to mono if needed. |
|
181 |
+ </para><para> |
|
182 |
+ The second parameter is the event route that will be called when the file was played. |
|
183 |
+ </para> |
|
184 |
+ <example> |
|
185 |
+ <title>usage example</title> |
|
186 |
+ <programlisting format="linespecific"> |
|
187 |
+... |
|
188 |
+ rms_play("file.wav", "event_route_name"); |
|
189 |
+... |
|
190 |
+ </programlisting></example> |
|
191 |
+ </section> |
|
192 |
+</section> |
|
193 |
+</chapter> |
0 | 194 |
new file mode 100755 |
... | ... |
@@ -0,0 +1,45 @@ |
1 |
+# https://github.com/jchavanton/rtp_media_server.git |
|
2 |
+apt-get install automake autogen autoconf libtool pkg-config |
|
3 |
+# bcunit |
|
4 |
+git clone https://github.com/BelledonneCommunications/bcunit.git |
|
5 |
+cd bcunit |
|
6 |
+git checkout 29c556fa8ac1ab21fba1291231ffa8dea43cf32a |
|
7 |
+./autogen.sh |
|
8 |
+./configure |
|
9 |
+make |
|
10 |
+make install |
|
11 |
+cd .. |
|
12 |
+ |
|
13 |
+# bctoolbox |
|
14 |
+apt-get install libmbedtls-dev |
|
15 |
+git clone https://github.com/BelledonneCommunications/bctoolbox.git |
|
16 |
+cd bctoolbox |
|
17 |
+git checkout 971953a9fa4058e9c8a40ca4a3fa12d832445255 |
|
18 |
+./autogen.sh |
|
19 |
+./configure |
|
20 |
+make |
|
21 |
+make install |
|
22 |
+cd .. |
|
23 |
+ |
|
24 |
+# oRTP |
|
25 |
+git clone https://github.com/BelledonneCommunications/ortp.git |
|
26 |
+git checkout 6e13ef49a55cdd19dae395c38cfff7ffa518a089 |
|
27 |
+cd ortp |
|
28 |
+./autogen.sh |
|
29 |
+./configure |
|
30 |
+make |
|
31 |
+make install |
|
32 |
+cd .. |
|
33 |
+ |
|
34 |
+# mediastreamer2 |
|
35 |
+apt-get install intltool libspeex-dev libspeexdsp-dev |
|
36 |
+git clone https://github.com/BelledonneCommunications/mediastreamer2.git |
|
37 |
+cd mediastreamer2 |
|
38 |
+git checkout d935123fc497d19a24019c6e7ae4fe0c5f19d55a |
|
39 |
+./autogen.sh |
|
40 |
+./configure --disable-sound --disable-video --enable-tools=no --disable-tests |
|
41 |
+make |
|
42 |
+make install |
|
43 |
+cd .. |
|
44 |
+ |
|
45 |
+ldconfig |
0 | 46 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,319 @@ |
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 |
+ |
|
25 |
+inline static void *ptr_shm_malloc(size_t size) |
|
26 |
+{ |
|
27 |
+ return shm_malloc(size); |
|
28 |
+} |
|
29 |
+inline static void *ptr_shm_realloc(void *ptr, size_t size) |
|
30 |
+{ |
|
31 |
+ return shm_realloc(ptr, size); |
|
32 |
+} |
|
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 |
+static shared_global_vars_t *vars; |
|
45 |
+ |
|
46 |
+MSFilterDesc *rms_ms_filter_descs[] = {&ms_alaw_dec_desc, &ms_alaw_enc_desc, |
|
47 |
+ &ms_ulaw_dec_desc, &ms_ulaw_enc_desc, &ms_rtp_send_desc, |
|
48 |
+ &ms_rtp_recv_desc, &ms_dtmf_gen_desc, &ms_volume_desc, |
|
49 |
+ &ms_equalizer_desc, &ms_channel_adapter_desc, &ms_audio_mixer_desc, |
|
50 |
+ &ms_tone_detector_desc, &ms_speex_dec_desc, &ms_speex_enc_desc, |
|
51 |
+ &ms_speex_ec_desc, &ms_file_player_desc, &ms_file_rec_desc, |
|
52 |
+ &ms_resample_desc, |
|
53 |
+ // &ms_opus_dec_desc, |
|
54 |
+ // &ms_opus_enc_desc, |
|
55 |
+ NULL}; |
|
56 |
+ |
|
57 |
+static MSFactory *rms_create_factory() |
|
58 |
+{ |
|
59 |
+ MSFactory *f = ms_factory_new(); |
|
60 |
+ int i; |
|
61 |
+ for(i = 0; rms_ms_filter_descs[i] != NULL; i++) { |
|
62 |
+ ms_factory_register_filter(f, rms_ms_filter_descs[i]); |
|
63 |
+ } |
|
64 |
+ ms_factory_init_plugins(f); |
|
65 |
+ ms_factory_enable_statistics(f, TRUE); |
|
66 |
+ ms_factory_reset_statistics(f); |
|
67 |
+ return f; |
|
68 |
+} |
|
69 |
+ |
|
70 |
+int rms_media_init() |
|
71 |
+{ |
|
72 |
+ OrtpMemoryFunctions ortp_memory_functions; |
|
73 |
+ ortp_memory_functions.malloc_fun = ptr_shm_malloc; |
|
74 |
+ ortp_memory_functions.realloc_fun = ptr_shm_realloc; |
|
75 |
+ ortp_memory_functions.free_fun = ptr_shm_free; |
|
76 |
+ ortp_set_memory_functions(&ortp_memory_functions); |
|
77 |
+ ortp_init(); |
|
78 |
+ vars = shm_malloc(sizeof(shared_global_vars_t)); |
|
79 |
+ return 1; |
|
80 |
+} |
|
81 |
+ |
|
82 |
+static MSTicker *rms_create_ticker(char *name) |
|
83 |
+{ |
|
84 |
+ MSTickerParams params; |
|
85 |
+ params.name = name; |
|
86 |
+ params.prio = MS_TICKER_PRIO_NORMAL; |
|
87 |
+ return ms_ticker_new_with_params(¶ms); |
|
88 |
+} |
|
89 |
+ |
|
90 |
+void rms_media_destroy(call_leg_media_t *m) |
|
91 |
+{ |
|
92 |
+ LM_INFO("rtp_session_destroy[%p]\n", m->rtps); |
|
93 |
+ rtp_session_destroy(m->rtps); |
|
94 |
+ m->rtps = NULL; |
|
95 |
+ LM_INFO("ms_ticker[%p]\n", m->ms_ticker); |
|
96 |
+ ms_ticker_destroy(m->ms_ticker); |
|
97 |
+ m->ms_ticker = NULL; |
|
98 |
+ LM_INFO("ms_factory_destroy[%p]\n", m->ms_factory); |
|
99 |
+ ms_factory_destroy(m->ms_factory); |
|
100 |
+ m->ms_factory = NULL; |
|
101 |
+} |
|
102 |
+ |
|
103 |
+int create_call_leg_media(call_leg_media_t *m) |
|
104 |
+{ |
|
105 |
+ m->ms_factory = rms_create_factory(); |
|
106 |
+ // create caller RTP session |
|
107 |
+ LM_INFO("RTP session [%s:%d]<>[%s:%d]\n", m->local_ip.s, m->local_port, |
|
108 |
+ m->remote_ip.s, m->remote_port); |
|
109 |
+ m->rtps = ms_create_duplex_rtp_session(m->local_ip.s, m->local_port, |
|
110 |
+ m->local_port + 1, ms_factory_get_mtu(m->ms_factory)); |
|
111 |
+ rtp_session_set_remote_addr_full(m->rtps, m->remote_ip.s, m->remote_port, |
|
112 |
+ m->remote_ip.s, m->remote_port + 1); |
|
113 |
+ rtp_session_set_payload_type(m->rtps, m->pt->type); |
|
114 |
+ rtp_session_enable_rtcp(m->rtps, FALSE); |
|
115 |
+ // create caller filters : rtprecv1/rtpsend1/encoder1/decoder1 |
|
116 |
+ m->ms_rtprecv = ms_factory_create_filter(m->ms_factory, MS_RTP_RECV_ID); |
|
117 |
+ m->ms_rtpsend = ms_factory_create_filter(m->ms_factory, MS_RTP_SEND_ID); |
|
118 |
+ |
|
119 |
+ LM_INFO("codec[%s]\n", m->pt->mime_type); |
|
120 |
+ m->ms_encoder = ms_factory_create_encoder(m->ms_factory, m->pt->mime_type); |
|
121 |
+ if(!m->ms_encoder) { |
|
122 |
+ LM_ERR("creating encoder failed.\n"); |
|
123 |
+ return 0; |
|
124 |
+ } |
|
125 |
+ m->ms_decoder = ms_factory_create_decoder(m->ms_factory, m->pt->mime_type); |
|
126 |
+ |
|
127 |
+ /* set filter params */ |
|
128 |
+ ms_filter_call_method(m->ms_rtpsend, MS_RTP_SEND_SET_SESSION, m->rtps); |
|
129 |
+ ms_filter_call_method(m->ms_rtprecv, MS_RTP_RECV_SET_SESSION, m->rtps); |
|
130 |
+ return 1; |
|
131 |
+} |
|
132 |
+ |
|
133 |
+int rms_bridge(call_leg_media_t *m1, call_leg_media_t *m2) |
|
134 |
+{ |
|
135 |
+ MSConnectionHelper h; |
|
136 |
+ m1->ms_ticker = rms_create_ticker(NULL); |
|
137 |
+ |
|
138 |
+ // direction 1 |
|
139 |
+ ms_connection_helper_start(&h); |
|
140 |
+ ms_connection_helper_link(&h, m1->ms_rtprecv, -1, 0); |
|
141 |
+ ms_connection_helper_link(&h, m2->ms_rtpsend, 0, -1); |
|
142 |
+ |
|
143 |
+ // direction 2 |
|
144 |
+ ms_connection_helper_start(&h); |
|
145 |
+ ms_connection_helper_link(&h, m2->ms_rtprecv, -1, 0); |
|
146 |
+ ms_connection_helper_link(&h, m1->ms_rtpsend, 0, -1); |
|
147 |
+ |
|
148 |
+ ms_ticker_attach_multiple( |
|
149 |
+ m1->ms_ticker, m1->ms_rtprecv, m2->ms_rtprecv, NULL); |
|
150 |
+ |
|
151 |
+ return 1; |
|
152 |
+} |
|
153 |
+ |
|
154 |
+static void rms_player_eof( |
|
155 |
+ void *user_data, MSFilter *f, unsigned int event, void *event_data) |
|
156 |
+{ |
|
157 |
+ if(event == MS_FILE_PLAYER_EOF) { |
|
158 |
+ rms_session_info_t *si = (rms_session_info_t *)user_data; |
|
159 |
+ si->action = RMS_DONE; |
|
160 |
+ } |
|
161 |
+ MS_UNUSED(f), MS_UNUSED(event_data); |
|
162 |
+} |
|
163 |
+ |
|
164 |
+int rms_stop_bridge(call_leg_media_t *m1, call_leg_media_t *m2) |
|
165 |
+{ |
|
166 |
+ MSConnectionHelper h; |
|
167 |
+ if(!m1->ms_ticker) |
|
168 |
+ return -1; |
|
169 |
+ if(m1->ms_rtpsend) |
|
170 |
+ ms_ticker_detach(m1->ms_ticker, m1->ms_rtpsend); |
|
171 |
+ if(m1->ms_rtprecv) |
|
172 |
+ ms_ticker_detach(m1->ms_ticker, m1->ms_rtprecv); |
|
173 |
+ if(m2->ms_rtpsend) |
|
174 |
+ ms_ticker_detach(m1->ms_ticker, m2->ms_rtpsend); |
|
175 |
+ if(m2->ms_rtprecv) |
|
176 |
+ ms_ticker_detach(m1->ms_ticker, m2->ms_rtprecv); |
|
177 |
+ rtp_stats_display(rtp_session_get_stats(m1->rtps), |
|
178 |
+ " AUDIO BRIDGE offer RTP STATISTICS "); |
|
179 |
+ rtp_stats_display(rtp_session_get_stats(m2->rtps), |
|
180 |
+ " AUDIO BRIDGE answer RTP STATISTICS "); |
|
181 |
+ ms_factory_log_statistics(m1->ms_factory); |
|
182 |
+ |
|
183 |
+ ms_connection_helper_start(&h); |
|
184 |
+ if(m1->ms_rtprecv) |
|
185 |
+ ms_connection_helper_unlink(&h, m1->ms_rtprecv, -1, 0); |
|
186 |
+ if(m2->ms_rtpsend) |
|
187 |
+ ms_connection_helper_unlink(&h, m2->ms_rtpsend, 0, -1); |
|
188 |
+ |
|
189 |
+ ms_connection_helper_start(&h); |
|
190 |
+ if(m2->ms_rtprecv) |
|
191 |
+ ms_connection_helper_unlink(&h, m2->ms_rtprecv, -1, 0); |
|
192 |
+ if(m1->ms_rtpsend) |
|
193 |
+ ms_connection_helper_unlink(&h, m1->ms_rtpsend, 0, -1); |
|
194 |
+ |
|
195 |
+ if(m1->ms_rtpsend) |
|
196 |
+ ms_filter_destroy(m1->ms_rtpsend); |
|
197 |
+ if(m1->ms_rtprecv) |
|
198 |
+ ms_filter_destroy(m1->ms_rtprecv); |
|
199 |
+ if(m2->ms_rtpsend) |
|
200 |
+ ms_filter_destroy(m2->ms_rtpsend); |
|
201 |
+ if(m2->ms_rtprecv) |
|
202 |
+ ms_filter_destroy(m2->ms_rtprecv); |
|
203 |
+ return 1; |
|
204 |
+} |
|
205 |
+ |
|
206 |
+int rms_playfile(call_leg_media_t *m, char *file_name) |
|
207 |
+{ |
|
208 |
+ int file_sample_rate = 8000; |
|
209 |
+ if(!m->ms_player) |
|
210 |
+ return 0; |
|
211 |
+ ms_filter_add_notify_callback(m->ms_player, rms_player_eof, m->si, TRUE); |
|
212 |
+ ms_filter_call_method(m->ms_player, MS_FILE_PLAYER_OPEN, (void *)file_name); |
|
213 |
+ ms_filter_call_method(m->ms_player, MS_FILE_PLAYER_START, NULL); |
|
214 |
+ ms_filter_call_method(m->ms_player, MS_FILTER_GET_SAMPLE_RATE, &file_sample_rate); |
|
215 |
+ ms_filter_call_method(m->ms_resampler, MS_FILTER_SET_SAMPLE_RATE, &file_sample_rate); |
|
216 |
+ ms_filter_call_method(m->ms_resampler, MS_FILTER_SET_OUTPUT_SAMPLE_RATE, &m->pt->clock_rate); |
|
217 |
+ ms_filter_call_method(m->ms_resampler, MS_FILTER_SET_OUTPUT_NCHANNELS, &m->pt->channels); |
|
218 |
+ LM_INFO("clock[%d][%d]\n", m->pt->clock_rate, file_sample_rate); |
|
219 |
+ return 1; |
|
220 |
+} |
|
221 |
+ |
|
222 |
+int rms_start_media(call_leg_media_t *m, char *file_name) |
|
223 |
+{ |
|
224 |
+ MSConnectionHelper h; |
|
225 |
+ int channels = 1; |
|
226 |
+ int file_sample_rate = 8000; |
|
227 |
+ m->ms_ticker = rms_create_ticker(NULL); |
|
228 |
+ if(!m->ms_ticker) goto error; |
|
229 |
+ m->ms_player = ms_factory_create_filter(m->ms_factory, MS_FILE_PLAYER_ID); |
|
230 |
+ if(!m->ms_player) goto error; |
|
231 |
+ m->ms_resampler = ms_factory_create_filter(m->ms_factory, MS_RESAMPLE_ID); |
|
232 |
+ if(!m->ms_resampler) goto error; |
|
233 |
+ // m->ms_recorder = ms_factory_create_filter(m->ms_factory, |
|
234 |
+ // MS_FILE_PLAYER_ID); |
|
235 |
+ m->ms_voidsink = ms_factory_create_filter(m->ms_factory, MS_VOID_SINK_ID); |
|
236 |
+ if(!m->ms_voidsink) goto error; |
|
237 |
+ LM_INFO("m[%p]call-id[%p]\n", m, m->si->callid.s); |
|
238 |
+ |
|
239 |
+ ms_filter_call_method( |
|
240 |
+ m->ms_player, MS_FILTER_SET_OUTPUT_NCHANNELS, &channels); |
|
241 |
+ ms_filter_call_method_noarg(m->ms_player, MS_FILE_PLAYER_START); |
|
242 |
+ ms_filter_call_method(m->ms_player, MS_FILTER_GET_SAMPLE_RATE, &file_sample_rate); |
|
243 |
+ ms_filter_call_method(m->ms_resampler, MS_FILTER_SET_SAMPLE_RATE, &file_sample_rate); |
|
244 |
+ ms_filter_call_method(m->ms_resampler, MS_FILTER_SET_OUTPUT_SAMPLE_RATE, &m->pt->clock_rate); |
|
245 |
+ |
|
246 |
+ // sending graph |
|
247 |
+ ms_connection_helper_start(&h); |
|
248 |
+ ms_connection_helper_link(&h, m->ms_player, -1, 0); |
|
249 |
+ |
|
250 |
+ ms_connection_helper_link(&h, m->ms_resampler, 0, 0); |
|
251 |
+ ms_connection_helper_link(&h, m->ms_encoder, 0, 0); |
|
252 |
+ ms_connection_helper_link(&h, m->ms_rtpsend, 0, -1); |
|
253 |
+ |
|
254 |
+ // receiving graph |
|
255 |
+ ms_connection_helper_start(&h); |
|
256 |
+ ms_connection_helper_link(&h, m->ms_rtprecv, -1, 0); |
|
257 |
+ // ms_connection_helper_link(&h, m->ms_decoder, 0, 0); |
|
258 |
+ ms_connection_helper_link(&h, m->ms_voidsink, 0, -1); |
|
259 |
+ |
|
260 |
+ ms_ticker_attach_multiple(m->ms_ticker, m->ms_player, m->ms_rtprecv, NULL); |
|
261 |
+ return 1; |
|
262 |
+error: |
|
263 |
+ LM_ERR(" can not start media!\n"); |
|
264 |
+ return 0; |
|
265 |
+} |
|
266 |
+ |
|
267 |
+int rms_stop_media(call_leg_media_t *m) |
|
268 |
+{ |
|
269 |
+ MSConnectionHelper h; |
|
270 |
+ if(!m->ms_ticker) { |
|
271 |
+ LM_ERR("RMS STOP MEDIA\n"); |
|
272 |
+ return -1; |
|
273 |
+ } |
|
274 |
+ if(m->ms_player) |
|
275 |
+ ms_ticker_detach(m->ms_ticker, m->ms_player); |
|
276 |
+ if(m->ms_rtprecv) |
|
277 |
+ ms_ticker_detach(m->ms_ticker, m->ms_rtprecv); |
|
278 |
+ |
|
279 |
+ rtp_stats_display( |
|
280 |
+ rtp_session_get_stats(m->rtps), " AUDIO SESSION'S RTP STATISTICS "); |
|
281 |
+ ms_factory_log_statistics(m->ms_factory); |
|
282 |
+ |
|
283 |
+ /*dismantle the sending graph*/ |
|
284 |
+ ms_connection_helper_start(&h); |
|
285 |
+ if(m->ms_player) |
|
286 |
+ ms_connection_helper_unlink(&h, m->ms_player, -1, 0); |
|
287 |
+ if(m->ms_resampler) |
|
288 |
+ ms_connection_helper_unlink(&h, m->ms_resampler, 0, 0); |
|
289 |
+ if(m->ms_encoder) |
|
290 |
+ ms_connection_helper_unlink(&h, m->ms_encoder, 0, 0); |
|
291 |
+ if(m->ms_rtpsend) |
|
292 |
+ ms_connection_helper_unlink(&h, m->ms_rtpsend, 0, -1); |
|
293 |
+ /*dismantle the receiving graph*/ |
|
294 |
+ ms_connection_helper_start(&h); |
|
295 |
+ if(m->ms_rtprecv) |
|
296 |
+ ms_connection_helper_unlink(&h, m->ms_rtprecv, -1, 0); |
|
297 |
+ if(m->ms_voidsink) |
|
298 |
+ ms_connection_helper_unlink(&h, m->ms_voidsink, 0, -1); |
|
299 |
+ |
|
300 |
+ if(m->ms_player) |
|
301 |
+ ms_filter_destroy(m->ms_player); |
|
302 |
+ if(m->ms_resampler) |
|
303 |
+ ms_filter_destroy(m->ms_resampler); |
|
304 |
+ if(m->ms_encoder) |
|
305 |
+ ms_filter_destroy(m->ms_encoder); |
|
306 |
+ if(m->ms_rtpsend) { |
|
307 |
+ LM_ERR("detroy rtpsend\n"); |
|
308 |
+ ms_filter_destroy(m->ms_rtpsend); |
|
309 |
+ } else { |
|
310 |
+ LM_ERR("no rtpsend\n"); |
|
311 |
+ } |
|
312 |
+ if(m->ms_rtprecv) |
|
313 |
+ ms_filter_destroy(m->ms_rtprecv); |
|
314 |
+ if(m->ms_voidsink) |
|
315 |
+ ms_filter_destroy(m->ms_voidsink); |
|
316 |
+ |
|
317 |
+ rms_media_destroy(m); |
|
318 |
+ return 1; |
|
319 |
+} |
0 | 320 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,101 @@ |
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_media_h |
|
22 |
+#define rms_media_h |
|
23 |
+ |
|
24 |
+#include "../../core/mem/shm.h" |
|
25 |
+#include <mediastreamer2/mediastream.h> |
|
26 |
+#include <mediastreamer2/msrtp.h> |
|
27 |
+#include <mediastreamer2/dtmfgen.h> |
|
28 |
+#include <mediastreamer2/msfileplayer.h> |
|
29 |
+#include <mediastreamer2/msfilerec.h> |
|
30 |
+#include <mediastreamer2/msrtp.h> |
|
31 |
+#include <mediastreamer2/mstonedetector.h> |
|
32 |
+#include <mediastreamer2/msfilter.h> |
|
33 |
+#include <mediastreamer2/mscommon.h> |
|
34 |
+#include <ortp/ortp.h> |
|
35 |
+#include <ortp/port.h> |
|
36 |
+ |
|
37 |
+struct rms_session_info; |
|
38 |
+ |
|
39 |
+typedef struct call_leg_media |
|
40 |
+{ |
|
41 |
+ MSFactory *ms_factory; |
|
42 |
+ RtpSession *rtps; |
|
43 |
+ PayloadType *pt; |
|
44 |
+ MSTicker *ms_ticker; |
|
45 |
+ MSFilter *ms_encoder; |
|
46 |
+ MSFilter *ms_decoder; |
|
47 |
+ MSFilter *ms_rtprecv; |
|
48 |
+ MSFilter *ms_rtpsend; |
|
49 |
+ MSFilter *ms_resampler; |
|
50 |
+ MSFilter *ms_player; |
|
51 |
+ MSFilter *ms_recorder; |
|
52 |
+ MSFilter *ms_dtmfgen; |
|
53 |
+ MSFilter *ms_tonedet; |
|
54 |
+ MSFilter *ms_voidsource; |
|
55 |
+ MSFilter *ms_voidsink; |
|
56 |
+ str local_ip; |
|
57 |
+ int local_port; |
|
58 |
+ str remote_ip; |
|
59 |
+ int remote_port; |
|
60 |
+ struct rms_session_info *si; |
|
61 |
+} call_leg_media_t; |
|
62 |
+ |
|
63 |
+int create_call_leg_media(call_leg_media_t *m); |
|
64 |
+ |
|
65 |
+int rms_media_init(); |
|
66 |
+void rms_media_destroy(); |
|
67 |
+ |
|
68 |
+MSFactory *rms_get_factory(); |
|
69 |
+ |
|
70 |
+int rms_stop_media(call_leg_media_t *m); |
|
71 |
+int rms_playfile(call_leg_media_t *m, char *file_name); |
|
72 |
+int rms_start_media(call_leg_media_t *m, char *file_name); |
|
73 |
+int rms_bridge(call_leg_media_t *m1, call_leg_media_t *m2); |
|
74 |
+int rms_stop_bridge(call_leg_media_t *m1, call_leg_media_t *m2); |
|
75 |
+ |
|
76 |
+extern MSFilterDesc ms_pcap_file_player_desc; |
|
77 |
+extern MSFilterDesc ms_rtp_send_desc; |
|
78 |
+extern MSFilterDesc ms_rtp_recv_desc; |
|
79 |
+extern MSFilterDesc ms_udp_send_desc; |
|
80 |
+extern MSFilterDesc ms_alaw_dec_desc; |
|
81 |
+extern MSFilterDesc ms_alaw_enc_desc; |
|
82 |
+extern MSFilterDesc ms_ulaw_dec_desc; |
|
83 |
+extern MSFilterDesc ms_ulaw_enc_desc; |
|
84 |
+extern MSFilterDesc ms_dtmf_gen_desc; |
|
85 |
+extern MSFilterDesc ms_volume_desc; |
|
86 |
+extern MSFilterDesc ms_equalizer_desc; |
|
87 |
+extern MSFilterDesc ms_channel_adapter_desc; |
|
88 |
+extern MSFilterDesc ms_audio_mixer_desc; |
|
89 |
+extern MSFilterDesc ms_tone_detector_desc; |
|
90 |
+extern MSFilterDesc ms_genericplc_desc; |
|
91 |
+extern MSFilterDesc ms_file_player_desc; |
|
92 |
+extern MSFilterDesc ms_file_rec_desc; |
|
93 |
+extern MSFilterDesc ms_vad_dtx_desc; |
|
94 |
+extern MSFilterDesc ms_speex_dec_desc; |
|
95 |
+extern MSFilterDesc ms_speex_enc_desc; |
|
96 |
+extern MSFilterDesc ms_speex_ec_desc; |
|
97 |
+extern MSFilterDesc ms_opus_enc_desc; |
|
98 |
+extern MSFilterDesc ms_opus_dec_desc; |
|
99 |
+extern MSFilterDesc ms_resample_desc; |
|
100 |
+ |
|
101 |
+#endif |
0 | 102 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,291 @@ |
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 "rms_sdp.h" |
|
22 |
+#include "rms_util.h" |
|
23 |
+#include "../../core/data_lump.h" |
|
24 |
+#include "../../core/parser/parse_content.h" |
|
25 |
+ |
|
26 |
+// https://tools.ietf.org/html/rfc4566 |
|
27 |
+// (protocol version) |
|
28 |
+const char *sdp_v = "v=0\r\n"; |
|
29 |
+// (session name) |
|
30 |
+const char *sdp_s = "s=-\r\n"; |
|
31 |
+// (time the session is active) |
|
32 |
+const char *sdp_t = "t=0 0\r\n"; |
|
33 |
+//"a=rtpmap:101 telephone-event/8000\r\n" |
|
34 |
+//"a=fmtp:101 0-15\r\n"; |
|
35 |
+//"a=rtpmap:0 PCMU/8000\r\n" |
|
36 |
+//"a=rtpmap:8 PCMA/8000\r\n" |
|
37 |
+//"a=rtpmap:96 opus/48000/2\r\n" |
|
38 |
+//"a=fmtp:96 useinbandfec=1\r\n"; |
|
39 |
+ |
|
40 |
+static char *rms_sdp_get_rtpmap(str body, int type_number) |
|
41 |
+{ |
|
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); |
|
51 |
+ } |
|
52 |
+ pos++; |
|
53 |
+ } |
|
54 |
+ return NULL; |
|
55 |
+} |
|
56 |
+ |
|
57 |
+void rms_sdp_info_init(rms_sdp_info_t *sdp_info) |
|
58 |
+{ |
|
59 |
+ memset(sdp_info, 0, sizeof(rms_sdp_info_t)); |
|
60 |
+} |
|
61 |
+ |
|
62 |
+void rms_sdp_info_free(rms_sdp_info_t *sdp_info) |
|
63 |
+{ |
|
64 |
+ if(sdp_info->remote_ip.s) { |
|
65 |
+ shm_free(sdp_info->remote_ip.s); |
|
66 |
+ sdp_info->remote_ip.s = NULL; |
|
67 |
+ } |
|
68 |
+ if(sdp_info->payloads.s) { |
|
69 |
+ shm_free(sdp_info->payloads.s); |
|
70 |
+ sdp_info->payloads.s = NULL; |
|
71 |
+ } |
|
72 |
+ if(sdp_info->new_body.s) { |
|
73 |
+ shm_free(sdp_info->new_body.s); |
|
74 |
+ sdp_info->new_body.s = NULL; |
|
75 |
+ } |
|
76 |
+} |
|
77 |
+ |
|
78 |
+int rms_sdp_prepare_new_body(rms_sdp_info_t *sdp_info, int payload_type_number) |
|
79 |
+{ |
|
80 |
+ if(sdp_info->new_body.s) |
|
81 |
+ return 0; |
|
82 |
+ |
|
83 |
+ str *body = &sdp_info->new_body; |
|
84 |
+ body->len = strlen(sdp_v) + strlen(sdp_s) + strlen(sdp_t); |
|
85 |
+ |
|
86 |
+ // (originator and session identifier) |
|
87 |
+ char sdp_o[128]; |
|
88 |
+ snprintf( |
|
89 |
+ sdp_o, 128, "o=- 1028316687 1 IN IP4 %s\r\n", sdp_info->local_ip.s); |
|
90 |
+ body->len += strlen(sdp_o); |
|
91 |
+ |
|
92 |
+ // (connection information -- not required if included in all media) |
|
93 |
+ char sdp_c[128]; |
|
94 |
+ snprintf(sdp_c, 128, "c=IN IP4 %s\r\n", sdp_info->local_ip.s); |
|
95 |
+ body->len += strlen(sdp_c); |
|
96 |
+ |
|
97 |
+ char sdp_m[128]; |
|
98 |
+ snprintf(sdp_m, 128, "m=audio %d RTP/AVP %d\r\n", sdp_info->udp_local_port, |
|
99 |
+ payload_type_number); |
|
100 |
+ body->len += strlen(sdp_m); |
|
101 |
+ |
|
102 |
+ body->s = pkg_malloc(body->len + 1); |
|
103 |
+ if (!body->s) return 0; |
|
104 |
+ strcpy(body->s, sdp_v); |
|
105 |
+ strcat(body->s, sdp_o); |
|
106 |
+ strcat(body->s, sdp_s); |
|
107 |
+ strcat(body->s, sdp_c); |
|
108 |
+ strcat(body->s, sdp_t); |
|
109 |
+ strcat(body->s, sdp_m); |
|
110 |
+ return 1; |
|
111 |
+} |
|
112 |
+ |
|
113 |
+PayloadType *rms_sdp_check_payload(rms_sdp_info_t *sdp) |
|
114 |
+{ |
|
115 |
+ // https://tools.ietf.org/html/rfc3551 |
|
116 |
+ LM_INFO("payloads[%s]\n", sdp->payloads.s); // 0 8 |
|
117 |
+ PayloadType *pt = payload_type_new(); |
|
118 |
+ char *payloads = sdp->payloads.s; |
|
119 |
+ char *payload_type_number = strtok(payloads, " "); |
|
120 |
+ if(!payload_type_number) { |
|
121 |
+ payload_type_destroy(pt); |
|
122 |
+ return NULL; |
|
123 |
+ } |
|
124 |
+ pt->type = atoi(payload_type_number); |
|
125 |
+ pt->clock_rate = 8000; |
|
126 |
+ pt->channels = 1; |
|
127 |
+ pt->mime_type = NULL; |
|
128 |
+ while(!pt->mime_type) { |
|
129 |
+ if(pt->type > 127) { |
|
130 |
+ return NULL; |
|
131 |
+ // } else if (pt->type >= 96) { |
|
132 |
+ // continue; |
|
133 |
+ // char *rtpmap = |
|
134 |
+ // rms_sdp_get_rtpmap(sdp->recv_body, pt->type); |
|
135 |
+ // pt->mime_type = rms_char_dup(strtok(rtpmap, |
|
136 |
+ //"/"),1); |
|
137 |
+ // if (strcasecmp(pt->mime_type,"opus") == 0) { |
|
138 |
+ // pt->clock_rate = atoi(strtok(NULL, |
|
139 |
+ //"/")); |
|
140 |
+ // pt->channels = atoi(strtok(NULL, "/")); |
|
141 |
+ // shm_free(rtpmap); |
|
142 |
+ // return pt; |
|
143 |
+ // } |
|
144 |
+ // shm_free(pt->mime_type); |
|
145 |
+ // pt->mime_type=NULL; |
|
146 |
+ // shm_free(rtpmap); |
|
147 |
+ } else if(pt->type == 0) { |
|
148 |
+ pt->mime_type = rms_char_dup("pcmu", 1); /* ia=rtpmap:0 PCMU/8000*/ |
|
149 |
+ } else if(pt->type == 8) { |
|
150 |
+ pt->mime_type = rms_char_dup("pcma", 1); |
|
151 |
+ // } else if (pt->type == 9) { |
|
152 |
+ // pt->mime_type=rms_char_dup("g722", 1); |
|
153 |
+ // } else if (pt->type == 18) { |
|
154 |
+ // pt->mime_type=rms_char_dup("g729", 1); |
|
155 |
+ } |
|
156 |
+ if(pt->mime_type) |
|
157 |
+ break; |
|
158 |
+ payload_type_number = strtok(NULL, " "); |
|
159 |
+ if(!payload_type_number) { |
|
160 |
+ payload_type_destroy(pt); |
|
161 |
+ return NULL; |
|
162 |
+ } |
|
163 |
+ pt->type = atoi(payload_type_number); |
|
164 |
+ } |
|
165 |
+ LM_INFO("payload_type:%d %s/%d/%d\n", pt->type, pt->mime_type, |
|
166 |
+ pt->clock_rate, pt->channels); |
|
167 |
+ return pt; |
|
168 |
+} |
|
169 |
+ |
|
170 |
+ |
|
171 |
+ |
|
172 |
+int rms_sdp_set_body(struct sip_msg *msg, str *new_body) |
|
173 |
+{ |
|
174 |
+ struct lump *anchor; |
|
175 |
+ char *buf; |
|
176 |
+ int len; |
|
177 |
+ char *value_s; |
|
178 |
+ int value_len; |
|
179 |
+ str body = {0, 0}; |
|
180 |
+ str content_type_sdp = str_init("application/sdp"); |
|
181 |
+ |
|
182 |
+ if(!new_body->s || new_body->len == 0) { |
|
183 |
+ LM_ERR("invalid body parameter\n"); |
|
184 |
+ return -1; |
|
185 |
+ } |
|
186 |
+ |
|
187 |
+ body.len = 0; |
|
188 |
+ body.s = get_body(msg); |
|
189 |
+ if(body.s == 0) { |
|
190 |
+ LM_ERR("malformed sip message\n"); |
|
191 |
+ return -1; |
|
192 |
+ } |
|
193 |
+ |
|
194 |
+ del_nonshm_lump(&(msg->body_lumps)); |
|
195 |
+ msg->body_lumps = NULL; |
|
196 |
+ |
|
197 |
+ if(msg->content_length) { |
|
198 |
+ body.len = get_content_length(msg); |
|
199 |
+ if(body.len > 0) { |
|
200 |
+ if(body.s + body.len > msg->buf + msg->len) { |
|
201 |
+ LM_ERR("invalid content length: %d\n", body.len); |
|
202 |
+ return -1; |
|
203 |
+ } |
|
204 |
+ if(del_lump(msg, body.s - msg->buf, body.len, 0) == 0) { |
|
205 |
+ LM_ERR("cannot delete existing body"); |
|
206 |
+ return -1; |
|
207 |
+ } |
|
208 |
+ } |
|
209 |
+ } |
|
210 |
+ |
|
211 |
+ anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0); |
|
212 |
+ if(!anchor) { |
|
213 |
+ LM_ERR("failed to get anchor\n"); |
|
214 |
+ return -1; |
|
215 |
+ } |
|
216 |
+ |
|
217 |
+ if(msg->content_length == 0) { |
|
218 |
+ /* need to add Content-Length */ |
|
219 |
+ len = new_body->len; |
|
220 |
+ value_s = int2str(len, &value_len); |
|
221 |
+ LM_DBG("content-length: %d (%s)\n", value_len, value_s); |
|
222 |
+ |
|
223 |
+ len = CONTENT_LENGTH_LEN + value_len + CRLF_LEN; |
|
224 |
+ buf = pkg_malloc(sizeof(char) * (len)); |
|
225 |
+ if(!buf) { |
|
226 |
+ LM_ERR("out of pkg memory\n"); |
|
227 |
+ return -1; |
|
228 |
+ } |
|
229 |
+ |
|
230 |
+ memcpy(buf, CONTENT_LENGTH, CONTENT_LENGTH_LEN); |
|
231 |
+ memcpy(buf + CONTENT_LENGTH_LEN, value_s, value_len); |
|
232 |
+ memcpy(buf + CONTENT_LENGTH_LEN + value_len, CRLF, CRLF_LEN); |
|
233 |
+ if(insert_new_lump_after(anchor, buf, len, 0) == 0) { |
|
234 |
+ LM_ERR("failed to insert content-length lump\n"); |
|
235 |
+ pkg_free(buf); |
|
236 |
+ return -1; |
|
237 |
+ } |
|
238 |
+ } |
|
239 |
+ |
|
240 |
+ /* add content-type */ |
|
241 |
+ if(msg->content_type == NULL |
|
242 |
+ || msg->content_type->body.len != content_type_sdp.len |
|
243 |
+ || strncmp(msg->content_type->body.s, content_type_sdp.s, |
|
244 |
+ content_type_sdp.len) |
|
245 |
+ != 0) { |
|
246 |
+ if(msg->content_type != NULL) { |
|
247 |
+ if(del_lump(msg, msg->content_type->name.s - msg->buf, |
|
248 |
+ msg->content_type->len, 0) |
|
249 |
+ == 0) { |
|
250 |
+ LM_ERR("failed to delete content type\n"); |
|
251 |
+ return -1; |
|
252 |
+ } |
|
253 |
+ } |
|
254 |
+ value_len = content_type_sdp.len; |
|
255 |
+ len = sizeof("Content-Type: ") - 1 + value_len + CRLF_LEN; |
|
256 |
+ buf = pkg_malloc(sizeof(char) * (len)); |
|
257 |
+ if(!buf) { |
|
258 |
+ LM_ERR("out of pkg memory\n"); |
|
259 |
+ return -1; |
|
260 |
+ } |
|
261 |
+ memcpy(buf, "Content-Type: ", sizeof("Content-Type: ") - 1); |
|
262 |
+ memcpy(buf + sizeof("Content-Type: ") - 1, content_type_sdp.s, |
|
263 |
+ value_len); |
|
264 |
+ memcpy(buf + sizeof("Content-Type: ") - 1 + value_len, CRLF, CRLF_LEN); |
|
265 |
+ if(insert_new_lump_after(anchor, buf, len, 0) == 0) { |
|
266 |
+ LM_ERR("failed to insert content-type lump\n"); |
|
267 |
+ pkg_free(buf); |
|
268 |
+ return -1; |
|
269 |
+ } |
|
270 |
+ } |
|
271 |
+ anchor = anchor_lump(msg, body.s - msg->buf, 0, 0); |
|
272 |
+ |
|
273 |
+ if(anchor == 0) { |
|
274 |
+ LM_ERR("failed to get body anchor\n"); |
|
275 |
+ return -1; |
|
276 |
+ } |
|
277 |
+ |
|
278 |
+ buf = pkg_malloc(sizeof(char) * (new_body->len)); |
|
279 |
+ if(!buf) { |
|
280 |
+ LM_ERR("out of pkg memory\n"); |
|
281 |
+ return -1; |
|
282 |
+ } |
|
283 |
+ memcpy(buf, new_body->s, new_body->len); |
|
284 |
+ if(!insert_new_lump_after(anchor, buf, new_body->len, 0)) { |
|
285 |
+ LM_ERR("failed to insert body lump\n"); |
|
286 |
+ pkg_free(buf); |
|
287 |
+ return -1; |
|
288 |
+ } |
|
289 |
+ LM_DBG("new body: [%.*s]", new_body->len, new_body->s); |
|
290 |
+ return 1; |
|
291 |
+} |
0 | 292 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,45 @@ |
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_sdp_h |
|
22 |
+#define rms_sdp_h |
|
23 |
+ |
|
24 |
+#include "../../core/sr_module.h" |
|
25 |
+#include <mediastreamer2/mediastream.h> |
|
26 |
+ |
|
27 |
+typedef struct rms_sdp_info |
|
28 |
+{ |
|
29 |
+ str remote_ip; |
|
30 |
+ str local_ip; |
|
31 |
+ str payloads; |
|
32 |
+ int remote_port; |
|
33 |
+ int ipv6; |
|
34 |
+ str new_body; |
|
35 |
+ str recv_body; |
|
36 |
+ int udp_local_port; |
|
37 |
+} rms_sdp_info_t; |
|
38 |
+ |
|
39 |
+int rms_sdp_set_body(struct sip_msg *msg, str *new_body); |
|
40 |
+int rms_sdp_prepare_new_body(rms_sdp_info_t *, int payload_type_number); |
|
41 |
+void rms_sdp_info_init(rms_sdp_info_t *sdp_info); |
|
42 |
+void rms_sdp_info_free(rms_sdp_info_t *sdp_info); |
|
43 |
+PayloadType *rms_sdp_check_payload(rms_sdp_info_t *); |
|
44 |
+ |
|
45 |
+#endif |
0 | 46 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,73 @@ |
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_util_h |
|
22 |
+#define rms_util_h |
|
23 |
+ |
|
24 |
+/** |
|
25 |
+ * \brief Make a copy of a str structure using shm_malloc/pkg_malloc |
|
26 |
+ * garanty to return a null terminated string, even if the source is not |
|
27 |
+ * \param dst destination |
|
28 |
+ * \param src source |
|
29 |
+ * \param shared use shared memory |
|
30 |
+ * \return 0 on success, -1 on failure |
|
31 |
+ */ |
|
32 |
+static inline int rms_str_dup(str *dst, str *src, int shared) |
|
33 |
+{ |
|
34 |
+ if(!dst) { |
|
35 |
+ LM_ERR("dst null\n"); |
|
36 |
+ return -1; |
|
37 |
+ } |
|
38 |
+ dst->len = 0; |
|
39 |
+ dst->s = NULL; |
|
40 |
+ if(!src || !src->s || src->len < 0) { |
|
41 |
+ LM_ERR("src null or invalid\n"); |
|
42 |
+ return 0; |
|
43 |
+ } |
|
44 |
+ if(src->len == 0) |
|
45 |
+ return 1; |
|
46 |
+ dst->len = src->len; |
|
47 |
+ if(shared) { |
|
48 |
+ dst->s = shm_malloc(dst->len+1); |
|
49 |
+ } else { |
|
50 |
+ dst->s = pkg_malloc(dst->len+1); |
|
51 |
+ } |
|
52 |
+ if(!dst->s) { |
|
53 |
+ LM_ERR("%s_malloc: can't allocate memory (%d bytes)\n", |
|
54 |
+ shared ? "shm" : "pkg", src->len); |
|
55 |
+ return -1; |
|
56 |
+ } |
|
57 |
+ memcpy(dst->s, src->s, src->len); |
|
58 |
+ dst->s[dst->len] = '\0'; |
|
59 |
+ return 1; |
|
60 |
+} |
|
61 |
+ |
|
62 |
+static inline char* rms_char_dup(char *s, int shared) |
|
63 |
+{ |
|
64 |
+ str src; |
|
65 |
+ str dst; |
|
66 |
+ src.s = s; |
|
67 |
+ src.len = strlen(s); |
|
68 |
+ if(!rms_str_dup(&dst, &src, shared)) |
|
69 |
+ return NULL; |
|
70 |
+ return dst.s; |
|
71 |
+} |
|
72 |
+ |
|
73 |
+#endif |
0 | 74 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,716 @@ |
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 |
+#include "../../core/fmsg.h" |
|
23 |
+ |
|
24 |
+MODULE_VERSION |
|
25 |
+ |
|
26 |
+static int mod_init(void); |
|
27 |
+static void mod_destroy(void); |
|
28 |
+static int child_init(int); |
|
29 |
+ |
|
30 |
+static rms_session_info_t *rms_session_list; |
|
31 |
+str playback_fn = {0, 0}; |
|
32 |
+str log_fn = {0, 0}; |
|
33 |
+ |
|
34 |
+static rms_t rms; |
|
35 |
+ |
|
36 |
+static int rms_session_free(rms_session_info_t *si); |
|
37 |
+static rms_session_info_t *rms_session_search(char *callid, int len); |
|
38 |
+static int fixup_rms_action_play(void **param, int param_no); |
|
39 |
+static int rms_hangup_call(rms_session_info_t *si); |
|
40 |
+ |
|
41 |
+static int rms_answer_f(struct sip_msg *); |
|
42 |
+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 *); |
|
46 |
+static int rms_hangup_f(struct sip_msg *); |
|
47 |
+static int rms_sessions_dump_f(struct sip_msg *, char *, char *); |
|
48 |
+ |
|
49 |
+static cmd_export_t cmds[] = { |
|
50 |
+ {"rms_answer", (cmd_function)rms_answer_f, 0, 0, 0, ANY_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, ANY_ROUTE}, |
|
55 |
+ {"rms_media_stop", (cmd_function)rms_media_stop_f, 0, 0, 0, ANY_ROUTE}, |
|
56 |
+ {"rms_hangup", (cmd_function)rms_hangup_f, 0, 0, 0, ANY_ROUTE}, |
|
57 |
+ {"rms_sessions_dump", (cmd_function)rms_sessions_dump_f, 0, 0, 0, |
|
58 |
+ ANY_ROUTE}, |
|
59 |
+ {0, 0, 0, 0, 0, 0}}; |
|
60 |
+ |
|
61 |
+static param_export_t mod_params[] = { |
|
62 |
+ {"log_file_name", PARAM_STR, &log_fn}, {0, 0, 0}}; |
|
63 |
+ |
|
64 |
+struct module_exports exports = { |
|
65 |
+ "rtp_media_server", DEFAULT_DLFLAGS, /* dlopen flags */ |
|
66 |
+ cmds, mod_params, 0, /* RPC export */ |
|
67 |
+ 0, 0, mod_init, child_init, mod_destroy, |
|
68 |
+}; |
|
69 |
+ |
|
70 |
+static void run_action_route(rms_session_info_t *si, char *route) |
|
71 |
+{ |
|
72 |
+ int rt, backup_rt; |
|
73 |
+ struct run_act_ctx ctx; |
|
74 |
+ sip_msg_t *fmsg; |
|
75 |
+ |
|
76 |
+ if(route == NULL) { |
|
77 |
+ LM_ERR("bad route\n"); |
|
78 |
+ return; |
|
79 |
+ } |
|
80 |
+ rt = -1; |
|
81 |
+ rt = route_lookup(&event_rt, route); |
|
82 |
+ if(rt < 0 || event_rt.rlist[rt] == NULL) { |
|
83 |
+ LM_DBG("route does not exist"); |
|
84 |
+ return; |
|
85 |
+ } |
|
86 |
+ if(faked_msg_init() < 0) { |
|
87 |
+ LM_ERR("faked_msg_init() failed\n"); |
|
88 |
+ return; |
|
89 |
+ } |
|
90 |
+ fmsg = faked_msg_next(); |
|
91 |
+ struct hdr_field callid; |
|
92 |
+ callid.body.s = si->callid.s; |
|
93 |
+ callid.body.len = si->callid.len; |
|
94 |
+ |
|
95 |
+ fmsg->callid = &callid; |
|
96 |
+ |
|
97 |
+ backup_rt = get_route_type(); |
|
98 |
+ set_route_type(EVENT_ROUTE); |
|
99 |
+ init_run_actions_ctx(&ctx); |
|
100 |
+ if(rt >= 0) { |
|
101 |
+ run_top_route(event_rt.rlist[rt], fmsg, 0); |
|
102 |
+ } |
|
103 |
+ set_route_type(backup_rt); |
|
104 |
+} |
|
105 |
+ |
|
106 |
+static int fixup_rms_action_play(void **param, int param_no) |
|
107 |
+{ |
|
108 |
+ if(param_no == 1) |
|
109 |
+ return fixup_spve_null(param, 1); |
|
110 |
+ if(param_no == 2) |
|
111 |
+ return fixup_spve_null(param, 1); |
|
112 |
+ LM_ERR("invalid parameter count [%d]\n", param_no); |
|
113 |
+ return -1; |
|
114 |
+} |
|
115 |
+ |
|
116 |
+/** |
|
117 |
+ * @return 0 to continue to load the OpenSER, -1 to stop the loading |
|
118 |
+ * and abort OpenSER. |
|
119 |
+ */ |
|
120 |
+static int mod_init(void) |
|
121 |
+{ |
|
122 |
+ LM_INFO("RTP media server module init\n"); |
|
123 |
+ rms.udp_start_port = 50000; |
|
124 |
+ rms.udp_end_port = 60000; |
|
125 |
+ rms.udp_last_port = 50000; |
|
126 |
+ rms_media_init(); |
|
127 |
+ rms_session_list = shm_malloc(sizeof(rms_session_info_t)); |
|
128 |
+ clist_init(rms_session_list, next, prev); |
|
129 |
+ |
|
130 |
+ register_procs(1); |
|
131 |
+ if(load_tm_api(&tmb) != 0) { |
|
132 |
+ LM_ERR("can't load TM API\n"); |
|
133 |
+ return -1; |
|
134 |
+ } |
|
135 |
+ FILE *log_file = fopen(log_fn.s, "w+"); |
|
136 |
+ if(log_file) { |
|
137 |
+ LM_INFO("ortp logs are redirected [%s]\n", log_fn.s); |
|
138 |
+ } else { |
|
139 |
+ log_file = stdout; |
|
140 |
+ LM_INFO("ortp can not open logs file [%s]\n", log_fn.s); |
|
141 |
+ } |
|
142 |
+ ortp_set_log_file(log_file); |
|
143 |
+ ortp_set_log_level_mask( |
|
144 |
+ NULL, ORTP_MESSAGE | ORTP_WARNING | ORTP_ERROR | ORTP_FATAL); |
|
145 |
+ return (0); |
|
146 |
+} |
|
147 |
+ |
|
148 |
+/** |
|
149 |
+ * Called only once when OpenSER is shuting down to clean up module |
|
150 |
+ * resources. |
|
151 |
+ */ |
|
152 |
+static void mod_destroy() |
|
153 |
+{ |
|
154 |
+ rms_media_destroy(); |
|
155 |
+ LM_INFO("RTP media server module destroy\n"); |
|
156 |
+ return; |
|
157 |
+} |
|
158 |
+ |
|
159 |
+void rms_signal_handler(int signum) |
|
160 |
+{ |
|
161 |
+ LM_INFO("signal received [%d]\n", signum); |
|
162 |
+} |
|
163 |
+ |
|
164 |
+/** |
|
165 |
+ * Most interaction with the session and media streams that are controlled |
|
166 |
+ * in this function this is safer in the event where a library is using non shared memory |
|
167 |
+ * all the mediastreamer2 ticker threads are spawned from here. |
|
168 |
+ */ |
|
169 |
+static void rms_session_manage_loop() |
|
170 |
+{ |
|
171 |
+ while(1) { |
|
172 |
+ lock(&session_list_mutex); |
|
173 |
+ rms_session_info_t *si; |
|
174 |
+ clist_foreach(rms_session_list, si, next) |
|
175 |
+ { |
|
176 |
+ if(si->action == RMS_HANGUP) { |
|
177 |
+ LM_INFO("session action RMS_HANGUP [%s]\n", si->callid.s); |
|
178 |
+ rms_hangup_call(si); |
|
179 |
+ si->action = RMS_STOP; |
|
180 |
+ } else if(si->action == RMS_STOP) { |
|
181 |
+ LM_INFO("session action RMS_STOP [%s]\n", si->callid.s); |
|
182 |
+ rms_stop_media(&si->caller_media); |
|
183 |