summaryrefslogtreecommitdiff
path: root/toxmsi/phone.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxmsi/phone.c')
-rw-r--r--toxmsi/phone.c668
1 files changed, 0 insertions, 668 deletions
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 */