summaryrefslogtreecommitdiff
path: root/toxav/toxav.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxav/toxav.c')
-rw-r--r--toxav/toxav.c562
1 files changed, 332 insertions, 230 deletions
diff --git a/toxav/toxav.c b/toxav/toxav.c
index a042b9dd..a301e007 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -17,8 +17,6 @@
17 * You should have received a copy of the GNU General Public License 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/>. 18 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
19 * 19 *
20 *
21 * Report bugs/suggestions at #tox-dev @ freenode.net:6667
22 */ 20 */
23 21
24#ifdef HAVE_CONFIG_H 22#ifdef HAVE_CONFIG_H
@@ -29,19 +27,22 @@
29#define _GNU_SOURCE /* implicit declaration warning */ 27#define _GNU_SOURCE /* implicit declaration warning */
30 28
31#include "rtp.h" 29#include "rtp.h"
32#include "media.h" 30#include "codec.h"
33#include "msi.h" 31#include "msi.h"
34#include "toxav.h" 32#include "toxav.h"
35 33
36#include "../toxcore/logger.h" 34#include "../toxcore/logger.h"
37 35
38
39#include <assert.h> 36#include <assert.h>
40#include <stdlib.h> 37#include <stdlib.h>
41#include <string.h> 38#include <string.h>
42 39
43/* Assume 60 fps*/ 40/* Assume 60 fps*/
44#define MAX_ENCODE_TIME_US ((1000 / 60) * 1000) 41#define MAX_ENCODE_TIME_US ((1000 / 24) * 1000)
42
43#define MAX_VIDEOFRAME_SIZE 0x40000 /* 256KiB */
44#define VIDEOFRAME_PIECE_SIZE 0x500 /* 1.25 KiB*/
45#define VIDEOFRAME_HEADER_SIZE 0x2
45 46
46 47
47#define inline__ inline __attribute__((always_inline)) 48#define inline__ inline __attribute__((always_inline))
@@ -61,6 +62,13 @@ typedef struct _CallSpecific {
61 * reuse them really. 62 * reuse them really.
62 */ 63 */
63 JitterBuffer *j_buf; /** Jitter buffer for audio */ 64 JitterBuffer *j_buf; /** Jitter buffer for audio */
65
66 uint32_t frame_limit; /* largest address written to in frame_buf for current input frame*/
67 uint8_t frame_id, frame_outid; /* id of input and output video frame */
68 void *frame_buf; /* buffer for split video payloads */
69
70 _Bool call_active;
71 pthread_mutex_t mutex;
64} CallSpecific; 72} CallSpecific;
65 73
66 74
@@ -68,19 +76,25 @@ struct _ToxAv {
68 Messenger *messenger; 76 Messenger *messenger;
69 MSISession *msi_session; /** Main msi session */ 77 MSISession *msi_session; /** Main msi session */
70 CallSpecific *calls; /** Per-call params */ 78 CallSpecific *calls; /** Per-call params */
79
80 void (*audio_callback)(ToxAv *, int32_t, int16_t *, int);
81 void (*video_callback)(ToxAv *, int32_t, vpx_image_t *);
82
71 uint32_t max_calls; 83 uint32_t max_calls;
72}; 84};
73 85
74const ToxAvCodecSettings av_DefaultSettings = { 86const ToxAvCodecSettings av_DefaultSettings = {
75 1000000, 87 500,
76 800, 88 1280,
77 600, 89 720,
78 90
79 64000, 91 64000,
80 20, 92 20,
81 48000, 93 48000,
82 1, 94 1,
83 20 95 600,
96
97 6
84}; 98};
85 99
86 100
@@ -123,8 +137,6 @@ ToxAv *toxav_new( Tox *messenger, int32_t max_calls)
123 */ 137 */
124void toxav_kill ( ToxAv *av ) 138void toxav_kill ( ToxAv *av )
125{ 139{
126 msi_terminate_session(av->msi_session);
127
128 int i = 0; 140 int i = 0;
129 141
130 for (; i < av->max_calls; i ++) { 142 for (; i < av->max_calls; i ++) {
@@ -142,6 +154,8 @@ void toxav_kill ( ToxAv *av )
142 if ( av->calls[i].cs ) codec_terminate_session(av->calls[i].cs); 154 if ( av->calls[i].cs ) codec_terminate_session(av->calls[i].cs);
143 } 155 }
144 156
157 msi_terminate_session(av->msi_session);
158
145 free(av->calls); 159 free(av->calls);
146 free(av); 160 free(av);
147} 161}
@@ -159,6 +173,28 @@ void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID
159} 173}
160 174
161/** 175/**
176 * @brief Register callback for recieving audio data
177 *
178 * @param callback The callback
179 * @return void
180 */
181void toxav_register_audio_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, int16_t *, int))
182{
183 av->audio_callback = callback;
184}
185
186/**
187 * @brief Register callback for recieving video data
188 *
189 * @param callback The callback
190 * @return void
191 */
192void toxav_register_video_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, vpx_image_t *))
193{
194 av->video_callback = callback;
195}
196
197/**
162 * @brief Call user. Use its friend_id. 198 * @brief Call user. Use its friend_id.
163 * 199 *
164 * @param av Handler. 200 * @param av Handler.
@@ -255,6 +291,10 @@ int toxav_cancel ( ToxAv *av, int32_t call_index, int peer_id, const char *reaso
255 return ErrorNoCall; 291 return ErrorNoCall;
256 } 292 }
257 293
294 if ( av->msi_session->calls[call_index]->state != call_inviting ) {
295 return ErrorInvalidState;
296 }
297
258 return msi_cancel(av->msi_session, call_index, peer_id, reason); 298 return msi_cancel(av->msi_session, call_index, peer_id, reason);
259} 299}
260 300
@@ -285,59 +325,80 @@ int toxav_stop_call ( ToxAv *av, int32_t call_index )
285 */ 325 */
286int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video ) 326int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video )
287{ 327{
288 if ( !av->msi_session || cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) { 328 if ( !av->msi_session || cii(call_index, av->msi_session) ||
289 LOGGER_ERROR("Error while starting audio RTP session: invalid call!\n"); 329 !av->msi_session->calls[call_index] || av->calls[call_index].call_active) {
330 LOGGER_ERROR("Error while starting RTP session: invalid call!\n");
290 return ErrorInternal; 331 return ErrorInternal;
291 } 332 }
292 333
293 CallSpecific *call = &av->calls[call_index]; 334 CallSpecific *call = &av->calls[call_index];
294 335
295 call->crtps[audio_index] = 336 call->crtps[audio_index] =
296 rtp_init_session( 337 rtp_init_session(type_audio, av->messenger, av->msi_session->calls[call_index]->peers[0]);
297 type_audio,
298 av->messenger,
299 av->msi_session->calls[call_index]->peers[0],
300 av->msi_session->calls[call_index]->key_peer,
301 av->msi_session->calls[call_index]->key_local,
302 av->msi_session->calls[call_index]->nonce_peer,
303 av->msi_session->calls[call_index]->nonce_local);
304 338
305 339
306 if ( !call->crtps[audio_index] ) { 340 if ( !call->crtps[audio_index] ) {
307 LOGGER_ERROR("Error while starting audio RTP session!\n"); 341 LOGGER_ERROR("Error while starting audio RTP session!\n");
308 return ErrorStartingAudioRtp; 342 return ErrorInternal;
309 } 343 }
310 344
345 call->crtps[audio_index]->call_index = call_index;
346 call->crtps[audio_index]->av = av;
311 347
312 if ( support_video ) { 348 if ( support_video ) {
313 call->crtps[video_index] = 349 call->crtps[video_index] =
314 rtp_init_session ( 350 rtp_init_session(type_video, av->messenger, av->msi_session->calls[call_index]->peers[0]);
315 type_video,
316 av->messenger,
317 av->msi_session->calls[call_index]->peers[0],
318 av->msi_session->calls[call_index]->key_peer,
319 av->msi_session->calls[call_index]->key_local,
320 av->msi_session->calls[call_index]->nonce_peer,
321 av->msi_session->calls[call_index]->nonce_local);
322
323 351
324 if ( !call->crtps[video_index] ) { 352 if ( !call->crtps[video_index] ) {
325 LOGGER_ERROR("Error while starting video RTP session!\n"); 353 LOGGER_ERROR("Error while starting video RTP session!\n");
326 return ErrorStartingVideoRtp; 354 goto error;
355 }
356
357 call->crtps[video_index]->call_index = call_index;
358 call->crtps[video_index]->av = av;
359
360 call->frame_limit = 0;
361 call->frame_id = 0;
362 call->frame_outid = 0;
363
364 call->frame_buf = calloc(MAX_VIDEOFRAME_SIZE, 1);
365
366 if (!call->frame_buf) {
367 LOGGER_WARNING("Frame buffer allocation failed!");
368 goto error;
327 } 369 }
370
371 }
372
373 if ( !(call->j_buf = create_queue(codec_settings->jbuf_capacity)) ) {
374 LOGGER_WARNING("Jitter buffer creaton failed!");
375 goto error;
328 } 376 }
329 377
330 if ( !(call->j_buf = create_queue(codec_settings->jbuf_capacity)) ) return ErrorInternal; 378 if ( (call->cs = codec_init_session(codec_settings->audio_bitrate,
379 codec_settings->audio_frame_duration,
380 codec_settings->audio_sample_rate,
381 codec_settings->audio_channels,
382 codec_settings->audio_VAD_tolerance,
383 codec_settings->max_video_width,
384 codec_settings->max_video_height,
385 codec_settings->video_bitrate) )) {
331 386
332 call->cs = codec_init_session(codec_settings->audio_bitrate, 387 if ( pthread_mutex_init(&call->mutex, NULL) != 0 ) goto error;
333 codec_settings->audio_frame_duration, 388
334 codec_settings->audio_sample_rate, 389 call->call_active = 1;
335 codec_settings->audio_channels, 390
336 codec_settings->video_width, 391 return ErrorNone;
337 codec_settings->video_height, 392 }
338 codec_settings->video_bitrate);
339 393
340 return call->cs ? ErrorNone : ErrorInternal; 394error:
395 rtp_terminate_session(call->crtps[audio_index], av->messenger);
396 rtp_terminate_session(call->crtps[video_index], av->messenger);
397 free(call->frame_buf);
398 terminate_queue(call->j_buf);
399 codec_terminate_session(call->cs);
400
401 return ErrorInternal;
341} 402}
342 403
343/** 404/**
@@ -350,34 +411,35 @@ int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettin
350 */ 411 */
351int toxav_kill_transmission ( ToxAv *av, int32_t call_index ) 412int toxav_kill_transmission ( ToxAv *av, int32_t call_index )
352{ 413{
353 if (cii(call_index, av->msi_session)) return ErrorNoCall; 414 if (cii(call_index, av->msi_session)) {
415 LOGGER_WARNING("Invalid call index: %d", call_index);
416 return ErrorNoCall;
417 }
354 418
355 CallSpecific *call = &av->calls[call_index]; 419 CallSpecific *call = &av->calls[call_index];
356 420
357 if ( call->crtps[audio_index] && -1 == rtp_terminate_session(call->crtps[audio_index], av->messenger) ) { 421 pthread_mutex_lock(&call->mutex);
358 LOGGER_ERROR("Error while terminating audio RTP session!\n");
359 return ErrorTerminatingAudioRtp;
360 }
361 422
362 if ( call->crtps[video_index] && -1 == rtp_terminate_session(call->crtps[video_index], av->messenger) ) { 423 if (!call->call_active) {
363 LOGGER_ERROR("Error while terminating video RTP session!\n"); 424 pthread_mutex_unlock(&call->mutex);
364 return ErrorTerminatingVideoRtp; 425 LOGGER_WARNING("Action on inactive call: %d", call_index);
426 return ErrorNoCall;
365 } 427 }
366 428
429
430 call->call_active = 0;
431
432 rtp_terminate_session(call->crtps[audio_index], av->messenger);
367 call->crtps[audio_index] = NULL; 433 call->crtps[audio_index] = NULL;
434 rtp_terminate_session(call->crtps[video_index], av->messenger);
368 call->crtps[video_index] = NULL; 435 call->crtps[video_index] = NULL;
436 terminate_queue(call->j_buf);
437 call->j_buf = NULL;
438 codec_terminate_session(call->cs);
439 call->cs = NULL;
369 440
370 if ( call->j_buf ) { 441 pthread_mutex_unlock(&call->mutex);
371 terminate_queue(call->j_buf); 442 pthread_mutex_destroy(&call->mutex);
372 call->j_buf = NULL;
373 LOGGER_DEBUG("Terminated j queue");
374 } else LOGGER_DEBUG("No j queue");
375
376 if ( call->cs ) {
377 codec_terminate_session(call->cs);
378 call->cs = NULL;
379 LOGGER_DEBUG("Terminated codec session");
380 } else LOGGER_DEBUG("No codec session");
381 443
382 return ErrorNone; 444 return ErrorNone;
383} 445}
@@ -395,122 +457,83 @@ int toxav_kill_transmission ( ToxAv *av, int32_t call_index )
395 * @retval -1 Failure. 457 * @retval -1 Failure.
396 */ 458 */
397inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, const uint8_t *payload, 459inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, const uint8_t *payload,
398 uint16_t length ) 460 unsigned int length )
399{ 461{
400 if (cii(call_index, av->msi_session)) return ErrorNoCall; 462 CallSpecific *call = &av->calls[call_index];
401 463
402 if ( av->calls[call_index].crtps[type - TypeAudio] ) 464 if (call->crtps[type - TypeAudio]) {
403 return rtp_send_msg ( av->calls[call_index].crtps[type - TypeAudio], av->msi_session->messenger_handle, payload,
404 length );
405 else return -1;
406}
407 465
408/** 466 if (type == TypeAudio) {
409 * @brief Receive RTP payload. 467 return rtp_send_msg(call->crtps[type - TypeAudio], av->messenger, payload, length);
410 * 468 } else {
411 * @param av Handler. 469 if (length == 0 || length > MAX_VIDEOFRAME_SIZE) {
412 * @param type Type of the payload. 470 LOGGER_ERROR("Invalid video frame size: %u\n", length);
413 * @param dest Storage. 471 return ErrorInternal;
414 * @return int 472 }
415 * @retval ToxAvError On Error.
416 * @retval >=0 Size of received payload.
417 */
418inline__ int toxav_recv_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, uint8_t *dest )
419{
420 if ( !dest ) return ErrorInternal;
421 473
422 if (cii(call_index, av->msi_session)) return ErrorNoCall; 474 /* number of pieces - 1*/
475 uint8_t numparts = (length - 1) / VIDEOFRAME_PIECE_SIZE;
423 476
424 CallSpecific *call = &av->calls[call_index]; 477 uint8_t load[2 + VIDEOFRAME_PIECE_SIZE];
478 load[0] = call->frame_outid++;
479 load[1] = 0;
425 480
426 if ( !call->crtps[type - TypeAudio] ) return ErrorNoRtpSession; 481 int i;
427 482
428 RTPMessage *message; 483 for (i = 0; i < numparts; i++) {
484 memcpy(load + VIDEOFRAME_HEADER_SIZE, payload, VIDEOFRAME_PIECE_SIZE);
485 payload += VIDEOFRAME_PIECE_SIZE;
429 486
430 if ( type == TypeAudio ) { 487 if (rtp_send_msg(call->crtps[type - TypeAudio], av->messenger,
488 load, VIDEOFRAME_HEADER_SIZE + VIDEOFRAME_PIECE_SIZE) != 0) {
431 489
432 do { 490 return ErrorInternal;
433 message = rtp_recv_msg(call->crtps[audio_index]); 491 }
434 492
435 if (message) { 493 load[1]++;
436 /* push the packet into the queue */
437 queue(call->j_buf, message);
438 } 494 }
439 } while (message);
440 495
441 int success = 0; 496 /* remainder = length % VIDEOFRAME_PIECE_SIZE, VIDEOFRAME_PIECE_SIZE if = 0 */
442 message = dequeue(call->j_buf, &success); 497 length = ((length - 1) % VIDEOFRAME_PIECE_SIZE) + 1;
498 memcpy(load + VIDEOFRAME_HEADER_SIZE, payload, length);
443 499
444 if ( success == 2) return ErrorAudioPacketLost; 500 return rtp_send_msg(call->crtps[type - TypeAudio], av->messenger, load, VIDEOFRAME_HEADER_SIZE + length);
501 }
445 } else { 502 } else {
446 message = rtp_recv_msg(call->crtps[video_index]); 503 return ErrorNoRtpSession;
447 }
448
449 if ( message ) {
450 memcpy(dest, message->data, message->length);
451
452 int length = message->length;
453
454 rtp_free_msg(NULL, message);
455
456 return length;
457 } 504 }
458
459 return 0;
460} 505}
461 506
462/** 507/**
463 * @brief Receive decoded video packet. 508 * @brief Encode and send video packet.
464 * 509 *
465 * @param av Handler. 510 * @param av Handler.
466 * @param output Storage. 511 * @param input The packet.
467 * @return int 512 * @return int
468 * @retval 0 Success. 513 * @retval 0 Success.
469 * @retval ToxAvError On Error. 514 * @retval ToxAvError On error.
470 */ 515 */
471inline__ int toxav_recv_video ( ToxAv *av, int32_t call_index, vpx_image_t **output) 516inline__ int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size)
472{ 517{
473 if ( !output ) return ErrorInternal; 518 if (cii(call_index, av->msi_session)) {
474 519 LOGGER_WARNING("Invalid call index: %d", call_index);
475 if (cii(call_index, av->msi_session)) return ErrorNoCall; 520 return ErrorNoCall;
521 }
476 522
477 uint8_t packet [RTP_PAYLOAD_SIZE];
478 int recved_size = 0;
479 int rc;
480 CallSpecific *call = &av->calls[call_index]; 523 CallSpecific *call = &av->calls[call_index];
524 pthread_mutex_lock(&call->mutex);
481 525
482 do {
483 recved_size = toxav_recv_rtp_payload(av, call_index, TypeVideo, packet);
484
485 if (recved_size > 0 && ( rc = vpx_codec_decode(&call->cs->v_decoder, packet, recved_size, NULL, 0) ) != VPX_CODEC_OK) {
486 LOGGER_ERROR("Error decoding video: %s\n", vpx_codec_err_to_string(rc));
487 return ErrorInternal;
488 }
489
490 } while (recved_size > 0);
491 526
492 vpx_codec_iter_t iter = NULL; 527 if (!call->call_active) {
493 vpx_image_t *img; 528 pthread_mutex_unlock(&call->mutex);
494 img = vpx_codec_get_frame(&call->cs->v_decoder, &iter); 529 LOGGER_WARNING("Action on inactive call: %d", call_index);
495 530 return ErrorNoCall;
496 *output = img; 531 }
497 return 0;
498}
499 532
500/** 533 int rc = toxav_send_rtp_payload(av, call_index, TypeVideo, frame, frame_size);
501 * @brief Encode and send video packet. 534 pthread_mutex_unlock(&call->mutex);
502 *
503 * @param av Handler.
504 * @param input The packet.
505 * @return int
506 * @retval 0 Success.
507 * @retval ToxAvError On error.
508 */
509inline__ int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size)
510{
511 if (cii(call_index, av->msi_session)) return ErrorNoCall;
512 535
513 return toxav_send_rtp_payload(av, call_index, TypeVideo, frame, frame_size); 536 return rc;
514} 537}
515 538
516/** 539/**
@@ -526,14 +549,31 @@ inline__ int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *fr
526 */ 549 */
527inline__ int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input) 550inline__ int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input)
528{ 551{
529 if (cii(call_index, av->msi_session)) return ErrorNoCall; 552 if (cii(call_index, av->msi_session)) {
553 LOGGER_WARNING("Invalid call index: %d", call_index);
554 return ErrorNoCall;
555 }
556
530 557
531 CallSpecific *call = &av->calls[call_index]; 558 CallSpecific *call = &av->calls[call_index];
559 pthread_mutex_lock(&call->mutex);
560
561 if (!call->call_active) {
562 pthread_mutex_unlock(&call->mutex);
563 LOGGER_WARNING("Action on inactive call: %d", call_index);
564 return ErrorNoCall;
565 }
566
567 if (reconfigure_video_encoder_resolution(call->cs, input->d_w, input->d_h) != 0) {
568 pthread_mutex_unlock(&call->mutex);
569 return ErrorInternal;
570 }
532 571
533 int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US); 572 int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US);
534 573
535 if ( rc != VPX_CODEC_OK) { 574 if ( rc != VPX_CODEC_OK) {
536 LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(rc)); 575 LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(rc));
576 pthread_mutex_unlock(&call->mutex);
537 return ErrorInternal; 577 return ErrorInternal;
538 } 578 }
539 579
@@ -545,61 +585,21 @@ inline__ int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *d
545 585
546 while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) { 586 while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) {
547 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { 587 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
548 if ( copied + pkt->data.frame.sz > dest_max ) return ErrorPacketTooLarge; 588 if ( copied + pkt->data.frame.sz > dest_max ) {
589 pthread_mutex_unlock(&call->mutex);
590 return ErrorPacketTooLarge;
591 }
549 592
550 memcpy(dest + copied, pkt->data.frame.buf, pkt->data.frame.sz); 593 memcpy(dest + copied, pkt->data.frame.buf, pkt->data.frame.sz);
551 copied += pkt->data.frame.sz; 594 copied += pkt->data.frame.sz;
552 } 595 }
553 } 596 }
554 597
598 pthread_mutex_unlock(&call->mutex);
555 return copied; 599 return copied;
556} 600}
557 601
558/** 602/**
559 * @brief Receive decoded audio frame.
560 *
561 * @param av Handler.
562 * @param frame_size The size of dest in frames/samples (one frame/sample is 16 bits or 2 bytes
563 * and corresponds to one sample of audio.)
564 * @param dest Destination of the raw audio (16 bit signed pcm with AUDIO_CHANNELS channels).
565 * Make sure it has enough space for frame_size frames/samples.
566 * @return int
567 * @retval >=0 Size of received data in frames/samples.
568 * @retval ToxAvError On error.
569 */
570inline__ int toxav_recv_audio ( ToxAv *av, int32_t call_index, int frame_size, int16_t *dest )
571{
572 if ( !dest ) return ErrorInternal;
573
574 if (cii(call_index, av->msi_session)) return ErrorNoCall;
575
576 CallSpecific *call = &av->calls[call_index];
577
578 uint8_t packet [RTP_PAYLOAD_SIZE];
579
580 int recved_size = toxav_recv_rtp_payload(av, call_index, TypeAudio, packet);
581
582 if ( recved_size == ErrorAudioPacketLost ) {
583 int dec_size = opus_decode(call->cs->audio_decoder, NULL, 0, dest, frame_size, 1);
584
585 if ( dec_size < 0 ) {
586 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
587 return ErrorInternal;
588 } else return dec_size;
589
590 } else if ( recved_size ) {
591 int dec_size = opus_decode(call->cs->audio_decoder, packet, recved_size, dest, frame_size, 0);
592
593 if ( dec_size < 0 ) {
594 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
595 return ErrorInternal;
596 } else return dec_size;
597 } else {
598 return 0; /* Nothing received */
599 }
600}
601
602/**
603 * @brief Send audio frame. 603 * @brief Send audio frame.
604 * 604 *
605 * @param av Handler. 605 * @param av Handler.
@@ -612,9 +612,25 @@ inline__ int toxav_recv_audio ( ToxAv *av, int32_t call_index, int frame_size, i
612 */ 612 */
613inline__ int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size) 613inline__ int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size)
614{ 614{
615 if (cii(call_index, av->msi_session)) return ErrorNoCall; 615 if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) {
616 LOGGER_WARNING("Action on inactive call: %d", call_index);
617 return ErrorNoCall;
618 }
619
620 CallSpecific *call = &av->calls[call_index];
621 pthread_mutex_lock(&call->mutex);
622
623
624 if (!call->call_active) {
625 pthread_mutex_unlock(&call->mutex);
626 LOGGER_WARNING("Action on inactive call: %d", call_index);
627 return ErrorNoCall;
628 }
616 629
617 return toxav_send_rtp_payload(av, call_index, TypeAudio, frame, frame_size); 630 int rc = toxav_send_rtp_payload(av, call_index, TypeAudio, frame, frame_size);
631 pthread_mutex_unlock(&call->mutex);
632
633 return rc;
618} 634}
619 635
620/** 636/**
@@ -632,9 +648,23 @@ inline__ int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *fr
632inline__ int toxav_prepare_audio_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, 648inline__ int toxav_prepare_audio_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max,
633 const int16_t *frame, int frame_size) 649 const int16_t *frame, int frame_size)
634{ 650{
635 if (cii(call_index, av->msi_session)) return ErrorNoCall; 651 if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) {
652 LOGGER_WARNING("Action on inactive call: %d", call_index);
653 return ErrorNoCall;
654 }
655
656 CallSpecific *call = &av->calls[call_index];
657 pthread_mutex_lock(&call->mutex);
636 658
637 int32_t rc = opus_encode(av->calls[call_index].cs->audio_encoder, frame, frame_size, dest, dest_max); 659
660 if (!call->call_active) {
661 pthread_mutex_unlock(&call->mutex);
662 LOGGER_WARNING("Action on inactive call: %d", call_index);
663 return ErrorNoCall;
664 }
665
666 int32_t rc = opus_encode(call->cs->audio_encoder, frame, frame_size, dest, dest_max);
667 pthread_mutex_unlock(&call->mutex);
638 668
639 if (rc < 0) { 669 if (rc < 0) {
640 LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc)); 670 LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc));
@@ -672,8 +702,6 @@ int toxav_get_peer_transmission_type ( ToxAv *av, int32_t call_index, int peer )
672 */ 702 */
673int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer ) 703int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer )
674{ 704{
675 assert(av->msi_session);
676
677 if ( peer < 0 || cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] 705 if ( peer < 0 || cii(call_index, av->msi_session) || !av->msi_session->calls[call_index]
678 || av->msi_session->calls[call_index]->peer_count <= peer ) 706 || av->msi_session->calls[call_index]->peer_count <= peer )
679 return ErrorInternal; 707 return ErrorInternal;
@@ -682,6 +710,23 @@ int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer )
682} 710}
683 711
684/** 712/**
713 * @brief Get id of peer participating in conversation
714 *
715 * @param av Handler
716 * @param peer peer index
717 * @return int
718 * @retval ToxAvError No peer id
719 */
720ToxAvCallState toxav_get_call_state(ToxAv *av, int32_t call_index)
721{
722 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] )
723 return av_CallNonExistant;
724
725 return av->msi_session->calls[call_index]->state;
726
727}
728
729/**
685 * @brief Is certain capability supported 730 * @brief Is certain capability supported
686 * 731 *
687 * @param av Handler 732 * @param av Handler
@@ -695,43 +740,100 @@ inline__ int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCa
695 /* 0 is error here */ 740 /* 0 is error here */
696} 741}
697 742
698/** 743inline__ Tox *toxav_get_tox(ToxAv *av)
699 * @brief Set queue limit
700 *
701 * @param av Handler
702 * @param call_index index
703 * @param limit the limit
704 * @return void
705 */
706inline__ int toxav_set_audio_queue_limit(ToxAv *av, int32_t call_index, uint64_t limit)
707{ 744{
708 if ( av->calls[call_index].crtps[audio_index] ) 745 return (Tox *)av->messenger;
709 rtp_queue_adjust_limit(av->calls[call_index].crtps[audio_index], limit);
710 else
711 return ErrorNoRtpSession;
712
713 return ErrorNone;
714} 746}
715 747
716/** 748int toxav_has_activity(ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t frame_size, float ref_energy)
717 * @brief Set queue limit
718 *
719 * @param av Handler
720 * @param call_index index
721 * @param limit the limit
722 * @return void
723 */
724inline__ int toxav_set_video_queue_limit(ToxAv *av, int32_t call_index, uint64_t limit)
725{ 749{
726 if ( av->calls[call_index].crtps[video_index] ) 750 if ( !av->calls[call_index].cs ) return ErrorInvalidCodecState;
727 rtp_queue_adjust_limit(av->calls[call_index].crtps[video_index], limit);
728 else
729 return ErrorNoRtpSession;
730 751
731 return ErrorNone; 752 return energy_VAD(av->calls[call_index].cs, PCM, frame_size, ref_energy);
732} 753}
733 754
734inline__ Tox *toxav_get_tox(ToxAv *av) 755void toxav_handle_packet(RTPSession *_session, RTPMessage *_msg)
735{ 756{
736 return (Tox *)av->messenger; 757 ToxAv *av = _session->av;
737} \ No newline at end of file 758 int32_t call_index = _session->call_index;
759 CallSpecific *call = &av->calls[call_index];
760
761 if (_session->payload_type == type_audio % 128) {
762 queue(call->j_buf, _msg);
763
764 int success = 0, dec_size;
765 int frame_size = 960;
766 int16_t dest[frame_size];
767
768 while ((_msg = dequeue(call->j_buf, &success)) || success == 2) {
769 if (success == 2) {
770 dec_size = opus_decode(call->cs->audio_decoder, NULL, 0, dest, frame_size, 1);
771 } else {
772 dec_size = opus_decode(call->cs->audio_decoder, _msg->data, _msg->length, dest, frame_size, 0);
773 rtp_free_msg(NULL, _msg);
774 }
775
776 if (dec_size < 0) {
777 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
778 continue;
779 }
780
781 av->audio_callback(av, call_index, dest, frame_size);
782 }
783 } else {
784 uint8_t *packet = _msg->data;
785 int recved_size = _msg->length;
786
787 if (recved_size < VIDEOFRAME_HEADER_SIZE) {
788 goto end;
789 }
790
791 uint8_t i = packet[0] - call->frame_id;
792
793 if (i == 0) {
794 /* piece of current frame */
795 } else if (i > 0 && i < 128) {
796 /* recieved a piece of a frame ahead, flush current frame and start reading this new frame */
797 int rc = vpx_codec_decode(&call->cs->v_decoder, call->frame_buf, call->frame_limit, NULL, 0);
798 call->frame_id = packet[0];
799 memset(call->frame_buf, 0, call->frame_limit);
800 call->frame_limit = 0;
801
802 if (rc != VPX_CODEC_OK) {
803 LOGGER_ERROR("Error decoding video: %u %s\n", i, vpx_codec_err_to_string(rc));
804 }
805 } else {
806 /* old packet, dont read */
807 LOGGER_DEBUG("Old packet: %u\n", i);
808 goto end;
809 }
810
811 if (packet[1] > (MAX_VIDEOFRAME_SIZE - VIDEOFRAME_PIECE_SIZE + 1) /
812 VIDEOFRAME_PIECE_SIZE) { //TODO, fix this check? not sure
813 /* packet out of buffer range */
814 goto end;
815 }
816
817 LOGGER_DEBUG("Video Packet: %u %u\n", packet[0], packet[1]);
818 memcpy(call->frame_buf + packet[1] * VIDEOFRAME_PIECE_SIZE, packet + VIDEOFRAME_HEADER_SIZE,
819 recved_size - VIDEOFRAME_HEADER_SIZE);
820 uint32_t limit = packet[1] * VIDEOFRAME_PIECE_SIZE + recved_size - VIDEOFRAME_HEADER_SIZE;
821
822 if (limit > call->frame_limit) {
823 call->frame_limit = limit;
824 LOGGER_DEBUG("Limit: %u\n", call->frame_limit);
825 }
826
827end:
828 ;
829 vpx_codec_iter_t iter = NULL;
830 vpx_image_t *img;
831 img = vpx_codec_get_frame(&call->cs->v_decoder, &iter);
832
833 if (img) {
834 av->video_callback(av, call_index, img);
835 }
836
837 rtp_free_msg(NULL, _msg);
838 }
839}