summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--toxav/media.c (renamed from toxav/toxmedia.c)206
-rw-r--r--toxav/media.h (renamed from toxav/toxmedia.h)29
-rw-r--r--[-rwxr-xr-x]toxav/msi.c (renamed from toxav/toxmsi.c)44
-rw-r--r--[-rwxr-xr-x]toxav/msi.h (renamed from toxav/toxmsi.h)9
-rwxr-xr-xtoxav/phone.c465
-rw-r--r--[-rwxr-xr-x]toxav/rtp.c (renamed from toxav/toxrtp.c)3
-rw-r--r--[-rwxr-xr-x]toxav/rtp.h (renamed from toxav/toxrtp.h)0
-rw-r--r--toxav/toxav.c352
-rw-r--r--toxav/toxav.h129
9 files changed, 818 insertions, 419 deletions
diff --git a/toxav/toxmedia.c b/toxav/media.c
index a31b9ab0..e18c1803 100644
--- a/toxav/toxmedia.c
+++ b/toxav/media.c
@@ -37,9 +37,8 @@
37#include <opus/opus.h> 37#include <opus/opus.h>
38#include <assert.h> 38#include <assert.h>
39 39
40#include "toxmsi.h" 40#include "rtp.h"
41#include "toxrtp.h" 41#include "media.h"
42#include "toxmedia.h"
43 42
44struct jitter_buffer { 43struct jitter_buffer {
45 RTPMessage **queue; 44 RTPMessage **queue;
@@ -79,8 +78,6 @@ struct jitter_buffer *create_queue(int capacity)
79/* returns 1 if 'a' has a higher sequence number than 'b' */ 78/* returns 1 if 'a' has a higher sequence number than 'b' */
80uint8_t sequence_number_older(uint16_t sn_a, uint16_t sn_b, uint32_t ts_a, uint32_t ts_b) 79uint8_t sequence_number_older(uint16_t sn_a, uint16_t sn_b, uint32_t ts_a, uint32_t ts_b)
81{ 80{
82 /* should be stable enough */
83
84 /* TODO: There is already this kind of function in toxrtp.c. 81 /* TODO: There is already this kind of function in toxrtp.c.
85 * Maybe merge? 82 * Maybe merge?
86 */ 83 */
@@ -141,7 +138,6 @@ int empty_queue(struct jitter_buffer *q)
141{ 138{
142 while (q->size > 0) { 139 while (q->size > 0) {
143 q->size--; 140 q->size--;
144 /* FIXME: */
145 rtp_free_msg(NULL, q->queue[q->front]); 141 rtp_free_msg(NULL, q->queue[q->front]);
146 q->front++; 142 q->front++;
147 143
@@ -207,64 +203,56 @@ int queue(struct jitter_buffer *q, RTPMessage *pk)
207 return 0; 203 return 0;
208} 204}
209 205
210int init_receive_audio(codec_state *cs)
211{
212 int rc;
213 cs->audio_decoder = opus_decoder_create(48000, 1, &rc );
214
215 if ( rc != OPUS_OK ){
216 printf("Error while starting audio decoder!\n");
217 return 0;
218 }
219
220 rc = opus_decoder_init(cs->audio_decoder, 48000, 1);
221
222 if ( rc != OPUS_OK ){
223 printf("Error while starting audio decoder!\n");
224 return 0;
225 }
226
227
228 printf("Init audio decoder successful\n");
229 return 1;
230}
231 206
232int init_receive_video(codec_state *cs) 207int init_video_decoder(CodecState *cs)
233{ 208{
234 cs->video_decoder = avcodec_find_decoder(VIDEO_CODEC); 209 cs->video_decoder = avcodec_find_decoder(VIDEO_CODEC);
235 210
236 if (!cs->video_decoder) { 211 if (!cs->video_decoder) {
237 printf("Init video_decoder failed\n"); 212 fprintf(stderr, "Init video_decoder failed!\n");
238 return 0; 213 return -1;
239 } 214 }
240 215
241 cs->video_decoder_ctx = avcodec_alloc_context3(cs->video_decoder); 216 cs->video_decoder_ctx = avcodec_alloc_context3(cs->video_decoder);
242 217
243 if (!cs->video_decoder_ctx) { 218 if (!cs->video_decoder_ctx) {
244 printf("Init video_decoder_ctx failed\n"); 219 fprintf(stderr, "Init video_decoder_ctx failed!\n");
245 return 0; 220 return -1;
246 } 221 }
247 222
248 if (avcodec_open2(cs->video_decoder_ctx, cs->video_decoder, NULL) < 0) { 223 if (avcodec_open2(cs->video_decoder_ctx, cs->video_decoder, NULL) < 0) {
249 printf("Opening video decoder failed\n"); 224 fprintf(stderr, "Opening video decoder failed!\n");
250 return 0; 225 return -1;
251 } 226 }
227
228 return 0;
229}
252 230
253 printf("Init video decoder successful\n"); 231int init_audio_decoder(CodecState *cs, uint32_t audio_channels)
254 return 1; 232{
233 int rc;
234 cs->audio_decoder = opus_decoder_create(cs->audio_sample_rate, audio_channels, &rc );
235
236 if ( rc != OPUS_OK ){
237 fprintf(stderr, "Error while starting audio decoder!\n");
238 return -1;
239 }
240
241 return 0;
255} 242}
256 243
257int init_send_video(codec_state *cs) 244
245int init_video_encoder(CodecState *cs, const char* webcam, const char* video_driver, uint32_t video_bitrate)
258{ 246{
259 cs->video_input_format = av_find_input_format(VIDEO_DRIVER); 247 cs->video_input_format = av_find_input_format(video_driver);
260 248
261 if (avformat_open_input(&cs->video_format_ctx, DEFAULT_WEBCAM, cs->video_input_format, NULL) != 0) { 249 if (avformat_open_input(&cs->video_format_ctx, webcam, cs->video_input_format, NULL) != 0) {
262 printf("opening video_input_format failed\n"); 250 fprintf(stderr, "Opening video_input_format failed!\n");
263 return 0; 251 return -1;
264 } 252 }
265 253
266 avformat_find_stream_info(cs->video_format_ctx, NULL); 254 avformat_find_stream_info(cs->video_format_ctx, NULL);
267 av_dump_format(cs->video_format_ctx, 0, DEFAULT_WEBCAM, 0); 255 av_dump_format(cs->video_format_ctx, 0, webcam, 0);
268 256
269 int i; 257 int i;
270 258
@@ -279,42 +267,42 @@ int init_send_video(codec_state *cs)
279 cs->webcam_decoder = avcodec_find_decoder(cs->webcam_decoder_ctx->codec_id); 267 cs->webcam_decoder = avcodec_find_decoder(cs->webcam_decoder_ctx->codec_id);
280 268
281 if (cs->webcam_decoder == NULL) { 269 if (cs->webcam_decoder == NULL) {
282 printf("Unsupported codec\n"); 270 fprintf(stderr, "Unsupported codec!\n");
283 return 0; 271 return -1;
284 } 272 }
285 273
286 if (cs->webcam_decoder_ctx == NULL) { 274 if (cs->webcam_decoder_ctx == NULL) {
287 printf("init webcam_decoder_ctx failed\n"); 275 fprintf(stderr, "Init webcam_decoder_ctx failed!\n");
288 return 0; 276 return -1;
289 } 277 }
290 278
291 if (avcodec_open2(cs->webcam_decoder_ctx, cs->webcam_decoder, NULL) < 0) { 279 if (avcodec_open2(cs->webcam_decoder_ctx, cs->webcam_decoder, NULL) < 0) {
292 printf("opening webcam decoder failed\n"); 280 fprintf(stderr, "Opening webcam decoder failed!\n");
293 return 0; 281 return -1;
294 } 282 }
295 283
296 cs->video_encoder = avcodec_find_encoder(VIDEO_CODEC); 284 cs->video_encoder = avcodec_find_encoder(VIDEO_CODEC);
297 285
298 if (!cs->video_encoder) { 286 if (!cs->video_encoder) {
299 printf("init video_encoder failed\n"); 287 fprintf(stderr, "Init video_encoder failed!\n");
300 return 0; 288 return -1;
301 } 289 }
302 290
303 cs->video_encoder_ctx = avcodec_alloc_context3(cs->video_encoder); 291 cs->video_encoder_ctx = avcodec_alloc_context3(cs->video_encoder);
304 292
305 if (!cs->video_encoder_ctx) { 293 if (!cs->video_encoder_ctx) {
306 printf("init video_encoder_ctx failed\n"); 294 fprintf(stderr, "Init video_encoder_ctx failed!\n");
307 return 0; 295 return -1;
308 } 296 }
309 297
310 cs->video_encoder_ctx->bit_rate = VIDEO_BITRATE; 298 cs->video_encoder_ctx->bit_rate = video_bitrate;
311 cs->video_encoder_ctx->rc_min_rate = cs->video_encoder_ctx->rc_max_rate = cs->video_encoder_ctx->bit_rate; 299 cs->video_encoder_ctx->rc_min_rate = cs->video_encoder_ctx->rc_max_rate = cs->video_encoder_ctx->bit_rate;
312 av_opt_set_double(cs->video_encoder_ctx->priv_data, "max-intra-rate", 90, 0); 300 av_opt_set_double(cs->video_encoder_ctx->priv_data, "max-intra-rate", 90, 0);
313 av_opt_set(cs->video_encoder_ctx->priv_data, "quality", "realtime", 0); 301 av_opt_set(cs->video_encoder_ctx->priv_data, "quality", "realtime", 0);
314 302
315 cs->video_encoder_ctx->thread_count = 4; 303 cs->video_encoder_ctx->thread_count = 4;
316 cs->video_encoder_ctx->rc_buffer_aggressivity = 0.95; 304 cs->video_encoder_ctx->rc_buffer_aggressivity = 0.95;
317 cs->video_encoder_ctx->rc_buffer_size = VIDEO_BITRATE * 6; 305 cs->video_encoder_ctx->rc_buffer_size = video_bitrate * 6;
318 cs->video_encoder_ctx->profile = 3; 306 cs->video_encoder_ctx->profile = 3;
319 cs->video_encoder_ctx->qmax = 54; 307 cs->video_encoder_ctx->qmax = 54;
320 cs->video_encoder_ctx->qmin = 4; 308 cs->video_encoder_ctx->qmin = 4;
@@ -326,66 +314,84 @@ int init_send_video(codec_state *cs)
326 cs->video_encoder_ctx->height = cs->webcam_decoder_ctx->height; 314 cs->video_encoder_ctx->height = cs->webcam_decoder_ctx->height;
327 315
328 if (avcodec_open2(cs->video_encoder_ctx, cs->video_encoder, NULL) < 0) { 316 if (avcodec_open2(cs->video_encoder_ctx, cs->video_encoder, NULL) < 0) {
329 printf("opening video encoder failed\n"); 317 fprintf(stderr, "Opening video encoder failed!\n");
330 return 0; 318 return -1;
331 } 319 }
332 320
333 printf("init video encoder successful\n"); 321 return 0;
334 return 1;
335} 322}
336 323
337int init_send_audio(codec_state *cs) 324int init_audio_encoder(CodecState *cs)
338{ 325{
339 cs->support_send_audio = 0;
340
341 int err = OPUS_OK; 326 int err = OPUS_OK;
342 cs->audio_bitrate = AUDIO_BITRATE; 327 cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, 1, OPUS_APPLICATION_VOIP, &err);
343 cs->audio_encoder = opus_encoder_create(AUDIO_SAMPLE_RATE, 1, OPUS_APPLICATION_VOIP, &err); 328
344 err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate)); 329 err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate));
345 err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10)); 330 err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10));
346 err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); 331 err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
347 332
333 /* NOTE: What do we do with this? */
348 int nfo; 334 int nfo;
349 err = opus_encoder_ctl(cs->audio_encoder, OPUS_GET_LOOKAHEAD(&nfo)); 335 err = opus_encoder_ctl(cs->audio_encoder, OPUS_GET_LOOKAHEAD(&nfo));
350 /* printf("Encoder lookahead delay : %d\n", nfo); */ 336
351 printf("init audio encoder successful\n"); 337 return err == OPUS_OK ? 0 : -1;
352
353 return 1;
354} 338}
355 339
356int init_encoder(codec_state *cs) 340
341CodecState* codec_init_session ( uint32_t audio_bitrate,
342 uint16_t audio_frame_duration,
343 uint32_t audio_sample_rate,
344 uint32_t audio_channels,
345 uint32_t video_bitrate,
346 const char* webcam,
347 const char* webcam_driver )
357{ 348{
349 CodecState* _retu = av_calloc(sizeof(CodecState), 1);
350 assert(_retu);
351
352
358 avdevice_register_all(); 353 avdevice_register_all();
359 avcodec_register_all(); 354 avcodec_register_all();
360 avdevice_register_all();
361 av_register_all(); 355 av_register_all();
362 356
363 pthread_mutex_init(&cs->ctrl_mutex, NULL); 357
364 358 _retu->audio_bitrate = audio_bitrate;
365 cs->support_send_video = init_send_video(cs); 359 _retu->audio_sample_rate = audio_sample_rate;
366 cs->support_send_audio = init_send_audio(cs); 360
367 361 pthread_mutex_init(&_retu->ctrl_mutex, NULL);
368 cs->send_audio = 1; 362
369 cs->send_video = 1; 363
370 364 /* Encoders */
371 return 1; 365 if ( 0 == init_video_encoder(_retu, webcam, webcam_driver, video_bitrate) )
366 printf("Video encoder initialized!\n");
367
368 if ( 0 == init_audio_encoder(_retu) )
369 printf("Audio encoder initialized!\n");
370
371
372 /* Decoders */
373 if ( 0 == init_video_decoder(_retu) )
374 printf("Video decoder initialized!\n");
375
376 if ( 0 == init_audio_decoder(_retu, audio_channels) )
377 printf("Audio decoder initialized!\n");
378
379
380 return _retu;
372} 381}
373 382
374int init_decoder(codec_state *cs) 383void codec_terminate_session ( CodecState* cs )
375{ 384{
376 avdevice_register_all(); 385 if ( cs->audio_encoder ) {
377 avcodec_register_all(); 386 opus_encoder_destroy(cs->audio_encoder);
378 avdevice_register_all(); 387 printf("Terminated encoder!\n");
379 av_register_all(); 388 }
380 389
381 cs->receive_video = 0; 390 if ( cs->audio_decoder ) {
382 cs->receive_audio = 0; 391 opus_decoder_destroy(cs->audio_decoder);
383 392 printf("Terminated decoder!\n");
384 cs->support_receive_video = init_receive_video(cs); 393 }
385 cs->support_receive_audio = init_receive_audio(cs); 394
386 395 /* TODO: Terminate video */
387 cs->receive_audio = 1; 396
388 cs->receive_video = 1; 397}
389
390 return 1;
391} \ No newline at end of file
diff --git a/toxav/toxmedia.h b/toxav/media.h
index 65d1e320..ef2de27c 100644
--- a/toxav/toxmedia.h
+++ b/toxav/media.h
@@ -27,8 +27,6 @@
27 27
28#include <stdio.h> 28#include <stdio.h>
29#include <math.h> 29#include <math.h>
30#include "toxrtp.h"
31#include "toxmsi.h"
32#include "../toxcore/tox.h" 30#include "../toxcore/tox.h"
33 31
34/* Video encoding/decoding */ 32/* Video encoding/decoding */
@@ -75,16 +73,7 @@
75#define DEFAULT_WEBCAM "0" 73#define DEFAULT_WEBCAM "0"
76#endif 74#endif
77 75
78typedef struct { 76typedef struct _CodecState{
79 uint8_t send_audio;
80 uint8_t receive_audio;
81 uint8_t send_video;
82 uint8_t receive_video;
83
84 uint8_t support_send_audio;
85 uint8_t support_send_video;
86 uint8_t support_receive_audio;
87 uint8_t support_receive_video;
88 77
89 /* video encoding */ 78 /* video encoding */
90 AVInputFormat *video_input_format; 79 AVInputFormat *video_input_format;
@@ -102,19 +91,19 @@ typedef struct {
102 /* audio encoding */ 91 /* audio encoding */
103 OpusEncoder *audio_encoder; 92 OpusEncoder *audio_encoder;
104 int audio_bitrate; 93 int audio_bitrate;
94 int audio_sample_rate;
105 95
106 /* audio decoding */ 96 /* audio decoding */
107 OpusDecoder *audio_decoder; 97 OpusDecoder *audio_decoder;
108
109 uint8_t req_video_refresh;
110 98
111 pthread_mutex_t ctrl_mutex; 99 pthread_mutex_t ctrl_mutex;
112 100
113 101
114 uint32_t frame_rate; 102 uint32_t frame_rate;
115 103
116} codec_state; 104} CodecState;
117 105
106typedef struct _RTPMessage RTPMessage;
118 107
119struct jitter_buffer *create_queue(int capacity); 108struct jitter_buffer *create_queue(int capacity);
120int empty_queue(struct jitter_buffer *q); 109int empty_queue(struct jitter_buffer *q);
@@ -123,8 +112,14 @@ int queue(struct jitter_buffer *q, RTPMessage *pk);
123RTPMessage *dequeue(struct jitter_buffer *q, int *success); 112RTPMessage *dequeue(struct jitter_buffer *q, int *success);
124 113
125 114
126int init_encoder(codec_state *cs); 115CodecState* codec_init_session( uint32_t audio_bitrate,
127int init_decoder(codec_state *cs); 116 uint16_t audio_frame_duration,
117 uint32_t audio_sample_rate,
118 uint32_t audio_channels,
119 uint32_t video_bitrate,
120 const char* webcam,
121 const char* webcam_driver );
128 122
123void codec_terminate_session(CodecState* cs);
129 124
130#endif 125#endif
diff --git a/toxav/toxmsi.c b/toxav/msi.c
index d5c35730..014a904f 100755..100644
--- a/toxav/toxmsi.c
+++ b/toxav/msi.c
@@ -29,7 +29,7 @@
29 29
30#define _BSD_SOURCE 30#define _BSD_SOURCE
31 31
32#include "toxmsi.h" 32#include "msi.h"
33#include "../toxcore/util.h" 33#include "../toxcore/util.h"
34#include "../toxcore/network.h" 34#include "../toxcore/network.h"
35#include "../toxcore/event.h" 35#include "../toxcore/event.h"
@@ -335,8 +335,6 @@ MSIMessage* msi_new_message ( uint8_t type, const uint8_t* type_id ) {
335 MSIMessage* _retu = calloc ( sizeof ( MSIMessage ), 1 ); 335 MSIMessage* _retu = calloc ( sizeof ( MSIMessage ), 1 );
336 assert ( _retu ); 336 assert ( _retu );
337 337
338 memset ( _retu, 0, sizeof ( MSIMessage ) );
339
340 if ( type == TYPE_REQUEST ) { 338 if ( type == TYPE_REQUEST ) {
341 ALLOCATE_HEADER ( _retu->request, type_id, strlen ( (const char*)type_id ) ) 339 ALLOCATE_HEADER ( _retu->request, type_id, strlen ( (const char*)type_id ) )
342 340
@@ -641,7 +639,7 @@ int handle_error ( MSISession* session, MSICallError errid, uint32_t to ) {
641 session->last_error_id = errid; 639 session->last_error_id = errid;
642 session->last_error_str = stringify_error ( errid ); 640 session->last_error_str = stringify_error ( errid );
643 641
644 event.rise ( callbacks[MSI_OnError], session ); 642 event.rise ( callbacks[MSI_OnError], session->agent_handler );
645 643
646 return 0; 644 return 0;
647} 645}
@@ -692,12 +690,12 @@ void* handle_timeout ( void* arg )
692 /* Cancel all? */ 690 /* Cancel all? */
693 uint16_t _it = 0; 691 uint16_t _it = 0;
694 for ( ; _it < _peer_count; _it++ ) 692 for ( ; _it < _peer_count; _it++ )
695 msi_cancel ( arg, _peers[_it] ); 693 msi_cancel ( arg, _peers[_it], (const uint8_t*)"Timeout" );
696 694
697 } 695 }
698 696
699 ( *callbacks[MSI_OnTimeout] ) ( arg ); 697 ( *callbacks[MSI_OnTimeout] ) ( _session->agent_handler );
700 ( *callbacks[MSI_OnEnding ] ) ( arg ); 698 ( *callbacks[MSI_OnEnding ] ) ( _session->agent_handler );
701 699
702 return NULL; 700 return NULL;
703} 701}
@@ -829,7 +827,7 @@ int handle_recv_invite ( MSISession* session, MSIMessage* msg ) {
829 send_message ( session, _msg_ringing, msg->friend_id ); 827 send_message ( session, _msg_ringing, msg->friend_id );
830 free_message ( _msg_ringing ); 828 free_message ( _msg_ringing );
831 829
832 event.rise ( callbacks[MSI_OnInvite], session ); 830 event.rise ( callbacks[MSI_OnInvite], session->agent_handler );
833 831
834 return 1; 832 return 1;
835} 833}
@@ -852,7 +850,7 @@ int handle_recv_start ( MSISession* session, MSIMessage* msg ) {
852 850
853 flush_peer_type ( session, msg, 0 ); 851 flush_peer_type ( session, msg, 0 );
854 852
855 event.rise ( callbacks[MSI_OnStart], session ); 853 event.rise ( callbacks[MSI_OnStart], session->agent_handler );
856 854
857 return 1; 855 return 1;
858} 856}
@@ -868,7 +866,7 @@ int handle_recv_reject ( MSISession* session, MSIMessage* msg ) {
868 free_message ( _msg_end ); 866 free_message ( _msg_end );
869 867
870 event.timer_release ( session->call->request_timer_id ); 868 event.timer_release ( session->call->request_timer_id );
871 event.rise ( callbacks[MSI_OnReject], session ); 869 event.rise ( callbacks[MSI_OnReject], session->agent_handler );
872 session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); 870 session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout );
873 871
874 return 1; 872 return 1;
@@ -882,7 +880,7 @@ int handle_recv_cancel ( MSISession* session, MSIMessage* msg ) {
882 880
883 terminate_call ( session ); 881 terminate_call ( session );
884 882
885 event.rise ( callbacks[MSI_OnCancel], session ); 883 event.rise ( callbacks[MSI_OnCancel], session->agent_handler );
886 884
887 return 1; 885 return 1;
888} 886}
@@ -899,7 +897,7 @@ int handle_recv_end ( MSISession* session, MSIMessage* msg ) {
899 897
900 terminate_call ( session ); 898 terminate_call ( session );
901 899
902 event.rise ( callbacks[MSI_OnEnd], session ); 900 event.rise ( callbacks[MSI_OnEnd], session->agent_handler );
903 901
904 return 1; 902 return 1;
905} 903}
@@ -912,7 +910,7 @@ int handle_recv_ringing ( MSISession* session, MSIMessage* msg ) {
912 return 0; 910 return 0;
913 911
914 session->call->ringing_timer_id = event.timer_alloc ( handle_timeout, session, session->call->ringing_tout_ms ); 912 session->call->ringing_timer_id = event.timer_alloc ( handle_timeout, session, session->call->ringing_tout_ms );
915 event.rise ( callbacks[MSI_OnRinging], session ); 913 event.rise ( callbacks[MSI_OnRinging], session->agent_handler );
916 914
917 return 1; 915 return 1;
918} 916}
@@ -950,7 +948,7 @@ int handle_recv_starting ( MSISession* session, MSIMessage* msg ) {
950 948
951 flush_peer_type ( session, msg, 0 ); 949 flush_peer_type ( session, msg, 0 );
952 950
953 event.rise ( callbacks[MSI_OnStarting], session ); 951 event.rise ( callbacks[MSI_OnStarting], session->agent_handler );
954 event.timer_release ( session->call->ringing_timer_id ); 952 event.timer_release ( session->call->ringing_timer_id );
955 953
956 return 1; 954 return 1;
@@ -964,7 +962,7 @@ int handle_recv_ending ( MSISession* session, MSIMessage* msg ) {
964 962
965 terminate_call ( session ); 963 terminate_call ( session );
966 964
967 event.rise ( callbacks[MSI_OnEnding], session ); 965 event.rise ( callbacks[MSI_OnEnding], session->agent_handler );
968 966
969 return 1; 967 return 1;
970} 968}
@@ -980,7 +978,7 @@ int handle_recv_error ( MSISession* session, MSIMessage* msg ) {
980 978
981 terminate_call ( session ); 979 terminate_call ( session );
982 980
983 event.rise ( callbacks[MSI_OnEnding], session ); 981 event.rise ( callbacks[MSI_OnEnding], session->agent_handler );
984 982
985 return 1; 983 return 1;
986} 984}
@@ -1138,14 +1136,13 @@ void msi_register_callback ( MSICallback callback, MSICallbackID id )
1138 * @return MSISession* The created session. 1136 * @return MSISession* The created session.
1139 * @retval NULL Error occured. 1137 * @retval NULL Error occured.
1140 */ 1138 */
1141MSISession* msi_init_session ( Tox* messenger, const uint8_t* user_agent ) { 1139MSISession* msi_init_session ( Tox* messenger, const uint8_t* ua_name ) {
1142 assert ( messenger ); 1140 assert ( messenger );
1143 assert ( user_agent );
1144 1141
1145 MSISession* _retu = calloc ( sizeof ( MSISession ), 1 ); 1142 MSISession* _retu = calloc ( sizeof ( MSISession ), 1 );
1146 assert ( _retu ); 1143 assert ( _retu );
1147 1144
1148 _retu->user_agent = user_agent; 1145 _retu->ua_name = ua_name;
1149 _retu->messenger_handle = messenger; 1146 _retu->messenger_handle = messenger;
1150 _retu->agent_handler = NULL; 1147 _retu->agent_handler = NULL;
1151 1148
@@ -1300,14 +1297,17 @@ int msi_answer ( MSISession* session, MSICallType call_type ) {
1300 * @brief Cancel request. 1297 * @brief Cancel request.
1301 * 1298 *
1302 * @param session Control session. 1299 * @param session Control session.
1303 * @param friend_id The friend. 1300 * @param reason Set optional reason header. Pass NULL if none.
1304 * @return int 1301 * @return int
1305 */ 1302 */
1306int msi_cancel ( MSISession* session, int friend_id ) { 1303int msi_cancel ( MSISession* session, uint32_t peer, const uint8_t* reason ) {
1307 assert ( session ); 1304 assert ( session );
1308 1305
1309 MSIMessage* _msg_cancel = msi_new_message ( TYPE_REQUEST, stringify_request ( cancel ) ); 1306 MSIMessage* _msg_cancel = msi_new_message ( TYPE_REQUEST, stringify_request ( cancel ) );
1310 send_message ( session, _msg_cancel, friend_id ); 1307
1308 if ( reason ) msi_msg_set_reason(_msg_cancel, reason, strlen((const char*)reason));
1309
1310 send_message ( session, _msg_cancel, peer );
1311 free_message ( _msg_cancel ); 1311 free_message ( _msg_cancel );
1312 1312
1313 terminate_call ( session ); 1313 terminate_call ( session );
diff --git a/toxav/toxmsi.h b/toxav/msi.h
index 04987fee..20d6671d 100755..100644
--- a/toxav/toxmsi.h
+++ b/toxav/msi.h
@@ -103,7 +103,7 @@ typedef struct _MSISession {
103 int last_error_id; /* Determine the last error */ 103 int last_error_id; /* Determine the last error */
104 const uint8_t* last_error_str; 104 const uint8_t* last_error_str;
105 105
106 const uint8_t* user_agent; 106 const uint8_t* ua_name;
107 107
108 void* agent_handler; /* Pointer to an object that is handling msi */ 108 void* agent_handler; /* Pointer to an object that is handling msi */
109 Tox* messenger_handle; 109 Tox* messenger_handle;
@@ -156,7 +156,7 @@ void msi_register_callback(MSICallback callback, MSICallbackID id);
156 * @return MSISession* The created session. 156 * @return MSISession* The created session.
157 * @retval NULL Error occured. 157 * @retval NULL Error occured.
158 */ 158 */
159MSISession* msi_init_session ( Tox* messenger, const uint8_t* user_agent ); 159MSISession* msi_init_session ( Tox* messenger, const uint8_t* ua_name );
160 160
161 161
162/** 162/**
@@ -205,10 +205,11 @@ int msi_answer ( MSISession* session, MSICallType call_type );
205 * @brief Cancel request. 205 * @brief Cancel request.
206 * 206 *
207 * @param session Control session. 207 * @param session Control session.
208 * @param friend_id The friend. 208 * @param peer To which peer.
209 * @param reason Set optional reason header. Pass NULL if none.
209 * @return int 210 * @return int
210 */ 211 */
211int msi_cancel ( MSISession* session, int friend_id ); 212int msi_cancel ( MSISession* session, uint32_t peer, const uint8_t* reason );
212 213
213 214
214/** 215/**
diff --git a/toxav/phone.c b/toxav/phone.c
index d8318ff9..4f078e2b 100755
--- a/toxav/phone.c
+++ b/toxav/phone.c
@@ -51,9 +51,8 @@
51#include <pthread.h> 51#include <pthread.h>
52#include <opus/opus.h> 52#include <opus/opus.h>
53 53
54#include "toxmsi.h" 54#include "media.h"
55#include "toxrtp.h" 55#include "toxav.h"
56#include "toxmedia.h"
57#include "../toxcore/event.h" 56#include "../toxcore/event.h"
58#include "../toxcore/tox.h" 57#include "../toxcore/tox.h"
59 58
@@ -75,13 +74,9 @@ typedef struct av_friend_s {
75} av_friend_t; 74} av_friend_t;
76 75
77typedef struct av_session_s { 76typedef struct av_session_s {
78 MSISession* _msi;
79 RTPSession* _rtp_audio;
80 RTPSession* _rtp_video;
81
82 /* Encoding/decoding/capturing/playing */ 77 /* Encoding/decoding/capturing/playing */
78 ToxAv* av;
83 79
84 codec_state* cs;
85 VideoPicture video_picture; 80 VideoPicture video_picture;
86 struct ALCdevice *audio_capture_device; 81 struct ALCdevice *audio_capture_device;
87 82
@@ -91,8 +86,9 @@ typedef struct av_session_s {
91 /* context for converting webcam image format to something the video encoder can use */ 86 /* context for converting webcam image format to something the video encoder can use */
92 struct SwsContext *sws_ctx; 87 struct SwsContext *sws_ctx;
93 88
94 /**/ 89 /* Thread running control */
95 90 int running_decaud, running_encaud,
91 running_decvid, running_encvid;
96 92
97 pthread_mutex_t _mutex; 93 pthread_mutex_t _mutex;
98 94
@@ -243,7 +239,7 @@ static void fraddr_to_str(uint8_t *id_bin, char *id_str)
243 239
244int display_received_frame(av_session_t* _phone, AVFrame *r_video_frame) 240int display_received_frame(av_session_t* _phone, AVFrame *r_video_frame)
245{ 241{
246 codec_state* cs = _phone->cs; 242 CodecState* cs = get_cs_temp(_phone->av);
247 AVPicture pict; 243 AVPicture pict;
248 SDL_LockYUVOverlay(_phone->video_picture.bmp); 244 SDL_LockYUVOverlay(_phone->video_picture.bmp);
249 245
@@ -268,71 +264,15 @@ int display_received_frame(av_session_t* _phone, AVFrame *r_video_frame)
268 return 1; 264 return 1;
269} 265}
270 266
271int video_encoder_refresh(codec_state *cs, int bps)
272{
273 if (cs->video_encoder_ctx)
274 avcodec_close(cs->video_encoder_ctx);
275
276 cs->video_encoder = avcodec_find_encoder(VIDEO_CODEC);
277
278 if (!cs->video_encoder) {
279 printf("init video_encoder failed\n");
280 return -1;
281 }
282
283 cs->video_encoder_ctx = avcodec_alloc_context3(cs->video_encoder);
284
285 if (!cs->video_encoder_ctx) {
286 printf("init video_encoder_ctx failed\n");
287 return -1;
288 }
289
290 cs->video_encoder_ctx->bit_rate = bps;
291 cs->video_encoder_ctx->rc_min_rate = cs->video_encoder_ctx->rc_max_rate = cs->video_encoder_ctx->bit_rate;
292 av_opt_set_double(cs->video_encoder_ctx->priv_data, "max-intra-rate", 90, 0);
293 av_opt_set(cs->video_encoder_ctx->priv_data, "quality", "realtime", 0);
294
295 cs->video_encoder_ctx->thread_count = 4;
296 cs->video_encoder_ctx->rc_buffer_aggressivity = 0.95;
297 cs->video_encoder_ctx->rc_buffer_size = bps * 6;
298 cs->video_encoder_ctx->profile = 0;
299 cs->video_encoder_ctx->qmax = 54;
300 cs->video_encoder_ctx->qmin = 4;
301 AVRational myrational = {1, 25};
302 cs->video_encoder_ctx->time_base = myrational;
303 cs->video_encoder_ctx->gop_size = 99999;
304 cs->video_encoder_ctx->pix_fmt = PIX_FMT_YUV420P;
305 cs->video_encoder_ctx->width = cs->webcam_decoder_ctx->width;
306 cs->video_encoder_ctx->height = cs->webcam_decoder_ctx->height;
307
308 if (avcodec_open2(cs->video_encoder_ctx, cs->video_encoder, NULL) < 0) {
309 printf("opening video encoder failed\n");
310 return -1;
311 }
312 return 0;
313}
314
315int video_decoder_refresh(av_session_t* _phone, int width, int height)
316{
317 printf("need to refresh\n");
318 screen = SDL_SetVideoMode(width, height, 0, 0);
319
320 if (_phone->video_picture.bmp)
321 SDL_FreeYUVOverlay(_phone->video_picture.bmp);
322
323 _phone->video_picture.bmp = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, screen);
324 _phone->sws_SDL_r_ctx = sws_getContext(width, height, _phone->cs->video_decoder_ctx->pix_fmt, width, height, PIX_FMT_YUV420P,
325 SWS_BILINEAR, NULL, NULL, NULL);
326 return 1;
327}
328
329void *encode_video_thread(void *arg) 267void *encode_video_thread(void *arg)
330{ 268{
331 INFO("Started encode video thread!"); 269 INFO("Started encode video thread!");
332 270
333 av_session_t* _phone = arg; 271 av_session_t* _phone = arg;
334 272
335 codec_state *cs = _phone->cs; 273 _phone->running_encvid = 1;
274
275 CodecState *cs = get_cs_temp(_phone->av);
336 AVPacket pkt1, *packet = &pkt1; 276 AVPacket pkt1, *packet = &pkt1;
337 int p = 0; 277 int p = 0;
338 int got_packet; 278 int got_packet;
@@ -354,7 +294,7 @@ void *encode_video_thread(void *arg)
354 cs->webcam_decoder_ctx->pix_fmt, cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height, PIX_FMT_YUV420P, 294 cs->webcam_decoder_ctx->pix_fmt, cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height, PIX_FMT_YUV420P,
355 SWS_BILINEAR, NULL, NULL, NULL); 295 SWS_BILINEAR, NULL, NULL, NULL);
356 296
357 while (cs->send_video) { 297 while (_phone->running_encvid) {
358 298
359 if (av_read_frame(cs->video_format_ctx, packet) < 0) { 299 if (av_read_frame(cs->video_format_ctx, packet) < 0) {
360 printf("error reading frame\n"); 300 printf("error reading frame\n");
@@ -400,9 +340,7 @@ void *encode_video_thread(void *arg)
400 340
401 if (!enc_video_packet.data) fprintf(stderr, "video packet data is NULL\n"); 341 if (!enc_video_packet.data) fprintf(stderr, "video packet data is NULL\n");
402 342
403 if ( 0 > rtp_send_msg ( _phone->_rtp_video, _phone->_messenger, enc_video_packet.data, enc_video_packet.size) ) { 343 toxav_send_rtp_payload(_phone->av, TypeVideo, enc_video_packet.data, enc_video_packet.size);
404 printf("Failed sending message\n");
405 }
406 344
407 av_free_packet(&enc_video_packet); 345 av_free_packet(&enc_video_packet);
408 } 346 }
@@ -420,6 +358,9 @@ void *encode_video_thread(void *arg)
420 avcodec_close(cs->webcam_decoder_ctx); 358 avcodec_close(cs->webcam_decoder_ctx);
421 avcodec_close(cs->video_encoder_ctx); 359 avcodec_close(cs->video_encoder_ctx);
422 pthread_mutex_unlock(&cs->ctrl_mutex); 360 pthread_mutex_unlock(&cs->ctrl_mutex);
361
362 _phone->running_encvid = -1;
363
423 pthread_exit ( NULL ); 364 pthread_exit ( NULL );
424} 365}
425 366
@@ -427,8 +368,8 @@ void *encode_audio_thread(void *arg)
427{ 368{
428 INFO("Started encode audio thread!"); 369 INFO("Started encode audio thread!");
429 av_session_t* _phone = arg; 370 av_session_t* _phone = arg;
371 _phone->running_encaud = 1;
430 372
431 codec_state *cs = _phone->cs;
432 unsigned char encoded_data[4096]; 373 unsigned char encoded_data[4096];
433 int encoded_size = 0; 374 int encoded_size = 0;
434 int16_t frame[4096]; 375 int16_t frame[4096];
@@ -436,39 +377,46 @@ void *encode_audio_thread(void *arg)
436 ALint sample = 0; 377 ALint sample = 0;
437 alcCaptureStart((ALCdevice*)_phone->audio_capture_device); 378 alcCaptureStart((ALCdevice*)_phone->audio_capture_device);
438 379
439 while (cs->send_audio) { 380 while (_phone->running_encaud) {
440 alcGetIntegerv((ALCdevice*)_phone->audio_capture_device, ALC_CAPTURE_SAMPLES, (ALCsizei)sizeof(ALint), &sample); 381 alcGetIntegerv((ALCdevice*)_phone->audio_capture_device, ALC_CAPTURE_SAMPLES, (ALCsizei)sizeof(ALint), &sample);
441 382
442 if (sample >= frame_size) { 383 if (sample >= frame_size) {
443 alcCaptureSamples((ALCdevice*)_phone->audio_capture_device, frame, frame_size); 384 alcCaptureSamples((ALCdevice*)_phone->audio_capture_device, frame, frame_size);
444 encoded_size = opus_encode(cs->audio_encoder, frame, frame_size, encoded_data, MAX_RTP_SIZE); 385
386 encoded_size = toxav_encode_audio(_phone->av, frame, frame_size, encoded_data);
445 387
446 if (encoded_size <= 0) { 388 if (encoded_size <= 0) {
447 printf("Could not encode audio packet\n"); 389 printf("Could not encode audio packet\n");
448 } else { 390 } else {
449 rtp_send_msg ( _phone->_rtp_audio, _phone->_messenger, encoded_data, encoded_size ); 391 if ( -1 == toxav_send_rtp_payload(_phone->av, TypeAudio, encoded_data, encoded_size) )
392 assert(0);
450 } 393 }
451 } else { 394 } else {
452 usleep(1000); 395 usleep(1000);
453 } 396 }
454 } 397 }
455 398
456 /* clean up codecs */ 399 /* clean up codecs *
457 pthread_mutex_lock(&cs->ctrl_mutex); 400 pthread_mutex_lock(&cs->ctrl_mutex);*/
458 alcCaptureStop((ALCdevice*)_phone->audio_capture_device); 401 alcCaptureStop((ALCdevice*)_phone->audio_capture_device);
459 alcCaptureCloseDevice((ALCdevice*)_phone->audio_capture_device); 402 alcCaptureCloseDevice((ALCdevice*)_phone->audio_capture_device);
460 pthread_mutex_unlock(&cs->ctrl_mutex); 403 /*pthread_mutex_unlock(&cs->ctrl_mutex);*/
461 pthread_exit ( NULL ); 404 _phone->running_encaud = -1;
405 pthread_exit ( NULL );
462} 406}
463 407
464void *decode_video_thread(void *arg) 408void *decode_video_thread(void *arg)
465{ 409{
466 INFO("Started decode video thread!"); 410 INFO("Started decode video thread!");
467 av_session_t* _phone = arg; 411 av_session_t* _phone = arg;
412 _phone->running_decvid = 1;
468 413
469 codec_state *cs = _phone->cs; 414 CodecState *cs = get_cs_temp(_phone->av);
470 cs->video_stream = 0; 415 cs->video_stream = 0;
471 RTPMessage *r_msg; 416
417 int recved_size;
418 uint8_t dest[RTP_PAYLOAD_SIZE];
419
472 int dec_frame_finished; 420 int dec_frame_finished;
473 AVFrame *r_video_frame; 421 AVFrame *r_video_frame;
474 r_video_frame = avcodec_alloc_frame(); 422 r_video_frame = avcodec_alloc_frame();
@@ -477,20 +425,34 @@ void *decode_video_thread(void *arg)
477 int width = 0; 425 int width = 0;
478 int height = 0; 426 int height = 0;
479 427
480 while (cs->receive_video) { 428 while (_phone->running_decvid) {
481 r_msg = rtp_recv_msg ( _phone->_rtp_video );
482 429
483 if (r_msg) { 430 recved_size = toxav_recv_rtp_payload(_phone->av, TypeVideo, 1, dest);
484 memcpy(dec_video_packet.data, r_msg->data, r_msg->length); 431
485 dec_video_packet.size = r_msg->length; 432 if (recved_size) {
433 memcpy(dec_video_packet.data, dest, recved_size);
434 dec_video_packet.size = recved_size;
435
486 avcodec_decode_video2(cs->video_decoder_ctx, r_video_frame, &dec_frame_finished, &dec_video_packet); 436 avcodec_decode_video2(cs->video_decoder_ctx, r_video_frame, &dec_frame_finished, &dec_video_packet);
487 437
488 if (dec_frame_finished) { 438 if (dec_frame_finished) {
439
440 /* Check if size has changed */
489 if (cs->video_decoder_ctx->width != width || cs->video_decoder_ctx->height != height) { 441 if (cs->video_decoder_ctx->width != width || cs->video_decoder_ctx->height != height) {
442
490 width = cs->video_decoder_ctx->width; 443 width = cs->video_decoder_ctx->width;
491 height = cs->video_decoder_ctx->height; 444 height = cs->video_decoder_ctx->height;
445
492 printf("w: %d h: %d \n", width, height); 446 printf("w: %d h: %d \n", width, height);
493 video_decoder_refresh(_phone, width, height); 447
448 screen = SDL_SetVideoMode(width, height, 0, 0);
449
450 if (_phone->video_picture.bmp)
451 SDL_FreeYUVOverlay(_phone->video_picture.bmp);
452
453 _phone->video_picture.bmp = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, screen);
454 _phone->sws_SDL_r_ctx = sws_getContext(width, height, cs->video_decoder_ctx->pix_fmt, width, height, PIX_FMT_YUV420P,
455 SWS_BILINEAR, NULL, NULL, NULL);
494 } 456 }
495 457
496 display_received_frame(_phone, r_video_frame); 458 display_received_frame(_phone, r_video_frame);
@@ -498,18 +460,20 @@ void *decode_video_thread(void *arg)
498 /* TODO: request the sender to create a new i-frame immediatly */ 460 /* TODO: request the sender to create a new i-frame immediatly */
499 printf("Bad video packet\n"); 461 printf("Bad video packet\n");
500 } 462 }
501
502 rtp_free_msg(NULL, r_msg);
503 } 463 }
504 464
505 usleep(1000); 465 usleep(1000);
506 } 466 }
507 467
508 /* clean up codecs */ 468 /* clean up codecs */
509 pthread_mutex_lock(&cs->ctrl_mutex);
510 av_free(r_video_frame); 469 av_free(r_video_frame);
470
471 pthread_mutex_lock(&cs->ctrl_mutex);
511 avcodec_close(cs->video_decoder_ctx); 472 avcodec_close(cs->video_decoder_ctx);
512 pthread_mutex_unlock(&cs->ctrl_mutex); 473 pthread_mutex_unlock(&cs->ctrl_mutex);
474
475 _phone->running_decvid = -1;
476
513 pthread_exit ( NULL ); 477 pthread_exit ( NULL );
514} 478}
515 479
@@ -517,9 +481,10 @@ void *decode_audio_thread(void *arg)
517{ 481{
518 INFO("Started decode audio thread!"); 482 INFO("Started decode audio thread!");
519 av_session_t* _phone = arg; 483 av_session_t* _phone = arg;
520 484 _phone->running_decaud = 1;
521 codec_state *cs = _phone->cs; 485
522 RTPMessage *r_msg; 486 int recved_size;
487 uint8_t dest [RTP_PAYLOAD_SIZE];
523 488
524 int frame_size = AUDIO_FRAME_SIZE; 489 int frame_size = AUDIO_FRAME_SIZE;
525 int data_size; 490 int data_size;
@@ -538,7 +503,7 @@ void *decode_audio_thread(void *arg)
538 alSourcei(source, AL_LOOPING, AL_FALSE); 503 alSourcei(source, AL_LOOPING, AL_FALSE);
539 504
540 ALuint buffer; 505 ALuint buffer;
541 ALint val; 506 ALint ready;
542 507
543 uint16_t zeros[frame_size]; 508 uint16_t zeros[frame_size];
544 memset(zeros, 0, frame_size); 509 memset(zeros, 0, frame_size);
@@ -557,83 +522,58 @@ void *decode_audio_thread(void *arg)
557 goto ending; 522 goto ending;
558 } 523 }
559 524
560 struct jitter_buffer *j_buf = NULL; 525 int dec_frame_len = 0;
561
562 j_buf = create_queue(20);
563
564 int success = 0;
565 526
566 int dec_frame_len = 0; 527 while (_phone->running_decaud) {
567
568
569 while (cs->receive_audio) {
570 528
571 r_msg = rtp_recv_msg ( _phone->_rtp_audio ); 529 alGetSourcei(source, AL_BUFFERS_PROCESSED, &ready);
572 530
573 if (r_msg) { 531 recved_size = toxav_recv_rtp_payload(_phone->av, TypeAudio, ready, dest);
574 /* push the packet into the queue */
575 queue(j_buf, r_msg);
576 }
577 532
578 success = 0; 533 if ( recved_size == ErrorAudioPacketLost ) {
579 alGetSourcei(source, AL_BUFFERS_PROCESSED, &val); 534 printf("Lost packet\n");
535 dec_frame_len = toxav_decode_audio(_phone->av, NULL, 0, frame_size, PCM);
580 536
581 /* grab a packet from the queue */ 537 } else if ( recved_size ) {
582 if (val > 0) { 538 dec_frame_len = toxav_decode_audio(_phone->av, dest, recved_size, frame_size, PCM);
583 r_msg = dequeue(j_buf, &success);
584 } 539 }
585 540
586 if (success > 0) { 541
587 /* good packet */ 542 /* Play the packet */
588 if (success == 1) { 543 if (dec_frame_len) {
589 dec_frame_len = opus_decode(cs->audio_decoder, r_msg->data, r_msg->length, PCM, frame_size, 0); 544 alGetSourcei(source, AL_BUFFERS_PROCESSED, &ready);
590 rtp_free_msg(NULL, r_msg); 545
591 } 546 if (ready <= 0)
547 continue;
548
549 alSourceUnqueueBuffers(source, 1, &buffer);
550 data_size = av_samples_get_buffer_size(NULL, 1, dec_frame_len, AV_SAMPLE_FMT_S16, 1);
551 alBufferData(buffer, AL_FORMAT_MONO16, PCM, data_size, 48000);
552 int error = alGetError();
592 553
593 /* lost packet */ 554 if (error != AL_NO_ERROR) {
594 else if (success == 2) { 555 fprintf(stderr, "Error setting buffer %d\n", error);
595 printf("Lost packet\n"); 556 break;
596 dec_frame_len = opus_decode(cs->audio_decoder, NULL, 0, PCM, frame_size, 1);
597 } 557 }
598 558
599 if (dec_frame_len) { 559 alSourceQueueBuffers(source, 1, &buffer);
600 alGetSourcei(source, AL_BUFFERS_PROCESSED, &val); 560
601 561 if (alGetError() != AL_NO_ERROR) {
602 if (val <= 0) 562 fprintf(stderr, "Error: could not buffer audio\n");
603 continue; 563 break;
604
605 alSourceUnqueueBuffers(source, 1, &buffer);
606 data_size = av_samples_get_buffer_size(NULL, 1, dec_frame_len, AV_SAMPLE_FMT_S16, 1);
607 alBufferData(buffer, AL_FORMAT_MONO16, PCM, data_size, 48000);
608 int error = alGetError();
609
610 if (error != AL_NO_ERROR) {
611 fprintf(stderr, "Error setting buffer %d\n", error);
612 break;
613 }
614
615 alSourceQueueBuffers(source, 1, &buffer);
616
617 if (alGetError() != AL_NO_ERROR) {
618 fprintf(stderr, "Error: could not buffer audio\n");
619 break;
620 }
621
622 alGetSourcei(source, AL_SOURCE_STATE, &val);
623
624 if (val != AL_PLAYING)
625 alSourcePlay(source);
626
627
628 } 564 }
629 } 565
566 alGetSourcei(source, AL_SOURCE_STATE, &ready);
567
568 if (ready != AL_PLAYING) alSourcePlay(source);
569 }
630 570
631 usleep(1000); 571 usleep(1000);
632 } 572 }
633 573
634 574
635ending: 575ending:
636 /* clean up codecs */ 576 /* clean up codecs * /
637 pthread_mutex_lock(&cs->ctrl_mutex); 577 pthread_mutex_lock(&cs->ctrl_mutex);
638 578
639 alDeleteSources(1, &source); 579 alDeleteSources(1, &source);
@@ -642,7 +582,10 @@ ending:
642 alcDestroyContext(ctx); 582 alcDestroyContext(ctx);
643 alcCloseDevice(dev); 583 alcCloseDevice(dev);
644 584
645 pthread_mutex_unlock(&cs->ctrl_mutex); 585 pthread_mutex_unlock(&cs->ctrl_mutex); */
586
587 _phone->running_decaud = -1;
588
646 pthread_exit ( NULL ); 589 pthread_exit ( NULL );
647} 590}
648 591
@@ -650,61 +593,42 @@ ending:
650 593
651 594
652 595
653int phone_startmedia_loop ( av_session_t* _phone ) 596int phone_startmedia_loop ( ToxAv* arg )
654{ 597{
655 if ( !_phone ){ 598 if ( !arg ){
656 return -1; 599 return -1;
657 } 600 }
658 601
659 _phone->_rtp_audio = rtp_init_session ( 602 toxav_prepare_transmission(arg);
660 type_audio, 603
661 _phone->_messenger,
662 _phone->_msi->call->peers[0],
663 _phone->_msi->call->key_peer,
664 _phone->_msi->call->key_local,
665 _phone->_msi->call->nonce_peer,
666 _phone->_msi->call->nonce_local
667 );
668
669 _phone->_rtp_video = rtp_init_session (
670 type_video,
671 _phone->_messenger,
672 _phone->_msi->call->peers[0],
673 _phone->_msi->call->key_peer,
674 _phone->_msi->call->key_local,
675 _phone->_msi->call->nonce_peer,
676 _phone->_msi->call->nonce_local
677 );
678
679 init_encoder(_phone->cs);
680 init_decoder(_phone->cs);
681
682 /* 604 /*
683 * Rise all threads 605 * Rise all threads
684 */ 606 */
685 607
686 /* Only checks for last peer */ 608 /* Only checks for last peer */
687 if ( _phone->_msi->call->type_peer[0] == type_video && 0 > event.rise(encode_video_thread, _phone) ) 609 if ( toxav_get_peer_transmission_type(arg, 0) == TypeVideo &&
610 0 > event.rise(encode_video_thread, toxav_get_agent_handler(arg)) )
688 { 611 {
689 INFO("Error while starting encode_video_thread()"); 612 INFO("Error while starting encode_video_thread()");
690 return -1; 613 return -1;
691 } 614 }
692 615
693 /* Always send audio */ 616 /* Always send audio */
694 if ( 0 > event.rise(encode_audio_thread, _phone) ) 617 if ( 0 > event.rise(encode_audio_thread, toxav_get_agent_handler(arg)) )
695 { 618 {
696 INFO("Error while starting encode_audio_thread()"); 619 INFO("Error while starting encode_audio_thread()");
697 return -1; 620 return -1;
698 } 621 }
699 622
700 /* Only checks for last peer */ 623 /* Only checks for last peer */
701 if ( _phone->_msi->call->type_peer[0] == type_video && 0 > event.rise(decode_video_thread, _phone) ) 624 if ( toxav_get_peer_transmission_type(arg, 0) == TypeVideo &&
625 0 > event.rise(decode_video_thread, toxav_get_agent_handler(arg)) )
702 { 626 {
703 INFO("Error while starting decode_video_thread()"); 627 INFO("Error while starting decode_video_thread()");
704 return -1; 628 return -1;
705 } 629 }
706 630
707 if ( 0 > event.rise(decode_audio_thread, _phone) ) 631 if ( 0 > event.rise(decode_audio_thread, toxav_get_agent_handler(arg)) )
708 { 632 {
709 INFO("Error while starting decode_audio_thread()"); 633 INFO("Error while starting decode_audio_thread()");
710 return -1; 634 return -1;
@@ -734,13 +658,13 @@ int phone_startmedia_loop ( av_session_t* _phone )
734 658
735void* callback_recv_invite ( void* _arg ) 659void* callback_recv_invite ( void* _arg )
736{ 660{
737 MSISession* _msi = _arg; 661 assert(_arg);
738 662
739 switch ( _msi->call->type_peer[_msi->call->peer_count - 1] ){ 663 switch ( toxav_get_peer_transmission_type(_arg, 0) ){
740 case type_audio: 664 case TypeAudio:
741 INFO( "Incoming audio call!"); 665 INFO( "Incoming audio call!");
742 break; 666 break;
743 case type_video: 667 case TypeVideo:
744 INFO( "Incoming video call!"); 668 INFO( "Incoming video call!");
745 break; 669 break;
746 } 670 }
@@ -754,8 +678,7 @@ void* callback_recv_ringing ( void* _arg )
754} 678}
755void* callback_recv_starting ( void* _arg ) 679void* callback_recv_starting ( void* _arg )
756{ 680{
757 MSISession* _session = _arg; 681 if ( 0 != phone_startmedia_loop(_arg) ){
758 if ( 0 != phone_startmedia_loop(_session->agent_handler) ){
759 INFO("Starting call failed!"); 682 INFO("Starting call failed!");
760 } else { 683 } else {
761 INFO ("Call started! ( press h to hangup )"); 684 INFO ("Call started! ( press h to hangup )");
@@ -764,15 +687,21 @@ void* callback_recv_starting ( void* _arg )
764} 687}
765void* callback_recv_ending ( void* _arg ) 688void* callback_recv_ending ( void* _arg )
766{ 689{
767 av_session_t* _phone = ((MSISession*)_arg)->agent_handler; 690 av_session_t* _phone = toxav_get_agent_handler(_arg);
768 691
769 _phone->cs->send_audio = 0; 692 _phone->running_encaud = 0;
770 _phone->cs->send_video = 0; 693 _phone->running_decaud = 0;
771 _phone->cs->receive_audio = 0; 694 _phone->running_encvid = 0;
772 _phone->cs->receive_video = 0; 695 _phone->running_decvid = 0;
773 696
774 /* Wait until all threads are done */ 697 /* Wait until all threads are done */
775 usleep(10000000); 698
699 while ( _phone->running_encaud != -1 ||
700 _phone->running_decaud != -1 ||
701 _phone->running_encvid != -1 ||
702 _phone->running_decvid != -1 )
703
704 usleep(10000000);
776 705
777 INFO ( "Call ended!" ); 706 INFO ( "Call ended!" );
778 pthread_exit(NULL); 707 pthread_exit(NULL);
@@ -780,16 +709,15 @@ void* callback_recv_ending ( void* _arg )
780 709
781void* callback_recv_error ( void* _arg ) 710void* callback_recv_error ( void* _arg )
782{ 711{
783 MSISession* _session = _arg; 712 /*MSISession* _session = _arg;
784 713
785 INFO( "Error: %s", _session->last_error_str ); 714 INFO( "Error: %s", _session->last_error_str ); */
786 pthread_exit(NULL); 715 pthread_exit(NULL);
787} 716}
788 717
789void* callback_call_started ( void* _arg ) 718void* callback_call_started ( void* _arg )
790{ 719{
791 MSISession* _session = _arg; 720 if ( 0 != phone_startmedia_loop(_arg) ){
792 if ( 0 != phone_startmedia_loop(_session->agent_handler) ){
793 INFO("Starting call failed!"); 721 INFO("Starting call failed!");
794 } else { 722 } else {
795 INFO ("Call started! ( press h to hangup )"); 723 INFO ("Call started! ( press h to hangup )");
@@ -809,16 +737,23 @@ void* callback_call_rejected ( void* _arg )
809} 737}
810void* callback_call_ended ( void* _arg ) 738void* callback_call_ended ( void* _arg )
811{ 739{
812 av_session_t* _phone = ((MSISession*)_arg)->agent_handler; 740 av_session_t* _phone = toxav_get_agent_handler(_arg);
813 741
814 _phone->cs->send_audio = 0; 742 _phone->running_encaud = 0;
815 _phone->cs->send_video = 0; 743 _phone->running_decaud = 0;
816 _phone->cs->receive_audio = 0; 744 _phone->running_encvid = 0;
817 _phone->cs->receive_video = 0; 745 _phone->running_decvid = 0;
818 746
819 /* Wait until all threads are done */ 747 /* Wait until all threads are done */
820 usleep(10000000); 748
749 while ( _phone->running_encaud != -1 ||
750 _phone->running_decaud != -1 ||
751 _phone->running_encvid != -1 ||
752 _phone->running_decvid != -1 )
753
754 usleep(10000000);
821 755
756 toxav_kill_transmission(_phone->av);
822 INFO ( "Call ended!" ); 757 INFO ( "Call ended!" );
823 pthread_exit(NULL); 758 pthread_exit(NULL);
824} 759}
@@ -844,9 +779,7 @@ av_session_t* av_init_session()
844 } 779 }
845 780
846 _retu->_friends = NULL; 781 _retu->_friends = NULL;
847 782 _retu->av = toxav_new(_retu->_messenger, _retu, _USERAGENT);
848 _retu->_rtp_audio = NULL;
849 _retu->_rtp_video = NULL;
850 783
851 784
852 const ALchar *_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); 785 const ALchar *_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
@@ -878,9 +811,7 @@ av_session_t* av_init_session()
878 else { 811 else {
879 INFO("Selected: %d ( %s )", selection, device_names[selection]); 812 INFO("Selected: %d ( %s )", selection, device_names[selection]);
880 } 813 }
881 814
882 _retu->cs = av_calloc(sizeof(codec_state), 1);
883
884 _retu->audio_capture_device = 815 _retu->audio_capture_device =
885 (struct ALCdevice*)alcCaptureOpenDevice( 816 (struct ALCdevice*)alcCaptureOpenDevice(
886 device_names[selection], AUDIO_SAMPLE_RATE, AL_FORMAT_MONO16, AUDIO_FRAME_SIZE * 4); 817 device_names[selection], AUDIO_SAMPLE_RATE, AL_FORMAT_MONO16, AUDIO_FRAME_SIZE * 4);
@@ -890,36 +821,29 @@ av_session_t* av_init_session()
890 printf("Could not start capture device! %d\n", alcGetError((ALCdevice*)_retu->audio_capture_device)); 821 printf("Could not start capture device! %d\n", alcGetError((ALCdevice*)_retu->audio_capture_device));
891 return 0; 822 return 0;
892 } 823 }
893 824
894 825
895 uint8_t _byte_address[TOX_FRIEND_ADDRESS_SIZE]; 826 uint8_t _byte_address[TOX_FRIEND_ADDRESS_SIZE];
896 tox_get_address(_retu->_messenger, _byte_address ); 827 tox_get_address(_retu->_messenger, _byte_address );
897 fraddr_to_str( _byte_address, _retu->_my_public_id ); 828 fraddr_to_str( _byte_address, _retu->_my_public_id );
898 829
899 830
900 /* Initialize msi */
901 _retu->_msi = msi_init_session ( _retu->_messenger, (const uint8_t*)_USERAGENT );
902
903 if ( !_retu->_msi ) {
904 fprintf ( stderr, "msi_init_session() failed\n" );
905 return NULL;
906 }
907
908 _retu->_msi->agent_handler = _retu;
909 831
910 /* ------------------ */ 832 /* ------------------ */
911 msi_register_callback(callback_call_started, MSI_OnStart); 833
912 msi_register_callback(callback_call_canceled, MSI_OnCancel); 834 toxav_register_callstate_callback(callback_call_started, OnStart);
913 msi_register_callback(callback_call_rejected, MSI_OnReject); 835 toxav_register_callstate_callback(callback_call_canceled, OnCancel);
914 msi_register_callback(callback_call_ended, MSI_OnEnd); 836 toxav_register_callstate_callback(callback_call_rejected, OnReject);
915 msi_register_callback(callback_recv_invite, MSI_OnInvite); 837 toxav_register_callstate_callback(callback_call_ended, OnEnd);
916 838 toxav_register_callstate_callback(callback_recv_invite, OnInvite);
917 msi_register_callback(callback_recv_ringing, MSI_OnRinging); 839
918 msi_register_callback(callback_recv_starting, MSI_OnStarting); 840 toxav_register_callstate_callback(callback_recv_ringing, OnRinging);
919 msi_register_callback(callback_recv_ending, MSI_OnEnding); 841 toxav_register_callstate_callback(callback_recv_starting, OnStarting);
920 842 toxav_register_callstate_callback(callback_recv_ending, OnEnding);
921 msi_register_callback(callback_recv_error, MSI_OnError); 843
922 msi_register_callback(callback_requ_timeout, MSI_OnTimeout); 844 toxav_register_callstate_callback(callback_recv_error, OnError);
845 toxav_register_callstate_callback(callback_requ_timeout, OnTimeout);
846
923 /* ------------------ */ 847 /* ------------------ */
924 848
925 return _retu; 849 return _retu;
@@ -927,17 +851,18 @@ av_session_t* av_init_session()
927 851
928int av_terminate_session(av_session_t* _phone) 852int av_terminate_session(av_session_t* _phone)
929{ 853{
930 if ( _phone->_msi->call ){ 854 toxav_hangup(_phone->av);
931 msi_hangup(_phone->_msi); /* Hangup the phone first */
932 }
933 855
934 free(_phone->_friends); 856 free(_phone->_friends);
935 msi_terminate_session(_phone->_msi);
936 pthread_mutex_destroy ( &_phone->_mutex ); 857 pthread_mutex_destroy ( &_phone->_mutex );
937 858
938 Tox* _p = _phone->_messenger; 859 Tox* _p = _phone->_messenger;
939 _phone->_messenger = NULL; usleep(100000); /* Wait for tox_pool to end */ 860 _phone->_messenger = NULL; usleep(100000); /* Wait for tox_poll to end */
861
940 tox_kill(_p); 862 tox_kill(_p);
863 toxav_kill(_phone->av);
864
865 free(_phone);
941 866
942 printf("\r[i] Quit!\n"); 867 printf("\r[i] Quit!\n");
943 return 0; 868 return 0;
@@ -1047,22 +972,17 @@ void do_phone ( av_session_t* _phone )
1047 } break; 972 } break;
1048 case 'c': 973 case 'c':
1049 { 974 {
1050 if ( _phone->_msi->call ){ 975 ToxAvCallType _ctype;
1051 INFO("Already in a call");
1052 break;
1053 }
1054
1055 MSICallType _ctype;
1056 976
1057 if ( _len < 5 ){ 977 if ( _len < 5 ){
1058 INFO("Invalid input; usage: c a/v [friend]"); 978 INFO("Invalid input; usage: c a/v [friend]");
1059 break; 979 break;
1060 } 980 }
1061 else if ( _line[2] == 'a' || _line[2] != 'v' ){ /* default and audio */ 981 else if ( _line[2] == 'a' || _line[2] != 'v' ){ /* default and audio */
1062 _ctype = type_audio; 982 _ctype = TypeAudio;
1063 } 983 }
1064 else { /* video */ 984 else { /* video */
1065 _ctype = type_video; 985 _ctype = TypeVideo;
1066 } 986 }
1067 987
1068 char* _end; 988 char* _end;
@@ -1073,45 +993,41 @@ void do_phone ( av_session_t* _phone )
1073 break; 993 break;
1074 } 994 }
1075 995
1076 /* Set timeout */ 996 if ( toxav_call(_phone->av, _friend, _ctype, 30) == ErrorAlreadyInCall ){
1077 msi_invite ( _phone->_msi, _ctype, 10 * 1000, _friend ); 997 INFO("Already in a call");
1078 INFO("Calling friend: %d!", _friend); 998 break;
999 }
1000 else INFO("Calling friend: %d!", _friend);
1079 1001
1080 } break; 1002 } break;
1081 case 'h': 1003 case 'h':
1082 { 1004 {
1083 if ( !_phone->_msi->call ){ 1005 if ( toxav_hangup(_phone->av) == ErrorNoCall ) {
1084 INFO("No call!"); 1006 INFO("No call!");
1085 break; 1007 break;
1086 } 1008 }
1087 1009 else INFO("Hung up...");
1088 msi_hangup(_phone->_msi);
1089
1090 INFO("Hung up...");
1091 1010
1092 } break; 1011 } break;
1093 case 'a': 1012 case 'a':
1094 { 1013 {
1095 1014 ToxAvError rc;
1096 if ( _phone->_msi->call && _phone->_msi->call->state != call_starting ) { 1015
1097 break;
1098 }
1099
1100 if ( _len > 1 && _line[2] == 'v' ) 1016 if ( _len > 1 && _line[2] == 'v' )
1101 msi_answer(_phone->_msi, type_video); 1017 rc = toxav_answer(_phone->av, TypeVideo);
1102 else 1018 else
1103 msi_answer(_phone->_msi, type_audio); 1019 rc = toxav_answer(_phone->av, TypeAudio);
1020
1021 if ( rc == ErrorInvalidState ) {
1022 INFO("No call to answer!");
1023 }
1104 1024
1105 } break; 1025 } break;
1106 case 'r': 1026 case 'r':
1107 { 1027 {
1108 if ( _phone->_msi->call && _phone->_msi->call->state != call_starting ){ 1028 if ( toxav_reject(_phone->av, "User action") == ErrorInvalidState )
1109 break; 1029 INFO("No state to cancel!");
1110 } 1030 else INFO("Call Rejected...");
1111
1112 msi_reject(_phone->_msi, NULL);
1113
1114 INFO("Call Rejected...");
1115 1031
1116 } break; 1032 } break;
1117 case 'q': 1033 case 'q':
@@ -1124,7 +1040,6 @@ void do_phone ( av_session_t* _phone )
1124 } 1040 }
1125 default: 1041 default:
1126 { 1042 {
1127 INFO("Invalid command!");
1128 } break; 1043 } break;
1129 1044
1130 } 1045 }
diff --git a/toxav/toxrtp.c b/toxav/rtp.c
index d573d403..e23fa132 100755..100644
--- a/toxav/toxrtp.c
+++ b/toxav/rtp.c
@@ -26,7 +26,7 @@
26#include "config.h" 26#include "config.h"
27#endif /* HAVE_CONFIG_H */ 27#endif /* HAVE_CONFIG_H */
28 28
29#include "toxrtp.h" 29#include "rtp.h"
30#include <assert.h> 30#include <assert.h>
31#include <stdlib.h> 31#include <stdlib.h>
32 32
@@ -245,6 +245,7 @@ RTPHeader* extract_header ( const uint8_t* payload, int length )
245 * Now it my happen that this is out of order but 245 * Now it my happen that this is out of order but
246 * it cuts down chances of parsing some invalid value 246 * it cuts down chances of parsing some invalid value
247 */ 247 */
248
248 if ( GET_FLAG_VERSION(_retu) != RTP_VERSION ){ 249 if ( GET_FLAG_VERSION(_retu) != RTP_VERSION ){
249 /* Deallocate */ 250 /* Deallocate */
250 free(_retu); 251 free(_retu);
diff --git a/toxav/toxrtp.h b/toxav/rtp.h
index 4b0d681f..4b0d681f 100755..100644
--- a/toxav/toxrtp.h
+++ b/toxav/rtp.h
diff --git a/toxav/toxav.c b/toxav/toxav.c
new file mode 100644
index 00000000..8757d7fd
--- /dev/null
+++ b/toxav/toxav.c
@@ -0,0 +1,352 @@
1/** toxav.c
2 *
3 * Copyright (C) 2013 Tox project All Rights Reserved.
4 *
5 * This file is part of Tox.
6 *
7 * Tox is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * Tox is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
19 *
20 *
21 * Report bugs/suggestions at either #tox-dev @ freenode.net:6667 or
22 * my email: eniz_vukovic@hotmail.com
23 */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif /* HAVE_CONFIG_H */
28
29#include "toxav.h"
30#include "../toxcore/tox.h"
31#include "rtp.h"
32#include "msi.h"
33#include "media.h"
34
35#include <stdlib.h>
36#include <string.h>
37#include <assert.h>
38
39#define inline__ inline __attribute__((always_inline))
40
41static const uint8_t audio_index = 0, video_index = 1;
42
43
44typedef enum {
45 ts_closing,
46 ts_running,
47 ts_closed
48
49} ThreadState;
50
51typedef struct _ToxAv
52{
53 Tox* messenger;
54
55 MSISession* msi_session; /** Main msi session */
56
57 RTPSession* rtp_sessions[2]; /* Audio is first and video is second */
58
59 /* TODO: Add media session */
60 struct jitter_buffer* j_buf;
61 CodecState* cs;
62 /* TODO: Add media session threads */
63
64
65 void* agent_handler;
66} ToxAv;
67
68
69
70
71
72/********************************************************************************************************************
73 ********************************************************************************************************************
74 ********************************************************************************************************************
75 ********************************************************************************************************************
76 ********************************************************************************************************************
77 *
78 *
79 *
80 * PUBLIC API FUNCTIONS IMPLEMENTATIONS
81 *
82 *
83 *
84 ********************************************************************************************************************
85 ********************************************************************************************************************
86 ********************************************************************************************************************
87 ********************************************************************************************************************
88 ********************************************************************************************************************/
89
90
91
92ToxAv* toxav_new( Tox* messenger, void* useragent, const char* ua_name )
93{
94 ToxAv* av = calloc ( sizeof(ToxAv), 1);
95
96 av->msi_session = msi_init_session(messenger, (const unsigned char*) ua_name );
97 av->msi_session->agent_handler = av;
98
99 av->rtp_sessions[0] = av->rtp_sessions [1] = NULL;
100
101 av->messenger = messenger;
102
103 /* NOTE: This should be user defined or? */
104 av->j_buf = create_queue(20);
105
106 av->cs = codec_init_session(AUDIO_BITRATE, AUDIO_FRAME_DURATION, AUDIO_SAMPLE_RATE, 1, VIDEO_BITRATE, DEFAULT_WEBCAM, VIDEO_DRIVER);
107
108 av->agent_handler = useragent;
109
110 return av;
111}
112
113void toxav_kill ( ToxAv* av )
114{
115 msi_terminate_session(av->msi_session);
116
117 if ( av->rtp_sessions[audio_index] ) {
118 rtp_terminate_session(av->rtp_sessions[audio_index], av->msi_session->messenger_handle);
119 }
120
121 if ( av->rtp_sessions[video_index] ) {
122 rtp_terminate_session(av->rtp_sessions[video_index], av->msi_session->messenger_handle);
123 }
124
125 codec_terminate_session(av->cs);
126
127 free(av);
128}
129
130void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID id )
131{
132 msi_register_callback((MSICallback)callback, (MSICallbackID) id);
133}
134
135
136
137int toxav_call (ToxAv* av, int user, ToxAvCallType call_type, int ringing_seconds )
138{
139 if ( av->msi_session->call ) {
140 return ErrorAlreadyInCall;
141 }
142
143 return msi_invite(av->msi_session, call_type, ringing_seconds * 1000, user);
144}
145
146int toxav_hangup ( ToxAv* av )
147{
148 if ( !av->msi_session->call ) {
149 return ErrorNoCall;
150 }
151
152 if ( av->msi_session->call->state != call_active ) {
153 return ErrorInvalidState;
154 }
155
156 return msi_hangup(av->msi_session);
157}
158
159int toxav_answer ( ToxAv* av, ToxAvCallType call_type )
160{
161 if ( !av->msi_session->call ) {
162 return ErrorNoCall;
163 }
164
165 if ( av->msi_session->call->state != call_starting ) {
166 return ErrorInvalidState;
167 }
168
169 return msi_answer(av->msi_session, call_type);
170}
171
172int toxav_reject ( ToxAv* av, const char* reason )
173{
174 if ( !av->msi_session->call ) {
175 return ErrorNoCall;
176 }
177
178 if ( av->msi_session->call->state != call_starting ) {
179 return ErrorInvalidState;
180 }
181
182 return msi_reject(av->msi_session, (const uint8_t*) reason);
183}
184
185int toxav_cancel ( ToxAv* av, const char* reason )
186{
187 if ( !av->msi_session->call ) {
188 return ErrorNoCall;
189 }
190
191 return msi_cancel(av->msi_session, 0, (const uint8_t*)reason);
192}
193
194/* You can stop the call at any state */
195int toxav_stop_call ( ToxAv* av )
196{
197 if ( !av->msi_session->call ) {
198 return ErrorNoCall;
199 }
200
201 return msi_stopcall(av->msi_session);
202}
203
204
205int toxav_prepare_transmission ( ToxAv* av )
206{
207 assert(av->msi_session);
208 if ( !av->msi_session || !av->msi_session->call ) {
209 return ErrorNoCall;
210 }
211
212 av->rtp_sessions[audio_index] = rtp_init_session(
213 type_audio,
214 av->messenger,
215 av->msi_session->call->peers[0],
216 av->msi_session->call->key_peer,
217 av->msi_session->call->key_local,
218 av->msi_session->call->nonce_peer,
219 av->msi_session->call->nonce_local
220 );
221
222
223 if ( !av->rtp_sessions[audio_index] ) {
224 fprintf(stderr, "Error while starting audio RTP session!\n");
225 return ErrorStartingAudioRtp;
226 }
227
228 av->rtp_sessions[video_index] = rtp_init_session (
229 type_video,
230 av->messenger,
231 av->msi_session->call->peers[0],
232 av->msi_session->call->key_peer,
233 av->msi_session->call->key_local,
234 av->msi_session->call->nonce_peer,
235 av->msi_session->call->nonce_local
236 );
237
238
239 if ( !av->rtp_sessions[video_index] ) {
240 fprintf(stderr, "Error while starting video RTP session!\n");
241 return ErrorStartingVideoRtp;
242 }
243
244 return ErrorNone;
245}
246
247
248int toxav_kill_transmission ( ToxAv* av )
249{
250 /* Both sessions should be active at any time */
251 if ( !av->rtp_sessions[0] || !av->rtp_sessions[0] )
252 return ErrorNoTransmission;
253
254
255 if ( -1 == rtp_terminate_session(av->rtp_sessions[audio_index], av->messenger) ) {
256 fprintf(stderr, "Error while terminating audio RTP session!\n");
257 return ErrorTerminatingAudioRtp;
258 }
259
260 if ( -1 == rtp_terminate_session(av->rtp_sessions[video_index], av->messenger) ) {
261 fprintf(stderr, "Error while terminating video RTP session!\n");
262 return ErrorTerminatingVideoRtp;
263 }
264
265 return ErrorNone;
266}
267
268
269inline__ int toxav_send_rtp_payload ( ToxAv* av, ToxAvCallType type, const uint8_t* payload, uint16_t length )
270{
271 if ( av->rtp_sessions[type - TypeAudio] )
272 return rtp_send_msg ( av->rtp_sessions[type - TypeAudio], av->msi_session->messenger_handle, payload, length );
273 else return -1;
274}
275
276inline__ int toxav_recv_rtp_payload ( ToxAv* av, ToxAvCallType type, int ready, uint8_t* dest )
277{
278 if ( !dest ) return ErrorInternal;
279
280 if ( !av->rtp_sessions[type - TypeAudio] ) return ErrorNoRtpSession;
281
282 RTPMessage* message;
283
284 if ( type == TypeAudio ) {
285
286 message = rtp_recv_msg(av->rtp_sessions[audio_index]);
287
288 if (message) {
289 /* push the packet into the queue */
290 queue(av->j_buf, message);
291 }
292
293 if (ready) {
294 int success = 0;
295 message = dequeue(av->j_buf, &success);
296
297 if ( success == 2) return ErrorAudioPacketLost;
298 }
299 else return 0;
300 }
301 else {
302 message = rtp_recv_msg(av->rtp_sessions[video_index]);
303 }
304
305 if ( message ) {
306 memcpy(dest, message->data, message->length);
307
308 int length = message->length;
309
310 rtp_free_msg(NULL, message);
311
312 return length;
313 }
314
315 return 0;
316}
317
318inline__ int toxav_decode_audio ( ToxAv* av, const uint8_t* payload, uint16_t length, int frame_size, short int* dest )
319{
320 if ( !dest ) return ErrorInternal;
321
322 return opus_decode(av->cs->audio_decoder, payload, length, dest, frame_size, payload ? 0 : 1);
323}
324
325inline__ int toxav_encode_audio ( ToxAv* av, const short int* frame, int frame_size, uint8_t* dest )
326{
327 if ( !dest )
328 return ErrorInternal;
329
330 return opus_encode(av->cs->audio_encoder, frame, frame_size, dest, RTP_PAYLOAD_SIZE);
331}
332
333int toxav_get_peer_transmission_type ( ToxAv* av, int peer )
334{
335 assert(av->msi_session);
336 if ( peer < 0 || !av->msi_session->call || av->msi_session->call->peer_count <= peer )
337 return ErrorInternal;
338
339 return av->msi_session->call->type_peer[peer];
340}
341
342void* toxav_get_agent_handler ( ToxAv* av )
343{
344 return av->agent_handler;
345}
346
347
348/* Only temporary */
349void* get_cs_temp(ToxAv* av)
350{
351 return av->cs;
352}
diff --git a/toxav/toxav.h b/toxav/toxav.h
new file mode 100644
index 00000000..96a666a2
--- /dev/null
+++ b/toxav/toxav.h
@@ -0,0 +1,129 @@
1/** toxav.h
2 *
3 * Copyright (C) 2013 Tox project All Rights Reserved.
4 *
5 * This file is part of Tox.
6 *
7 * Tox is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * Tox is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
19 *
20 *
21 * Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or
22 * my email: eniz_vukovic@hotmail.com
23 */
24
25
26#ifndef __TOXAV
27#define __TOXAV
28#include <inttypes.h>
29
30typedef void* ( *ToxAVCallback ) ( void* arg );
31typedef struct _ToxAv ToxAv;
32
33#ifndef __TOX_DEFINED__
34#define __TOX_DEFINED__
35typedef struct Tox Tox;
36#endif
37
38#define RTP_PAYLOAD_SIZE 10400
39
40/**
41 * @brief Callbacks ids that handle the call states
42 */
43typedef enum {
44 /* Requests */
45 OnInvite,
46 OnStart,
47 OnCancel,
48 OnReject,
49 OnEnd,
50
51 /* Responses */
52 OnRinging,
53 OnStarting,
54 OnEnding,
55
56 /* Protocol */
57 OnError,
58 OnTimeout
59
60} ToxAvCallbackID;
61
62
63/**
64 * @brief Call type identifier.
65 */
66typedef enum {
67 TypeAudio = 70,
68 TypeVideo
69} ToxAvCallType;
70
71
72typedef enum {
73 ErrorNone = 0,
74 ErrorInternal = -1, /* Internal error */
75 ErrorAlreadyInCall = -2, /* Already has an active call */
76 ErrorNoCall = -3, /* Trying to perform call action while not in a call */
77 ErrorInvalidState = -4, /* Trying to perform call action while in invalid state*/
78 ErrorNoRtpSession = -5, /* Trying to perform rtp action on invalid session */
79 ErrorAudioPacketLost = -6, /* Indicating packet loss */
80 ErrorStartingAudioRtp = -7, /* Error in toxav_prepare_transmission() */
81 ErrorStartingVideoRtp = -8 , /* Error in toxav_prepare_transmission() */
82 ErrorNoTransmission = -9, /* Returned in toxav_kill_transmission() */
83 ErrorTerminatingAudioRtp = -10, /* Returned in toxav_kill_transmission() */
84 ErrorTerminatingVideoRtp = -11, /* Returned in toxav_kill_transmission() */
85
86} ToxAvError;
87
88
89ToxAv* toxav_new(Tox* messenger, void* useragent, const char* ua_name);
90void toxav_kill(ToxAv* av);
91
92void toxav_register_callstate_callback (ToxAVCallback callback, ToxAvCallbackID id);
93
94
95int toxav_call(ToxAv* av, int user, ToxAvCallType call_type, int ringing_seconds);
96int toxav_hangup(ToxAv* av);
97int toxav_answer(ToxAv* av, ToxAvCallType call_type );
98int toxav_reject(ToxAv* av, const char* reason);
99int toxav_cancel(ToxAv* av, const char* reason);
100int toxav_stop_call(ToxAv* av);
101
102int toxav_prepare_transmission(ToxAv* av);
103int toxav_kill_transmission(ToxAv* av);
104
105
106int toxav_send_rtp_payload(ToxAv* av, ToxAvCallType type, const uint8_t* payload, uint16_t length);
107
108/* Return length of received packet. Returns 0 if nothing recved. Dest has to have
109 * MAX_RTP_PAYLOAD_SIZE space available. Returns -1 if packet is not ready (ready < 1) for deque.
110 * For video packets set 'ready' at _any_ value.
111 */
112int toxav_recv_rtp_payload(ToxAv* av, ToxAvCallType type, int ready, uint8_t* dest);
113
114
115
116
117int toxav_decode_audio( ToxAv* av, const uint8_t* payload, uint16_t length, int frame_size, short int* dest );
118
119/* Please make sure 'dest' has enough storage for RTP_PAYLOAD_SIZE length of data */
120int toxav_encode_audio( ToxAv* av, const short int* frame, int frame_size, uint8_t* dest );
121
122
123
124int toxav_get_peer_transmission_type ( ToxAv* av, int peer );
125void* toxav_get_agent_handler ( ToxAv* av );
126
127/* Use this to get handle of CodecState from ToxAv struct */
128void* get_cs_temp( ToxAv* av );
129#endif /* __TOXAV */ \ No newline at end of file