1 /*
2 mediastreamer2 library - modular sound and video processing and streaming
3 Copyright (C) 2006-2013 Belledonne Communications, Grenoble
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #include "mediastreamer2/mediastream.h"
21 #include "mediastreamer2/msrtt4103.h"
22 #include "mediastreamer2_tester.h"
23 #include "mediastreamer2_tester_private.h"
24 #include <math.h>
25
26 #ifdef _MSC_VER
27 #define unlink _unlink
28 #endif
29
30 static RtpProfile rtp_profile;
31
32 #define T140_PAYLOAD_TYPE 98
33 #define T140_RED_PAYLOAD_TYPE 99
34
35 static MSFactory *_factory = NULL;
tester_init(void)36 static int tester_init(void) {
37 _factory = ms_factory_new_with_voip();
38
39 ortp_init();
40 rtp_profile_set_payload(&rtp_profile, T140_PAYLOAD_TYPE, &payload_type_t140);
41 rtp_profile_set_payload(&rtp_profile, T140_RED_PAYLOAD_TYPE, &payload_type_t140_red);
42 return 0;
43 }
44
tester_cleanup(void)45 static int tester_cleanup(void) {
46
47 ms_factory_destroy(_factory);
48 rtp_profile_clear_all(&rtp_profile);
49 return 0;
50 }
51
52 typedef struct _text_stream_tester_stats_t {
53 OrtpEvQueue *q;
54 rtp_stats_t rtp;
55 int number_of_received_char;
56 char received_chars[4096];
57 } text_stream_tester_stats_t;
58
59 typedef struct _text_stream_tester_t {
60 TextStream *ts;
61 text_stream_tester_stats_t stats;
62 char* local_ip;
63 int local_rtp;
64 int local_rtcp;
65 int payload_type;
66 } text_stream_tester_t;
67
68
reset_stats(text_stream_tester_stats_t * s)69 static void reset_stats(text_stream_tester_stats_t *s) {
70 memset(s, 0, sizeof(text_stream_tester_stats_t));
71 }
72
text_stream_tester_set_local_ip(text_stream_tester_t * obj,const char * ip)73 void text_stream_tester_set_local_ip(text_stream_tester_t* obj, const char* ip) {
74 char* new_ip = ip ? ms_strdup(ip) : NULL;
75 if (obj->local_ip) ms_free(obj->local_ip);
76 obj->local_ip = new_ip;
77 }
78
text_stream_tester_new(void)79 text_stream_tester_t* text_stream_tester_new(void) {
80 text_stream_tester_t* tst = ms_new0(text_stream_tester_t, 1);
81 text_stream_tester_set_local_ip(tst, "127.0.0.1");
82 tst->local_rtp = -1; /*random*/
83 tst->local_rtcp = -1; /*random*/
84 return tst;
85 }
86
text_stream_tester_create(const char * local_ip,int local_rtp,int local_rtcp)87 text_stream_tester_t* text_stream_tester_create(const char* local_ip, int local_rtp, int local_rtcp) {
88 text_stream_tester_t *tst = text_stream_tester_new();
89 if (local_ip)
90 text_stream_tester_set_local_ip(tst, local_ip);
91 tst->local_rtp = local_rtp;
92 tst->local_rtcp = local_rtcp;
93 return tst;
94 }
95
text_stream_tester_destroy(text_stream_tester_t * obj)96 void text_stream_tester_destroy(text_stream_tester_t* obj) {
97 if(obj->local_ip) ms_free(obj->local_ip);
98 ms_free(obj);
99 }
100
create_text_stream(text_stream_tester_t * tst,int payload_type)101 static void create_text_stream(text_stream_tester_t *tst, int payload_type) {
102 tst->ts = text_stream_new2(_factory, tst->local_ip, tst->local_rtp, tst->local_rtcp);
103 tst->local_rtp = rtp_session_get_local_port(tst->ts->ms.sessions.rtp_session);
104 tst->local_rtcp = rtp_session_get_local_rtcp_port(tst->ts->ms.sessions.rtp_session);
105 reset_stats(&tst->stats);
106 rtp_session_set_multicast_loopback(tst->ts->ms.sessions.rtp_session, TRUE);
107 tst->stats.q = ortp_ev_queue_new();
108 rtp_session_register_event_queue(tst->ts->ms.sessions.rtp_session, tst->stats.q);
109 tst->payload_type = payload_type;
110 }
111
destroy_text_stream(text_stream_tester_t * tst)112 static void destroy_text_stream(text_stream_tester_t *tst) {
113 text_stream_stop(tst->ts);
114 }
115
real_time_text_character_received(void * userdata,struct _MSFilter * f,unsigned int id,void * arg)116 static void real_time_text_character_received(void *userdata, struct _MSFilter *f, unsigned int id, void *arg) {
117 if (id == MS_RTT_4103_RECEIVED_CHAR) {
118 text_stream_tester_t *tst = (text_stream_tester_t *)userdata;
119 if (tst->stats.q != NULL) {
120 RealtimeTextReceivedCharacter *data = (RealtimeTextReceivedCharacter *)arg;
121 ms_message("Received RTT char: %lu, %c", (unsigned long)data->character, (char)data->character);
122 if (tst->stats.number_of_received_char < (int)sizeof(tst->stats.received_chars)-1){
123 tst->stats.received_chars[tst->stats.number_of_received_char++] = (char)data->character;
124 }else{
125 ms_fatal("tst->stats.received_chars buffer overflow (number_of_received_char=%i)",
126 tst->stats.number_of_received_char);
127 }
128 }
129 }
130 }
131
init_text_streams(text_stream_tester_t * tst1,text_stream_tester_t * tst2,bool_t avpf,bool_t one_way,OrtpNetworkSimulatorParams * params,int payload_type)132 static void init_text_streams(text_stream_tester_t *tst1, text_stream_tester_t *tst2, bool_t avpf, bool_t one_way, OrtpNetworkSimulatorParams *params, int payload_type) {
133 create_text_stream(tst1, payload_type);
134 create_text_stream(tst2, payload_type);
135
136 /* Configure network simulator. */
137 if ((params != NULL) && (params->enabled == TRUE)) {
138 rtp_session_enable_network_simulation(tst1->ts->ms.sessions.rtp_session, params);
139 rtp_session_enable_network_simulation(tst2->ts->ms.sessions.rtp_session, params);
140 }
141
142 text_stream_start(tst1->ts, &rtp_profile, tst2->local_ip, tst2->local_rtp, tst2->local_ip, tst2->local_rtcp, payload_type);
143 ms_filter_add_notify_callback(tst1->ts->rttsink, real_time_text_character_received, tst1, TRUE);
144 text_stream_start(tst2->ts, &rtp_profile, tst1->local_ip, tst1->local_rtp, tst1->local_ip, tst1->local_rtcp, payload_type);
145 ms_filter_add_notify_callback(tst2->ts->rttsink, real_time_text_character_received, tst2, TRUE);
146 }
147
uninit_text_streams(text_stream_tester_t * tst1,text_stream_tester_t * tst2)148 static void uninit_text_streams(text_stream_tester_t *tst1, text_stream_tester_t *tst2) {
149 destroy_text_stream(tst1);
150 destroy_text_stream(tst2);
151 }
152
basic_text_stream(void)153 static void basic_text_stream(void) {
154 text_stream_tester_t* marielle = text_stream_tester_new();
155 text_stream_tester_t* margaux = text_stream_tester_new();
156 const char* helloworld = "Hello World !";
157 size_t i = 0;
158 int strcmpresult = -2;
159
160 init_text_streams(marielle, margaux, FALSE, FALSE, NULL, T140_PAYLOAD_TYPE /* ignored */);
161
162 for (; i < strlen(helloworld); i++) {
163 char c = helloworld[i];
164 text_stream_putchar32(margaux->ts, (uint32_t)c);
165 }
166
167 BC_ASSERT_TRUE(wait_for_until(&marielle->ts->ms, &margaux->ts->ms, &marielle->stats.number_of_received_char, (int)strlen(helloworld), 5000));
168 ms_message("Received message is: %s", marielle->stats.received_chars);
169 strcmpresult = strcmp(marielle->stats.received_chars, helloworld);
170 BC_ASSERT_EQUAL(strcmpresult, 0, int, "%d");
171
172 uninit_text_streams(marielle, margaux);
173 text_stream_tester_destroy(marielle);
174 text_stream_tester_destroy(margaux);
175 }
176
basic_text_stream2(void)177 static void basic_text_stream2(void) {
178 text_stream_tester_t* marielle = text_stream_tester_new();
179 text_stream_tester_t* margaux = text_stream_tester_new();
180 const char* helloworld = "Hello World !";
181 size_t i = 0;
182 int strcmpresult = -2;
183 int dummy = 0;
184
185 init_text_streams(marielle, margaux, FALSE, FALSE, NULL, T140_PAYLOAD_TYPE /* ignored */);
186
187 for (; i < strlen(helloworld); i++) {
188 char c = helloworld[i];
189 text_stream_putchar32(margaux->ts, (uint32_t)c);
190 wait_for_until(&marielle->ts->ms, &margaux->ts->ms, &dummy, 1, 500);
191 }
192
193 BC_ASSERT_TRUE(wait_for_until(&marielle->ts->ms, &margaux->ts->ms, &marielle->stats.number_of_received_char, (int)strlen(helloworld), 1000));
194 ms_message("Received message is: %s", marielle->stats.received_chars);
195 strcmpresult = strcmp(marielle->stats.received_chars, helloworld);
196 BC_ASSERT_EQUAL(strcmpresult, 0, int, "%d");
197
198 uninit_text_streams(marielle, margaux);
199 text_stream_tester_destroy(marielle);
200 text_stream_tester_destroy(margaux);
201 }
202
copy_paste_text_longer_than_rtt_buffer(void)203 static void copy_paste_text_longer_than_rtt_buffer(void) {
204 text_stream_tester_t* marielle = text_stream_tester_new();
205 text_stream_tester_t* margaux = text_stream_tester_new();
206 const char* helloworld = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus imperdiet ultricies condimentum. Pellentesque tellus massa, maximus id dignissim vel, aliquam eget sapien. Suspendisse convallis est ut cursus suscipit. Duis in massa dui. Vivamus lobortis maximus nisi, eget interdum ante faucibus ac. Donec varius lorem id arcu facilisis, et dignissim magna molestie. Nunc lobortis feugiat dapibus. Nam tempus auctor dignissim. Sed pellentesque urna vitae quam mattis, in dictum justo tristique. Nullam vehicula enim eu lacus sollicitudin aliquet. Nunc eget arcu id odio viverra ultrices. Ut sit amet urna id libero posuere viverra dapibus sed nunc. Nulla eget vehicula magna, ut pulvinar ex. Nulla tincidunt justo at ipsum pretium, quis tempus arcu semper. Pellentesque non commodo neque. Maecenas consequat dapibus justo vel ornare. Suspendisse varius diam ac tincidunt fermentum. Etiam orci neque, malesuada sit amet purus vehicula, vestibulum scelerisque lectus. Proin volutpat venenatis enim a sollicitudin. Praesent posuere.";
207 size_t i = 0;
208 int strcmpresult = -2;
209
210 init_text_streams(marielle, margaux, FALSE, FALSE, NULL, T140_PAYLOAD_TYPE /* ignored */);
211
212 for (; i < strlen(helloworld); i++) {
213 char c = helloworld[i];
214 text_stream_putchar32(margaux->ts, (uint32_t)c);
215 }
216
217 BC_ASSERT_FALSE(wait_for_until(&marielle->ts->ms, &margaux->ts->ms, &marielle->stats.number_of_received_char, (int)strlen(helloworld), 5000));
218 ms_message("Received message is: %s", marielle->stats.received_chars);
219 strcmpresult = strcmp(marielle->stats.received_chars, helloworld);
220 BC_ASSERT_LOWER(strcmpresult, 0, int, "%d");
221
222 uninit_text_streams(marielle, margaux);
223 text_stream_tester_destroy(marielle);
224 text_stream_tester_destroy(margaux);
225 }
226
227 #ifdef HAVE_SRTP
srtp_protected_text_stream(void)228 static void srtp_protected_text_stream(void) {
229 text_stream_tester_t* marielle = text_stream_tester_new();
230 text_stream_tester_t* margaux = text_stream_tester_new();
231 const char* helloworld = "Hello World !";
232 size_t i = 0;
233 int strcmpresult = -2;
234 int dummy = 0;
235
236 init_text_streams(marielle, margaux, FALSE, FALSE, NULL, T140_PAYLOAD_TYPE /* ignored */);
237 BC_ASSERT_EQUAL(ms_media_stream_sessions_set_encryption_mandatory(&marielle->ts->ms.sessions, TRUE), 0, int, "%d");
238
239 BC_ASSERT_TRUE(ms_srtp_supported());
240
241 BC_ASSERT_EQUAL(ms_media_stream_sessions_set_srtp_send_key_b64(&(marielle->ts->ms.sessions), MS_AES_128_SHA1_32, "d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj"),0,int,"%d");
242 BC_ASSERT_EQUAL(ms_media_stream_sessions_set_srtp_send_key_b64(&(margaux->ts->ms.sessions), MS_AES_128_SHA1_32, "6jCLmtRkVW9E/BUuJtYj/R2z6+4iEe06/DWohQ9F"),0,int,"%d");
243 BC_ASSERT_EQUAL(ms_media_stream_sessions_set_srtp_recv_key_b64(&(margaux->ts->ms.sessions), MS_AES_128_SHA1_32, "d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj"),0,int,"%d");
244 BC_ASSERT_EQUAL(ms_media_stream_sessions_set_srtp_recv_key_b64(&(marielle->ts->ms.sessions), MS_AES_128_SHA1_32, "6jCLmtRkVW9E/BUuJtYj/R2z6+4iEe06/DWohQ9F"),0,int,"%d");
245
246 BC_ASSERT_TRUE(media_stream_secured(&marielle->ts->ms));
247 BC_ASSERT_TRUE(media_stream_secured(&margaux->ts->ms));
248
249 for (; i < strlen(helloworld); i++) {
250 char c = helloworld[i];
251 text_stream_putchar32(margaux->ts, (uint32_t)c);
252 wait_for_until(&marielle->ts->ms, &margaux->ts->ms, &dummy, 1, 500);
253 }
254
255 BC_ASSERT_TRUE(wait_for_until(&marielle->ts->ms, &margaux->ts->ms, &marielle->stats.number_of_received_char, (int)strlen(helloworld), 1000));
256 ms_message("Received message is: %s", marielle->stats.received_chars);
257 strcmpresult = strcmp(marielle->stats.received_chars, helloworld);
258 BC_ASSERT_EQUAL(strcmpresult, 0, int, "%d");
259
260 uninit_text_streams(marielle, margaux);
261 text_stream_tester_destroy(marielle);
262 text_stream_tester_destroy(margaux);
263 }
264 #endif
265
266 static test_t tests[] = {
267 TEST_NO_TAG("Basic text stream: copy paste short text", basic_text_stream),
268 TEST_NO_TAG("Basic text stream: slow typing", basic_text_stream2),
269 TEST_NO_TAG("copy paste text longer than buffer size", copy_paste_text_longer_than_rtt_buffer),
270 #ifdef HAVE_SRTP
271 TEST_NO_TAG("slow typing with SRTP", srtp_protected_text_stream),
272 #endif
273 };
274
275 test_suite_t text_stream_test_suite = {
276 "TextStream",
277 tester_init,
278 tester_cleanup,
279 NULL,
280 NULL,
281 sizeof(tests) / sizeof(tests[0]),
282 tests
283 };
284