summaryrefslogtreecommitdiff
path: root/toxmsi
diff options
context:
space:
mode:
authorirungentoo <irungentoo@gmail.com>2014-02-16 19:13:34 -0500
committerirungentoo <irungentoo@gmail.com>2014-02-16 19:13:34 -0500
commit9d1eb27717472f5655242fac7b8123a44f1ff33c (patch)
treefd205f1ea53749717d9930d93ddb153fc8a16929 /toxmsi
parentfd3dc22ef3bd77beb78faf24cd43e9d2b9706f5d (diff)
parentf79b327fd639b2dcca9d4d2c137f93c1dce622fc (diff)
Merge branch 'av-fix' into av-good
Diffstat (limited to 'toxmsi')
-rw-r--r--toxmsi/Makefile.inc69
-rw-r--r--toxmsi/phone.c668
-rw-r--r--toxmsi/phone.h62
-rw-r--r--toxmsi/toxmedia.c825
-rw-r--r--toxmsi/toxmedia.h168
-rw-r--r--toxmsi/toxmsi.c835
-rw-r--r--toxmsi/toxmsi.h145
-rw-r--r--toxmsi/toxmsi_event.c214
-rw-r--r--toxmsi/toxmsi_event.h46
-rw-r--r--toxmsi/toxmsi_header.c181
-rw-r--r--toxmsi/toxmsi_header.h99
-rw-r--r--toxmsi/toxmsi_message.c267
-rw-r--r--toxmsi/toxmsi_message.h120
13 files changed, 0 insertions, 3699 deletions
diff --git a/toxmsi/Makefile.inc b/toxmsi/Makefile.inc
deleted file mode 100644
index 7d620e70..00000000
--- a/toxmsi/Makefile.inc
+++ /dev/null
@@ -1,69 +0,0 @@
1if BUILD_AV
2
3lib_LTLIBRARIES += libtoxmsi.la
4
5libtoxmsi_la_include_HEADERS = \
6 ../toxmsi/toxmsi.h \
7 ../toxmsi/toxmedia.h
8
9libtoxmsi_la_includedir = $(includedir)/tox
10
11
12libtoxmsi_la_SOURCES = ../toxmsi/toxmsi.h \
13 ../toxmsi/toxmsi.c \
14 ../toxmsi/toxmsi_message.h \
15 ../toxmsi/toxmsi_message.c \
16 ../toxmsi/toxmsi_header.h \
17 ../toxmsi/toxmsi_header.c \
18 ../toxmsi/toxmsi_event.h \
19 ../toxmsi/toxmsi_event.c \
20 ../toxrtp/tests/test_helper.h \
21 ../toxrtp/tests/test_helper.c
22
23libtoxmsi_la_CFLAGS = -I../toxcore \
24 -I../toxmsi \
25 -I../toxrtp \
26 $(NACL_CFLAGS) \
27 $(PTHREAD_CFLAGS)
28
29libtoxmsi_la_LDFLAGS = $(TOXMSI_LT_LDFLAGS) \
30 $(EXTRA_LT_LDFLAGS) \
31 $(NACL_LDFLAGS) \
32 $(PTHREAD_LIBS)
33
34libtoxmsi_la_LIBS = $(NACL_LIBS)
35
36noinst_PROGRAMS += phone
37
38phone_SOURCES = ../toxmsi/phone.c \
39 ../toxmsi/toxmedia.c
40
41phone_CFLAGS = -I../toxcore \
42 -I../toxrtp \
43 $(AVFORMAT_CFLAGS) \
44 $(AVCODEC_CFLAGS) \
45 $(AVUTIL_CFLAGS) \
46 $(AVDEVICE_CFLAGS) \
47 $(SWSCALE_CFLAGS) \
48 $(SDL_CFLAGS) \
49 $(OPENAL_CFLAGS) \
50 $(NACL_CFLAGS) \
51 $(OPUS_CFLAGS) \
52 $(PTHREAD_CFLAGS)
53
54
55phone_LDADD = $(PTHREAD_LIBS) \
56 libtoxrtp.la \
57 libtoxmsi.la \
58 $(NACL_LDFLAGS) \
59 $(AVFORMAT_LIBS) \
60 $(AVCODEC_LIBS) \
61 $(AVUTIL_LIBS) \
62 $(AVDEVICE_LIBS) \
63 $(SWSCALE_LIBS) \
64 $(SDL_LIBS) \
65 $(OPENAL_LIBS) \
66 $(NACL_LIBS) \
67 $(OPUS_LIBS)
68
69endif
diff --git a/toxmsi/phone.c b/toxmsi/phone.c
deleted file mode 100644
index 432be94c..00000000
--- a/toxmsi/phone.c
+++ /dev/null
@@ -1,668 +0,0 @@
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif /* HAVE_CONFIG_H */
4
5#define _BSD_SOURCE
6#define _GNU_SOURCE
7
8#define _CT_PHONE
9
10#ifdef _CT_PHONE
11#include "phone.h"
12#include <stdarg.h>
13#include <unistd.h>
14#include <stdio.h>
15#include <string.h>
16#include <stdlib.h>
17/* #include <termios.h> Can this be removed? */
18#include <pthread.h>
19#include "toxmedia.h"
20
21
22
23void INFO (const char *_format, ...)
24{
25 printf("\r[!] ");
26 va_list _arg;
27 va_start (_arg, _format);
28 vfprintf (stdout, _format, _arg);
29 va_end (_arg);
30 printf("\n\r >> ");
31 fflush(stdout);
32}
33
34int rtp_handlepacket ( void *_object, tox_IP_Port ip_port, uint8_t *data, uint32_t length )
35{
36 phone_t *_phone = _object;
37 rtp_msg_t *_msg;
38 uint8_t _payload_id;
39
40 if ( _phone->_msi->_call && _phone->_msi->_call->_state == call_active ) {
41
42 _msg = rtp_msg_parse ( NULL, data + 1, length - 1 ); /* ignore marker byte */
43
44 if ( !_msg )
45 return 0;
46
47 _payload_id = rtp_header_get_setting_payload_type(_msg->_header);
48
49 if ( _payload_id == _PAYLOAD_OPUS && _phone->_rtp_audio )
50 rtp_store_msg(_phone->_rtp_audio, _msg);
51 else if ( _payload_id == _PAYLOAD_VP8 && _phone->_rtp_video )
52 rtp_store_msg(_phone->_rtp_video, _msg);
53 else rtp_free_msg( NULL, _msg);
54 }
55
56 return SUCCESS;
57}
58int msi_handlepacket ( void *_object, tox_IP_Port ip_port, uint8_t *data, uint32_t length )
59{
60 msi_session_t *_session = _object;
61 msi_msg_t *_msg;
62
63 _msg = msi_parse_msg ( data + 1 ); /* ignore marker byte */
64
65 if ( _msg ) {
66 /* my current solution for "hole punching" */
67 _session->_friend_id = ip_port;
68 } else {
69 return FAILURE;
70 }
71
72 /* place message in a session */
73 msi_store_msg(_session, _msg);
74
75 return SUCCESS;
76}
77
78void *phone_receivepacket ( void *_phone_p )
79{
80 phone_t *_phone = _phone_p;
81
82
83 networking_registerhandler(_phone->_networking, MSI_PACKET, msi_handlepacket, _phone->_msi);
84 networking_registerhandler(_phone->_networking, RTP_PACKET, rtp_handlepacket, _phone);
85
86 /* Now start main networking loop */
87 while ( _phone->_networking ) { /* so not thread safe */
88 networking_poll(_phone->_networking);
89 usleep(10000);
90 }
91
92 pthread_exit ( NULL );
93}
94
95/* Media transport callback */
96typedef struct hmtc_args_s {
97 rtp_session_t **_rtp_audio;
98 rtp_session_t **_rtp_video;
99 call_type *_local_type_call;
100 call_state *_this_call;
101 void *_core_handler;
102} hmtc_args_t;
103
104void *phone_handle_media_transport_poll ( void *_hmtc_args_p )
105{
106 rtp_msg_t *_audio_msg, * _video_msg;
107
108 hmtc_args_t *_hmtc_args = _hmtc_args_p;
109
110 rtp_session_t *_rtp_audio = *_hmtc_args->_rtp_audio;
111 rtp_session_t *_rtp_video = *_hmtc_args->_rtp_video;
112
113 call_type *_type = _hmtc_args->_local_type_call;
114 void *_core_handler = _hmtc_args->_core_handler;
115
116
117 call_state *_this_call = _hmtc_args->_this_call;
118
119 while ( *_this_call == call_active ) {
120
121 // THREADLOCK()
122
123 _audio_msg = rtp_recv_msg ( _rtp_audio );
124 _video_msg = rtp_recv_msg ( _rtp_video );
125
126 if ( _audio_msg ) {
127 /* Do whatever with msg */
128 puts("audio");
129 /* Do whatever with msg
130 puts(_audio_msg->_data);*/
131 rtp_free_msg ( _rtp_audio, _audio_msg );
132 }
133
134 if ( _video_msg ) {
135 /* Do whatever with msg */
136 puts("video");
137 /* Do whatever with msg
138 puts(_video_msg->_data); */
139 rtp_free_msg ( _rtp_video, _video_msg );
140 _video_msg = NULL;
141 }
142
143 /* -------------------- */
144
145 _audio_msg = rtp_msg_new ( _rtp_audio, (const uint8_t *)"audio\0", 6 ) ;
146 rtp_send_msg ( _rtp_audio, _audio_msg, _core_handler );
147 _audio_msg = NULL;
148
149 if ( *_type == type_video ) { /* if local call send video */
150 _video_msg = rtp_msg_new ( _rtp_video, (const uint8_t *)"video\0", 6 ) ;
151 rtp_send_msg ( _rtp_video, _video_msg, _core_handler );
152 _video_msg = NULL;
153 }
154
155 //THREADUNLOCK()
156
157 usleep ( 10000 );
158 /* -------------------- */
159 }
160
161 //THREADLOCK()
162
163 if ( _audio_msg ) {
164 rtp_free_msg(_rtp_audio, _audio_msg);
165 }
166
167 if ( _video_msg ) {
168 rtp_free_msg(_rtp_video, _video_msg);
169 }
170
171 rtp_release_session_recv(_rtp_video);
172 rtp_release_session_recv(_rtp_audio);
173
174 rtp_terminate_session(_rtp_audio);
175 rtp_terminate_session(_rtp_video);
176
177 *_hmtc_args->_rtp_audio = NULL;
178 *_hmtc_args->_rtp_video = NULL;
179
180 free(_hmtc_args_p);
181
182 //THREADUNLOCK()
183
184 INFO("Media thread finished!");
185
186 pthread_exit ( NULL );
187}
188
189pthread_t phone_startmedia_loop ( phone_t *_phone )
190{
191 if ( !_phone ) {
192 return 0;
193 }
194
195 int _status;
196
197 uint8_t _prefix = RTP_PACKET;
198
199 pthread_t _rtp_tid;
200 int _rtp_thread_running = 1;
201
202 _phone->_rtp_audio = rtp_init_session ( -1, 1 );
203 rtp_set_prefix ( _phone->_rtp_audio, &_prefix, 1 );
204 rtp_add_receiver ( _phone->_rtp_audio, &_phone->_msi->_friend_id );
205 rtp_set_payload_type(_phone->_rtp_audio, _PAYLOAD_OPUS);
206
207 _phone->_rtp_video = rtp_init_session ( -1, 1 );
208 rtp_set_prefix ( _phone->_rtp_video, &_prefix, 1 );
209 rtp_add_receiver ( _phone->_rtp_video, &_phone->_msi->_friend_id );
210 rtp_set_payload_type(_phone->_rtp_video, _PAYLOAD_VP8);
211
212
213
214 hmtc_args_t *rtp_targs = calloc(sizeof(hmtc_args_t), 1);
215
216
217 rtp_targs->_rtp_audio = &_phone->_rtp_audio;
218 rtp_targs->_rtp_video = &_phone->_rtp_video;
219 rtp_targs->_local_type_call = &_phone->_msi->_call->_type_local;
220 rtp_targs->_this_call = &_phone->_msi->_call->_state;
221 rtp_targs->_core_handler = _phone->_networking;
222
223 codec_state *cs;
224 cs = _phone->cs;
225 //_status = pthread_create ( &_rtp_tid, NULL, phone_handle_media_transport_poll, rtp_targs );
226 cs->_rtp_audio = _phone->_rtp_audio;
227 cs->_rtp_video = _phone->_rtp_video;
228 cs->_networking = _phone->_networking;
229 cs->socket = _phone->_tox_sock;
230 cs->quit = 0;
231
232 printf("support: %d %d\n", cs->support_send_audio, cs->support_send_video);
233
234 if (cs->support_send_audio && cs->support_send_video) /* quick fix */
235 pthread_create(&_phone->cs->encode_audio_thread, NULL, encode_audio_thread, _phone->cs);
236
237 if (cs->support_receive_audio)
238 pthread_create(&_phone->cs->decode_audio_thread, NULL, decode_audio_thread, _phone->cs);
239
240 if (cs->support_send_video)
241 pthread_create(&_phone->cs->encode_video_thread, NULL, encode_video_thread, _phone->cs);
242
243 if (cs->support_receive_video)
244 pthread_create(&_phone->cs->decode_video_thread, NULL, decode_video_thread, _phone->cs);
245
246//
247 return 1;
248
249
250
251
252}
253
254
255/* Some example callbacks */
256
257MCBTYPE callback_recv_invite ( MCBARGS )
258{
259 const char *_call_type;
260
261 msi_session_t *_msi = _arg;
262
263 /* Get the last one */
264 call_type _type = _msi->_call->_type_peer[_msi->_call->_participants - 1];
265
266 switch ( _type ) {
267 case type_audio:
268 _call_type = "audio";
269 break;
270
271 case type_video:
272 _call_type = "video";
273 break;
274 }
275
276 INFO( "Incoming %s call!", _call_type );
277
278}
279MCBTYPE callback_recv_trying ( MCBARGS )
280{
281 INFO ( "Trying...");
282}
283MCBTYPE callback_recv_ringing ( MCBARGS )
284{
285 INFO ( "Ringing!" );
286}
287MCBTYPE callback_recv_starting ( MCBARGS )
288{
289 msi_session_t *_session = _arg;
290
291 if ( !phone_startmedia_loop(_session->_agent_handler) ) {
292 INFO("Starting call failed!");
293 } else {
294 INFO ("Call started! ( press h to hangup )");
295 }
296}
297MCBTYPE callback_recv_ending ( MCBARGS )
298{
299 msi_session_t *_session = _arg;
300 phone_t *_phone = _session->_agent_handler;
301 _phone->cs->quit = 1;
302
303 if (_phone->cs->encode_video_thread)
304 pthread_join(_phone->cs->encode_video_thread, NULL);
305
306 if (_phone->cs->encode_audio_thread)
307 pthread_join(_phone->cs->encode_audio_thread, NULL);
308
309 if (_phone->cs->decode_audio_thread)
310 pthread_join(_phone->cs->decode_audio_thread, NULL);
311
312 if (_phone->cs->decode_video_thread)
313 pthread_join(_phone->cs->decode_video_thread, NULL);
314
315 SDL_Quit();
316 printf("all A/V threads successfully shut down\n");
317
318 INFO ( "Call ended!" );
319}
320
321MCBTYPE callback_recv_error ( MCBARGS )
322{
323 msi_session_t *_session = _arg;
324
325 INFO( "Error: %s", _session->_last_error_str );
326}
327
328MCBTYPE callback_call_started ( MCBARGS )
329{
330 msi_session_t *_session = _arg;
331
332 if ( !phone_startmedia_loop(_session->_agent_handler) ) {
333 INFO("Starting call failed!");
334 } else {
335 INFO ("Call started! ( press h to hangup )");
336 }
337
338}
339MCBTYPE callback_call_canceled ( MCBARGS )
340{
341 INFO ( "Call canceled!" );
342}
343MCBTYPE callback_call_rejected ( MCBARGS )
344{
345 INFO ( "Call rejected!\n" );
346}
347MCBTYPE callback_call_ended ( MCBARGS )
348{
349
350 msi_session_t *_session = _arg;
351 phone_t *_phone = _session->_agent_handler;
352 _phone->cs->quit = 1;
353
354 if (_phone->cs->encode_video_thread)
355 pthread_join(_phone->cs->encode_video_thread, NULL);
356
357 if (_phone->cs->encode_audio_thread)
358 pthread_join(_phone->cs->encode_audio_thread, NULL);
359
360 if (_phone->cs->decode_audio_thread)
361 pthread_join(_phone->cs->decode_audio_thread, NULL);
362
363 if (_phone->cs->decode_video_thread)
364 pthread_join(_phone->cs->decode_video_thread, NULL);
365
366 SDL_Quit();
367 printf("all A/V threads successfully shut down\n");
368
369 INFO ( "Call ended!" );
370}
371
372MCBTYPE callback_requ_timeout ( MCBARGS )
373{
374 INFO( "No answer! " );
375}
376
377
378phone_t *initPhone(uint16_t _listen_port, uint16_t _send_port)
379{
380 phone_t *_retu = calloc(sizeof(phone_t), 1);
381 _retu->cs = av_calloc(sizeof(codec_state), 1);
382
383 /* Initialize our mutex */
384 pthread_mutex_init ( &_mutex, NULL );
385
386 IP_Port _local;
387 ip_init(&_local.ip, 0);
388 _local.ip.ip4.uint32 = htonl ( INADDR_ANY );
389
390 /* Bind local receive port to any address */
391 _retu->_networking = new_networking ( _local.ip, _listen_port );
392
393 if ( !_retu->_networking ) {
394 fprintf ( stderr, "new_networking() failed!\n" );
395 return NULL;
396 }
397
398 _retu->_send_port = _send_port;
399 _retu->_recv_port = _listen_port;
400
401 _retu->_tox_sock = _retu->_networking->sock;
402
403 _retu->_rtp_audio = NULL;
404 _retu->_rtp_video = NULL;
405
406
407 /* Initialize msi */
408 _retu->_msi = msi_init_session ( _retu->_networking, (const uint8_t *)_USERAGENT );
409
410 if ( !_retu->_msi ) {
411 fprintf ( stderr, "msi_init_session() failed\n" );
412 return NULL;
413 }
414
415 /* Initiate codecs */
416 init_encoder(_retu->cs);
417 init_decoder(_retu->cs);
418
419 _retu->_msi->_agent_handler = _retu;
420 /* Initiate callbacks */
421 msi_register_callback_send ( sendpacket ); /* Using core's send */
422
423 msi_register_callback_call_started ( callback_call_started );
424 msi_register_callback_call_canceled ( callback_call_canceled );
425 msi_register_callback_call_rejected ( callback_call_rejected );
426 msi_register_callback_call_ended ( callback_call_ended );
427
428 msi_register_callback_recv_invite ( callback_recv_invite );
429 msi_register_callback_recv_ringing ( callback_recv_ringing );
430 msi_register_callback_recv_starting ( callback_recv_starting );
431 msi_register_callback_recv_ending ( callback_recv_ending );
432 msi_register_callback_recv_error(callback_recv_error);
433
434 msi_register_callback_requ_timeout ( callback_requ_timeout );
435 /* ------------------ */
436
437 /* Now start msi main loop. It's a must!
438 * Define a frequency in ms; 10 ms is just fine
439 */
440 msi_start_main_loop ( _retu->_msi, 10 );
441
442 return _retu;
443}
444
445pthread_t phone_startmain_loop(phone_t *_phone)
446{
447 int _status;
448 /* Start receive thread */
449 pthread_t _recv_thread, _phone_loop_thread;
450 _status = pthread_create ( &_recv_thread, NULL, phone_receivepacket, _phone );
451
452 if ( _status < 0 ) {
453 printf ( "Error while starting handle call: %d, %s\n", errno, strerror ( errno ) );
454 return 0;
455 }
456
457 _status = pthread_detach ( _recv_thread );
458
459 if ( _status < 0 ) {
460 printf ( "Error while starting handle call: %d, %s\n", errno, strerror ( errno ) );
461 return 0;
462 }
463
464 _status = pthread_create ( &_phone_loop_thread, NULL, phone_poll, _phone );
465
466 if ( _status < 0 ) {
467 printf ( "Error while starting main phone loop: %d, %s\n", errno, strerror ( errno ) );
468 return 0;
469 }
470
471 _status = pthread_join ( _phone_loop_thread, NULL );
472
473 if ( _status < 0 ) {
474 printf ( "Error while starting main phone loop: %d, %s\n", errno, strerror ( errno ) );
475 return 0;
476 }
477
478 return _phone_loop_thread;
479}
480
481void *phone_poll ( void *_p_phone )
482{
483 phone_t *_phone = _p_phone;
484
485 int _status = SUCCESS;
486
487 char _line[100];
488 size_t _len;
489
490
491 char _dest[17]; /* For parsing destination ip */
492 memset(_dest, '\0', 17);
493
494 INFO("Welcome to tox_phone version: " _USERAGENT "\n"
495 "Usage: \n"
496 "c [a/v] (type) [0.0.0.0] (dest ip) (calls dest ip)\n"
497 "h (if call is active hang up)\n"
498 "a [a/v] (answer incoming call: a - audio / v - audio + video (audio is default))\n"
499 "r (reject incoming call)\n"
500 "q (quit)\n"
501 "================================================================================"
502 );
503
504 while ( 1 ) {
505 fgets(_line, sizeof(_line), stdin);
506 int i;
507
508 for (i = 0; i < 100; i++) {
509 if (_line[i] == '\n') {
510 _line[i] = '\0';
511 }
512 }
513
514 _len = strlen(_line);
515
516 if ( !_len ) {
517 printf(" >> ");
518 fflush(stdout);
519 continue;
520 }
521
522 if ( _len > 1 && _line[1] != ' ' && _line[1] != '\n' ) {
523 INFO("Invalid input!");
524 continue;
525 }
526
527 switch (_line[0]) {
528
529 case 'c': {
530 if ( _phone->_msi->_call ) {
531 INFO("Already in a call");
532 break;
533 }
534
535 call_type _ctype;
536
537 if ( _len < 11 ) {
538 INFO("Invalid input; usage: c a/v 0.0.0.0");
539 break;
540 } else if ( _line[2] == 'a' || _line[2] != 'v' ) { /* default and audio */
541 _ctype = type_audio;
542 } else { /* video */
543 _ctype = type_video;
544 }
545
546 strcpy(_dest, _line + 4 );
547 _status = t_setipport(_dest, _phone->_send_port, &(_phone->_msi->_friend_id));
548
549 if ( _status < 0 ) {
550 INFO("Could not resolve address!");
551 } else {
552 /* Set timeout */
553 msi_invite ( _phone->_msi, _ctype, 30 * 1000 );
554 INFO("Calling!");
555 }
556
557 t_memset((uint8_t *)_dest, '\0', 17);
558
559 }
560 break;
561
562 case 'h': {
563 if ( !_phone->_msi->_call ) {
564 break;
565 }
566
567 msi_hangup(_phone->_msi);
568
569 INFO("Hung up...");
570
571 }
572 break;
573
574 case 'a': {
575 if ( _phone->_msi->_call && _phone->_msi->_call->_state != call_starting ) {
576 break;
577 }
578
579 if ( _len > 1 && _line[2] == 'v' )
580 msi_answer(_phone->_msi, type_video);
581 else
582 msi_answer(_phone->_msi, type_audio);
583
584 }
585 break;
586
587 case 'r': {
588 if ( _phone->_msi->_call && _phone->_msi->_call->_state != call_starting ) {
589 break;
590 }
591
592 msi_reject(_phone->_msi);
593
594 INFO("Call Rejected...");
595
596 }
597 break;
598
599 case 'q': {
600 INFO("Quitting!");
601 pthread_exit(NULL);
602 }
603
604 default: {
605 INFO("Invalid command!");
606 }
607 break;
608
609 }
610
611 usleep(1000);
612 }
613
614 pthread_exit(NULL);
615}
616
617int quitPhone(phone_t *_phone)
618{
619 if ( _phone->_msi->_call ) {
620 msi_hangup(_phone->_msi); /* Hangup the phone first */
621 }
622
623 msi_terminate_session(_phone->_msi);
624 pthread_mutex_destroy ( &_mutex );
625
626 printf("\r[i] Quit!\n");
627 return SUCCESS;
628}
629
630/* ---------------------- */
631
632int print_help ( const char *_name )
633{
634 printf ( "Usage: %s -m (mode) -r/s ( for setting the ports on test version )\n", _name );
635 return FAILURE;
636}
637
638int main ( int argc, char *argv [] )
639{
640 arg_t *_args = parse_args ( argc, argv );
641
642 const char *_mode = find_arg_duble ( _args, "-m" );
643 uint16_t _listen_port;
644 uint16_t _send_port;
645
646 if ( !_mode )
647 return print_help ( argv[0] );
648
649 if ( _mode[0] == 'r' ) {
650 _send_port = 31000;
651 _listen_port = 31001;
652 } else if ( _mode[0] == 's' ) {
653 _send_port = 31001;
654 _listen_port = 31000;
655 } else return print_help ( argv[0] );
656
657 phone_t *_phone = initPhone(_listen_port, _send_port);
658
659 if ( _phone ) {
660 phone_startmain_loop(_phone);
661
662 quitPhone(_phone);
663 }
664
665 return SUCCESS;
666}
667
668#endif /* _CT_PHONE */
diff --git a/toxmsi/phone.h b/toxmsi/phone.h
deleted file mode 100644
index f96aac73..00000000
--- a/toxmsi/phone.h
+++ /dev/null
@@ -1,62 +0,0 @@
1#ifndef _PHONE_H_
2#define _PHONE_H_
3
4#include "toxmsi.h"
5#include "../toxrtp/toxrtp.h"
6#include "toxmsi_message.h"
7#include "../toxrtp/toxrtp_message.h"
8#include "../toxrtp/tests/test_helper.h"
9#include <assert.h>
10#include <pthread.h>
11#include "toxmedia.h"
12
13/* Define client version */
14#define _USERAGENT "tox_phone-v.0.2.1"
15
16static pthread_mutex_t _mutex;
17
18#define THREADLOCK() \
19pthread_mutex_lock ( &_mutex );
20
21#define THREADUNLOCK() \
22pthread_mutex_unlock ( &_mutex );
23
24typedef struct phone_s {
25 msi_session_t* _msi;
26
27 rtp_session_t* _rtp_audio;
28 rtp_session_t* _rtp_video;
29
30 uint32_t _frame_rate;
31
32 uint16_t _send_port, _recv_port;
33
34 int _tox_sock;
35
36 pthread_t _medialoop_id;
37 codec_state *cs;
38
39 Networking_Core* _networking;
40} phone_t;
41
42phone_t* initPhone(uint16_t _listen_port, uint16_t _send_port);
43int quitPhone(phone_t* _phone);
44
45/* My recv functions */
46int rtp_handlepacket ( void* _object, tox_IP_Port ip_port, uint8_t* data, uint32_t length );
47int msi_handlepacket ( void* _object, tox_IP_Port ip_port, uint8_t* data, uint32_t length );
48
49/* This is basically representation of networking_poll of toxcore */
50void* phone_receivepacket ( void* _phone );
51
52/* Phones main loop */
53void* phone_poll ( void* _phone );
54
55pthread_t phone_startmain_loop(phone_t* _phone);
56pthread_t phone_startmedia_loop ( phone_t* _phone );
57
58/* Thread handlers */
59void* phone_handle_receive_callback ( void* _p );
60void* phone_handle_media_transport_poll ( void* _hmtc_args_p );
61
62#endif /* _PHONE_H_ */
diff --git a/toxmsi/toxmedia.c b/toxmsi/toxmedia.c
deleted file mode 100644
index 4c9f5261..00000000
--- a/toxmsi/toxmedia.c
+++ /dev/null
@@ -1,825 +0,0 @@
1/* AV_codec.c
2// *
3 * Audio and video codec intitialisation, encoding/decoding and playback
4 *
5 * Copyright (C) 2013 Tox project All Rights Reserved.
6 *
7 * This file is part of Tox.
8 *
9 * Tox is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * Tox is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24/*----------------------------------------------------------------------------------*/
25
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#endif /* HAVE_CONFIG_H */
29
30#include <stdio.h>
31#include <math.h>
32#include <libavcodec/avcodec.h>
33#include <libavformat/avformat.h>
34#include <libswscale/swscale.h>
35#include <libavdevice/avdevice.h>
36#include <libavutil/opt.h>
37#include <AL/al.h>
38#include <AL/alc.h>
39#include <SDL/SDL.h>
40#include <SDL/SDL_thread.h>
41#include <pthread.h>
42#include <opus/opus.h>
43
44#include "toxmsi.h"
45#include "toxmsi_message.h"
46#include "../toxrtp/toxrtp_message.h"
47#include "../toxrtp/tests/test_helper.h"
48#include "phone.h"
49#include "toxmedia.h"
50
51SDL_Surface *screen;
52
53int display_received_frame(codec_state *cs, AVFrame *r_video_frame)
54{
55 AVPicture pict;
56 SDL_LockYUVOverlay(cs->video_picture.bmp);
57
58 pict.data[0] = cs->video_picture.bmp->pixels[0];
59 pict.data[1] = cs->video_picture.bmp->pixels[2];
60 pict.data[2] = cs->video_picture.bmp->pixels[1];
61 pict.linesize[0] = cs->video_picture.bmp->pitches[0];
62 pict.linesize[1] = cs->video_picture.bmp->pitches[2];
63 pict.linesize[2] = cs->video_picture.bmp->pitches[1];
64
65 /* Convert the image into YUV format that SDL uses */
66 sws_scale(cs->sws_SDL_r_ctx, (uint8_t const * const *)r_video_frame->data, r_video_frame->linesize, 0,
67 cs->video_decoder_ctx->height, pict.data, pict.linesize );
68
69 SDL_UnlockYUVOverlay(cs->video_picture.bmp);
70 SDL_Rect rect;
71 rect.x = 0;
72 rect.y = 0;
73 rect.w = cs->video_decoder_ctx->width;
74 rect.h = cs->video_decoder_ctx->height;
75 SDL_DisplayYUVOverlay(cs->video_picture.bmp, &rect);
76 return 1;
77}
78
79struct jitter_buffer {
80 rtp_msg_t **queue;
81 uint16_t capacity;
82 uint16_t size;
83 uint16_t front;
84 uint16_t rear;
85 uint8_t queue_ready;
86 uint16_t current_id;
87 uint32_t current_ts;
88 uint8_t id_set;
89};
90
91struct jitter_buffer *create_queue(int capacity)
92{
93 struct jitter_buffer *q;
94 q = (struct jitter_buffer *)calloc(sizeof(struct jitter_buffer),1);
95 q->queue = (rtp_msg_t **)calloc((sizeof(rtp_msg_t) * capacity),1);
96 int i = 0;
97
98 for (i = 0; i < capacity; ++i) {
99 q->queue[i] = NULL;
100 }
101
102 q->size = 0;
103 q->capacity = capacity;
104 q->front = 0;
105 q->rear = -1;
106 q->queue_ready = 0;
107 q->current_id = 0;
108 q->current_ts = 0;
109 q->id_set = 0;
110 return q;
111}
112
113/* returns 1 if 'a' has a higher sequence number than 'b' */
114uint8_t sequence_number_older(uint16_t sn_a, uint16_t sn_b, uint32_t ts_a, uint32_t ts_b)
115{
116 /* should be stable enough */
117 return (sn_a > sn_b || ts_a > ts_b);
118}
119
120/* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */
121rtp_msg_t *dequeue(struct jitter_buffer *q, int *success)
122{
123 if (q->size == 0 || q->queue_ready == 0) {
124 q->queue_ready = 0;
125 *success = 0;
126 return NULL;
127 }
128
129 int front = q->front;
130
131 if (q->id_set == 0) {
132 q->current_id = q->queue[front]->_header->_sequence_number;
133 q->current_ts = q->queue[front]->_header->_timestamp;
134 q->id_set = 1;
135 } else {
136 int next_id = q->queue[front]->_header->_sequence_number;
137 int next_ts = q->queue[front]->_header->_timestamp;
138
139 /* if this packet is indeed the expected packet */
140 if (next_id == (q->current_id + 1) % _MAX_SEQU_NUM) {
141 q->current_id = next_id;
142 q->current_ts = next_ts;
143 } else {
144 if (sequence_number_older(next_id, q->current_id, next_ts, q->current_ts)) {
145 printf("nextid: %d current: %d\n", next_id, q->current_id);
146 q->current_id = (q->current_id + 1) % _MAX_SEQU_NUM;
147 *success = 2; /* tell the decoder the packet is lost */
148 return NULL;
149 } else {
150 /* packet too old */
151 printf("packet too old\n");
152 *success = 0;
153 return NULL;
154 }
155 }
156 }
157
158 q->size--;
159 q->front++;
160
161 if (q->front == q->capacity)
162 q->front = 0;
163
164 *success = 1;
165 q->current_id = q->queue[front]->_header->_sequence_number;
166 q->current_ts = q->queue[front]->_header->_timestamp;
167 return q->queue[front];
168}
169
170int empty_queue(struct jitter_buffer *q)
171{
172 while (q->size > 0) {
173 q->size--;
174 /* FIXME: */
175 /* rtp_free_msg(cs->_rtp_video, q->queue[q->front]); */
176 q->front++;
177
178 if (q->front == q->capacity)
179 q->front = 0;
180 }
181
182 q->id_set = 0;
183 q->queue_ready = 0;
184 return 0;
185}
186
187int queue(struct jitter_buffer *q, rtp_msg_t *pk)
188{
189 if (q->size == q->capacity) {
190 printf("buffer full, emptying buffer...\n");
191 empty_queue(q);
192 return 0;
193 }
194
195 if (q->size > 8)
196 q->queue_ready = 1;
197
198 ++q->size;
199 ++q->rear;
200
201 if (q->rear == q->capacity)
202 q->rear = 0;
203
204 q->queue[q->rear] = pk;
205
206 int a;
207 int b;
208 int j;
209 a = q->rear;
210
211 for (j = 0; j < q->size - 1; ++j) {
212 b = a - 1;
213
214 if (b < 0)
215 b += q->capacity;
216
217 if (sequence_number_older(q->queue[b]->_header->_sequence_number, q->queue[a]->_header->_sequence_number,
218 q->queue[b]->_header->_timestamp, q->queue[a]->_header->_timestamp)) {
219 rtp_msg_t *temp;
220 temp = q->queue[a];
221 q->queue[a] = q->queue[b];
222 q->queue[b] = temp;
223 printf("had to swap\n");
224 } else {
225 break;
226 }
227
228 a -= 1;
229
230 if (a < 0)
231 a += q->capacity;
232 }
233
234 if (pk)
235 return 1;
236
237 return 0;
238}
239
240int init_receive_audio(codec_state *cs)
241{
242 int err = OPUS_OK;
243 cs->audio_decoder = opus_decoder_create(48000, 1, &err);
244 opus_decoder_init(cs->audio_decoder, 48000, 1);
245 printf("init audio decoder successful\n");
246 return 1;
247}
248
249int init_receive_video(codec_state *cs)
250{
251 cs->video_decoder = avcodec_find_decoder(VIDEO_CODEC);
252
253 if (!cs->video_decoder) {
254 printf("init video_decoder failed\n");
255 return 0;
256 }
257
258 cs->video_decoder_ctx = avcodec_alloc_context3(cs->video_decoder);
259
260 if (!cs->video_decoder_ctx) {
261 printf("init video_decoder_ctx failed\n");
262 return 0;
263 }
264
265 if (avcodec_open2(cs->video_decoder_ctx, cs->video_decoder, NULL) < 0) {
266 printf("opening video decoder failed\n");
267 return 0;
268 }
269
270 printf("init video decoder successful\n");
271 return 1;
272}
273
274int init_send_video(codec_state *cs)
275{
276 cs->video_input_format = av_find_input_format(VIDEO_DRIVER);
277
278 if (avformat_open_input(&cs->video_format_ctx, DEFAULT_WEBCAM, cs->video_input_format, NULL) != 0) {
279 printf("opening video_input_format failed\n");
280 return 0;
281 }
282
283 avformat_find_stream_info(cs->video_format_ctx, NULL);
284 av_dump_format(cs->video_format_ctx, 0, DEFAULT_WEBCAM, 0);
285
286 int i;
287
288 for (i = 0; i < cs->video_format_ctx->nb_streams; ++i) {
289 if (cs->video_format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
290 cs->video_stream = i;
291 break;
292 }
293 }
294
295 cs->webcam_decoder_ctx = cs->video_format_ctx->streams[cs->video_stream]->codec;
296 cs->webcam_decoder = avcodec_find_decoder(cs->webcam_decoder_ctx->codec_id);
297
298 if (cs->webcam_decoder == NULL) {
299 printf("Unsupported codec\n");
300 return 0;
301 }
302
303 if (cs->webcam_decoder_ctx == NULL) {
304 printf("init webcam_decoder_ctx failed\n");
305 return 0;
306 }
307
308 if (avcodec_open2(cs->webcam_decoder_ctx, cs->webcam_decoder, NULL) < 0) {
309 printf("opening webcam decoder failed\n");
310 return 0;
311 }
312
313 cs->video_encoder = avcodec_find_encoder(VIDEO_CODEC);
314
315 if (!cs->video_encoder) {
316 printf("init video_encoder failed\n");
317 return 0;
318 }
319
320 cs->video_encoder_ctx = avcodec_alloc_context3(cs->video_encoder);
321
322 if (!cs->video_encoder_ctx) {
323 printf("init video_encoder_ctx failed\n");
324 return 0;
325 }
326
327 cs->video_encoder_ctx->bit_rate = VIDEO_BITRATE;
328 cs->video_encoder_ctx->rc_min_rate = cs->video_encoder_ctx->rc_max_rate = cs->video_encoder_ctx->bit_rate;
329 av_opt_set_double(cs->video_encoder_ctx->priv_data, "max-intra-rate", 90, 0);
330 av_opt_set(cs->video_encoder_ctx->priv_data, "quality", "realtime", 0);
331
332 cs->video_encoder_ctx->thread_count = 4;
333 cs->video_encoder_ctx->rc_buffer_aggressivity = 0.95;
334 cs->video_encoder_ctx->rc_buffer_size = VIDEO_BITRATE * 6;
335 cs->video_encoder_ctx->profile = 3;
336 cs->video_encoder_ctx->qmax = 54;
337 cs->video_encoder_ctx->qmin = 4;
338 AVRational myrational = {1, 25};
339 cs->video_encoder_ctx->time_base = myrational;
340 cs->video_encoder_ctx->gop_size = 99999;
341 cs->video_encoder_ctx->pix_fmt = PIX_FMT_YUV420P;
342 cs->video_encoder_ctx->width = cs->webcam_decoder_ctx->width;
343 cs->video_encoder_ctx->height = cs->webcam_decoder_ctx->height;
344
345 if (avcodec_open2(cs->video_encoder_ctx, cs->video_encoder, NULL) < 0) {
346 printf("opening video encoder failed\n");
347 return 0;
348 }
349
350 printf("init video encoder successful\n");
351 return 1;
352}
353
354int init_send_audio(codec_state *cs)
355{
356 cs->support_send_audio = 0;
357
358 const ALchar *pDeviceList = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
359 int i = 0;
360 const ALchar *device_names[20];
361
362 if (pDeviceList) {
363 printf("\nAvailable Capture Devices are:\n");
364
365 while (*pDeviceList) {
366 device_names[i] = pDeviceList;
367 printf("%d) %s\n", i, device_names[i]);
368 pDeviceList += strlen(pDeviceList) + 1;
369 ++i;
370 }
371 }
372
373 printf("enter capture device number: \n");
374 char dev[2];
375 fgets(dev, sizeof(dev), stdin);
376 cs->audio_capture_device = alcCaptureOpenDevice(device_names[dev[0] - 48], AUDIO_SAMPLE_RATE, AL_FORMAT_MONO16,
377 AUDIO_FRAME_SIZE * 4);
378
379 if (alcGetError(cs->audio_capture_device) != AL_NO_ERROR) {
380 printf("could not start capture device! %d\n", alcGetError(cs->audio_capture_device));
381 return 0;
382 }
383
384 int err = OPUS_OK;
385 cs->audio_bitrate = AUDIO_BITRATE;
386 cs->audio_encoder = opus_encoder_create(AUDIO_SAMPLE_RATE, 1, OPUS_APPLICATION_VOIP, &err);
387 err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate));
388 err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10));
389 err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
390
391 opus_encoder_init(cs->audio_encoder, AUDIO_SAMPLE_RATE, 1, OPUS_APPLICATION_VOIP);
392
393 int nfo;
394 err = opus_encoder_ctl(cs->audio_encoder, OPUS_GET_LOOKAHEAD(&nfo));
395 /* printf("Encoder lookahead delay : %d\n", nfo); */
396 printf("init audio encoder successful\n");
397
398 return 1;
399}
400
401int init_encoder(codec_state *cs)
402{
403 avdevice_register_all();
404 avcodec_register_all();
405 avdevice_register_all();
406 av_register_all();
407
408 pthread_mutex_init(&cs->rtp_msg_mutex_lock, NULL);
409 pthread_mutex_init(&cs->avcodec_mutex_lock, NULL);
410
411 cs->support_send_video = init_send_video(cs);
412 cs->support_send_audio = init_send_audio(cs);
413
414 cs->send_audio = 1;
415 cs->send_video = 1;
416
417 return 1;
418}
419
420int init_decoder(codec_state *cs)
421{
422 avdevice_register_all();
423 avcodec_register_all();
424 avdevice_register_all();
425 av_register_all();
426
427 cs->receive_video = 0;
428 cs->receive_audio = 0;
429
430 cs->support_receive_video = init_receive_video(cs);
431 cs->support_receive_audio = init_receive_audio(cs);
432
433 cs->receive_audio = 1;
434 cs->receive_video = 1;
435
436 return 1;
437}
438
439int video_encoder_refresh(codec_state *cs, int bps)
440{
441 if (cs->video_encoder_ctx)
442 avcodec_close(cs->video_encoder_ctx);
443
444 cs->video_encoder = avcodec_find_encoder(VIDEO_CODEC);
445
446 if (!cs->video_encoder) {
447 printf("init video_encoder failed\n");
448 return -1;
449 }
450
451 cs->video_encoder_ctx = avcodec_alloc_context3(cs->video_encoder);
452
453 if (!cs->video_encoder_ctx) {
454 printf("init video_encoder_ctx failed\n");
455 return -1;
456 }
457
458 cs->video_encoder_ctx->bit_rate = bps;
459 cs->video_encoder_ctx->rc_min_rate = cs->video_encoder_ctx->rc_max_rate = cs->video_encoder_ctx->bit_rate;
460 av_opt_set_double(cs->video_encoder_ctx->priv_data, "max-intra-rate", 90, 0);
461 av_opt_set(cs->video_encoder_ctx->priv_data, "quality", "realtime", 0);
462
463 cs->video_encoder_ctx->thread_count = 4;
464 cs->video_encoder_ctx->rc_buffer_aggressivity = 0.95;
465 cs->video_encoder_ctx->rc_buffer_size = bps * 6;
466 cs->video_encoder_ctx->profile = 0;
467 cs->video_encoder_ctx->qmax = 54;
468 cs->video_encoder_ctx->qmin = 4;
469 AVRational myrational = {1, 25};
470 cs->video_encoder_ctx->time_base = myrational;
471 cs->video_encoder_ctx->gop_size = 99999;
472 cs->video_encoder_ctx->pix_fmt = PIX_FMT_YUV420P;
473 cs->video_encoder_ctx->width = cs->webcam_decoder_ctx->width;
474 cs->video_encoder_ctx->height = cs->webcam_decoder_ctx->height;
475
476 if (avcodec_open2(cs->video_encoder_ctx, cs->video_encoder, NULL) < 0) {
477 printf("opening video encoder failed\n");
478 return -1;
479 }
480 return 0;
481}
482
483void *encode_video_thread(void *arg)
484{
485 codec_state *cs = (codec_state *)arg;
486 AVPacket pkt1, *packet = &pkt1;
487 int p = 0;
488 int err;
489 int got_packet;
490 rtp_msg_t *s_video_msg;
491 int video_frame_finished;
492 AVFrame *s_video_frame;
493 AVFrame *webcam_frame;
494 s_video_frame = avcodec_alloc_frame();
495 webcam_frame = avcodec_alloc_frame();
496 AVPacket enc_video_packet;
497
498 uint8_t *buffer;
499 int numBytes;
500 /* Determine required buffer size and allocate buffer */
501 numBytes = avpicture_get_size(PIX_FMT_YUV420P, cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height);
502 buffer = (uint8_t *)av_calloc(numBytes * sizeof(uint8_t),1);
503 avpicture_fill((AVPicture *)s_video_frame, buffer, PIX_FMT_YUV420P, cs->webcam_decoder_ctx->width,
504 cs->webcam_decoder_ctx->height);
505 cs->sws_ctx = sws_getContext(cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height,
506 cs->webcam_decoder_ctx->pix_fmt, cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height, PIX_FMT_YUV420P,
507 SWS_BILINEAR, NULL, NULL, NULL);
508
509 while (!cs->quit && cs->send_video) {
510
511 if (av_read_frame(cs->video_format_ctx, packet) < 0) {
512 printf("error reading frame\n");
513
514 if (cs->video_format_ctx->pb->error != 0)
515 break;
516
517 continue;
518 }
519
520 if (packet->stream_index == cs->video_stream) {
521 if (avcodec_decode_video2(cs->webcam_decoder_ctx, webcam_frame, &video_frame_finished, packet) < 0) {
522 printf("couldn't decode\n");
523 continue;
524 }
525
526 av_free_packet(packet);
527 sws_scale(cs->sws_ctx, (uint8_t const * const *)webcam_frame->data, webcam_frame->linesize, 0,
528 cs->webcam_decoder_ctx->height, s_video_frame->data, s_video_frame->linesize);
529 /* create a new I-frame every 60 frames */
530 ++p;
531
532 if (p == 60) {
533
534 s_video_frame->pict_type = AV_PICTURE_TYPE_BI ;
535 } else if (p == 61) {
536 s_video_frame->pict_type = AV_PICTURE_TYPE_I ;
537 p = 0;
538 } else {
539 s_video_frame->pict_type = AV_PICTURE_TYPE_P ;
540 }
541
542 if (video_frame_finished) {
543 err = avcodec_encode_video2(cs->video_encoder_ctx, &enc_video_packet, s_video_frame, &got_packet);
544
545 if (err < 0) {
546 printf("could not encode video frame\n");
547 continue;
548 }
549
550 if (!got_packet) {
551 continue;
552 }
553
554 pthread_mutex_lock(&cs->rtp_msg_mutex_lock);
555 THREADLOCK()
556
557 if (!enc_video_packet.data) fprintf(stderr, "video packet data is NULL\n");
558
559 s_video_msg = rtp_msg_new ( cs->_rtp_video, enc_video_packet.data, enc_video_packet.size ) ;
560
561 if (!s_video_msg) {
562 printf("invalid message\n");
563 }
564
565 rtp_send_msg ( cs->_rtp_video, s_video_msg, cs->_networking );
566 THREADUNLOCK()
567 pthread_mutex_unlock(&cs->rtp_msg_mutex_lock);
568 av_free_packet(&enc_video_packet);
569 }
570 } else {
571 av_free_packet(packet);
572 }
573 }
574
575 /* clean up codecs */
576 pthread_mutex_lock(&cs->avcodec_mutex_lock);
577 av_free(buffer);
578 av_free(webcam_frame);
579 av_free(s_video_frame);
580 sws_freeContext(cs->sws_ctx);
581 avcodec_close(cs->webcam_decoder_ctx);
582 avcodec_close(cs->video_encoder_ctx);
583 pthread_mutex_unlock(&cs->avcodec_mutex_lock);
584 pthread_exit ( NULL );
585}
586
587void *encode_audio_thread(void *arg)
588{
589 codec_state *cs = (codec_state *)arg;
590 rtp_msg_t *s_audio_msg;
591 unsigned char encoded_data[4096];
592 int encoded_size = 0;
593 int16_t frame[4096];
594 int frame_size = AUDIO_FRAME_SIZE;
595 ALint sample = 0;
596 alcCaptureStart(cs->audio_capture_device);
597
598 while (!cs->quit && cs->send_audio) {
599 alcGetIntegerv(cs->audio_capture_device, ALC_CAPTURE_SAMPLES, (ALCsizei)sizeof(ALint), &sample);
600
601 if (sample >= frame_size) {
602 alcCaptureSamples(cs->audio_capture_device, frame, frame_size);
603 encoded_size = opus_encode(cs->audio_encoder, frame, frame_size, encoded_data, 480);
604
605 if (encoded_size <= 0) {
606 printf("Could not encode audio packet\n");
607 } else {
608 pthread_mutex_lock(&cs->rtp_msg_mutex_lock);
609 THREADLOCK()
610 rtp_set_payload_type(cs->_rtp_audio, 96);
611 s_audio_msg = rtp_msg_new (cs->_rtp_audio, encoded_data, encoded_size) ;
612 rtp_send_msg ( cs->_rtp_audio, s_audio_msg, cs->_networking );
613 pthread_mutex_unlock(&cs->rtp_msg_mutex_lock);
614 THREADUNLOCK()
615 }
616 } else {
617 usleep(1000);
618 }
619 }
620
621 /* clean up codecs */
622 pthread_mutex_lock(&cs->avcodec_mutex_lock);
623 alcCaptureStop(cs->audio_capture_device);
624 alcCaptureCloseDevice(cs->audio_capture_device);
625
626 pthread_mutex_unlock(&cs->avcodec_mutex_lock);
627 pthread_exit ( NULL );
628}
629
630
631int video_decoder_refresh(codec_state *cs, int width, int height)
632{
633 printf("need to refresh\n");
634 screen = SDL_SetVideoMode(width, height, 0, 0);
635
636 if (cs->video_picture.bmp)
637 SDL_FreeYUVOverlay(cs->video_picture.bmp);
638
639 cs->video_picture.bmp = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, screen);
640 cs->sws_SDL_r_ctx = sws_getContext(width, height, cs->video_decoder_ctx->pix_fmt, width, height, PIX_FMT_YUV420P,
641 SWS_BILINEAR, NULL, NULL, NULL);
642 return 1;
643}
644
645void *decode_video_thread(void *arg)
646{
647 codec_state *cs = (codec_state *)arg;
648 cs->video_stream = 0;
649 rtp_msg_t *r_msg;
650 int dec_frame_finished;
651 AVFrame *r_video_frame;
652 r_video_frame = avcodec_alloc_frame();
653 AVPacket dec_video_packet;
654 av_new_packet (&dec_video_packet, 65536);
655 int width = 0;
656 int height = 0;
657
658 while (!cs->quit && cs->receive_video) {
659 r_msg = rtp_recv_msg ( cs->_rtp_video );
660
661 if (r_msg) {
662 memcpy(dec_video_packet.data, r_msg->_data, r_msg->_length);
663 dec_video_packet.size = r_msg->_length;
664 avcodec_decode_video2(cs->video_decoder_ctx, r_video_frame, &dec_frame_finished, &dec_video_packet);
665
666 if (dec_frame_finished) {
667 if (cs->video_decoder_ctx->width != width || cs->video_decoder_ctx->height != height) {
668 width = cs->video_decoder_ctx->width;
669 height = cs->video_decoder_ctx->height;
670 printf("w: %d h%d \n", width, height);
671 video_decoder_refresh(cs, width, height);
672 }
673
674 display_received_frame(cs, r_video_frame);
675 } else {
676 /* TODO: request the sender to create a new i-frame immediatly */
677 printf("bad video packet\n");
678 }
679
680 rtp_free_msg(cs->_rtp_video, r_msg);
681 }
682
683 usleep(1000);
684 }
685
686 printf("vend\n");
687 /* clean up codecs */
688 pthread_mutex_lock(&cs->avcodec_mutex_lock);
689 av_free(r_video_frame);
690 avcodec_close(cs->video_decoder_ctx);
691 pthread_mutex_unlock(&cs->avcodec_mutex_lock);
692 pthread_exit ( NULL );
693}
694
695void *decode_audio_thread(void *arg)
696{
697 codec_state *cs = (codec_state *)arg;
698 rtp_msg_t *r_msg;
699
700 int frame_size = AUDIO_FRAME_SIZE;
701 int data_size;
702
703 ALCdevice *dev;
704 ALCcontext *ctx;
705 ALuint source, *buffers;
706 dev = alcOpenDevice(NULL);
707 ctx = alcCreateContext(dev, NULL);
708 alcMakeContextCurrent(ctx);
709 int openal_buffers = 5;
710
711 buffers = calloc(sizeof(ALuint) * openal_buffers,1);
712 alGenBuffers(openal_buffers, buffers);
713 alGenSources((ALuint)1, &source);
714 alSourcei(source, AL_LOOPING, AL_FALSE);
715
716 ALuint buffer;
717 ALint val;
718
719 ALenum error;
720 uint16_t zeros[frame_size];
721 int i;
722
723 for (i = 0; i < frame_size; i++) {
724 zeros[i] = 0;
725 }
726
727 for (i = 0; i < openal_buffers; ++i) {
728 alBufferData(buffers[i], AL_FORMAT_MONO16, zeros, frame_size, 48000);
729 }
730
731 alSourceQueueBuffers(source, openal_buffers, buffers);
732 alSourcePlay(source);
733
734 if (alGetError() != AL_NO_ERROR) {
735 fprintf(stderr, "Error starting audio\n");
736 cs->quit = 1;
737 }
738
739 struct jitter_buffer *j_buf = NULL;
740
741 j_buf = create_queue(20);
742
743 int success = 0;
744
745 int dec_frame_len;
746
747 opus_int16 PCM[frame_size];
748
749 while (!cs->quit && cs->receive_audio) {
750 THREADLOCK()
751 r_msg = rtp_recv_msg ( cs->_rtp_audio );
752
753 if (r_msg) {
754 /* push the packet into the queue */
755 queue(j_buf, r_msg);
756 }
757
758 /* grab a packet from the queue */
759 success = 0;
760 alGetSourcei(source, AL_BUFFERS_PROCESSED, &val);
761
762 if (val > 0)
763 r_msg = dequeue(j_buf, &success);
764
765 if (success > 0) {
766 /* good packet */
767 if (success == 1) {
768 dec_frame_len = opus_decode(cs->audio_decoder, r_msg->_data, r_msg->_length, PCM, frame_size, 0);
769 rtp_free_msg(cs->_rtp_audio, r_msg);
770 }
771
772 /* lost packet */
773 if (success == 2) {
774 printf("lost packet\n");
775 dec_frame_len = opus_decode(cs->audio_decoder, NULL, 0, PCM, frame_size, 1);
776 }
777
778 if (dec_frame_len > 0) {
779 alGetSourcei(source, AL_BUFFERS_PROCESSED, &val);
780
781 if (val <= 0)
782 continue;
783
784 alSourceUnqueueBuffers(source, 1, &buffer);
785 data_size = av_samples_get_buffer_size(NULL, 1, dec_frame_len, AV_SAMPLE_FMT_S16, 1);
786 alBufferData(buffer, AL_FORMAT_MONO16, PCM, data_size, 48000);
787 int error = alGetError();
788
789 if (error != AL_NO_ERROR) {
790 fprintf(stderr, "Error setting buffer %d\n", error);
791 break;
792 }
793
794 alSourceQueueBuffers(source, 1, &buffer);
795
796 if (alGetError() != AL_NO_ERROR) {
797 fprintf(stderr, "error: could not buffer audio\n");
798 break;
799 }
800
801 alGetSourcei(source, AL_SOURCE_STATE, &val);
802
803 if (val != AL_PLAYING)
804 alSourcePlay(source);
805
806
807 }
808 }
809
810 THREADUNLOCK()
811 usleep(1000);
812 }
813
814 /* clean up codecs */
815 pthread_mutex_lock(&cs->avcodec_mutex_lock);
816
817 /* clean up openal */
818 alDeleteSources(1, &source);
819 alDeleteBuffers(openal_buffers, buffers);
820 alcMakeContextCurrent(NULL);
821 alcDestroyContext(ctx);
822 alcCloseDevice(dev);
823 pthread_mutex_unlock(&cs->avcodec_mutex_lock);
824 pthread_exit ( NULL );
825}
diff --git a/toxmsi/toxmedia.h b/toxmsi/toxmedia.h
deleted file mode 100644
index 8734b173..00000000
--- a/toxmsi/toxmedia.h
+++ /dev/null
@@ -1,168 +0,0 @@
1/* AV_codec.h
2 *
3 * Audio and video codec intitialisation, encoding/decoding and playback
4 *
5 * Copyright (C) 2013 Tox project All Rights Reserved.
6 *
7 * This file is part of Tox.
8 *
9 * Tox is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * Tox is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24/*----------------------------------------------------------------------------------*/
25#ifndef _AVCODEC_H_
26#define _AVCODEC_H_
27
28#include <stdio.h>
29#include <math.h>
30#include <libavcodec/avcodec.h>
31#include <libavformat/avformat.h>
32#include <libswscale/swscale.h>
33#include <libavdevice/avdevice.h>
34#include <libavutil/opt.h>
35#include <pthread.h>
36#include <AL/al.h>
37#include <AL/alc.h>
38#include "toxrtp.h"
39#include "tox.h"
40
41#include <SDL/SDL.h>
42#include <opus/opus.h>
43
44/* ffmpeg VP8 codec ID */
45#define VIDEO_CODEC AV_CODEC_ID_VP8
46
47/* ffmpeg Opus codec ID */
48#define AUDIO_CODEC AV_CODEC_ID_OPUS
49
50/* default video bitrate in bytes/s */
51#define VIDEO_BITRATE 10*1000
52
53/* default audio bitrate in bytes/s */
54#define AUDIO_BITRATE 64000
55
56/* audio frame duration in miliseconds */
57#define AUDIO_FRAME_DURATION 20
58
59/* audio sample rate recommended to be 48kHz for Opus */
60#define AUDIO_SAMPLE_RATE 48000
61
62/* the amount of samples in one audio frame */
63#define AUDIO_FRAME_SIZE AUDIO_SAMPLE_RATE*AUDIO_FRAME_DURATION/1000
64
65/* the quit event for SDL */
66#define FF_QUIT_EVENT (SDL_USEREVENT + 2)
67
68#ifdef __linux__
69#define VIDEO_DRIVER "video4linux2"
70#define DEFAULT_WEBCAM "/dev/video0"
71#endif
72
73#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
74#define VIDEO_DRIVER "vfwcap"
75#define DEFAULT_WEBCAM "0"
76#endif
77
78extern SDL_Surface *screen;
79
80typedef struct {
81 SDL_Overlay *bmp;
82 int width, height;
83} VideoPicture;
84
85
86typedef struct {
87 uint8_t send_audio;
88 uint8_t receive_audio;
89 uint8_t send_video;
90 uint8_t receive_video;
91
92 uint8_t support_send_audio;
93 uint8_t support_send_video;
94 uint8_t support_receive_audio;
95 uint8_t support_receive_video;
96
97 /* video encoding */
98 AVInputFormat *video_input_format;
99 AVFormatContext *video_format_ctx;
100 uint8_t video_stream;
101 AVCodecContext *webcam_decoder_ctx;
102 AVCodec *webcam_decoder;
103 AVCodecContext *video_encoder_ctx;
104 AVCodec *video_encoder;
105
106 /* video decoding */
107 AVCodecContext *video_decoder_ctx;
108 AVCodec *video_decoder;
109
110 /* audio encoding */
111 ALCdevice *audio_capture_device;
112 OpusEncoder *audio_encoder;
113 int audio_bitrate;
114
115 /* audio decoding */
116 OpusDecoder *audio_decoder;
117
118 uint8_t req_video_refresh;
119
120 /* context for converting image format to something SDL can use*/
121 struct SwsContext *sws_SDL_r_ctx;
122
123 /* context for converting webcam image format to something the video encoder can use */
124 struct SwsContext *sws_ctx;
125
126 /* rendered video picture, ready for display */
127 VideoPicture video_picture;
128
129 rtp_session_t *_rtp_video;
130 rtp_session_t *_rtp_audio;
131 int socket;
132 Networking_Core *_networking;
133
134 pthread_t encode_audio_thread;
135 pthread_t encode_video_thread;
136
137 pthread_t decode_audio_thread;
138 pthread_t decode_video_thread;
139
140 pthread_mutex_t rtp_msg_mutex_lock;
141 pthread_mutex_t avcodec_mutex_lock;
142
143 uint8_t quit;
144 SDL_Event SDL_event;
145
146 msi_session_t *_msi;
147 uint32_t _frame_rate;
148 uint16_t _send_port, _recv_port;
149 int _tox_sock;
150 //pthread_id _medialoop_id;
151
152} codec_state;
153
154int display_received_frame(codec_state *cs, AVFrame *r_video_frame);
155int init_receive_audio(codec_state *cs);
156int init_decoder(codec_state *cs);
157int init_send_video(codec_state *cs);
158int init_send_audio(codec_state *cs);
159int init_encoder(codec_state *cs);
160int video_encoder_refresh(codec_state *cs, int bps);
161void *encode_video_thread(void *arg);
162void *encode_audio_thread(void *arg);
163int video_decoder_refresh(codec_state *cs, int width, int height);
164int handle_rtp_video_packet(codec_state *cs, rtp_msg_t *r_msg);
165void *decode_video_thread(void *arg);
166void *decode_audio_thread(void *arg);
167
168#endif
diff --git a/toxmsi/toxmsi.c b/toxmsi/toxmsi.c
deleted file mode 100644
index 38af28fb..00000000
--- a/toxmsi/toxmsi.c
+++ /dev/null
@@ -1,835 +0,0 @@
1
2#ifdef HAVE_CONFIG_H
3#include "config.h"
4#endif /* HAVE_CONFIG_H */
5
6#define _BSD_SOURCE
7
8#include "toxmsi.h"
9#include "toxmsi_event.h"
10#include "toxmsi_message.h"
11#include "../toxrtp/toxrtp_helper.h"
12#include "../toxcore/network.h"
13
14#include <assert.h>
15#include <unistd.h>
16#include <string.h>
17
18#define same(x, y) strcmp((const char*) x, (const char*) y) == 0
19
20typedef enum {
21 error_deadcall = 1, /* has call id but it's from old call */
22 error_id_mismatch, /* non-existing call */
23
24 error_no_callid, /* not having call id */
25 error_no_call, /* no call in session */
26
27 error_busy
28} msi_error_t; /* Error codes */
29
30static inline const uint8_t *stringify_error(msi_error_t _error_code)
31{
32 static const uint8_t* strings[] =
33 {
34 (uint8_t*)"",
35 (uint8_t*)"Using dead call",
36 (uint8_t*)"Call id not set to any call",
37 (uint8_t*)"Call id not available",
38 (uint8_t*)"No active call in session",
39 (uint8_t*)"Callee busy"
40 };
41
42 return strings[_error_code];
43}
44
45static inline const uint8_t *stringify_error_code(msi_error_t _error_code)
46{
47 static const uint8_t* strings[] =
48 {
49 (uint8_t*)"",
50 (uint8_t*)"1",
51 (uint8_t*)"2",
52 (uint8_t*)"3",
53 (uint8_t*)"4",
54 (uint8_t*)"5"
55 };
56
57 return strings[_error_code];
58}
59
60/* ******************* */
61/* --------- GLOBAL FUNCTIONS USED BY THIS FILE --------- */
62
63/* CALLBACKS */
64/*int (*msi_send_message_callback) ( int, uint8_t*, uint32_t ) = NULL;*/
65int ( *msi_send_message_callback ) ( void* _core_handler, tox_IP_Port, uint8_t*, uint32_t ) = NULL;
66int ( *msi_recv_message_callback ) ( tox_IP_Port*, uint8_t*, uint32_t* ) = NULL;
67
68MCBTYPE ( *msi_recv_invite_callback ) ( MCBARGS ) = NULL;
69MCBTYPE ( *msi_start_call_callback ) ( MCBARGS ) = NULL;
70MCBTYPE ( *msi_reject_call_callback ) ( MCBARGS ) = NULL;
71MCBTYPE ( *msi_cancel_call_callback ) ( MCBARGS ) = NULL;
72MCBTYPE ( *msi_end_call_callback ) ( MCBARGS ) = NULL;
73
74MCBTYPE ( *msi_ringing_callback ) ( MCBARGS ) = NULL;
75MCBTYPE ( *msi_starting_callback ) ( MCBARGS ) = NULL;
76MCBTYPE ( *msi_ending_callback ) ( MCBARGS ) = NULL;
77MCBTYPE ( *msi_error_callback ) ( MCBARGS ) = NULL;
78
79MCBTYPE ( *msi_timeout_callback ) ( MCBARGS ) = NULL;
80/* End of CALLBACKS */
81
82/*------------------------*/
83/*------------------------*/
84/*------------------------*/
85/*------------------------*/
86/*------------------------*/
87/*------------------------*/
88/*------------------------*/
89/*------------------------*/
90/*------------------------*/
91/*------------------------*/
92/*------------------------*/
93/*------------------------*/
94
95/* REGISTER CALLBACKS */
96/*void msi_register_callback_send(int (*callback) ( int, uint8_t*, uint32_t ) )*/
97void msi_register_callback_send ( int ( *callback ) ( void* _core_handler, tox_IP_Port, uint8_t*, uint32_t ) )
98{
99 msi_send_message_callback = callback;
100}
101
102void msi_register_callback_recv ( int ( *callback ) ( tox_IP_Port*, uint8_t*, uint32_t* ) )
103{
104 msi_recv_message_callback = callback;
105}
106
107/* Function to be called when received invite.
108 * This callback is all about what you do with it.
109 * Everything else is done internally.
110 */
111void msi_register_callback_recv_invite ( MCALLBACK )
112{
113 msi_recv_invite_callback = callback;
114}
115
116/* Function to be called when the call is started
117 * This callback is all about what you do with it.
118 * Everything else is done internally.
119 */
120void msi_register_callback_call_started ( MCALLBACK )
121{
122 msi_start_call_callback = callback;
123}
124
125/* Function to be called when call is rejected
126 * This callback is all about what you do with it.
127 * Everything else is done internally.
128 */
129void msi_register_callback_call_rejected ( MCALLBACK )
130{
131 msi_reject_call_callback = callback;
132}
133
134/* Function to be called when call is canceled
135 * This callback is all about what you do with it.
136 * Everything else is done internally.
137 */
138void msi_register_callback_call_canceled ( MCALLBACK )
139{
140 msi_cancel_call_callback = callback;
141}
142
143void msi_register_callback_call_ended ( MCALLBACK )
144{
145 msi_end_call_callback = callback;
146}
147
148
149/* Functions to be called when gotten x response */
150
151void msi_register_callback_recv_ringing ( MCALLBACK )
152{
153 msi_ringing_callback = callback;
154}
155void msi_register_callback_recv_starting ( MCALLBACK )
156{
157 msi_starting_callback = callback;
158}
159void msi_register_callback_recv_ending ( MCALLBACK )
160{
161 msi_ending_callback = callback;
162}
163
164void msi_register_callback_recv_error ( MCALLBACK )
165{
166 msi_error_callback = callback;
167}
168
169/* Timeout */
170void msi_register_callback_requ_timeout ( MCALLBACK )
171{
172 msi_timeout_callback = callback;
173}
174/* END REGISTERING */
175
176/*------------------------*/
177/*------------------------*/
178/*------------------------*/
179/*------------------------*/
180/*------------------------*/
181/*------------------------*/
182/*------------------------*/
183/*------------------------*/
184/*------------------------*/
185/*------------------------*/
186/*------------------------*/
187/*------------------------*/
188
189/* Function for receiving and parsing a message that will be used internally */
190
191msi_msg_t* receive_message ( msi_session_t* _session )
192{
193 assert(_session);
194
195
196 msi_msg_t* _retu = _session->_oldest_msg;
197
198 pthread_mutex_lock ( &_session->_mutex );
199
200 if ( _retu )
201 _session->_oldest_msg = _retu->_next;
202
203 if ( !_session->_oldest_msg )
204 _session->_last_msg = NULL;
205
206 pthread_mutex_unlock ( &_session->_mutex );
207
208 return _retu;
209}
210
211void msi_store_msg ( msi_session_t* _session, msi_msg_t* _msg )
212{
213 assert(_session);
214 assert(_msg);
215
216 pthread_mutex_lock ( &_session->_mutex );
217
218 if ( _session->_last_msg ) {
219 _session->_last_msg->_next = _msg;
220 _session->_last_msg = _msg;
221 } else {
222 _session->_last_msg = _session->_oldest_msg = _msg;
223 }
224
225 pthread_mutex_unlock ( &_session->_mutex );
226}
227
228int msi_send_msg ( msi_session_t* _session, msi_msg_t* _msg )
229{
230 int _status;
231
232 if ( !_session->_call ) /* Which should never happen */
233 return FAILURE;
234
235 msi_msg_set_call_id ( _msg, _session->_call->_id );
236
237 uint8_t _msg_string_final [MSI_MAXMSG_SIZE];
238 t_memset ( _msg_string_final, '\0', MSI_MAXMSG_SIZE );
239
240 _msg_string_final[0] = 69;
241
242 uint8_t* _msg_string = msi_msg_to_string ( _msg );
243
244 size_t _lenght = t_memlen ( _msg_string );
245
246 memcpy ( _msg_string_final + 1, _msg_string, _lenght );
247
248 _lenght += 1;
249
250 _status = ( *msi_send_message_callback ) ( _session->_core_handler, _session->_friend_id, _msg_string_final, _lenght );
251
252 free ( _msg_string );
253
254 return _status;
255}
256
257/* Random stuff */
258void flush_peer_type ( msi_session_t* _session, msi_msg_t* _msg, int _peer_id )
259{
260 if ( _msg->_call_type ) {
261 if ( strcmp ( ( const char* ) _msg->_call_type->_header_value, CT_AUDIO_HEADER_VALUE ) == 0 ) {
262 _session->_call->_type_peer[_peer_id] = type_audio;
263
264 } else if ( strcmp ( ( const char* ) _msg->_call_type->_header_value, CT_VIDEO_HEADER_VALUE ) == 0 ) {
265 _session->_call->_type_peer[_peer_id] = type_video;
266 } else {} /* Error */
267 } else {} /* Error */
268}
269
270int has_call_error ( msi_session_t* _session, msi_msg_t* _msg )
271{
272 msi_msg_t* _msg_error = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _error ) );
273
274 if ( !_msg->_call_id ) {
275 msi_msg_set_reason(_msg_error, stringify_error_code(error_no_callid) );
276
277 } else if ( !_session->_call ) {
278 msi_msg_set_reason(_msg_error, stringify_error_code(error_no_call) );
279
280 } else if ( strcmp((const char*)_session->_call->_id, (const char*)_msg->_call_id->_header_value ) != 0 ) {
281 msi_msg_set_reason(_msg_error, stringify_error_code(error_id_mismatch) );
282 }
283
284 if ( _msg_error->_reason ) {
285 msi_send_msg ( _session, _msg_error );
286 msi_free_msg ( _msg_error );
287 return SUCCESS;
288 }
289
290 msi_free_msg ( _msg_error );
291 return FAILURE;
292}
293
294/* --------- END OF GLOBAL FUNCTIONS USED BY THIS FILE --------- */
295
296/*------------------------*/
297/*------------------------*/
298/*------------------------*/
299/*------------------------*/
300/*------------------------*/
301/*------------------------*/
302/*------------------------*/
303/*------------------------*/
304/*------------------------*/
305/*------------------------*/
306/*------------------------*/
307/*------------------------*/
308
309msi_session_t* msi_init_session ( void* _core_handler, const uint8_t* _user_agent )
310{
311 assert(_core_handler);
312 assert(_user_agent);
313
314 msi_session_t* _session = calloc ( sizeof ( msi_session_t ), 1 );
315 assert(_session);
316
317 _session->_oldest_msg = _session->_last_msg = NULL;
318 _session->_core_handler = _core_handler;
319
320 _session->_user_agent = t_strallcpy ( _user_agent );
321 _session->_agent_handler = NULL;
322
323 _session->_key = 0;
324 _session->_call = NULL;
325
326 _session->_frequ = 10000; /* default value? */
327 _session->_call_timeout = 30000; /* default value? */
328
329 /* Use the same frequency */
330 _session->_event_handler = init_event_poll ( _session->_frequ );
331
332 pthread_mutex_init ( &_session->_mutex, NULL );
333
334 return _session;
335}
336
337int msi_terminate_session ( msi_session_t* _session )
338{
339 assert(_session);
340
341 int _status = 0;
342
343 terminate_event_poll ( _session->_event_handler );
344 free ( _session );
345 /* TODO: terminate the rest of the session */
346
347 pthread_mutex_destroy ( &_session->_mutex );
348
349 return _status;
350}
351
352msi_call_t* msi_init_call ( msi_session_t* _session, int _peers, uint32_t _timeoutms )
353{
354 assert(_session);
355 assert(_peers);
356
357 msi_call_t* _call = calloc ( sizeof ( msi_call_t ), 1 );
358 _call->_type_peer = calloc ( sizeof ( call_type ), _peers );
359
360 assert(_call);
361 assert(_call->_type_peer);
362
363 _call->_participants = _peers;
364 _call->_key = _session->_key;
365 _call->_timeoutst = _timeoutms;
366 _call->_outgoing_timer_id = 0;
367
368 return _call;
369}
370
371int msi_terminate_call ( msi_session_t* _session )
372{
373 assert(_session);
374
375 if ( _session->_call->_type_peer )
376 free ( _session->_call->_type_peer );
377
378 cancel_timer_event(_session->_event_handler, _session->_call->_outgoing_timer_id);
379
380 free ( _session->_call );
381
382 _session->_call = NULL;
383
384 return SUCCESS;
385}
386/*------------------------*/
387/*------------------------*/
388/*------------------------*/
389/*------------------------*/
390/*------------------------*/
391/*------------------------*/
392/*------------------------*/
393/*------------------------*/
394/*------------------------*/
395/*------------------------*/
396/*------------------------*/
397/*------------------------*/
398
399/* STATE HANDLERS */
400
401/* REQUESTS */
402int msi_handle_recv_invite ( msi_session_t* _session, msi_msg_t* _msg )
403{
404 assert(_session);
405
406 if ( _session->_call ) {
407 msi_msg_t* _msg_error = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _error ) );
408 msi_msg_set_reason(_msg_error, stringify_error_code(error_busy));
409 msi_send_msg(_session, _msg_error);
410 msi_free_msg(_msg_error);
411
412 return 0;
413 }
414 if ( !_msg->_call_id ) {
415 msi_msg_t* _msg_error = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _error ) );
416 msi_msg_set_reason(_msg_error, stringify_error_code(error_no_callid));
417 msi_send_msg(_session, _msg_error);
418 msi_free_msg(_msg_error);
419 return 0;
420 }
421
422 _session->_call = msi_init_call ( _session, 1, _session->_call_timeout );
423 t_memcpy(_session->_call->_id, _msg->_call_id->_header_value, _CALL_ID_LEN);
424 _session->_call->_state = call_starting;
425
426 flush_peer_type ( _session, _msg, 0 );
427
428 msi_msg_t* _msg_ringing = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _ringing ) );
429 msi_send_msg ( _session, _msg_ringing );
430 msi_free_msg ( _msg_ringing );
431
432 throw_event ( _session->_event_handler, msi_recv_invite_callback, _session );
433 return 1;
434}
435int msi_handle_recv_start ( msi_session_t* _session, msi_msg_t* _msg )
436{
437 assert(_session);
438
439 if ( has_call_error(_session, _msg) == 0 )
440 return 0;
441
442 _session->_call->_state = call_active;
443
444 flush_peer_type ( _session, _msg, 0 );
445
446 throw_event ( _session->_event_handler, msi_start_call_callback, _session );
447 return 1;
448}
449int msi_handle_recv_reject ( msi_session_t* _session, msi_msg_t* _msg )
450{
451 assert(_session);
452
453 if ( has_call_error(_session, _msg) == 0 )
454 return 0;
455
456 msi_msg_t* _msg_end = msi_msg_new ( TYPE_REQUEST, stringify_request ( _end ) );
457 msi_send_msg ( _session, _msg_end );
458 msi_free_msg ( _msg_end );
459
460 throw_event ( _session->_event_handler, msi_reject_call_callback, _session );
461
462 return 1;
463}
464int msi_handle_recv_cancel ( msi_session_t* _session, msi_msg_t* _msg )
465{
466 assert(_session);
467
468 if ( has_call_error(_session, _msg) == 0 )
469 return 0;
470
471 msi_msg_t* _msg_ending = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _ending ) );
472 msi_send_msg ( _session, _msg_ending );
473 msi_free_msg ( _msg_ending );
474
475 msi_terminate_call ( _session );
476
477 throw_event ( _session->_event_handler, msi_cancel_call_callback, _session );
478
479 return 1;
480}
481int msi_handle_recv_end ( msi_session_t* _session, msi_msg_t* _msg )
482{
483 assert(_session);
484
485 if ( has_call_error(_session, _msg) == 0 )
486 return 0;
487
488 msi_msg_t* _msg_ending = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _ending ) );
489 msi_send_msg ( _session, _msg_ending );
490 msi_free_msg ( _msg_ending );
491
492 msi_terminate_call ( _session );
493
494 throw_event ( _session->_event_handler, msi_end_call_callback, _session );
495
496 return 1;
497}
498/*--------*/
499
500/* RESPONSES */
501int msi_handle_recv_ringing ( msi_session_t* _session, msi_msg_t* _msg )
502{
503 assert(_session);
504
505 if ( has_call_error(_session, _msg) == 0 )
506 return 0;
507
508 throw_event ( _session->_event_handler, msi_ringing_callback, _session );
509
510 return 1;
511}
512int msi_handle_recv_starting ( msi_session_t* _session, msi_msg_t* _msg )
513{
514 assert(_session);
515
516 if ( has_call_error(_session, _msg) == 0 )
517 return 0;
518
519 _session->_call->_state = call_active;
520
521 msi_msg_t* _msg_start = msi_msg_new ( TYPE_REQUEST, stringify_request ( _start ) );
522 msi_send_msg ( _session, _msg_start );
523 msi_free_msg ( _msg_start );
524
525 flush_peer_type ( _session, _msg, 0 );
526
527 throw_event ( _session->_event_handler, msi_starting_callback, _session );
528 cancel_timer_event(_session->_event_handler, _session->_call->_outgoing_timer_id);
529 _session->_call->_outgoing_timer_id = 0;
530
531 return 1;
532}
533int msi_handle_recv_ending ( msi_session_t* _session, msi_msg_t* _msg )
534{
535 assert(_session);
536
537 if ( has_call_error(_session, _msg) == 0 )
538 return 0;
539
540 msi_terminate_call ( _session );
541 throw_event ( _session->_event_handler, msi_ending_callback, _session );
542
543 return 1;
544}
545int msi_handle_recv_error ( msi_session_t* _session, msi_msg_t* _msg )
546{
547 assert(_session);
548 assert(_session->_call);
549
550 /* Handle error accordingly */
551 if ( _msg->_reason ) {
552 _session->_last_error_id = atoi((const char*)_msg->_reason->_header_value);
553 _session->_last_error_str = stringify_error(_session->_last_error_id);
554 }
555
556 msi_terminate_call(_session);
557
558 throw_event ( _session->_event_handler, msi_error_callback, _session );
559
560 return 1;
561}
562/* ------------------ */
563
564MCBTYPE msi_handle_timeout (void* _arg)
565{
566 msi_session_t* _session = _arg;
567 msi_terminate_call(_session);
568
569 (*msi_timeout_callback) (_arg);
570 (*msi_ending_callback) (_arg);
571
572}
573
574/*------------------------*/
575/*------------------------*/
576/*------------------------*/
577/*------------------------*/
578/*------------------------*/
579/*------------------------*/
580/*------------------------*/
581/*------------------------*/
582/*------------------------*/
583/*------------------------*/
584/*------------------------*/
585/*------------------------*/
586
587int msi_invite ( msi_session_t* _session, call_type _call_type, uint32_t _timeoutms )
588{
589 assert(_session);
590
591 if ( !msi_send_message_callback )
592 return 0;
593
594 msi_msg_t* _msg_invite = msi_msg_new ( TYPE_REQUEST, stringify_request ( _invite ) );
595
596 _session->_call = msi_init_call ( _session, 1, _timeoutms ); /* Just one for now */
597 msi_genterate_call_id(_session->_call->_id, _CALL_ID_LEN);
598 _session->_call->_type_local = _call_type;
599 /* Do whatever with message */
600
601 if ( _call_type == type_audio ) {
602 msi_msg_set_call_type ( _msg_invite, ( const uint8_t* ) CT_AUDIO_HEADER_VALUE );
603 } else {
604 msi_msg_set_call_type ( _msg_invite, ( const uint8_t* ) CT_VIDEO_HEADER_VALUE );
605 }
606
607 msi_send_msg ( _session, _msg_invite );
608 msi_free_msg ( _msg_invite );
609
610 _session->_call->_state = call_inviting;
611
612 _session->_call->_outgoing_timer_id = throw_timer_event(_session->_event_handler, msi_handle_timeout, _session, _timeoutms );
613
614 return 1;
615}
616int msi_hangup ( msi_session_t* _session )
617{
618 assert(_session);
619
620 if ( !_session->_call || ( !msi_send_message_callback && _session->_call->_state != call_active ) )
621 return 0;
622
623 msi_msg_t* _msg_ending = msi_msg_new ( TYPE_REQUEST, stringify_request ( _end ) );
624 msi_send_msg ( _session, _msg_ending );
625 msi_free_msg ( _msg_ending );
626
627 return 1;
628}
629
630
631int msi_answer ( msi_session_t* _session, call_type _call_type )
632{
633 assert(_session);
634
635 if ( !msi_send_message_callback || !_session->_call )
636 return 0;
637
638 msi_msg_t* _msg_starting = msi_msg_new ( TYPE_RESPONSE, stringify_response ( _starting ) );
639 _session->_call->_type_local = _call_type;
640
641 if ( _call_type == type_audio ) {
642 msi_msg_set_call_type ( _msg_starting, ( const uint8_t* ) CT_AUDIO_HEADER_VALUE );
643 } else {
644 msi_msg_set_call_type ( _msg_starting, ( const uint8_t* ) CT_VIDEO_HEADER_VALUE );
645 }
646
647 msi_send_msg ( _session, _msg_starting );
648 msi_free_msg ( _msg_starting );
649
650 _session->_call->_state = call_active;
651 return 1;
652}
653int msi_cancel ( msi_session_t* _session )
654{
655 assert(_session);
656
657 if ( !_session->_call || !msi_send_message_callback )
658 return 0;
659
660 msi_msg_t* _msg_cancel = msi_msg_new ( TYPE_REQUEST, stringify_request ( _cancel ) );
661 msi_send_msg ( _session, _msg_cancel );
662 msi_free_msg ( _msg_cancel );
663
664
665
666 return 1;
667}
668int msi_reject ( msi_session_t* _session )
669{
670 assert(_session);
671
672 if ( !_session->_call || !msi_send_message_callback )
673 return 0;
674
675 msi_msg_t* _msg_reject = msi_msg_new ( TYPE_REQUEST, stringify_request ( _reject ) );
676 msi_send_msg ( _session, _msg_reject );
677 msi_free_msg ( _msg_reject );
678
679 return 1;
680}
681
682/*------------------------*/
683/*------------------------*/
684/*------------------------*/
685/*------------------------*/
686/*------------------------*/
687/*------------------------*/
688/*------------------------*/
689/*------------------------*/
690/*------------------------*/
691/*------------------------*/
692/*------------------------*/
693/*------------------------*/
694
695/* OUR MAIN POOL FUNCTION */
696/*
697 * Forks it self to other thread and then handles the session initiation.
698 *
699 * BASIC call flow:
700 *
701 * ALICE BOB
702 * | invite --> |
703 * | |
704 * | <-- ringing |
705 * | |
706 * | <-- starting |
707 * | |
708 * | start --> |
709 * | |
710 * | <-- MEDIA TRANS --> |
711 * | |
712 * | end --> |
713 * | |
714 * | <-- ending |
715 *
716 * Alice calls Bob by sending invite packet.
717 * Bob recvs the packet and sends an ringing packet;
718 * which notifies Alice that her invite is acknowledged.
719 * Ringing screen shown on both sides.
720 * Bob accepts the invite for a call by sending starting packet.
721 * Alice recvs the starting packet and sends the started packet to
722 * inform Bob that she recved the starting packet.
723 * Now the media transmission is established ( i.e. RTP transmission ).
724 * Alice hangs up and sends end packet.
725 * Bob recves the end packet and sends ending packet
726 * as the acknowledgement that the call is ending.
727 *
728 *
729 */
730
731
732/*
733 * Needs a bit more work on the protocol
734 */
735void* msi_poll_stack ( void* _session_p )
736{
737 msi_session_t* _session = ( msi_session_t* ) _session_p;
738 msi_msg_t* _msg = NULL;
739
740 uint32_t* _frequ = &_session->_frequ;
741 while ( _session ) {
742
743 /* At this point it's already parsed */
744 _msg = receive_message ( _session );
745
746 if ( _msg ) {
747
748 if ( _msg->_request ) { /* Handle request */
749
750 const uint8_t* _request_value = _msg->_request->_header_value;
751
752 if ( same ( _request_value, stringify_request ( _invite ) ) ) {
753 msi_handle_recv_invite ( _session, _msg );
754
755 } else if ( same ( _request_value, stringify_request ( _start ) ) ) {
756 msi_handle_recv_start ( _session, _msg );
757
758 } else if ( same ( _request_value, stringify_request ( _cancel ) ) ) {
759 msi_handle_recv_cancel ( _session, _msg );
760
761 } else if ( same ( _request_value, stringify_request ( _reject ) ) ) {
762 msi_handle_recv_reject ( _session, _msg );
763
764 } else if ( same ( _request_value, stringify_request ( _end ) ) ) {
765 msi_handle_recv_end ( _session, _msg );
766 }
767
768 } else if ( _msg->_response ) { /* Handle response */
769
770 const uint8_t* _response_value = _msg->_response->_header_value;
771
772 if ( same ( _response_value, stringify_response ( _ringing ) ) ) {
773 msi_handle_recv_ringing ( _session, _msg );
774
775 } else if ( same ( _response_value, stringify_response ( _starting ) ) ) {
776 msi_handle_recv_starting ( _session, _msg );
777
778 } else if ( same ( _response_value, stringify_response ( _ending ) ) ) {
779 msi_handle_recv_ending ( _session, _msg );
780
781 } else if ( same ( _response_value, stringify_response ( _error ) ) ) {
782 msi_handle_recv_error ( _session, _msg );
783 }
784
785 }
786
787 msi_free_msg ( _msg );
788
789 }
790 usleep ( *_frequ );
791 }
792
793 return NULL;
794}
795
796/*------------------------*/
797/*------------------------*/
798/*------------------------*/
799/*------------------------*/
800/*------------------------*/
801/*------------------------*/
802/*------------------------*/
803/*------------------------*/
804/*------------------------*/
805/*------------------------*/
806/*------------------------*/
807/*------------------------*/
808
809/* Easy way to start the poll */
810
811pthread_t msi_start_main_loop ( msi_session_t* _session, uint32_t _frequms )
812{
813 assert(_session);
814
815 int _status;
816 pthread_t _thread_id;
817
818
819 _session->_frequ = _frequms * 1000;
820
821 _status = pthread_create ( &_thread_id, NULL, msi_poll_stack, _session );
822
823 if ( _status < 0 ) {
824 printf ( "Error while starting main loop: %d, %s\n", errno, strerror ( errno ) );
825 return _status;
826 }
827
828 _status = pthread_detach ( _thread_id );
829
830 if ( _status < 0 ) {
831 printf ( "Error while starting main loop: %d, %s\n", errno, strerror ( errno ) );
832 }
833
834 return _thread_id;
835}
diff --git a/toxmsi/toxmsi.h b/toxmsi/toxmsi.h
deleted file mode 100644
index d8985c64..00000000
--- a/toxmsi/toxmsi.h
+++ /dev/null
@@ -1,145 +0,0 @@
1/* msi_initiation.h
2*
3* Has function for session initiation along with session description.
4* It follows the Tox API ( http://wiki.tox.im/index.php/Messaging_Protocol ). !Red!
5*
6*
7* Copyright (C) 2013 Tox project All Rights Reserved.
8*
9* This file is part of Tox.
10*
11* Tox is free software: you can redistribute it and/or modify
12* it under the terms of the GNU General Public License as published by
13* the Free Software Foundation, either version 3 of the License, or
14* (at your option) any later version.
15*
16* Tox is distributed in the hope that it will be useful,
17* but WITHOUT ANY WARRANTY; without even the implied warranty of
18* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19* GNU General Public License for more details.
20*
21* You should have received a copy of the GNU General Public License
22* along with Tox. If not, see <http://www.gnu.org/licenses/>.
23*
24*/
25
26
27#ifndef _MSI_IMPL_H_
28#define _MSI_IMPL_H_
29
30#include <inttypes.h>
31#include "tox.h"
32#include <pthread.h>
33
34#define MCBTYPE void
35#define MCBARGS void* _arg
36#define MCALLBACK MCBTYPE(*callback)(void* _arg)
37
38#define MSI_PACKET 69
39
40#define CT_AUDIO_HEADER_VALUE "AUDIO"
41#define CT_VIDEO_HEADER_VALUE "VIDEO"
42
43/* define size for call_id */
44#define _CALL_ID_LEN 12
45
46typedef enum {
47 type_audio = 1,
48 type_video,
49} call_type;
50
51typedef enum {
52 call_inviting, /* when sending call invite */
53 call_starting, /* when getting call invite */
54 call_active,
55 call_hold
56
57} call_state;
58
59typedef int crypto_key;
60
61typedef struct msi_call_s { /* Call info structure */
62 call_state _state;
63 call_type _type_local;
64 call_type* _type_peer; /* Support for conference starts with this */
65 uint8_t _id[_CALL_ID_LEN]; /* Random value identifying the call */
66 crypto_key _key; /* What is the type again? */
67 uint16_t _participants; /* Number of participants */
68 uint32_t _timeoutst; /* Time of the timeout for some action to end; 0 if infinite */
69 int _outgoing_timer_id; /* Timer id */
70
71} msi_call_t;
72
73typedef struct msi_session_s {
74 pthread_mutex_t _mutex;
75
76 crypto_key _key; /* The key */
77
78 /* Call information/handler. ( Maybe only information? ) */
79 msi_call_t* _call;
80
81 /* Storage for message receiving */
82 struct msi_msg_s* _oldest_msg;
83 struct msi_msg_s* _last_msg; /* tail */
84
85 /*int _friend_id;*/
86 tox_IP_Port _friend_id;
87
88 int _last_error_id; /* Determine the last error */
89 const uint8_t* _last_error_str;
90
91 const uint8_t* _user_agent;
92
93 void* _agent_handler; /* Pointer to an object that is handling msi */
94 void* _core_handler; /* Pointer to networking core or to anything that
95 * should handle interaction with core/networking
96 */
97 void* _event_handler; /* Pointer to an object which handles the events */
98
99 uint32_t _frequ;
100 uint32_t _call_timeout; /* Time of the timeout for some action to end; 0 if infinite */
101} msi_session_t;
102
103
104
105msi_session_t* msi_init_session ( void* _core_handler, const uint8_t* _user_agent );
106int msi_terminate_session ( msi_session_t* _session );
107
108pthread_t msi_start_main_loop ( msi_session_t* _session, uint32_t _frequms );
109
110/* Registering callbacks */
111
112/*void msi_register_callback_send(int (*callback) ( int, uint8_t*, uint32_t ) );*/
113void msi_register_callback_send ( int ( *callback ) ( void* _core_handler, tox_IP_Port, uint8_t*, uint32_t ) );
114
115/* Callbacks that handle the states */
116void msi_register_callback_call_started ( MCALLBACK );
117void msi_register_callback_call_canceled ( MCALLBACK );
118void msi_register_callback_call_rejected ( MCALLBACK );
119void msi_register_callback_call_ended ( MCALLBACK );
120
121void msi_register_callback_recv_invite ( MCALLBACK );
122void msi_register_callback_recv_ringing ( MCALLBACK );
123void msi_register_callback_recv_starting ( MCALLBACK );
124void msi_register_callback_recv_ending ( MCALLBACK );
125void msi_register_callback_recv_error ( MCALLBACK );
126
127void msi_register_callback_requ_timeout ( MCALLBACK );
128/* -------- */
129
130
131/* Function handling receiving from core */
132/*static int msi_handlepacket ( tox_IP_Port ip_port, uint8_t* _data, uint16_t _lenght ); */
133
134/* functions describing the usage of msi */
135int msi_invite ( msi_session_t* _session, call_type _call_type, uint32_t _timeoutms );
136int msi_hangup ( msi_session_t* _session );
137
138int msi_answer ( msi_session_t* _session, call_type _call_type );
139int msi_cancel ( msi_session_t* _session );
140int msi_reject ( msi_session_t* _session );
141
142int msi_send_msg ( msi_session_t* _session, struct msi_msg_s* _msg );
143void msi_store_msg ( msi_session_t* _session, struct msi_msg_s* _msg );
144
145#endif /* _MSI_IMPL_H_ */
diff --git a/toxmsi/toxmsi_event.c b/toxmsi/toxmsi_event.c
deleted file mode 100644
index d8c0d269..00000000
--- a/toxmsi/toxmsi_event.c
+++ /dev/null
@@ -1,214 +0,0 @@
1
2#ifdef HAVE_CONFIG_H
3#include "config.h"
4#endif /* HAVE_CONFIG_H */
5
6#include <stdlib.h>
7
8#include "toxmsi_event.h"
9
10#include "../toxrtp/toxrtp_helper.h"
11#include <assert.h>
12#include <stdlib.h>
13#include <unistd.h>
14
15static int _unique_id = 1;
16
17/* clear events */
18void clear_events (event_container_t** _event_container, size_t* _counter)
19{
20 assert( *_event_container );
21
22 free(*_event_container);
23 *_event_container = NULL;
24
25 *_counter = 0;
26}
27
28int pop_id ( event_container_t** _event_container, size_t* _counter, int _id )
29{
30 if ( !*_event_container || !*_counter || !_id )
31 return FAILURE;
32
33 event_container_t* _it = *_event_container;
34 int i;
35
36 for ( i = *_counter; i > 0 ; -- i ){
37 if ( _it->_id == _id ) { /* Hit! */
38 break;
39 }
40 ++_it;
41 }
42
43 if ( i ) {
44 for ( ; i > 0; -- i ){ *_it = *(_it + 1); ++_it; }
45 -- (*_counter);
46 *_event_container = realloc(*_event_container, sizeof(event_container_t) * (*_counter)); /* resize */
47
48 if ( *_counter )
49 assert(*_event_container);
50
51 return SUCCESS;
52
53 } else {
54 assert(i);
55 return FAILURE;
56 }
57}
58
59/* main poll for event execution */
60void* event_poll( void* _event_handler_p )
61{
62 event_handler_t* _event_handler = _event_handler_p;
63 uint32_t* _frequms = &_event_handler->_frequms;
64
65
66 while ( _event_handler->_running )
67 {
68
69 if ( _event_handler->_events_count ){
70 pthread_mutex_lock(&_event_handler->_mutex);
71
72 int i;
73 for ( i = 0; i < _event_handler->_events_count; i ++ ){
74 _event_handler->_events[i]._event(_event_handler->_events[i]._event_args);
75
76 }
77 clear_events(&_event_handler->_events, &_event_handler->_events_count);
78
79 pthread_mutex_unlock(&_event_handler->_mutex);
80 }
81
82 if ( _event_handler->_timed_events_count ){
83 pthread_mutex_lock(&_event_handler->_mutex);
84
85 uint32_t _time = t_time();
86
87 if ( _event_handler->_timed_events[0]._timeout < _time ) {
88 _event_handler->_timed_events[0]._event(_event_handler->_timed_events[0]._event_args);
89
90 pop_id(&_event_handler->_timed_events,
91 &_event_handler->_timed_events_count,
92 _event_handler->_timed_events[0]._id);
93 }
94 pthread_mutex_unlock(&_event_handler->_mutex);
95 }
96
97
98 usleep(*_frequms);
99 }
100
101 _event_handler->_running = -1;
102 pthread_exit(NULL);
103}
104
105void push_event ( event_container_t** _container, size_t* _counter, event_t _func, event_arg_t _arg )
106{
107 (*_counter)++;
108 (*_container) = realloc((*_container), sizeof(event_container_t) * (*_counter));
109 assert((*_container) != NULL);
110
111 (*_container[*_counter - 1])._event = _func;
112 (*_container[*_counter - 1])._event_args = _arg;
113 (*_container[*_counter - 1])._timeout = 0;
114 (*_container[*_counter - 1])._id = 0;
115}
116
117void throw_event( void* _event_handler_p, event_t _func, event_arg_t _arg )
118{
119 if ( !_func )
120 return;
121
122 event_handler_t* _event_handler = _event_handler_p;
123
124 pthread_mutex_lock(&_event_handler->_mutex);
125
126 push_event(&_event_handler->_events, &_event_handler->_events_count, _func, _arg);
127
128 pthread_mutex_unlock(&_event_handler->_mutex);
129}
130
131int throw_timer_event ( void* _event_handler_p, event_t _func, event_arg_t _arg, uint32_t _timeout)
132{
133 if ( !_func )
134 return FAILURE;
135
136 event_handler_t* _event_handler = _event_handler_p;
137
138 pthread_mutex_lock(&_event_handler->_mutex);
139
140 push_event(&_event_handler->_timed_events, &_event_handler->_timed_events_count, _func, _arg);
141 size_t _counter = _event_handler->_timed_events_count;
142 _event_handler->_timed_events[_counter - 1]._timeout = _timeout + t_time();
143 _event_handler->_timed_events[_counter - 1]._id = _unique_id; ++_unique_id;
144
145
146 /* reorder */
147 if ( _counter > 1 ) {
148
149 int i = _counter - 1;
150 /* start from behind excluding last added member */
151 event_container_t* _it = &_event_handler->_timed_events[i - 1];
152
153 event_container_t _last_added = _event_handler->_timed_events[i];
154
155 for ( ; i > 0; --i ) {
156 if ( _it->_timeout > _timeout ){
157 *(_it + 1) = *_it;
158 *_it = _last_added; -- _it;
159 }
160 }
161
162 }
163
164 pthread_mutex_unlock(&_event_handler->_mutex);
165
166 return _event_handler->_timed_events[_counter - 1]._id;
167}
168int cancel_timer_event ( void* _event_handler_p, int _id )
169{
170 event_handler_t* _event_handler = _event_handler_p;
171 return pop_id(&_event_handler->_timed_events, &_event_handler->_timed_events_count, _id);
172}
173
174event_handler_t* init_event_poll (uint32_t _frequms)
175{
176 event_handler_t* _retu = calloc(sizeof(event_handler_t), 1);
177 assert(_retu);
178 /* Initialize basic events */
179 _retu->_events = NULL ;
180
181 /* Initialize timed events */
182 _retu->_timed_events = NULL;
183
184 _retu->_frequms = _frequms;
185 _retu->_running = 1;
186 pthread_mutex_init(&_retu->_mutex, NULL);
187
188 pthread_create(&_retu->_thread_id, NULL, event_poll, _retu);
189 int _rc = pthread_detach(_retu->_thread_id);
190 assert(_rc == 0);
191
192 return _retu;
193}
194
195int terminate_event_poll(event_handler_t* _handler)
196{
197 if ( !_handler )
198 return FAILURE;
199
200 _handler->_running = 0;
201 while (_handler->_running != -1); /* Wait for execution */
202
203 if (_handler->_events)
204 clear_events(&_handler->_events, &_handler->_events_count);
205 if (_handler->_events)
206 clear_events(&_handler->_timed_events, &_handler->_timed_events_count);
207
208 pthread_mutex_destroy( &_handler->_mutex );
209
210 free(_handler);
211
212 return SUCCESS;
213}
214
diff --git a/toxmsi/toxmsi_event.h b/toxmsi/toxmsi_event.h
deleted file mode 100644
index 032e4df5..00000000
--- a/toxmsi/toxmsi_event.h
+++ /dev/null
@@ -1,46 +0,0 @@
1#ifndef _MSI__EVENT_H_
2#define _MSI__EVENT_H_
3
4#include <stddef.h>
5#include <inttypes.h>
6#include <pthread.h>
7
8typedef void* event_arg_t;
9
10typedef void ( *event_t ) ( event_arg_t );
11typedef void ( *timed_event_t ) ( event_arg_t );
12
13typedef struct event_container_s {
14 event_t _event;
15 event_arg_t _event_args;
16 uint32_t _timeout;
17 long long _id;
18
19} event_container_t;
20
21typedef struct event_handler_s {
22 event_container_t* _events;
23 size_t _events_count;
24
25 event_container_t* _timed_events;
26 size_t _timed_events_count;
27
28 uint32_t _frequms;
29 int _running;
30
31 pthread_mutex_t _mutex;
32 pthread_t _thread_id;
33
34} event_handler_t;
35
36event_handler_t* init_event_poll ( uint32_t _frequms );
37int terminate_event_poll ( event_handler_t* _event_handler );
38
39void throw_event ( void* _event_handler_p, event_t _func, event_arg_t _arg );
40
41/* Not yet ready for use */
42int throw_timer_event ( void* _event_handler_p, event_t _func, event_arg_t _arg, uint32_t _timeout);
43int cancel_timer_event ( void* _event_handler_p, int _id );
44
45
46#endif /* _MSI__EVENT_H_ */
diff --git a/toxmsi/toxmsi_header.c b/toxmsi/toxmsi_header.c
deleted file mode 100644
index 448ebc7f..00000000
--- a/toxmsi/toxmsi_header.c
+++ /dev/null
@@ -1,181 +0,0 @@
1
2#ifdef HAVE_CONFIG_H
3#include "config.h"
4#endif /* HAVE_CONFIG_H */
5
6#include "toxmsi_message.h"
7#include <string.h>
8#include "../toxrtp/toxrtp_helper.h"
9#include <assert.h>
10#include "../toxcore/Lossless_UDP.h"
11
12#define ALLOC_ADD_DATA(_tempval, _hdrlist, _fielddef, _msgvar, _alloctype) \
13_tempval = msi_search_field(_hdrlist, (const uint8_t*)_fielddef); \
14if ( _tempval ){ \
15 _msgvar = calloc(sizeof(_alloctype), 1); \
16 assert(_msgvar); \
17 _msgvar->_header_value = _tempval; \
18}
19
20uint8_t* msi_search_field ( msi_header_t* _list, const uint8_t* _field )
21{
22 assert(_list);
23 assert(_field);
24
25 msi_header_t* _iterator;
26
27 for ( _iterator = _list;
28 _iterator && strcmp((const char*)_iterator->_header_field, (const char*)_field) != 0;
29 _iterator = _iterator->next );
30
31 if ( _iterator ){
32 return t_strallcpy(_iterator->_header_value);
33 } else return NULL;
34}
35
36int msi_parse_headers ( msi_msg_t* _msg )
37{
38 assert(_msg);
39
40 if ( !_msg->_headers )
41 return FAILURE;
42
43 msi_header_t* _list = _msg->_headers;
44 uint8_t* _field_current;
45
46 ALLOC_ADD_DATA(_field_current, _list, _CALL_ID_FIELD, _msg->_call_id, msi_header_call_id_t)
47 ALLOC_ADD_DATA(_field_current, _list, _VERSION_FIELD, _msg->_version, msi_header_version_t)
48 ALLOC_ADD_DATA(_field_current, _list, _REQUEST_FIELD, _msg->_request, msi_header_request_t)
49 ALLOC_ADD_DATA(_field_current, _list, _RESPONSE_FIELD, _msg->_response, msi_header_response_t)
50 ALLOC_ADD_DATA(_field_current, _list, _FRIENDID_FIELD, _msg->_friend_id, msi_header_friendid_t)
51 ALLOC_ADD_DATA(_field_current, _list, _CALLTYPE_FIELD, _msg->_call_type, msi_header_call_type_t)
52 ALLOC_ADD_DATA(_field_current, _list, _USERAGENT_FIELD, _msg->_user_agent, msi_header_user_agent_t)
53 ALLOC_ADD_DATA(_field_current, _list, _INFO_FIELD, _msg->_info, msi_header_info_t)
54 ALLOC_ADD_DATA(_field_current, _list, _REASON_FIELD, _msg->_reason, msi_header_reason_t)
55
56 /* Since we don't need the raw header anymore remove it */
57 msi_header_t* _temp;
58 while ( _list ){
59 _temp = _list->next;
60 free(_list->_header_field);
61 free(_list->_header_value);
62 free(_list);
63 _list = _temp;
64 }
65
66 _msg->_headers = NULL;
67
68 return SUCCESS;
69}
70
71/*
72 * If you find better way of parsing values let me know
73 */
74msi_header_t* msi_add_new_header ( uint8_t* _value )
75{
76 if ( !_value )
77 return NULL;
78
79 size_t _length = t_memlen(_value);
80
81 if ( !_length ) {
82 return NULL;
83 }
84
85 size_t _first_len = t_strfind(_value, (const uint8_t*)" ");
86 if ( !_first_len ){
87 return NULL;
88 }
89
90 size_t _second_len = (_length - _first_len);
91 if ( !_second_len ){
92 return NULL;
93 }
94
95
96 uint8_t* _identifier = calloc(sizeof (uint8_t), (_first_len + 1) );
97 uint8_t* _data = calloc(sizeof (uint8_t), (_second_len + 1) );
98
99 assert(_identifier);
100 assert(_data);
101
102
103 uint8_t* _p_it = _value;
104 size_t _num_it;
105
106 for ( _num_it = 0; *_p_it != ' '; _num_it++ ){
107 _identifier[_num_it] = *_p_it;
108 ++_p_it;
109 }
110 _identifier[_num_it] = '\0';
111 ++_p_it;
112
113
114 for ( _num_it = 0; *_p_it != '\r'; _num_it++ ){
115 _data[_num_it] = *_p_it;
116 ++_p_it;
117 }
118 _data[_num_it] = '\r';
119 _data[_num_it + 1] = '\0';
120
121 msi_header_t* _retu = calloc(sizeof(msi_header_t), 1);
122 assert(_retu);
123
124 _retu->_header_field = _identifier;
125 _retu->_header_value = _data;
126
127 _retu->next = NULL;
128
129 return _retu;
130}
131
132msi_header_t* msi_parse_raw_data ( const uint8_t* _data )
133{
134 assert(_data);
135
136 uint8_t* _header_string;
137
138 _header_string = (uint8_t*) strtok ((char*)_data, _RAW_TERMINATOR);
139
140 msi_header_t* _head = msi_add_new_header(_header_string);
141 msi_header_t* _it = _head;
142
143 while ( _header_string && _it ){
144
145 _header_string = (uint8_t*) strtok (NULL, _RAW_TERMINATOR);
146 _it->next = msi_add_new_header(_header_string);
147 if ( _it->next ){
148 _it = _it->next;
149 }
150 }
151
152 /* Iterate through list and remove all fault headers if any */
153
154 msi_header_t* _tmp = _it;
155
156 for ( _it = _head; _it; _it = _it->next ){
157
158 if ( !_it->_header_value || !_it->_header_field ) {
159 _tmp ->next = _it->next;
160
161 if ( _it->_header_field )
162 free(_it->_header_field);
163 if ( _it->_header_value )
164 free(_it->_header_value);
165
166 if ( _it == _head ){
167 _head = _head->next;
168 }
169
170 free(_it);
171 _it = _tmp;
172 } else
173 _tmp = _it;
174
175 }
176
177 return _head;
178}
179
180
181
diff --git a/toxmsi/toxmsi_header.h b/toxmsi/toxmsi_header.h
deleted file mode 100644
index 599fafa3..00000000
--- a/toxmsi/toxmsi_header.h
+++ /dev/null
@@ -1,99 +0,0 @@
1#ifndef _MSI_HEADER_
2#define _MSI_HEADER_
3
4/* Basic format of the unparsed header string
5 * ( No spaces in field allowed )
6 * Version 0.1.1\n\r
7 * Request INVITE\n\r
8 * Response\n\r
9 * Friend-id ( from ip )\n\r
10 * Call-type AUDIO\n\r
11 * User-agent phone-v.1.0.0\n\r
12 */
13
14
15/* define raw header terminator */
16static const char* _RAW_TERMINATOR = "\n\r";
17
18/* define string formats for the identifiers */
19#define _VERSION_FIELD "Version"
20#define _REQUEST_FIELD "Request"
21#define _RESPONSE_FIELD "Response"
22#define _FRIENDID_FIELD "Friend-id"
23#define _CALLTYPE_FIELD "Call-type"
24#define _USERAGENT_FIELD "User-agent"
25#define _INFO_FIELD "INFO"
26#define _REASON_FIELD "Reason"
27#define _CALL_ID_FIELD "Call-id"
28
29#define HEADER_VALUES \
30/*uint8_t* _header_field */ \
31uint8_t* _header_value;
32
33typedef struct msi_header_s { /* raw header list */
34 uint8_t* _header_field;
35 uint8_t* _header_value;
36
37 struct msi_header_s* next;
38
39} msi_header_t;
40
41
42
43typedef struct msi_header_version_s { /* Defines our version */
44 HEADER_VALUES
45
46} msi_header_version_t;
47
48typedef struct msi_header_request_s { /* Defines our request */
49 HEADER_VALUES
50
51} msi_header_request_t;
52
53typedef struct msi_header_response_s { /* Defines our response */
54 HEADER_VALUES
55
56} msi_header_response_t;
57
58typedef struct msi_header_friendid_s { /* Defines source that sent the message */
59 HEADER_VALUES
60
61} msi_header_friendid_t;
62
63typedef struct msi_header_call_type_s { /* Defines the type of the call */
64 HEADER_VALUES
65
66} msi_header_call_type_t;
67
68typedef struct msi_header_user_agent_s { /* Defines the device of the participant */
69 HEADER_VALUES
70
71} msi_header_user_agent_t;
72
73
74typedef struct msi_header_call_id_s { /* Call id that is used to identify the call */
75 HEADER_VALUES
76
77} msi_header_call_id_t;
78
79typedef struct msi_header_info_s { /* Defines informational message header */
80 HEADER_VALUES
81
82} msi_header_info_t;
83
84typedef struct msi_header_reason_s { /* Defines reason mostly for error messages */
85 HEADER_VALUES
86
87} msi_header_reason_t;
88
89struct msi_msg_s;
90
91/*
92 * Parses the header list to header types
93 */
94int msi_parse_headers ( struct msi_msg_s* _msg );
95
96/* Make sure it's null terminated */
97msi_header_t* msi_parse_raw_data ( const uint8_t* _data );
98
99#endif /* _MSI_HEADER_ */
diff --git a/toxmsi/toxmsi_message.c b/toxmsi/toxmsi_message.c
deleted file mode 100644
index 72d7ee01..00000000
--- a/toxmsi/toxmsi_message.c
+++ /dev/null
@@ -1,267 +0,0 @@
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif /* HAVE_CONFIG_H */
4
5#include "toxmsi_message.h"
6#include <stdlib.h>
7#include <string.h>
8#include "../toxrtp/toxrtp_helper.h"
9#include <assert.h>
10#include <stdlib.h>
11
12#define ALLOCATE_HEADER(_header_type, _var, _m_header_value) \
13_var = calloc( sizeof(_header_type), 1 ); \
14assert(_var); \
15_var->_header_value = t_strallcpy((const uint8_t*)_m_header_value);
16
17#define DEALLOCATE_HEADER(_header) \
18if ( _header && _header->_header_value ) { \
19free( _header->_header_value ); \
20free( _header ); }
21
22#define SET_HEADER(_header_type, _var, _m_header_value) \
23if ( _var ){ \
24free(_var->_header_value); \
25free(_var);} \
26ALLOCATE_HEADER( _header_type, _var, _m_header_value )
27
28
29/* Sets empty message
30 */
31void set_msg ( msi_msg_t* _msg )
32{
33 _msg->_call_type = NULL;
34 _msg->_version = NULL;
35 _msg->_request = NULL;
36 _msg->_response = NULL;
37 _msg->_friend_id = NULL;
38 _msg->_user_agent = NULL;
39 _msg->_call_id = NULL;
40 _msg->_reason = NULL;
41 _msg->_info = NULL;
42 _msg->_next = NULL;
43 _msg->_headers = NULL;
44}
45
46void msi_free_msg ( msi_msg_t* _msg )
47{
48 assert(_msg);
49
50 DEALLOCATE_HEADER(_msg->_call_type);
51 DEALLOCATE_HEADER(_msg->_friend_id);
52 DEALLOCATE_HEADER(_msg->_request);
53 DEALLOCATE_HEADER(_msg->_response);
54 DEALLOCATE_HEADER(_msg->_user_agent);
55 DEALLOCATE_HEADER(_msg->_version);
56 DEALLOCATE_HEADER(_msg->_info);
57 DEALLOCATE_HEADER(_msg->_reason);
58 DEALLOCATE_HEADER(_msg->_call_id);
59
60 free(_msg);
61}
62
63void append_header_to_string ( uint8_t* _dest, const uint8_t* _header_field, const uint8_t* _header_value )
64{
65 assert(_dest);
66 assert(_header_value);
67 assert(_header_field);
68
69 size_t _dest_len = t_memlen(_dest);
70
71 uint8_t* _storage_iterator = _dest + _dest_len;
72 const uint8_t* _header_fit = _header_field;
73 const uint8_t* _header_val = _header_value;
74 const uint8_t* _term_it = (const uint8_t*) _RAW_TERMINATOR;
75
76 while ( *_header_fit ){
77 *_storage_iterator = *_header_fit;
78 ++_header_fit;
79 ++_storage_iterator;
80 }
81
82 *_storage_iterator = ' '; /* place space */
83 ++_storage_iterator;
84
85 while ( *_header_val ){
86 *_storage_iterator = *_header_val;
87 ++_header_val;
88 ++_storage_iterator;
89 }
90
91 while ( *_term_it ){
92 *_storage_iterator = *_term_it;
93 ++_term_it;
94 ++_storage_iterator;
95 }
96}
97
98msi_msg_t* msi_parse_msg ( const uint8_t* _data )
99{
100 assert(_data);
101
102 msi_msg_t* _retu = calloc ( sizeof ( msi_msg_t ), 1 );
103 assert(_retu);
104
105 set_msg(_retu);
106
107 _retu->_headers = msi_parse_raw_data ( _data );
108
109 if ( msi_parse_headers (_retu) == FAILURE ) {
110 msi_free_msg(_retu);
111 return NULL;
112 }
113
114 if ( !_retu->_version || strcmp((const char*)_retu->_version->_header_value, VERSION_STRING) != 0 ){
115 msi_free_msg(_retu);
116 return NULL;
117 }
118
119 return _retu;
120}
121
122
123uint8_t* msi_msg_to_string ( msi_msg_t* _msg )
124{
125 assert(_msg);
126
127 uint8_t* _retu = calloc(sizeof(uint8_t), MSI_MAXMSG_SIZE );
128 assert(_retu);
129
130 t_memset(_retu, '\0', MSI_MAXMSG_SIZE);
131
132 if ( _msg->_version ){
133 append_header_to_string(_retu, (const uint8_t*)_VERSION_FIELD, _msg->_version->_header_value);
134 }
135
136 if ( _msg->_request ){
137 append_header_to_string(_retu, (const uint8_t*)_REQUEST_FIELD, _msg->_request->_header_value);
138 }
139
140 if ( _msg->_response ){
141 append_header_to_string(_retu, (const uint8_t*)_RESPONSE_FIELD, _msg->_response->_header_value);
142 }
143
144 if ( _msg->_friend_id ){
145 append_header_to_string(_retu, (const uint8_t*)_FRIENDID_FIELD, _msg->_friend_id->_header_value);
146 }
147
148 if ( _msg->_call_type ){
149 append_header_to_string(_retu, (const uint8_t*)_CALLTYPE_FIELD, _msg->_call_type->_header_value);
150 }
151
152 if ( _msg->_user_agent ){
153 append_header_to_string(_retu, (const uint8_t*)_USERAGENT_FIELD, _msg->_user_agent->_header_value);
154 }
155
156 if ( _msg->_info ){
157 append_header_to_string(_retu, (const uint8_t*)_INFO_FIELD, _msg->_info->_header_value);
158 }
159
160 if ( _msg->_call_id ){
161 append_header_to_string(_retu, (const uint8_t*)_CALL_ID_FIELD, _msg->_call_id->_header_value);
162 }
163
164 if ( _msg->_reason ){
165 append_header_to_string(_retu, (const uint8_t*)_REASON_FIELD, _msg->_reason->_header_value);
166 }
167
168 return _retu;
169}
170
171msi_msg_t* msi_msg_new ( uint8_t _type, const uint8_t* _typeid )
172{
173 msi_msg_t* _retu = calloc ( sizeof ( msi_msg_t ), 1 );
174 assert(_retu);
175
176 set_msg(_retu);
177
178 if ( _type == TYPE_REQUEST ){
179 ALLOCATE_HEADER( msi_header_request_t, _retu->_request, _typeid )
180 _retu->_response = NULL;
181
182 } else if ( _type == TYPE_RESPONSE ) {
183 ALLOCATE_HEADER( msi_header_response_t, _retu->_response, _typeid )
184 _retu->_request = NULL;
185
186 } else {
187 msi_free_msg(_retu);
188 return NULL;
189 }
190
191
192 ALLOCATE_HEADER( msi_header_version_t, _retu->_version, VERSION_STRING)
193
194 _retu->_friend_id = NULL;
195 _retu->_call_type = NULL;
196 _retu->_user_agent = NULL;
197 _retu->_info = NULL;
198
199 _retu->_next = NULL;
200
201 return _retu;
202}
203
204uint8_t* msi_genterate_call_id ( uint8_t* _storage, size_t _len )
205{
206 assert(_storage);
207
208 static const char _alphanum[] =
209 "0123456789"
210 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
211 "abcdefghijklmnopqrstuvwxyz"; /* avoids warning */
212
213 uint8_t _val = 0;
214 size_t _it;
215
216 /* Generate random values 1-255 */
217 for ( _it = 0; _it < _len; _it ++ ) {
218 while ( !_val ) _val = (uint8_t) _alphanum[ t_random(61) ];
219
220 _storage[_it] = _val;
221 _val = 0;
222 }
223
224 return _storage;
225}
226
227/* HEADER SETTING
228 */
229
230void msi_msg_set_call_type ( msi_msg_t* _msg, const uint8_t* _header_field )
231{
232 assert(_msg);
233 assert(_header_field);
234
235 SET_HEADER(msi_header_call_type_t, _msg->_call_type, _header_field)
236}
237void msi_msg_set_user_agent ( msi_msg_t* _msg, const uint8_t* _header_field )
238{
239 assert(_msg);
240 assert(_header_field);
241
242 SET_HEADER(msi_header_user_agent_t, _msg->_user_agent, _header_field)
243}
244void msi_msg_set_friend_id ( msi_msg_t* _msg, const uint8_t* _header_field )
245{
246 assert(_msg);
247 assert(_header_field);
248
249 SET_HEADER(msi_header_friendid_t, _msg->_friend_id, _header_field)
250}
251void msi_msg_set_info ( msi_msg_t* _msg, const uint8_t* _header_field )
252{
253}
254void msi_msg_set_reason ( msi_msg_t* _msg, const uint8_t* _header_field )
255{
256 assert(_msg);
257 assert(_header_field);
258
259 SET_HEADER(msi_header_reason_t, _msg->_reason, _header_field)
260}
261void msi_msg_set_call_id ( msi_msg_t* _msg, const uint8_t* _header_field )
262{
263 assert(_msg);
264 assert(_header_field);
265
266 SET_HEADER(msi_header_call_id_t, _msg->_call_id, _header_field)
267}
diff --git a/toxmsi/toxmsi_message.h b/toxmsi/toxmsi_message.h
deleted file mode 100644
index 87dfccc2..00000000
--- a/toxmsi/toxmsi_message.h
+++ /dev/null
@@ -1,120 +0,0 @@
1#ifndef _MSI_MESSAGE_H_
2#define _MSI_MESSAGE_H_
3
4#ifdef HAVE_CONFIG_H
5#include "config.h"
6#endif /* HAVE_CONFIG_H */
7
8#include <inttypes.h>
9#include "../toxcore/network.h"
10#include "../toxcore/tox.h"
11
12#include "toxmsi_header.h"
13
14#define TYPE_REQUEST 1
15#define TYPE_RESPONSE 2
16
17#define VERSION_STRING "0.2.2"
18
19#define MSI_MAXMSG_SIZE 65535
20
21typedef enum {
22 _invite,
23 _start,
24 _cancel,
25 _reject,
26 _end,
27
28} msi_request_t;
29
30static inline const uint8_t *stringify_request(msi_request_t _request)
31{
32 static const uint8_t* strings[] =
33 {
34 (uint8_t*)"INVITE",
35 (uint8_t*)"START",
36 (uint8_t*)"CANCEL",
37 (uint8_t*)"REJECT",
38 (uint8_t*)"END"
39 };
40
41 return strings[_request];
42}
43
44typedef enum {
45 _trying,
46 _ringing,
47 _starting,
48 _ending,
49 _error
50
51} msi_response_t;
52
53static inline const uint8_t *stringify_response(msi_response_t _response)
54{
55 static const uint8_t* strings[] =
56 {
57 (uint8_t*)"trying",
58 (uint8_t*)"ringing",
59 (uint8_t*)"starting",
60 (uint8_t*)"ending",
61 (uint8_t*)"error"
62 };
63
64 return strings[_response];
65}
66
67
68typedef struct msi_msg_s {
69 /* This is the header list which contains unparsed headers */
70 msi_header_t* _headers;
71
72 /* Headers parsed */
73 msi_header_version_t* _version;
74 msi_header_request_t* _request;
75 msi_header_response_t* _response;
76 msi_header_friendid_t* _friend_id;
77 msi_header_call_type_t* _call_type;
78 msi_header_user_agent_t* _user_agent;
79 msi_header_info_t* _info;
80 msi_header_reason_t* _reason;
81 msi_header_call_id_t* _call_id;
82
83 /* Pointer to next member since it's list duuh */
84 struct msi_msg_s* _next;
85
86} msi_msg_t;
87
88
89/*
90 * Parse data received from socket
91 */
92msi_msg_t* msi_parse_msg ( const uint8_t* _data );
93
94/*
95 * Make new message. Arguments: _type: (request, response); _type_field ( value )
96 */
97msi_msg_t* msi_msg_new ( uint8_t _type, const uint8_t* _type_field );
98
99/* Header setting */
100void msi_msg_set_call_type ( msi_msg_t* _msg, const uint8_t* _header_field );
101void msi_msg_set_user_agent ( msi_msg_t* _msg, const uint8_t* _header_field );
102void msi_msg_set_friend_id ( msi_msg_t* _msg, const uint8_t* _header_field );
103void msi_msg_set_info ( msi_msg_t* _msg, const uint8_t* _header_field );
104void msi_msg_set_reason ( msi_msg_t* _msg, const uint8_t* _header_field );
105void msi_msg_set_call_id ( msi_msg_t* _msg, const uint8_t* _header_field );
106
107
108uint8_t* msi_genterate_call_id ( uint8_t* _storage, size_t _len );
109/*
110 * Parses message struct to string.
111 * Allocates memory so don't forget to free it
112 */
113uint8_t* msi_msg_to_string ( msi_msg_t* _msg );
114
115/*
116 * msi_msg_s struct deallocator
117 */
118void msi_free_msg ( msi_msg_t* _msg );
119
120#endif /* _MSI_MESSAGE_H_ */