diff options
-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-x | toxav/phone.c | 465 | ||||
-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.c | 352 | ||||
-rw-r--r-- | toxav/toxav.h | 129 |
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 | ||
44 | struct jitter_buffer { | 43 | struct 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' */ |
80 | uint8_t sequence_number_older(uint16_t sn_a, uint16_t sn_b, uint32_t ts_a, uint32_t ts_b) | 79 | uint8_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 | ||
210 | int 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 | ||
232 | int init_receive_video(codec_state *cs) | 207 | int 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"); | 231 | int 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 | ||
257 | int init_send_video(codec_state *cs) | 244 | |
245 | int 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 | ||
337 | int init_send_audio(codec_state *cs) | 324 | int 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 | ||
356 | int init_encoder(codec_state *cs) | 340 | |
341 | CodecState* 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 | ||
374 | int init_decoder(codec_state *cs) | 383 | void 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 | ||
78 | typedef struct { | 76 | typedef 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 | ||
106 | typedef struct _RTPMessage RTPMessage; | ||
118 | 107 | ||
119 | struct jitter_buffer *create_queue(int capacity); | 108 | struct jitter_buffer *create_queue(int capacity); |
120 | int empty_queue(struct jitter_buffer *q); | 109 | int empty_queue(struct jitter_buffer *q); |
@@ -123,8 +112,14 @@ int queue(struct jitter_buffer *q, RTPMessage *pk); | |||
123 | RTPMessage *dequeue(struct jitter_buffer *q, int *success); | 112 | RTPMessage *dequeue(struct jitter_buffer *q, int *success); |
124 | 113 | ||
125 | 114 | ||
126 | int init_encoder(codec_state *cs); | 115 | CodecState* codec_init_session( uint32_t audio_bitrate, |
127 | int 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 | ||
123 | void 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 | */ |
1141 | MSISession* msi_init_session ( Tox* messenger, const uint8_t* user_agent ) { | 1139 | MSISession* 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 | */ |
1306 | int msi_cancel ( MSISession* session, int friend_id ) { | 1303 | int 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 | */ |
159 | MSISession* msi_init_session ( Tox* messenger, const uint8_t* user_agent ); | 159 | MSISession* 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 | */ |
211 | int msi_cancel ( MSISession* session, int friend_id ); | 212 | int 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 | ||
77 | typedef struct av_session_s { | 76 | typedef 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 | ||
244 | int display_received_frame(av_session_t* _phone, AVFrame *r_video_frame) | 240 | int 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 | ||
271 | int 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 | |||
315 | int 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 | |||
329 | void *encode_video_thread(void *arg) | 267 | void *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 | ||
464 | void *decode_video_thread(void *arg) | 408 | void *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 | ||
635 | ending: | 575 | ending: |
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 | ||
653 | int phone_startmedia_loop ( av_session_t* _phone ) | 596 | int 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 | ||
735 | void* callback_recv_invite ( void* _arg ) | 659 | void* 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 | } |
755 | void* callback_recv_starting ( void* _arg ) | 679 | void* 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 | } |
765 | void* callback_recv_ending ( void* _arg ) | 688 | void* 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 | ||
781 | void* callback_recv_error ( void* _arg ) | 710 | void* 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 | ||
789 | void* callback_call_started ( void* _arg ) | 718 | void* 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 | } |
810 | void* callback_call_ended ( void* _arg ) | 738 | void* 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 | ||
928 | int av_terminate_session(av_session_t* _phone) | 852 | int 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 | |||
41 | static const uint8_t audio_index = 0, video_index = 1; | ||
42 | |||
43 | |||
44 | typedef enum { | ||
45 | ts_closing, | ||
46 | ts_running, | ||
47 | ts_closed | ||
48 | |||
49 | } ThreadState; | ||
50 | |||
51 | typedef 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 | |||
92 | ToxAv* 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 | |||
113 | void 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 | |||
130 | void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID id ) | ||
131 | { | ||
132 | msi_register_callback((MSICallback)callback, (MSICallbackID) id); | ||
133 | } | ||
134 | |||
135 | |||
136 | |||
137 | int 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 | |||
146 | int 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 | |||
159 | int 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 | |||
172 | int 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 | |||
185 | int 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 */ | ||
195 | int 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 | |||
205 | int 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 | |||
248 | int 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 | |||
269 | inline__ 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 | |||
276 | inline__ 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 | |||
318 | inline__ 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 | |||
325 | inline__ 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 | |||
333 | int 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 | |||
342 | void* toxav_get_agent_handler ( ToxAv* av ) | ||
343 | { | ||
344 | return av->agent_handler; | ||
345 | } | ||
346 | |||
347 | |||
348 | /* Only temporary */ | ||
349 | void* 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 | |||
30 | typedef void* ( *ToxAVCallback ) ( void* arg ); | ||
31 | typedef struct _ToxAv ToxAv; | ||
32 | |||
33 | #ifndef __TOX_DEFINED__ | ||
34 | #define __TOX_DEFINED__ | ||
35 | typedef struct Tox Tox; | ||
36 | #endif | ||
37 | |||
38 | #define RTP_PAYLOAD_SIZE 10400 | ||
39 | |||
40 | /** | ||
41 | * @brief Callbacks ids that handle the call states | ||
42 | */ | ||
43 | typedef 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 | */ | ||
66 | typedef enum { | ||
67 | TypeAudio = 70, | ||
68 | TypeVideo | ||
69 | } ToxAvCallType; | ||
70 | |||
71 | |||
72 | typedef 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 | |||
89 | ToxAv* toxav_new(Tox* messenger, void* useragent, const char* ua_name); | ||
90 | void toxav_kill(ToxAv* av); | ||
91 | |||
92 | void toxav_register_callstate_callback (ToxAVCallback callback, ToxAvCallbackID id); | ||
93 | |||
94 | |||
95 | int toxav_call(ToxAv* av, int user, ToxAvCallType call_type, int ringing_seconds); | ||
96 | int toxav_hangup(ToxAv* av); | ||
97 | int toxav_answer(ToxAv* av, ToxAvCallType call_type ); | ||
98 | int toxav_reject(ToxAv* av, const char* reason); | ||
99 | int toxav_cancel(ToxAv* av, const char* reason); | ||
100 | int toxav_stop_call(ToxAv* av); | ||
101 | |||
102 | int toxav_prepare_transmission(ToxAv* av); | ||
103 | int toxav_kill_transmission(ToxAv* av); | ||
104 | |||
105 | |||
106 | int 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 | */ | ||
112 | int toxav_recv_rtp_payload(ToxAv* av, ToxAvCallType type, int ready, uint8_t* dest); | ||
113 | |||
114 | |||
115 | |||
116 | |||
117 | int 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 */ | ||
120 | int toxav_encode_audio( ToxAv* av, const short int* frame, int frame_size, uint8_t* dest ); | ||
121 | |||
122 | |||
123 | |||
124 | int toxav_get_peer_transmission_type ( ToxAv* av, int peer ); | ||
125 | void* toxav_get_agent_handler ( ToxAv* av ); | ||
126 | |||
127 | /* Use this to get handle of CodecState from ToxAv struct */ | ||
128 | void* get_cs_temp( ToxAv* av ); | ||
129 | #endif /* __TOXAV */ \ No newline at end of file | ||