summaryrefslogtreecommitdiff
path: root/toxav/toxav.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxav/toxav.c')
-rwxr-xr-xtoxav/toxav.c245
1 files changed, 130 insertions, 115 deletions
diff --git a/toxav/toxav.c b/toxav/toxav.c
index 0301c6b2..3a41754a 100755
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -25,17 +25,20 @@
25#include "config.h" 25#include "config.h"
26#endif /* HAVE_CONFIG_H */ 26#endif /* HAVE_CONFIG_H */
27 27
28
29#define _GNU_SOURCE /* implicit declaration warning */
30
28#include "rtp.h" 31#include "rtp.h"
29#include "media.h" 32#include "media.h"
30#include "msi.h" 33#include "msi.h"
34#include "toxav.h"
31 35
32#include "../toxcore/logger.h" 36#include "../toxcore/logger.h"
33 37
38
39#include <assert.h>
34#include <stdlib.h> 40#include <stdlib.h>
35#include <string.h> 41#include <string.h>
36#include <assert.h>
37
38#include "toxav.h"
39 42
40/* Assume 60 fps*/ 43/* Assume 60 fps*/
41#define MAX_ENCODE_TIME_US ((1000 / 60) * 1000) 44#define MAX_ENCODE_TIME_US ((1000 / 60) * 1000)
@@ -45,27 +48,23 @@
45 48
46static const uint8_t audio_index = 0, video_index = 1; 49static const uint8_t audio_index = 0, video_index = 1;
47 50
48typedef struct _CallRTPSessions { 51typedef struct _CallSpecific {
49 RTPSession *crtps[2]; /* Audio is first and video is second */ 52 RTPSession *crtps[2]; /** Audio is first and video is second */
50} CallRTPSessions; 53 CodecState *cs;/** Each call have its own encoders and decoders.
54 * You can, but don't have to, reuse encoders for
55 * multiple calls. If you choose to reuse encoders,
56 * make sure to also reuse encoded payload for every call.
57 * Decoders have to be unique for each call. FIXME: Now add refcounted encoders and
58 * reuse them really.
59 */
60 JitterBuffer *j_buf; /** Jitter buffer for audio */
61} CallSpecific;
51 62
52typedef enum {
53 ts_closing,
54 ts_running,
55 ts_closed
56
57} ThreadState;
58 63
59struct _ToxAv { 64struct _ToxAv {
60 Messenger *messenger; 65 Messenger *messenger;
61
62 MSISession *msi_session; /** Main msi session */ 66 MSISession *msi_session; /** Main msi session */
63 67 CallSpecific* calls; /** Per-call params */
64 CallRTPSessions* rtp_sessions;
65
66 struct jitter_buffer *j_buf;
67 CodecState *cs;
68
69 uint32_t max_calls; 68 uint32_t max_calls;
70}; 69};
71 70
@@ -93,7 +92,7 @@ const ToxAvCodecSettings av_DefaultSettings = {
93 * @return ToxAv* 92 * @return ToxAv*
94 * @retval NULL On error. 93 * @retval NULL On error.
95 */ 94 */
96ToxAv *toxav_new( Tox* messenger, ToxAvCodecSettings* codec_settings, uint32_t max_calls) 95ToxAv *toxav_new( Tox* messenger, uint32_t max_calls)
97{ 96{
98 ToxAv *av = calloc ( sizeof(ToxAv), 1); 97 ToxAv *av = calloc ( sizeof(ToxAv), 1);
99 98
@@ -105,19 +104,9 @@ ToxAv *toxav_new( Tox* messenger, ToxAvCodecSettings* codec_settings, uint32_t m
105 av->msi_session = msi_init_session(av->messenger, max_calls); 104 av->msi_session = msi_init_session(av->messenger, max_calls);
106 av->msi_session->agent_handler = av; 105 av->msi_session->agent_handler = av;
107 106
108 av->rtp_sessions = calloc(sizeof(CallRTPSessions), max_calls); 107 av->calls = calloc(sizeof(CallSpecific), max_calls);
109 av->max_calls = max_calls; 108 av->max_calls = max_calls;
110 109
111 av->j_buf = create_queue(codec_settings->jbuf_capacity);
112
113 av->cs = codec_init_session(codec_settings->audio_bitrate,
114 codec_settings->audio_frame_duration,
115 codec_settings->audio_sample_rate,
116 codec_settings->audio_channels,
117 codec_settings->video_width,
118 codec_settings->video_height,
119 codec_settings->video_bitrate);
120
121 return av; 110 return av;
122} 111}
123 112
@@ -133,19 +122,29 @@ void toxav_kill ( ToxAv *av )
133 122
134 int i = 0; 123 int i = 0;
135 for (; i < av->max_calls; i ++) { 124 for (; i < av->max_calls; i ++) {
136 if ( av->rtp_sessions[i].crtps[audio_index] ) { 125 if ( av->calls[i].crtps[audio_index] ) {
137 rtp_terminate_session(av->rtp_sessions[i].crtps[audio_index], av->msi_session->messenger_handle); 126 rtp_terminate_session(av->calls[i].crtps[audio_index], av->msi_session->messenger_handle);
138 } 127 }
139 128
140 if ( av->rtp_sessions[i].crtps[video_index] ) { 129 if ( av->calls[i].crtps[video_index] ) {
141 rtp_terminate_session(av->rtp_sessions[i].crtps[video_index], av->msi_session->messenger_handle); 130 rtp_terminate_session(av->calls[i].crtps[video_index], av->msi_session->messenger_handle);
131 }
132
133 av->calls[i].crtps[audio_index] = NULL;
134 av->calls[i].crtps[video_index] = NULL;
135
136 if ( av->calls[i].j_buf ) {
137 terminate_queue(av->calls[i].j_buf);
138 av->calls[i].j_buf = NULL;
139 }
140
141 if ( av->calls[i].cs ) {
142 codec_terminate_session(av->calls[i].cs);
143 av->calls[i].cs = NULL;
142 } 144 }
143 } 145 }
144 146
145 free(av->rtp_sessions); 147 free(av->calls);
146
147 codec_terminate_session(av->cs);
148
149 free(av); 148 free(av);
150} 149}
151 150
@@ -286,14 +285,16 @@ int toxav_stop_call ( ToxAv* av, uint32_t call_index )
286 * @retval 0 Success. 285 * @retval 0 Success.
287 * @retval ToxAvError On error. 286 * @retval ToxAvError On error.
288 */ 287 */
289int toxav_prepare_transmission ( ToxAv* av, uint32_t call_index, int support_video ) 288int toxav_prepare_transmission ( ToxAv* av, uint32_t call_index, ToxAvCodecSettings* codec_settings, int support_video )
290{ 289{
291 if ( !av->msi_session || av->msi_session->max_calls <= call_index || !av->msi_session->calls[call_index] ) { 290 if ( !av->msi_session || av->msi_session->max_calls <= call_index || !av->msi_session->calls[call_index] ) {
292 /*fprintf(stderr, "Error while starting audio RTP session: invalid call!\n");*/ 291 /*fprintf(stderr, "Error while starting audio RTP session: invalid call!\n");*/
293 return ErrorInternal; 292 return ErrorInternal;
294 } 293 }
295 294
296 av->rtp_sessions[call_index].crtps[audio_index] = 295 CallSpecific* call = &av->calls[call_index];
296
297 call->crtps[audio_index] =
297 rtp_init_session( 298 rtp_init_session(
298 type_audio, 299 type_audio,
299 av->messenger, 300 av->messenger,
@@ -301,18 +302,17 @@ int toxav_prepare_transmission ( ToxAv* av, uint32_t call_index, int support_vid
301 av->msi_session->calls[call_index]->key_peer, 302 av->msi_session->calls[call_index]->key_peer,
302 av->msi_session->calls[call_index]->key_local, 303 av->msi_session->calls[call_index]->key_local,
303 av->msi_session->calls[call_index]->nonce_peer, 304 av->msi_session->calls[call_index]->nonce_peer,
304 av->msi_session->calls[call_index]->nonce_local 305 av->msi_session->calls[call_index]->nonce_local);
305 );
306 306
307 307
308 if ( !av->rtp_sessions[call_index].crtps[audio_index] ) { 308 if ( !call->crtps[audio_index] ) {
309 /*fprintf(stderr, "Error while starting audio RTP session!\n");*/ 309 /*fprintf(stderr, "Error while starting audio RTP session!\n");*/
310 return ErrorStartingAudioRtp; 310 return ErrorStartingAudioRtp;
311 } 311 }
312 312
313 313
314 if ( support_video ) { 314 if ( support_video ) {
315 av->rtp_sessions[call_index].crtps[video_index] = 315 call->crtps[video_index] =
316 rtp_init_session ( 316 rtp_init_session (
317 type_video, 317 type_video,
318 av->messenger, 318 av->messenger,
@@ -320,18 +320,26 @@ int toxav_prepare_transmission ( ToxAv* av, uint32_t call_index, int support_vid
320 av->msi_session->calls[call_index]->key_peer, 320 av->msi_session->calls[call_index]->key_peer,
321 av->msi_session->calls[call_index]->key_local, 321 av->msi_session->calls[call_index]->key_local,
322 av->msi_session->calls[call_index]->nonce_peer, 322 av->msi_session->calls[call_index]->nonce_peer,
323 av->msi_session->calls[call_index]->nonce_local 323 av->msi_session->calls[call_index]->nonce_local);
324 );
325 324
326 325
327 if ( !av->rtp_sessions[call_index].crtps[video_index] ) { 326 if ( !call->crtps[video_index] ) {
328 /*fprintf(stderr, "Error while starting video RTP session!\n");*/ 327 /*fprintf(stderr, "Error while starting video RTP session!\n");*/
329 return ErrorStartingVideoRtp; 328 return ErrorStartingVideoRtp;
330 } 329 }
331 } 330 }
332 331
332 if ( !(call->j_buf = create_queue(codec_settings->jbuf_capacity)) ) return ErrorInternal;
333 333
334 return ErrorNone; 334 call->cs = codec_init_session(codec_settings->audio_bitrate,
335 codec_settings->audio_frame_duration,
336 codec_settings->audio_sample_rate,
337 codec_settings->audio_channels,
338 codec_settings->video_width,
339 codec_settings->video_height,
340 codec_settings->video_bitrate);
341
342 return call->cs ? ErrorNone : ErrorInternal;
335} 343}
336 344
337/** 345/**
@@ -344,19 +352,30 @@ int toxav_prepare_transmission ( ToxAv* av, uint32_t call_index, int support_vid
344 */ 352 */
345int toxav_kill_transmission ( ToxAv *av, uint32_t call_index ) 353int toxav_kill_transmission ( ToxAv *av, uint32_t call_index )
346{ 354{
347 if ( av->rtp_sessions[call_index].crtps[audio_index] && -1 == rtp_terminate_session(av->rtp_sessions[call_index].crtps[audio_index], av->messenger) ) { 355 CallSpecific* call = &av->calls[call_index];
356
357 if ( call->crtps[audio_index] && -1 == rtp_terminate_session(call->crtps[audio_index], av->messenger) ) {
348 /*fprintf(stderr, "Error while terminating audio RTP session!\n");*/ 358 /*fprintf(stderr, "Error while terminating audio RTP session!\n");*/
349 return ErrorTerminatingAudioRtp; 359 return ErrorTerminatingAudioRtp;
350 } 360 }
351 361
352 if ( av->rtp_sessions[call_index].crtps[video_index] && -1 == rtp_terminate_session(av->rtp_sessions[call_index].crtps[video_index], av->messenger) ) { 362 if ( call->crtps[video_index] && -1 == rtp_terminate_session(call->crtps[video_index], av->messenger) ) {
353 /*fprintf(stderr, "Error while terminating video RTP session!\n");*/ 363 /*fprintf(stderr, "Error while terminating video RTP session!\n");*/
354 return ErrorTerminatingVideoRtp; 364 return ErrorTerminatingVideoRtp;
355 } 365 }
356 366
357 av->rtp_sessions[call_index].crtps[audio_index] = NULL; 367 call->crtps[audio_index] = NULL;
358 av->rtp_sessions[call_index].crtps[video_index] = NULL; 368 call->crtps[video_index] = NULL;
359 369
370 if ( call->j_buf ) {
371 terminate_queue(call->j_buf);
372 call->j_buf = NULL;
373 }
374
375 if ( call->cs ) {
376 codec_terminate_session(call->cs);
377 call->cs = NULL;
378 }
360 379
361 return ErrorNone; 380 return ErrorNone;
362} 381}
@@ -375,8 +394,8 @@ int toxav_kill_transmission ( ToxAv *av, uint32_t call_index )
375 */ 394 */
376inline__ int toxav_send_rtp_payload ( ToxAv *av, uint32_t call_index, ToxAvCallType type, const uint8_t *payload, uint16_t length ) 395inline__ int toxav_send_rtp_payload ( ToxAv *av, uint32_t call_index, ToxAvCallType type, const uint8_t *payload, uint16_t length )
377{ 396{
378 if ( av->rtp_sessions[call_index].crtps[type - TypeAudio] ) 397 if ( av->calls[call_index].crtps[type - TypeAudio] )
379 return rtp_send_msg ( av->rtp_sessions[call_index].crtps[type - TypeAudio], av->msi_session->messenger_handle, payload, length ); 398 return rtp_send_msg ( av->calls[call_index].crtps[type - TypeAudio], av->msi_session->messenger_handle, payload, length );
380 else return -1; 399 else return -1;
381} 400}
382 401
@@ -394,27 +413,29 @@ inline__ int toxav_recv_rtp_payload ( ToxAv *av, uint32_t call_index, ToxAvCallT
394{ 413{
395 if ( !dest ) return ErrorInternal; 414 if ( !dest ) return ErrorInternal;
396 415
397 if ( !av->rtp_sessions[call_index].crtps[type - TypeAudio] ) return ErrorNoRtpSession; 416 CallSpecific* call = &av->calls[call_index];
417
418 if ( !call->crtps[type - TypeAudio] ) return ErrorNoRtpSession;
398 419
399 RTPMessage *message; 420 RTPMessage *message;
400 421
401 if ( type == TypeAudio ) { 422 if ( type == TypeAudio ) {
402 423
403 do { 424 do {
404 message = rtp_recv_msg(av->rtp_sessions[call_index].crtps[audio_index]); 425 message = rtp_recv_msg(call->crtps[audio_index]);
405 426
406 if (message) { 427 if (message) {
407 /* push the packet into the queue */ 428 /* push the packet into the queue */
408 queue(av->j_buf, message); 429 queue(call->j_buf, message);
409 } 430 }
410 } while (message); 431 } while (message);
411 432
412 int success = 0; 433 int success = 0;
413 message = dequeue(av->j_buf, &success); 434 message = dequeue(call->j_buf, &success);
414 435
415 if ( success == 2) return ErrorAudioPacketLost; 436 if ( success == 2) return ErrorAudioPacketLost;
416 } else { 437 } else {
417 message = rtp_recv_msg(av->rtp_sessions[call_index].crtps[video_index]); 438 message = rtp_recv_msg(call->crtps[video_index]);
418 } 439 }
419 440
420 if ( message ) { 441 if ( message ) {
@@ -446,11 +467,12 @@ inline__ int toxav_recv_video ( ToxAv *av, uint32_t call_index, vpx_image_t **ou
446 uint8_t packet [RTP_PAYLOAD_SIZE]; 467 uint8_t packet [RTP_PAYLOAD_SIZE];
447 int recved_size = 0; 468 int recved_size = 0;
448 int rc; 469 int rc;
470 CallSpecific* call = &av->calls[call_index];
449 471
450 do { 472 do {
451 recved_size = toxav_recv_rtp_payload(av, call_index, TypeVideo, packet); 473 recved_size = toxav_recv_rtp_payload(av, call_index, TypeVideo, packet);
452 474
453 if (recved_size > 0 && ( rc = vpx_codec_decode(&av->cs->v_decoder, packet, recved_size, NULL, 0) ) != VPX_CODEC_OK) { 475 if (recved_size > 0 && ( rc = vpx_codec_decode(&call->cs->v_decoder, packet, recved_size, NULL, 0) ) != VPX_CODEC_OK) {
454 /*fprintf(stderr, "Error decoding video: %s\n", vpx_codec_err_to_string(rc));*/ 476 /*fprintf(stderr, "Error decoding video: %s\n", vpx_codec_err_to_string(rc));*/
455 return ErrorInternal; 477 return ErrorInternal;
456 } 478 }
@@ -459,12 +481,10 @@ inline__ int toxav_recv_video ( ToxAv *av, uint32_t call_index, vpx_image_t **ou
459 481
460 vpx_codec_iter_t iter = NULL; 482 vpx_codec_iter_t iter = NULL;
461 vpx_image_t *img; 483 vpx_image_t *img;
462 img = vpx_codec_get_frame(&av->cs->v_decoder, &iter); 484 img = vpx_codec_get_frame(&call->cs->v_decoder, &iter);
463 485
464 *output = img; 486 *output = img;
465 return 0; 487 return 0;
466 /* Yeah, i set output to be NULL if nothing received
467 */
468} 488}
469 489
470/** 490/**
@@ -476,60 +496,47 @@ inline__ int toxav_recv_video ( ToxAv *av, uint32_t call_index, vpx_image_t **ou
476 * @retval 0 Success. 496 * @retval 0 Success.
477 * @retval ToxAvError On error. 497 * @retval ToxAvError On error.
478 */ 498 */
479inline__ int toxav_send_video ( ToxAv *av, uint32_t call_index, vpx_image_t *input) 499inline__ int toxav_send_video ( ToxAv *av, uint32_t call_index, const uint8_t* frame, int frame_size)
480{ 500{
481 int rc = vpx_codec_encode(&av->cs->v_encoder, input, av->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US); 501 return toxav_send_rtp_payload(av, call_index, TypeVideo, frame, frame_size);
482 if ( rc != VPX_CODEC_OK) {
483 /*fprintf(stderr, "Could not encode video frame: %s\n", vpx_codec_err_to_string(rc));*/
484 return ErrorInternal;
485 }
486
487 ++av->cs->frame_counter;
488
489 vpx_codec_iter_t iter = NULL;
490 const vpx_codec_cx_pkt_t *pkt;
491 int sent = 0;
492
493 while ( (pkt = vpx_codec_get_cx_data(&av->cs->v_encoder, &iter)) ) {
494 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
495 if (toxav_send_rtp_payload(av, call_index, TypeVideo, pkt->data.frame.buf, pkt->data.frame.sz) != -1)
496 ++sent;
497 }
498 }
499
500 if (sent > 0)
501 return ErrorNone;
502
503 return ErrorInternal;
504} 502}
505 503
506int toxav_prepare_video_frame(ToxAv* av, uint8_t* dest, int dest_max, vpx_image_t* input) 504/**
505 * @brief Encode video frame
506 *
507 * @param av Handler
508 * @param dest Where to
509 * @param dest_max Max size
510 * @param input What to encode
511 * @return int
512 * @retval ToxAvError On error.
513 * @retval >0 On success
514 */
515inline__ int toxav_prepare_video_frame(ToxAv* av, uint32_t call_index, uint8_t* dest, int dest_max, vpx_image_t* input)
507{ 516{
508 int rc = vpx_codec_encode(&av->cs->v_encoder, input, av->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US); 517 CallSpecific* call = &av->calls[call_index];
518
519 int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US);
509 if ( rc != VPX_CODEC_OK) { 520 if ( rc != VPX_CODEC_OK) {
510 /*fprintf(stderr, "Could not encode video frame: %s\n", vpx_codec_err_to_string(rc));*/ 521 fprintf(stderr, "Could not encode video frame: %s\n", vpx_codec_err_to_string(rc));
511 return ErrorInternal; 522 return ErrorInternal;
512 } 523 }
513 ++av->cs->frame_counter; 524 ++call->cs->frame_counter;
514 525
515 vpx_codec_iter_t iter = NULL; 526 vpx_codec_iter_t iter = NULL;
516 const vpx_codec_cx_pkt_t *pkt; 527 const vpx_codec_cx_pkt_t *pkt;
517 int counted = 0, copied = 0; 528 int copied = 0;
518 529
519 while ( (pkt = vpx_codec_get_cx_data(&av->cs->v_encoder, &iter)) ) { 530 while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) {
520 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { 531 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
521
522 if ( copied + pkt->data.frame.sz > dest_max ) return ErrorPacketTooLarge; 532 if ( copied + pkt->data.frame.sz > dest_max ) return ErrorPacketTooLarge;
523 533
524 mempcpy(dest + copied, pkt->data.frame.buf, pkt->data.frame.sz); 534 mempcpy(dest + copied, pkt->data.frame.buf, pkt->data.frame.sz);
525 535 copied += pkt->data.frame.sz;
526 if (toxav_send_rtp_payload(av, call_index, TypeVideo, pkt->data.frame.buf, pkt->data.frame.sz) != -1)
527 ++counted;
528 } 536 }
529 } 537 }
530 538
531 if (counted > 0) 539 return copied;
532 return ErrorNone;
533} 540}
534 541
535/** 542/**
@@ -547,21 +554,28 @@ int toxav_prepare_video_frame(ToxAv* av, uint8_t* dest, int dest_max, vpx_image_
547inline__ int toxav_recv_audio ( ToxAv *av, uint32_t call_index, int frame_size, int16_t *dest ) 554inline__ int toxav_recv_audio ( ToxAv *av, uint32_t call_index, int frame_size, int16_t *dest )
548{ 555{
549 if ( !dest ) return ErrorInternal; 556 if ( !dest ) return ErrorInternal;
557
558 CallSpecific* call = &av->calls[call_index];
550 559
551 uint8_t packet [RTP_PAYLOAD_SIZE]; 560 uint8_t packet [RTP_PAYLOAD_SIZE];
552 561
553 int recved_size = toxav_recv_rtp_payload(av, call_index, TypeAudio, packet); 562 int recved_size = toxav_recv_rtp_payload(av, call_index, TypeAudio, packet);
554 563
555 if ( recved_size == ErrorAudioPacketLost ) { 564 if ( recved_size == ErrorAudioPacketLost ) {
556 int dec_size = opus_decode(av->cs->audio_decoder, NULL, 0, dest, frame_size, 1); 565 int dec_size = opus_decode(call->cs->audio_decoder, NULL, 0, dest, frame_size, 1);
557 566
558 if ( dec_size != OPUS_OK ) return ErrorInternal; 567 if ( dec_size != OPUS_OK )
568 return ErrorInternal;
569 else
570 return dec_size;
559 571
560 } else if ( recved_size ) { 572 } else if ( recved_size ) {
561 int dec_size = opus_decode(av->cs->audio_decoder, packet, recved_size, dest, frame_size, 0); 573 int dec_size = opus_decode(call->cs->audio_decoder, packet, recved_size, dest, frame_size, 0);
562
563 if ( dec_size != OPUS_OK ) return ErrorInternal;
564 574
575 if ( dec_size != OPUS_OK )
576 return ErrorInternal;
577 else
578 return dec_size;
565 } else { 579 } else {
566 return 0; /* Nothing received */ 580 return 0; /* Nothing received */
567 } 581 }
@@ -578,7 +592,7 @@ inline__ int toxav_recv_audio ( ToxAv *av, uint32_t call_index, int frame_size,
578 * @retval 0 Success. 592 * @retval 0 Success.
579 * @retval ToxAvError On error. 593 * @retval ToxAvError On error.
580 */ 594 */
581inline__ int toxav_send_audio ( ToxAv *av, uint32_t call_index, const int16_t *frame, int frame_size) 595inline__ int toxav_send_audio ( ToxAv *av, uint32_t call_index, const uint8_t *frame, int frame_size)
582{ 596{
583 return toxav_send_rtp_payload(av, call_index, TypeAudio, frame, frame_size); 597 return toxav_send_rtp_payload(av, call_index, TypeAudio, frame, frame_size);
584} 598}
@@ -595,13 +609,14 @@ inline__ int toxav_send_audio ( ToxAv *av, uint32_t call_index, const int16_t *f
595 * @retval ToxAvError On error. 609 * @retval ToxAvError On error.
596 * @retval >0 On success 610 * @retval >0 On success
597 */ 611 */
598int toxav_prepare_audio_frame ( ToxAv* av, int16_t* dest, int dest_max, const int16_t* frame, int frame_size) 612inline__ int toxav_prepare_audio_frame ( ToxAv* av, uint32_t call_index, uint8_t* dest, int dest_max, const int16_t* frame, int frame_size)
599{ 613{
600 int32_t rc = opus_encode(av->cs->audio_encoder, frame, frame_size, dest, dest_max); 614 int32_t rc = opus_encode(av->calls[call_index].cs->audio_encoder, frame, frame_size, dest, dest_max);
601 615
602 if (rc <= 0) 616 if (rc < 0) {
617 fprintf(stderr, "Failed to encode payload: %s\n", opus_strerror(rc));
603 return ErrorInternal; 618 return ErrorInternal;
604 619 }
605 return rc; 620 return rc;
606} 621}
607 622
@@ -650,9 +665,9 @@ int toxav_get_peer_id ( ToxAv* av, uint32_t call_index, int peer )
650 * @retval 1 Yes. 665 * @retval 1 Yes.
651 * @retval 0 No. 666 * @retval 0 No.
652 */ 667 */
653inline__ int toxav_capability_supported ( ToxAv* av, ToxAvCapabilities capability ) 668inline__ int toxav_capability_supported ( ToxAv* av, uint32_t call_index, ToxAvCapabilities capability )
654{ 669{
655 return av->cs->capabilities & (Capabilities) capability; 670 return av->calls[call_index].cs->capabilities & (Capabilities) capability;
656} 671}
657 672
658/** 673/**
@@ -665,7 +680,7 @@ inline__ int toxav_capability_supported ( ToxAv* av, ToxAvCapabilities capabilit
665 */ 680 */
666void toxav_set_audio_queue_limit(ToxAv* av, uint32_t call_index, uint64_t limit) 681void toxav_set_audio_queue_limit(ToxAv* av, uint32_t call_index, uint64_t limit)
667{ 682{
668 rtp_queue_adjust_limit(av->rtp_sessions[call_index].crtps[audio_index], limit); 683 rtp_queue_adjust_limit(av->calls[call_index].crtps[audio_index], limit);
669} 684}
670 685
671/** 686/**
@@ -678,5 +693,5 @@ void toxav_set_audio_queue_limit(ToxAv* av, uint32_t call_index, uint64_t limit)
678 */ 693 */
679void toxav_set_video_queue_limit(ToxAv* av, uint32_t call_index, uint64_t limit) 694void toxav_set_video_queue_limit(ToxAv* av, uint32_t call_index, uint64_t limit)
680{ 695{
681 rtp_queue_adjust_limit(av->rtp_sessions[call_index].crtps[video_index], limit); 696 rtp_queue_adjust_limit(av->calls[call_index].crtps[video_index], limit);
682} 697}