summaryrefslogtreecommitdiff
path: root/toxav
diff options
context:
space:
mode:
Diffstat (limited to 'toxav')
-rw-r--r--toxav/media.c34
-rw-r--r--toxav/media.h12
-rwxr-xr-xtoxav/rtp.c6
-rwxr-xr-xtoxav/toxav.c245
-rwxr-xr-xtoxav/toxav.h28
5 files changed, 185 insertions, 140 deletions
diff --git a/toxav/media.c b/toxav/media.c
index 33d5d6b6..5700c2f2 100644
--- a/toxav/media.c
+++ b/toxav/media.c
@@ -36,8 +36,7 @@
36#include "rtp.h" 36#include "rtp.h"
37#include "media.h" 37#include "media.h"
38 38
39 39int empty_queue(JitterBuffer *q)
40int empty_queue(struct jitter_buffer *q)
41{ 40{
42 while (q->size > 0) { 41 while (q->size > 0) {
43 rtp_free_msg(NULL, q->queue[q->front]); 42 rtp_free_msg(NULL, q->queue[q->front]);
@@ -54,11 +53,11 @@ int empty_queue(struct jitter_buffer *q)
54 return 0; 53 return 0;
55} 54}
56 55
57struct jitter_buffer *create_queue(int capacity) 56JitterBuffer *create_queue(int capacity)
58{ 57{
59 struct jitter_buffer *q; 58 JitterBuffer *q;
60 q = calloc(sizeof(struct jitter_buffer), 1); 59 if ( !(q = calloc(sizeof(JitterBuffer), 1)) ) return NULL;
61 q->queue = calloc(sizeof(RTPMessage *), capacity); 60 if (!(q->queue = calloc(sizeof(RTPMessage *), capacity))) return NULL;
62 q->size = 0; 61 q->size = 0;
63 q->capacity = capacity; 62 q->capacity = capacity;
64 q->front = 0; 63 q->front = 0;
@@ -70,10 +69,20 @@ struct jitter_buffer *create_queue(int capacity)
70 return q; 69 return q;
71} 70}
72 71
72void terminate_queue(JitterBuffer* q)
73{
74 int i;
75 for ( i = 0; i < q->capacity; i ++ ) {
76 rtp_free_msg(NULL, q->queue[i]);
77 }
78 free(q->queue);
79 free(q);
80}
81
73#define sequnum_older(sn_a, sn_b, ts_a, ts_b) (sn_a > sn_b || ts_a > ts_b) 82#define sequnum_older(sn_a, sn_b, ts_a, ts_b) (sn_a > sn_b || ts_a > ts_b)
74 83
75/* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */ 84/* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */
76RTPMessage *dequeue(struct jitter_buffer *q, int *success) 85RTPMessage *dequeue(JitterBuffer *q, int *success)
77{ 86{
78 if (q->size == 0 || q->queue_ready == 0) { /* Empty queue */ 87 if (q->size == 0 || q->queue_ready == 0) { /* Empty queue */
79 q->queue_ready = 0; 88 q->queue_ready = 0;
@@ -122,10 +131,10 @@ RTPMessage *dequeue(struct jitter_buffer *q, int *success)
122} 131}
123 132
124 133
125void queue(struct jitter_buffer* q, RTPMessage* pk) 134void queue(JitterBuffer* q, RTPMessage* pk)
126{ 135{
127 if (q->size == q->capacity) { /* Full, empty queue */ 136 if (q->size == q->capacity) { /* Full, empty queue */
128 LOGGER_DEBUG("Queue full, emptying..."); 137 LOGGER_DEBUG("Queue full s(%d) c(%d), emptying...", q->size, q->capacity);
129 empty_queue(q); 138 empty_queue(q);
130 } 139 }
131 140
@@ -257,7 +266,7 @@ CodecState *codec_init_session ( uint32_t audio_bitrate,
257 uint32_t video_bitrate ) 266 uint32_t video_bitrate )
258{ 267{
259 CodecState *retu = calloc(sizeof(CodecState), 1); 268 CodecState *retu = calloc(sizeof(CodecState), 1);
260 assert(retu); 269 if(!retu) return NULL;
261 270
262 retu->audio_bitrate = audio_bitrate; 271 retu->audio_bitrate = audio_bitrate;
263 retu->audio_sample_rate = audio_sample_rate; 272 retu->audio_sample_rate = audio_sample_rate;
@@ -275,6 +284,11 @@ CodecState *codec_init_session ( uint32_t audio_bitrate,
275 retu->capabilities |= ( 0 == init_audio_encoder(retu, audio_channels) ) ? a_encoding : 0; 284 retu->capabilities |= ( 0 == init_audio_encoder(retu, audio_channels) ) ? a_encoding : 0;
276 retu->capabilities |= ( 0 == init_audio_decoder(retu, audio_channels) ) ? a_decoding : 0; 285 retu->capabilities |= ( 0 == init_audio_decoder(retu, audio_channels) ) ? a_decoding : 0;
277 286
287 if ( retu->capabilities == 0 ) { /* everything failed */
288 free (retu);
289 return NULL;
290 }
291
278 return retu; 292 return retu;
279} 293}
280 294
diff --git a/toxav/media.h b/toxav/media.h
index 68694664..a1193aae 100644
--- a/toxav/media.h
+++ b/toxav/media.h
@@ -69,7 +69,7 @@ typedef struct _CodecState {
69} CodecState; 69} CodecState;
70 70
71 71
72struct jitter_buffer { 72typedef struct _JitterBuffer {
73 RTPMessage **queue; 73 RTPMessage **queue;
74 uint16_t capacity; 74 uint16_t capacity;
75 uint16_t size; 75 uint16_t size;
@@ -79,12 +79,12 @@ struct jitter_buffer {
79 uint16_t current_id; 79 uint16_t current_id;
80 uint32_t current_ts; 80 uint32_t current_ts;
81 uint8_t id_set; 81 uint8_t id_set;
82}; 82} JitterBuffer;
83 83
84struct jitter_buffer *create_queue(int capacity); 84JitterBuffer *create_queue(int capacity);
85 85void terminate_queue(JitterBuffer *q);
86void queue(struct jitter_buffer *q, RTPMessage *pk); 86void queue(JitterBuffer *q, RTPMessage *pk);
87RTPMessage *dequeue(struct jitter_buffer *q, int *success); 87RTPMessage *dequeue(JitterBuffer *q, int *success);
88 88
89 89
90CodecState *codec_init_session ( uint32_t audio_bitrate, 90CodecState *codec_init_session ( uint32_t audio_bitrate,
diff --git a/toxav/rtp.c b/toxav/rtp.c
index a404202b..1e6296b0 100755
--- a/toxav/rtp.c
+++ b/toxav/rtp.c
@@ -754,11 +754,12 @@ RTPMessage *rtp_recv_msg ( RTPSession *session )
754 return NULL; 754 return NULL;
755 } 755 }
756 756
757 pthread_mutex_lock(&session->mutex);
758
757 if ( session->queue_size == 0 ) { 759 if ( session->queue_size == 0 ) {
758 return NULL; 760 return NULL;
759 } 761 }
760 762
761 pthread_mutex_lock(&session->mutex);
762 763
763 RTPMessage *_retu = session->oldest_msg; 764 RTPMessage *_retu = session->oldest_msg;
764 765
@@ -768,8 +769,11 @@ RTPMessage *rtp_recv_msg ( RTPSession *session )
768 if ( !session->oldest_msg ) 769 if ( !session->oldest_msg )
769 session->last_msg = NULL; 770 session->last_msg = NULL;
770 771
772 session->queue_size --;
773
771 pthread_mutex_unlock(&session->mutex); 774 pthread_mutex_unlock(&session->mutex);
772 775
776
773 return _retu; 777 return _retu;
774} 778}
775 779
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}
diff --git a/toxav/toxav.h b/toxav/toxav.h
index 5a8e8f56..6dac966b 100755
--- a/toxav/toxav.h
+++ b/toxav/toxav.h
@@ -133,7 +133,7 @@ extern const ToxAvCodecSettings av_DefaultSettings;
133 * @return ToxAv* 133 * @return ToxAv*
134 * @retval NULL On error. 134 * @retval NULL On error.
135 */ 135 */
136ToxAv *toxav_new(Tox *messenger, ToxAvCodecSettings* codec_settings, uint32_t max_calls); 136ToxAv *toxav_new(Tox *messenger, uint32_t max_calls);
137 137
138/** 138/**
139 * @brief Remove A/V session. 139 * @brief Remove A/V session.
@@ -228,7 +228,7 @@ int toxav_stop_call(ToxAv *av, uint32_t call_index);
228 * @retval 0 Success. 228 * @retval 0 Success.
229 * @retval ToxAvError On error. 229 * @retval ToxAvError On error.
230 */ 230 */
231int toxav_prepare_transmission(ToxAv* av, uint32_t call_index, int support_video); 231int toxav_prepare_transmission(ToxAv* av, uint32_t call_index, ToxAvCodecSettings* codec_settings, int support_video);
232 232
233/** 233/**
234 * @brief Call this at the end of the transmission. 234 * @brief Call this at the end of the transmission.
@@ -269,12 +269,13 @@ int toxav_recv_audio( ToxAv* av, uint32_t call_index, int frame_size, int16_t* d
269 * @brief Encode and send video packet. 269 * @brief Encode and send video packet.
270 * 270 *
271 * @param av Handler. 271 * @param av Handler.
272 * @param input The packet. 272 * @param frame The encoded frame.
273 * @param frame_size The size of the encoded frame.
273 * @return int 274 * @return int
274 * @retval 0 Success. 275 * @retval 0 Success.
275 * @retval ToxAvError On error. 276 * @retval ToxAvError On error.
276 */ 277 */
277int toxav_send_video ( ToxAv* av, uint32_t call_index, vpx_image_t* input); 278int toxav_send_video ( ToxAv* av, uint32_t call_index, const uint8_t* frame, int frame_size);
278 279
279/** 280/**
280 * @brief Send audio frame. 281 * @brief Send audio frame.
@@ -287,9 +288,20 @@ int toxav_send_video ( ToxAv* av, uint32_t call_index, vpx_image_t* input);
287 * @retval 0 Success. 288 * @retval 0 Success.
288 * @retval ToxAvError On error. 289 * @retval ToxAvError On error.
289 */ 290 */
290int toxav_send_audio ( ToxAv* av, uint32_t call_index, const int16_t* frame, int frame_size); 291int toxav_send_audio ( ToxAv* av, uint32_t call_index, const uint8_t* frame, int frame_size);
291 292
292int toxav_prepare_video_frame ( ToxAv* av, uint8_t* dest, int dest_max, vpx_image_t* input ); 293/**
294 * @brief Encode video frame
295 *
296 * @param av Handler
297 * @param dest Where to
298 * @param dest_max Max size
299 * @param input What to encode
300 * @return int
301 * @retval ToxAvError On error.
302 * @retval >0 On success
303 */
304int toxav_prepare_video_frame ( ToxAv* av, uint32_t call_index, uint8_t* dest, int dest_max, vpx_image_t* input );
293 305
294/** 306/**
295 * @brief Encode audio frame 307 * @brief Encode audio frame
@@ -303,7 +315,7 @@ int toxav_prepare_video_frame ( ToxAv* av, uint8_t* dest, int dest_max, vpx_imag
303 * @retval ToxAvError On error. 315 * @retval ToxAvError On error.
304 * @retval >0 On success 316 * @retval >0 On success
305 */ 317 */
306int toxav_prepare_audio_frame ( ToxAv* av, int16_t* dest, int dest_max, const int16_t* frame, int frame_size); 318int toxav_prepare_audio_frame ( ToxAv* av, uint32_t call_index, uint8_t* dest, int dest_max, const int16_t* frame, int frame_size);
307 319
308/** 320/**
309 * @brief Get peer transmission type. It can either be audio or video. 321 * @brief Get peer transmission type. It can either be audio or video.
@@ -334,7 +346,7 @@ int toxav_get_peer_id ( ToxAv* av, uint32_t call_index, int peer );
334 * @retval 1 Yes. 346 * @retval 1 Yes.
335 * @retval 0 No. 347 * @retval 0 No.
336 */ 348 */
337int toxav_capability_supported ( ToxAv* av, ToxAvCapabilities capability ); 349int toxav_capability_supported ( ToxAv* av, uint32_t call_index, ToxAvCapabilities capability );
338 350
339/** 351/**
340 * @brief Set queue limit 352 * @brief Set queue limit