summaryrefslogtreecommitdiff
path: root/toxav
diff options
context:
space:
mode:
authormannol <eniz_vukovic@hotmail.com>2014-11-18 00:46:46 +0100
committermannol <eniz_vukovic@hotmail.com>2014-11-18 00:46:46 +0100
commit386c9748d48d3bb4513e8e5c32e2b30a4d6a00d4 (patch)
tree55d0fb2e9fb6e1149317b9de355c28dd86c57014 /toxav
parent4e6f993e7d22865ee2ac90bd7dd3ff25b078c55c (diff)
av refactor
Diffstat (limited to 'toxav')
-rw-r--r--toxav/codec.c660
-rw-r--r--toxav/codec.h128
-rw-r--r--toxav/msi.c845
-rw-r--r--toxav/msi.h158
-rw-r--r--toxav/rtp.c132
-rw-r--r--toxav/rtp.h97
-rw-r--r--toxav/toxav.c1052
-rw-r--r--toxav/toxav.h327
8 files changed, 1301 insertions, 2098 deletions
diff --git a/toxav/codec.c b/toxav/codec.c
index 2f00319f..46fd6ba7 100644
--- a/toxav/codec.c
+++ b/toxav/codec.c
@@ -32,33 +32,124 @@
32#include <stdlib.h> 32#include <stdlib.h>
33#include <math.h> 33#include <math.h>
34#include <assert.h> 34#include <assert.h>
35#include <time.h>
35 36
37#include "msi.h"
36#include "rtp.h" 38#include "rtp.h"
37#include "codec.h" 39#include "codec.h"
38 40
39JitterBuffer *create_queue(unsigned int capacity) 41/* Assume 24 fps*/
42#define MAX_ENCODE_TIME_US ((1000 / 24) * 1000)
43#define MAX_DECODE_TIME_US 0
44
45// TODO this has to be exchanged in msi
46#define MAX_VIDEOFRAME_SIZE 0x40000 /* 256KiB */
47#define VIDEOFRAME_PIECE_SIZE 0x500 /* 1.25 KiB*/
48#define VIDEOFRAME_HEADER_SIZE 0x2
49
50/* FIXME: Might not be enough */
51#define VIDEO_DECODE_BUFFER_SIZE 20
52
53#define ARRAY(TYPE__) struct { uint16_t size; TYPE__ data[]; }
54#define PAIR(TYPE1__, TYPE2__) struct { TYPE1__ first; TYPE2__ second; }
55
56typedef ARRAY(uint8_t) Payload;
57
58static PAIR(CSVideoCallback, void*) vpcallback;
59static PAIR(CSAudioCallback, void*) apcallback;
60
61typedef struct {
62 uint16_t size; /* Max size */
63 uint16_t start;
64 uint16_t end;
65 Payload **packets;
66} PayloadBuffer;
67
68static _Bool buffer_full(const PayloadBuffer *b)
40{ 69{
41 unsigned int size = 1; 70 return (b->end + 1) % b->size == b->start;
71}
72
73static _Bool buffer_empty(const PayloadBuffer *b)
74{
75 return b->end == b->start;
76}
77
78static void buffer_write(PayloadBuffer *b, Payload *p)
79{
80 b->packets[b->end] = p;
81 b->end = (b->end + 1) % b->size;
82 if (b->end == b->start) b->start = (b->start + 1) % b->size; /* full, overwrite */
83}
84
85static void buffer_read(PayloadBuffer *b, Payload **p)
86{
87 *p = b->packets[b->start];
88 b->start = (b->start + 1) % b->size;
89}
90
91static void buffer_clear(PayloadBuffer *b)
92{
93 while (!buffer_empty(b)) {
94 Payload* p;
95 buffer_read(b, &p);
96 free(p);
97 }
98}
99
100static PayloadBuffer* buffer_new(int size)
101{
102 PayloadBuffer *buf = calloc(sizeof(PayloadBuffer), 1);
103 if (!buf) return NULL;
104
105 buf->size = size + 1; /* include empty elem */
106 if (!(buf->packets = calloc(buf->size, sizeof(Payload*)))) {
107 free(buf);
108 return NULL;
109 }
110 return buf;
111}
42 112
113static void buffer_free(PayloadBuffer *b)
114{
115 if (b) {
116 buffer_clear(b);
117 free(b->packets);
118 free(b);
119 }
120}
121
122/* JITTER BUFFER WORK */
123typedef struct _JitterBuffer {
124 RTPMessage **queue;
125 uint32_t size;
126 uint32_t capacity;
127 uint16_t bottom;
128 uint16_t top;
129} JitterBuffer;
130
131static JitterBuffer *jbuf_new(uint32_t capacity)
132{
133 unsigned int size = 1;
43 while (size <= capacity) { 134 while (size <= capacity) {
44 size *= 2; 135 size *= 2;
45 } 136 }
46 137
47 JitterBuffer *q; 138 JitterBuffer *q;
48 139
49 if ( !(q = calloc(sizeof(JitterBuffer), 1)) ) return NULL; 140 if ( !(q = calloc(sizeof(JitterBuffer), 1)) ) return NULL;
50 141
51 if (!(q->queue = calloc(sizeof(RTPMessage *), size))) { 142 if (!(q->queue = calloc(sizeof(RTPMessage *), size))) {
52 free(q); 143 free(q);
53 return NULL; 144 return NULL;
54 } 145 }
55 146
56 q->size = size; 147 q->size = size;
57 q->capacity = capacity; 148 q->capacity = capacity;
58 return q; 149 return q;
59} 150}
60 151
61static void clear_queue(JitterBuffer *q) 152static void jbuf_clear(JitterBuffer *q)
62{ 153{
63 for (; q->bottom != q->top; ++q->bottom) { 154 for (; q->bottom != q->top; ++q->bottom) {
64 if (q->queue[q->bottom % q->size]) { 155 if (q->queue[q->bottom % q->size]) {
@@ -68,48 +159,50 @@ static void clear_queue(JitterBuffer *q)
68 } 159 }
69} 160}
70 161
71void terminate_queue(JitterBuffer *q) 162static void jbuf_free(JitterBuffer *q)
72{ 163{
73 if (!q) return; 164 if (!q) return;
74 165
75 clear_queue(q); 166 jbuf_clear(q);
76 free(q->queue); 167 free(q->queue);
77 free(q); 168 free(q);
78} 169}
79 170
80void queue(JitterBuffer *q, RTPMessage *pk) 171static void jbuf_write(JitterBuffer *q, RTPMessage *m)
81{ 172{
82 uint16_t sequnum = pk->header->sequnum; 173 uint16_t sequnum = m->header->sequnum;
83 174
84 unsigned int num = sequnum % q->size; 175 unsigned int num = sequnum % q->size;
85 176
86 if ((uint32_t)(sequnum - q->bottom) > q->size) { 177 if ((uint32_t)(sequnum - q->bottom) > q->size) {
87 clear_queue(q); 178 jbuf_clear(q);
88 q->bottom = sequnum; 179 q->bottom = sequnum;
89 q->queue[num] = pk; 180 q->queue[num] = m;
90 q->top = sequnum + 1; 181 q->top = sequnum + 1;
91 return; 182 return;
92 } 183 }
93 184
94 if (q->queue[num]) 185 if (q->queue[num])
95 return; 186 return;
96 187
97 q->queue[num] = pk; 188 q->queue[num] = m;
98 189
99 if ((sequnum - q->bottom) >= (q->top - q->bottom)) 190 if ((sequnum - q->bottom) >= (q->top - q->bottom))
100 q->top = sequnum + 1; 191 q->top = sequnum + 1;
101} 192}
102 193
103/* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */ 194/* Success is 0 when there is nothing to dequeue,
104RTPMessage *dequeue(JitterBuffer *q, int *success) 195 * 1 when there's a good packet,
196 * 2 when there's a lost packet */
197static RTPMessage *jbuf_read(JitterBuffer *q, int32_t *success)
105{ 198{
106 if (q->top == q->bottom) { 199 if (q->top == q->bottom) {
107 *success = 0; 200 *success = 0;
108 return NULL; 201 return NULL;
109 } 202 }
110 203
111 unsigned int num = q->bottom % q->size; 204 unsigned int num = q->bottom % q->size;
112 205
113 if (q->queue[num]) { 206 if (q->queue[num]) {
114 RTPMessage *ret = q->queue[num]; 207 RTPMessage *ret = q->queue[num];
115 q->queue[num] = NULL; 208 q->queue[num] = NULL;
@@ -117,19 +210,18 @@ RTPMessage *dequeue(JitterBuffer *q, int *success)
117 *success = 1; 210 *success = 1;
118 return ret; 211 return ret;
119 } 212 }
120 213
121 if ((uint32_t)(q->top - q->bottom) > q->capacity) { 214 if ((uint32_t)(q->top - q->bottom) > q->capacity) {
122 ++q->bottom; 215 ++q->bottom;
123 *success = 2; 216 *success = 2;
124 return NULL; 217 return NULL;
125 } 218 }
126 219
127 *success = 0; 220 *success = 0;
128 return NULL; 221 return NULL;
129} 222}
130 223
131 224static int init_video_decoder(CSSession *cs)
132int init_video_decoder(CodecState *cs)
133{ 225{
134 int rc = vpx_codec_dec_init_ver(&cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0, VPX_DECODER_ABI_VERSION); 226 int rc = vpx_codec_dec_init_ver(&cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0, VPX_DECODER_ABI_VERSION);
135 227
@@ -141,72 +233,28 @@ int init_video_decoder(CodecState *cs)
141 return 0; 233 return 0;
142} 234}
143 235
144int init_audio_decoder(CodecState *cs, uint32_t audio_channels) 236static int init_audio_decoder(CSSession *cs)
145{ 237{
146 int rc; 238 int rc;
147 cs->audio_decoder = opus_decoder_create(cs->audio_sample_rate, audio_channels, &rc ); 239 cs->audio_decoder = opus_decoder_create(cs->audio_decoder_sample_rate, cs->audio_decoder_channels, &rc );
148 240
149 if ( rc != OPUS_OK ) { 241 if ( rc != OPUS_OK ) {
150 LOGGER_ERROR("Error while starting audio decoder: %s", opus_strerror(rc)); 242 LOGGER_ERROR("Error while starting audio decoder: %s", opus_strerror(rc));
151 return -1; 243 return -1;
152 } 244 }
153
154 cs->audio_decoder_channels = audio_channels;
155 return 0; 245 return 0;
156} 246}
157 247
158int reconfigure_video_encoder_resolution(CodecState *cs, uint16_t width, uint16_t height) 248static int init_video_encoder(CSSession *cs, uint16_t max_width, uint16_t max_height, uint32_t video_bitrate)
159{
160 vpx_codec_enc_cfg_t cfg = *cs->v_encoder.config.enc;
161
162 if (cfg.g_w == width && cfg.g_h == height)
163 return 0;
164
165 if (width * height > cs->max_width * cs->max_height)
166 return -1;
167
168 LOGGER_DEBUG("New video resolution: %u %u", width, height);
169 cfg.g_w = width;
170 cfg.g_h = height;
171 int rc = vpx_codec_enc_config_set(&cs->v_encoder, &cfg);
172
173 if ( rc != VPX_CODEC_OK) {
174 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
175 return -1;
176 }
177
178 return 0;
179}
180
181int reconfigure_video_encoder_bitrate(CodecState *cs, uint32_t video_bitrate)
182{
183 vpx_codec_enc_cfg_t cfg = *cs->v_encoder.config.enc;
184
185 if (cfg.rc_target_bitrate == video_bitrate)
186 return 0;
187
188 LOGGER_DEBUG("New video bitrate: %u", video_bitrate);
189 cfg.rc_target_bitrate = video_bitrate;
190 int rc = vpx_codec_enc_config_set(&cs->v_encoder, &cfg);
191
192 if ( rc != VPX_CODEC_OK) {
193 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
194 return -1;
195 }
196
197 return 0;
198}
199
200int init_video_encoder(CodecState *cs, uint16_t max_width, uint16_t max_height, uint32_t video_bitrate)
201{ 249{
202 vpx_codec_enc_cfg_t cfg; 250 vpx_codec_enc_cfg_t cfg;
203 int rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0); 251 int rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0);
204 252
205 if (rc != VPX_CODEC_OK) { 253 if (rc != VPX_CODEC_OK) {
206 LOGGER_ERROR("Failed to get config: %s", vpx_codec_err_to_string(rc)); 254 LOGGER_ERROR("Failed to get config: %s", vpx_codec_err_to_string(rc));
207 return -1; 255 return -1;
208 } 256 }
209 257
210 cfg.rc_target_bitrate = video_bitrate; 258 cfg.rc_target_bitrate = video_bitrate;
211 cfg.g_w = max_width; 259 cfg.g_w = max_width;
212 cfg.g_h = max_height; 260 cfg.g_h = max_height;
@@ -216,130 +264,375 @@ int init_video_encoder(CodecState *cs, uint16_t max_width, uint16_t max_height,
216 cfg.kf_min_dist = 0; 264 cfg.kf_min_dist = 0;
217 cfg.kf_max_dist = 5; 265 cfg.kf_max_dist = 5;
218 cfg.kf_mode = VPX_KF_AUTO; 266 cfg.kf_mode = VPX_KF_AUTO;
219 267
220 cs->max_width = max_width; 268 cs->max_width = max_width;
221 cs->max_height = max_height; 269 cs->max_height = max_height;
222 cs->bitrate = video_bitrate; 270
223
224 rc = vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION); 271 rc = vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION);
225 272
226 if ( rc != VPX_CODEC_OK) { 273 if ( rc != VPX_CODEC_OK) {
227 LOGGER_ERROR("Failed to initialize encoder: %s", vpx_codec_err_to_string(rc)); 274 LOGGER_ERROR("Failed to initialize encoder: %s", vpx_codec_err_to_string(rc));
228 return -1; 275 return -1;
229 } 276 }
230 277
231 rc = vpx_codec_control(&cs->v_encoder, VP8E_SET_CPUUSED, 8); 278 rc = vpx_codec_control(&cs->v_encoder, VP8E_SET_CPUUSED, 8);
232 279
233 if ( rc != VPX_CODEC_OK) { 280 if ( rc != VPX_CODEC_OK) {
234 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); 281 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
235 return -1; 282 return -1;
236 } 283 }
237 284
238 return 0; 285 return 0;
239} 286}
240 287
241int init_audio_encoder(CodecState *cs, uint32_t audio_channels) 288static int init_audio_encoder(CSSession *cs)
242{ 289{
243 int rc = OPUS_OK; 290 int rc = OPUS_OK;
244 cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, audio_channels, OPUS_APPLICATION_AUDIO, &rc); 291 cs->audio_encoder = opus_encoder_create(cs->audio_encoder_sample_rate,
245 292 cs->audio_encoder_channels, OPUS_APPLICATION_AUDIO, &rc);
293
246 if ( rc != OPUS_OK ) { 294 if ( rc != OPUS_OK ) {
247 LOGGER_ERROR("Error while starting audio encoder: %s", opus_strerror(rc)); 295 LOGGER_ERROR("Error while starting audio encoder: %s", opus_strerror(rc));
248 return -1; 296 return -1;
249 } 297 }
250 298
251 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate)); 299 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_encoder_bitrate));
252 300
253 if ( rc != OPUS_OK ) { 301 if ( rc != OPUS_OK ) {
254 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc)); 302 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc));
255 return -1; 303 return -1;
256 } 304 }
257 305
258 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10)); 306 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10));
259 307
260 if ( rc != OPUS_OK ) { 308 if ( rc != OPUS_OK ) {
261 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc)); 309 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc));
262 return -1; 310 return -1;
263 } 311 }
264
265 cs->audio_encoder_channels = audio_channels;
266 return 0; 312 return 0;
267} 313}
268 314
269 315static float calculate_sum_sq (int16_t *n, uint16_t k)
270CodecState *codec_init_session ( uint32_t audio_bitrate,
271 uint16_t audio_frame_duration,
272 uint32_t audio_sample_rate,
273 uint32_t encoder_audio_channels,
274 uint32_t decoder_audio_channels,
275 uint32_t audio_VAD_tolerance_ms,
276 uint16_t max_video_width,
277 uint16_t max_video_height,
278 uint32_t video_bitrate )
279{ 316{
280 CodecState *retu = calloc(sizeof(CodecState), 1); 317 float result = 0;
318 uint16_t i = 0;
319
320 for ( ; i < k; i ++) result += (float) (n[i] * n[i]);
321
322 return result;
323}
281 324
282 if (!retu) return NULL;
283 325
284 retu->audio_bitrate = audio_bitrate;
285 retu->audio_sample_rate = audio_sample_rate;
286 326
287 /* Encoders */ 327/* PUBLIC */
288 if (!max_video_width || !max_video_height) { /* Disable video */ 328int cs_split_video_payload(CSSession* cs, const uint8_t* payload, uint16_t length)
289 /*video_width = 320; 329{
290 video_height = 240; */ 330 if (!cs || !length || length > cs->max_video_frame_size) {
331 LOGGER_ERROR("Invalid CodecState or video frame size: %u", length);
332 return -1;
333 }
334
335 cs->split_video_frame[0] = cs->frameid_out++;
336 cs->split_video_frame[1] = 0;
337 cs->processing_video_frame = payload;
338 cs->processing_video_frame_size = length;
339
340 return ((length - 1) / cs->video_frame_piece_size) + 1;
341}
342
343const uint8_t* cs_get_split_video_frame(CSSession* cs, uint16_t* size)
344{
345 if (!cs || !size) return NULL;
346
347 if (cs->processing_video_frame_size > cs->video_frame_piece_size) {
348 memcpy(cs->split_video_frame + VIDEOFRAME_HEADER_SIZE,
349 cs->processing_video_frame,
350 cs->video_frame_piece_size);
351
352 cs->processing_video_frame += cs->video_frame_piece_size;
353 cs->processing_video_frame_size -= cs->video_frame_piece_size;
354
355 *size = cs->video_frame_piece_size + VIDEOFRAME_HEADER_SIZE;
291 } else { 356 } else {
292 retu->capabilities |= ( 0 == init_video_encoder(retu, max_video_width, max_video_height, 357 memcpy(cs->split_video_frame + VIDEOFRAME_HEADER_SIZE,
293 video_bitrate) ) ? v_encoding : 0; 358 cs->processing_video_frame,
294 retu->capabilities |= ( 0 == init_video_decoder(retu) ) ? v_decoding : 0; 359 cs->processing_video_frame_size);
360
361 *size = cs->processing_video_frame_size + VIDEOFRAME_HEADER_SIZE;
362 }
363
364 cs->split_video_frame[1]++;
365
366 return cs->split_video_frame;
367}
368
369void cs_do(CSSession* cs)
370{
371 if (!cs) return;
372
373 pthread_mutex_lock(cs->queue_mutex);
374 /*
375 if (!cs->active) {
376 pthread_mutex_unlock(cs->queue_mutex);
377 return;
378 }
379
380 /* Iterate over whole buffers and call playback callback * /
381 if (cs->abuf_ready) while (!DecodedAudioBuffer_empty(cs->abuf_ready)) {
382 DecodedAudio* p;
383 DecodedAudioBuffer_read(cs->abuf_ready, &p);
384 if (apcallback.first)
385 apcallback.first(cs->agent, cs->call_idx, p->data, p->size, apcallback.second);
386
387 free(p);
388 }
389
390 if (cs->vbuf_ready) while (!DecodedVideoBuffer_empty(cs->vbuf_ready)) {
391 vpx_image_t* p;
392 DecodedVideoBuffer_read(cs->vbuf_ready, &p);
393 if (vpcallback.first)
394 vpcallback.first(cs->agent, cs->call_idx, p, vpcallback.second);
395
396 vpx_img_free(p);
397 }
398 */
399
400 Payload* p;
401 int rc;
402
403 if (cs->abuf_raw && !buffer_empty(cs->abuf_raw)) {
404 /* Decode audio */
405 buffer_read(cs->abuf_raw, &p);
406
407 uint16_t fsize = (cs->audio_decoder_channels *
408 (cs->audio_decoder_sample_rate * cs->audio_decoder_frame_duration) / 1000);
409 int16_t tmp[fsize];
410
411 rc = opus_decode(cs->audio_decoder, p->data, p->size, tmp, fsize, (p->size == 0));
412 free(p);
413
414 if (rc < 0)
415 LOGGER_WARNING("Decoding error: %s", opus_strerror(rc));
416 else
417 /* Play */
418 apcallback.first(cs->agent, cs->call_idx, tmp, rc, apcallback.second);
419 }
420
421 if (cs->vbuf_raw && !buffer_empty(cs->vbuf_raw)) {
422 /* Decode video */
423 buffer_read(cs->vbuf_raw, &p);
424
425 rc = vpx_codec_decode(&cs->v_decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US);
426 free(p);
427
428 if (rc != VPX_CODEC_OK) {
429 LOGGER_ERROR("Error decoding video: %s", vpx_codec_err_to_string(rc));
430 } else {
431 vpx_codec_iter_t iter = NULL;
432 vpx_image_t* dest = vpx_codec_get_frame(&cs->v_decoder, &iter);
433
434 /* Play decoded images */
435 for (; dest; dest = vpx_codec_get_frame(&cs->v_decoder, &iter)) {
436 vpcallback.first(cs->agent, cs->call_idx, dest, vpcallback.second);
437 vpx_img_free(dest);
438 }
439 }
295 } 440 }
441
442 pthread_mutex_unlock(cs->queue_mutex);
443}
296 444
297 retu->capabilities |= ( 0 == init_audio_encoder(retu, encoder_audio_channels) ) ? a_encoding : 0; 445void cs_register_audio_callback(CSAudioCallback cb, void* data)
298 retu->capabilities |= ( 0 == init_audio_decoder(retu, decoder_audio_channels) ) ? a_decoding : 0; 446{
447 apcallback.first = cb;
448 apcallback.second = data;
449}
299 450
300 if ( retu->capabilities == 0 ) { /* everything failed */ 451void cs_register_video_callback(CSVideoCallback cb, void* data)
301 free (retu); 452{
302 return NULL; 453 vpcallback.first = cb;
454 vpcallback.second = data;
455}
456
457int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height)
458{
459 vpx_codec_enc_cfg_t cfg = *cs->v_encoder.config.enc;
460
461 if (cfg.g_w == width && cfg.g_h == height)
462 return 0;
463
464 if (width * height > cs->max_width * cs->max_height)
465 return -1;
466
467 LOGGER_DEBUG("New video resolution: %u %u", width, height);
468 cfg.g_w = width;
469 cfg.g_h = height;
470 int rc = vpx_codec_enc_config_set(&cs->v_encoder, &cfg);
471
472 if ( rc != VPX_CODEC_OK) {
473 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
474 return -1;
303 } 475 }
304 476
477 return 0;
478}
305 479
306 retu->EVAD_tolerance = audio_VAD_tolerance_ms > audio_frame_duration ? 480int cs_set_video_encoder_bitrate(CSSession *cs, uint32_t video_bitrate)
307 audio_VAD_tolerance_ms / audio_frame_duration : audio_frame_duration; 481{
482 vpx_codec_enc_cfg_t cfg = *cs->v_encoder.config.enc;
483
484 if (cfg.rc_target_bitrate == video_bitrate)
485 return 0;
308 486
309 return retu; 487 LOGGER_DEBUG("New video bitrate: %u", video_bitrate);
488 cfg.rc_target_bitrate = video_bitrate;
489 int rc = vpx_codec_enc_config_set(&cs->v_encoder, &cfg);
490
491 if ( rc != VPX_CODEC_OK) {
492 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
493 return -1;
494 }
495
496 return 0;
497}
498
499CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer, uint32_t jbuf_size, int has_video)
500{
501 CSSession *cs = calloc(sizeof(CSSession), 1);
502
503 if (!cs) {
504 LOGGER_WARNING("Allocation failed! Application might misbehave!");
505 return NULL;
506 }
507
508 if ( !(cs->j_buf = jbuf_new(jbuf_size)) ) {
509 LOGGER_WARNING("Jitter buffer creaton failed!");
510 goto error;
511 }
512
513 cs->audio_encoder_bitrate = cs_self->audio_bitrate;
514 cs->audio_encoder_sample_rate = cs_self->audio_sample_rate;
515 cs->audio_encoder_channels = cs_self->audio_channels;
516 cs->audio_encoder_frame_duration = cs_self->audio_frame_duration;
517
518 cs->audio_decoder_bitrate = cs_peer->audio_bitrate;
519 cs->audio_decoder_sample_rate = cs_peer->audio_sample_rate;
520 cs->audio_decoder_channels = cs_peer->audio_channels;
521 cs->audio_decoder_frame_duration = cs_peer->audio_frame_duration;
522
523
524 cs->capabilities |= ( 0 == init_audio_encoder(cs) ) ? a_encoding : 0;
525 cs->capabilities |= ( 0 == init_audio_decoder(cs) ) ? a_decoding : 0;
526
527 if ( !(cs->capabilities & a_encoding) || !(cs->capabilities & a_decoding) ) goto error;
528
529 if ( !(cs->abuf_raw = buffer_new(jbuf_size)) ) goto error;
530
531 pthread_mutexattr_t attr;
532 if (pthread_mutexattr_init(&attr) != 0) goto error;
533 if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) {
534 if (pthread_mutexattr_destroy(&attr) != 0)
535 LOGGER_WARNING("Failed to destroy mutex attribute!");
536 goto error;
537 }
538
539 if (pthread_mutex_init(cs->queue_mutex, &attr) != 0) {
540 pthread_mutexattr_destroy(&attr);
541 goto error;
542 }
543
544 if ((cs->support_video = has_video)) {
545 cs->max_video_frame_size = MAX_VIDEOFRAME_SIZE;
546 cs->video_frame_piece_size = VIDEOFRAME_PIECE_SIZE;
547
548 cs->capabilities |= ( 0 == init_video_encoder(cs, cs_self->max_video_width,
549 cs_self->max_video_height, cs_self->video_bitrate) ) ? v_encoding : 0;
550 cs->capabilities |= ( 0 == init_video_decoder(cs) ) ? v_decoding : 0;
551
552 if ( !(cs->capabilities & v_encoding) || !(cs->capabilities & v_decoding) ) goto error;
553
554 if ( !(cs->frame_buf = calloc(cs->max_video_frame_size, 1)) ) goto error;
555 if ( !(cs->split_video_frame = calloc(cs->video_frame_piece_size + VIDEOFRAME_HEADER_SIZE, 1)) )
556 goto error;
557
558 if ( !(cs->vbuf_raw = buffer_new(VIDEO_DECODE_BUFFER_SIZE)) ) goto error;
559 }
560
561 if (pthread_mutexattr_destroy(&attr) != 0)
562 LOGGER_WARNING("Failed to destroy mutex attribute!");
563
564
565 cs->active = 1;
566 return cs;
567
568error:
569 LOGGER_WARNING("Error initializing codec session! Application might misbehave!");
570
571 buffer_free(cs->abuf_raw);
572
573 if ( cs->audio_encoder ) opus_encoder_destroy(cs->audio_encoder);
574 if ( cs->audio_decoder ) opus_decoder_destroy(cs->audio_decoder);
575
576
577 if(has_video) {
578 if ( cs->capabilities & v_decoding ) vpx_codec_destroy(&cs->v_decoder);
579 if ( cs->capabilities & v_encoding ) vpx_codec_destroy(&cs->v_encoder);
580
581 buffer_free(cs->vbuf_raw);
582
583 free(cs->frame_buf);
584 free(cs->split_video_frame);
585 }
586
587 jbuf_free(cs->j_buf);
588 free(cs);
589
590 return NULL;
310} 591}
311 592
312void codec_terminate_session ( CodecState *cs ) 593void cs_kill(CSSession *cs)
313{ 594{
314 if (!cs) return; 595 if (!cs) return;
315 596
597 /* Lock running mutex and signal that cs is no longer active */
598 pthread_mutex_lock(cs->queue_mutex);
599 cs->active = 0;
600
601 /* Wait threads to close */
602 pthread_mutex_unlock(cs->queue_mutex);
603 pthread_mutex_lock(cs->queue_mutex);
604 pthread_mutex_unlock(cs->queue_mutex);
605
606 pthread_mutex_destroy(cs->queue_mutex);
607
608
316 if ( cs->audio_encoder ) 609 if ( cs->audio_encoder )
317 opus_encoder_destroy(cs->audio_encoder); 610 opus_encoder_destroy(cs->audio_encoder);
318 611
319 if ( cs->audio_decoder ) 612 if ( cs->audio_decoder )
320 opus_decoder_destroy(cs->audio_decoder); 613 opus_decoder_destroy(cs->audio_decoder);
321 614
322 if ( cs->capabilities & v_decoding ) 615 if ( cs->capabilities & v_decoding )
323 vpx_codec_destroy(&cs->v_decoder); 616 vpx_codec_destroy(&cs->v_decoder);
324 617
325 if ( cs->capabilities & v_encoding ) 618 if ( cs->capabilities & v_encoding )
326 vpx_codec_destroy(&cs->v_encoder); 619 vpx_codec_destroy(&cs->v_encoder);
327 620
621 jbuf_free(cs->j_buf);
622 buffer_free(cs->abuf_raw);
623 buffer_free(cs->vbuf_raw);
624 free(cs->frame_buf);
625
328 LOGGER_DEBUG("Terminated codec state: %p", cs); 626 LOGGER_DEBUG("Terminated codec state: %p", cs);
329 free(cs); 627 free(cs);
330} 628}
331 629
332static float calculate_sum_sq (int16_t *n, uint16_t k) 630void cs_set_vad_treshold(CSSession* cs, uint32_t treshold, uint16_t frame_duration)
333{ 631{
334 float result = 0; 632 cs->EVAD_tolerance = treshold > frame_duration ? treshold / frame_duration : frame_duration;
335 uint16_t i = 0;
336
337 for ( ; i < k; i ++) result += (float) (n[i] * n[i]);
338
339 return result;
340} 633}
341 634
342int energy_VAD(CodecState *cs, int16_t *PCM, uint16_t frame_size, float energy) 635int cs_calculate_vad(CSSession *cs, int16_t *PCM, uint16_t frame_size, float energy)
343{ 636{
344 float frame_energy = sqrt(calculate_sum_sq(PCM, frame_size)) / frame_size; 637 float frame_energy = sqrt(calculate_sum_sq(PCM, frame_size)) / frame_size;
345 638
@@ -355,3 +648,98 @@ int energy_VAD(CodecState *cs, int16_t *PCM, uint16_t frame_size, float energy)
355 648
356 return 0; 649 return 0;
357} 650}
651
652
653
654
655/* Called from RTP */
656void queue_message(RTPSession *session, RTPMessage *msg)
657{
658 CSSession *cs = session->cs;
659 if (!cs || !cs->active) return;
660
661 /* Audio */
662 if (session->payload_type == type_audio % 128) {
663 jbuf_write(cs->j_buf, msg);
664
665 pthread_mutex_lock(cs->queue_mutex);
666 int success = 0;
667 while ((msg = jbuf_read(cs->j_buf, &success)) || success == 2) {
668 Payload* p;
669
670 if (success == 2) {
671 p = malloc(sizeof(Payload));
672 if (p) p->size = 0;
673
674 } else {
675 p = malloc(sizeof(Payload) + msg->length);
676
677 if (p) {
678 p->size = msg->length;
679 memcpy(p->data, msg->data, msg->length);
680 }
681
682 rtp_free_msg(NULL, msg);
683 }
684
685 if (p) {
686 buffer_write(cs->abuf_raw, p);
687 } else {
688 LOGGER_WARNING("Allocation failed! Program might misbehave!");
689 }
690 }
691 pthread_mutex_unlock(cs->queue_mutex);
692 }
693 /* Video */
694 else {
695 uint8_t *packet = msg->data;
696 uint32_t packet_size = msg->length;
697
698 if (packet_size < VIDEOFRAME_HEADER_SIZE)
699 goto end;
700
701 if (packet[0] > cs->frameid_in || (msg->header->timestamp > cs->last_timestamp)) { /* New frame */
702 /* Flush last frames' data and get ready for this frame */
703 Payload* p = malloc(sizeof(Payload) + cs->frame_size);
704
705 if (p) {
706 pthread_mutex_lock(cs->queue_mutex);
707 if (buffer_full(cs->vbuf_raw)) {
708 LOGGER_DEBUG("Dropped video frame");
709 Payload* tp;
710 buffer_read(cs->vbuf_raw, &tp);
711 free(tp);
712 }
713 else {
714 p->size = cs->frame_size;
715 memcpy(p->data, cs->frame_buf, cs->frame_size);
716 }
717 buffer_write(cs->vbuf_raw, p);
718 pthread_mutex_unlock(cs->queue_mutex);
719 } else {
720 LOGGER_WARNING("Allocation failed! Program might misbehave!");
721 goto end;
722 }
723
724 cs->last_timestamp = msg->header->timestamp;
725 cs->frameid_in = packet[0];
726 memset(cs->frame_buf, 0, cs->frame_size);
727 cs->frame_size = 0;
728
729 } else if (packet[0] < cs->frameid_in) { /* Old frame; drop */
730 LOGGER_DEBUG("Old packet: %u", packet[0]);
731 goto end;
732 }
733
734 /* Otherwise it's part of the frame so just process */
735 /* LOGGER_DEBUG("Video Packet: %u %u", packet[0], packet[1]); */
736 memcpy(cs->frame_buf + cs->frame_size,
737 packet + VIDEOFRAME_HEADER_SIZE,
738 packet_size - VIDEOFRAME_HEADER_SIZE);
739
740 cs->frame_size += packet_size - VIDEOFRAME_HEADER_SIZE;
741
742 end:
743 rtp_free_msg(NULL, msg);
744 }
745} \ No newline at end of file
diff --git a/toxav/codec.h b/toxav/codec.h
index db4fbea0..90a74ce8 100644
--- a/toxav/codec.h
+++ b/toxav/codec.h
@@ -24,6 +24,9 @@
24#ifndef _CODEC_H_ 24#ifndef _CODEC_H_
25#define _CODEC_H_ 25#define _CODEC_H_
26 26
27#include "toxav.h"
28#include "rtp.h"
29
27#include <stdio.h> 30#include <stdio.h>
28#include <math.h> 31#include <math.h>
29#include <pthread.h> 32#include <pthread.h>
@@ -32,85 +35,126 @@
32#include <vpx/vpx_encoder.h> 35#include <vpx/vpx_encoder.h>
33#include <vpx/vp8dx.h> 36#include <vpx/vp8dx.h>
34#include <vpx/vp8cx.h> 37#include <vpx/vp8cx.h>
38#include <vpx/vpx_image.h>
35#define VIDEO_CODEC_DECODER_INTERFACE (vpx_codec_vp8_dx()) 39#define VIDEO_CODEC_DECODER_INTERFACE (vpx_codec_vp8_dx())
36#define VIDEO_CODEC_ENCODER_INTERFACE (vpx_codec_vp8_cx()) 40#define VIDEO_CODEC_ENCODER_INTERFACE (vpx_codec_vp8_cx())
37 41
38/* Audio encoding/decoding */ 42/* Audio encoding/decoding */
39#include <opus.h> 43#include <opus.h>
40 44
41typedef enum _Capabilities { 45typedef void (*CSAudioCallback) (void* agent, int32_t call_idx, const int16_t* PCM, uint16_t size, void* data);
42 none, 46typedef void (*CSVideoCallback) (void* agent, int32_t call_idx, const vpx_image_t* img, void* data);
47
48typedef enum _CsCapabilities {
43 a_encoding = 1 << 0, 49 a_encoding = 1 << 0,
44 a_decoding = 1 << 1, 50 a_decoding = 1 << 1,
45 v_encoding = 1 << 2, 51 v_encoding = 1 << 2,
46 v_decoding = 1 << 3 52 v_decoding = 1 << 3
47} Capabilities; 53} CsCapabilities;
48
49extern const uint16_t min_jbuf_size;
50 54
51typedef struct _CodecState { 55typedef struct _CSSession {
52 56
57/* VIDEO
58 *
59 *
60 */
61 int support_video;
62
53 /* video encoding */ 63 /* video encoding */
54 vpx_codec_ctx_t v_encoder; 64 vpx_codec_ctx_t v_encoder;
55 uint32_t frame_counter; 65 uint32_t frame_counter;
56 66
57 /* video decoding */ 67 /* video decoding */
58 vpx_codec_ctx_t v_decoder; 68 vpx_codec_ctx_t v_decoder;
59 int bitrate;
60 int max_width; 69 int max_width;
61 int max_height; 70 int max_height;
62 71
72
73 /* Data handling */
74 uint8_t *frame_buf; /* buffer for split video payloads */
75 uint32_t frame_size; /* largest address written to in frame_buf for current input frame*/
76 uint8_t frameid_in, frameid_out; /* id of input and output video frame */
77 uint32_t last_timestamp; /* calculating cycles */
78
79 /* Limits */
80 uint32_t video_frame_piece_size;
81 uint32_t max_video_frame_size;
82
83 /* Reassembling */
84 uint8_t *split_video_frame;
85 const uint8_t *processing_video_frame;
86 uint16_t processing_video_frame_size;
87
88
89
90/* AUDIO
91 *
92 *
93 */
94
63 /* audio encoding */ 95 /* audio encoding */
64 OpusEncoder *audio_encoder; 96 OpusEncoder *audio_encoder;
65 int audio_bitrate; 97 int audio_encoder_bitrate;
66 int audio_sample_rate; 98 int audio_encoder_sample_rate;
99 int audio_encoder_frame_duration;
67 int audio_encoder_channels; 100 int audio_encoder_channels;
68 101
69 /* audio decoding */ 102 /* audio decoding */
70 OpusDecoder *audio_decoder; 103 OpusDecoder *audio_decoder;
104 int audio_decoder_bitrate;
105 int audio_decoder_sample_rate;
106 int audio_decoder_frame_duration;
71 int audio_decoder_channels; 107 int audio_decoder_channels;
72 108
73 uint64_t capabilities; /* supports*/ 109 struct _JitterBuffer* j_buf;
110
74 111
75 /* Voice activity detection */ 112 /* Voice activity detection */
76 uint32_t EVAD_tolerance; /* In frames */ 113 uint32_t EVAD_tolerance; /* In frames */
77 uint32_t EVAD_tolerance_cr; 114 uint32_t EVAD_tolerance_cr;
78} CodecState; 115
79 116
80 117
81typedef struct _JitterBuffer { 118/* OTHER
82 RTPMessage **queue; 119 *
83 uint32_t size; 120 *
84 uint32_t capacity; 121 */
85 uint16_t bottom; 122
86 uint16_t top; 123 uint64_t capabilities; /* supports*/
87} JitterBuffer; 124
88 125 /* Buffering */
89JitterBuffer *create_queue(unsigned int capacity); 126 void* abuf_raw, *vbuf_raw; /* Un-decoded data */
90void terminate_queue(JitterBuffer *q); 127 _Bool active;
91void queue(JitterBuffer *q, RTPMessage *pk); 128 pthread_mutex_t queue_mutex[1];
92RTPMessage *dequeue(JitterBuffer *q, int *success); 129
93 130 void* agent; /* Pointer to ToxAv */
131 int32_t call_idx;
132} CSSession;
133
134CSSession *cs_new(const ToxAvCSettings* cs_self, const ToxAvCSettings* cs_peer, uint32_t jbuf_size, int has_video);
135void cs_kill(CSSession *cs);
136
137int cs_split_video_payload(CSSession* cs, const uint8_t* payload, uint16_t length);
138const uint8_t* cs_get_split_video_frame(CSSession* cs, uint16_t* size);
139
140/**
141 * Call playback callbacks
142 */
143void cs_do(CSSession* cs);
94 144
95CodecState *codec_init_session ( uint32_t audio_bitrate, 145void cs_register_audio_callback(CSAudioCallback cb, void* data);
96 uint16_t audio_frame_duration, 146void cs_register_video_callback(CSVideoCallback cb, void* data);
97 uint32_t audio_sample_rate,
98 uint32_t encoder_audio_channels,
99 uint32_t decoder_audio_channels,
100 uint32_t audio_VAD_tolerance_ms,
101 uint16_t max_video_width,
102 uint16_t max_video_height,
103 uint32_t video_bitrate );
104 147
105void codec_terminate_session(CodecState *cs); 148/* Reconfigure video encoder; return 0 on success or -1 on failure. */
149int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height);
150int cs_set_video_encoder_bitrate(CSSession *cs, uint32_t video_bitrate);
106 151
107/* Reconfigure video encoder
108 return 0 on success.
109 return -1 on failure. */
110int reconfigure_video_encoder_resolution(CodecState *cs, uint16_t width, uint16_t height);
111int reconfigure_video_encoder_bitrate(CodecState *cs, uint32_t video_bitrate);
112 152
113/* Calculate energy and return 1 if has voice, 0 if not */ 153/* Calculate energy and return 1 if has voice, 0 if not */
114int energy_VAD(CodecState *cs, int16_t *PCM, uint16_t frame_size, float energy); 154int cs_calculate_vad(CSSession *cs, int16_t *PCM, uint16_t frame_size, float energy);
155void cs_set_vad_treshold(CSSession *cs, uint32_t treshold, uint16_t frame_duration);
156
115 157
158/* Internal. Called from rtp_handle_message */
159void queue_message(RTPSession *session, RTPMessage *msg);
116#endif /* _CODEC_H_ */ 160#endif /* _CODEC_H_ */
diff --git a/toxav/msi.c b/toxav/msi.c
index 4445f567..f5e21a14 100644
--- a/toxav/msi.c
+++ b/toxav/msi.c
@@ -97,11 +97,6 @@ GENERIC_HEADER ( Reason, MSIReasonStrType )
97GENERIC_HEADER ( CSettings, MSIRawCSettingsType ) 97GENERIC_HEADER ( CSettings, MSIRawCSettingsType )
98 98
99 99
100/**
101 * @brief This is the message structure. It contains all of the headers and
102 * destination/source of the message stored in friend_id.
103 *
104 */
105typedef struct _MSIMessage { 100typedef struct _MSIMessage {
106 101
107 MSIHeaderRequest request; 102 MSIHeaderRequest request;
@@ -115,24 +110,19 @@ typedef struct _MSIMessage {
115} MSIMessage; 110} MSIMessage;
116 111
117 112
118inline__ void invoke_callback(MSISession *session, int32_t call_index, MSICallbackID id) 113static void invoke_callback(MSISession *s, int32_t c, MSICallbackID i)
119{ 114{
120 if ( session->callbacks[id].function ) { 115 if ( s->callbacks[i].function ) {
121 LOGGER_DEBUG("Invoking callback function: %d", id); 116 LOGGER_DEBUG("Invoking callback function: %d", i);
122 session->callbacks[id].function ( session->agent_handler, call_index, session->callbacks[id].data ); 117
118 s->callbacks[i].function( s->agent_handler, c, s->callbacks[i].data );
123 } 119 }
124} 120}
125 121
126/** 122/**
127 * @brief Parse raw 'data' received from socket into MSIMessage struct. 123 * Parse raw 'data' received from socket into MSIMessage struct.
128 * Every message has to have end value of 'end_byte' or _undefined_ behavior 124 * Every message has to have end value of 'end_byte' or _undefined_ behavior
129 * occures. The best practice is to check the end of the message at the handle_packet. 125 * occures. The best practice is to check the end of the message at the handle_packet.
130 *
131 * @param msg Container.
132 * @param data The data.
133 * @return int
134 * @retval -1 Error occurred.
135 * @retval 0 Success.
136 */ 126 */
137static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length ) 127static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length )
138{ 128{
@@ -211,12 +201,7 @@ static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t lengt
211} 201}
212 202
213/** 203/**
214 * @brief Create the message. 204 * Create the message.
215 *
216 * @param type Request or response.
217 * @param type_id Type of request/response.
218 * @return MSIMessage* Created message.
219 * @retval NULL Error occurred.
220 */ 205 */
221MSIMessage *msi_new_message ( MSIMessageType type, const uint8_t type_value ) 206MSIMessage *msi_new_message ( MSIMessageType type, const uint8_t type_value )
222{ 207{
@@ -241,11 +226,7 @@ MSIMessage *msi_new_message ( MSIMessageType type, const uint8_t type_value )
241 226
242 227
243/** 228/**
244 * @brief Parse data from handle_packet. 229 * Parse data from handle_packet.
245 *
246 * @param data The data.
247 * @return MSIMessage* Parsed message.
248 * @retval NULL Error occurred.
249 */ 230 */
250MSIMessage *parse_recv ( const uint8_t *data, uint16_t length ) 231MSIMessage *parse_recv ( const uint8_t *data, uint16_t length )
251{ 232{
@@ -272,16 +253,13 @@ MSIMessage *parse_recv ( const uint8_t *data, uint16_t length )
272 253
273 254
274/** 255/**
275 * @brief Speaks for it self. 256 * Speaks for itself.
276 *
277 * @param dest Container.
278 * @param header_field Field.
279 * @param header_value Field value.
280 * @param value_len Length of field value.
281 * @param length Pointer to container length.
282 * @return uint8_t* Iterated container.
283 */ 257 */
284uint8_t *format_output ( uint8_t *dest, MSIHeaderID id, const void *value, uint8_t value_len, uint16_t *length ) 258uint8_t *format_output ( uint8_t *dest,
259 MSIHeaderID id,
260 const void *value,
261 uint8_t value_len,
262 uint16_t *length )
285{ 263{
286 if ( dest == NULL ) { 264 if ( dest == NULL ) {
287 LOGGER_ERROR("No destination space!"); 265 LOGGER_ERROR("No destination space!");
@@ -307,11 +285,7 @@ uint8_t *format_output ( uint8_t *dest, MSIHeaderID id, const void *value, uint8
307 285
308 286
309/** 287/**
310 * @brief Parse MSIMessage to send. 288 * Parse MSIMessage to send.
311 *
312 * @param msg The message.
313 * @param dest Destination.
314 * @return uint16_t Its final size.
315 */ 289 */
316uint16_t parse_send ( MSIMessage *msg, uint8_t *dest ) 290uint16_t parse_send ( MSIMessage *msg, uint8_t *dest )
317{ 291{
@@ -452,119 +426,83 @@ void msi_msg_get_csettings ( MSIMessage *msg, MSICSettings *dest )
452} 426}
453 427
454typedef struct _Timer { 428typedef struct _Timer {
455 void *(*func)(void *); 429 void (*func)(struct _Timer*);
456 void *func_arg1;
457 int func_arg2;
458 uint64_t timeout; 430 uint64_t timeout;
459 int idx; 431 MSISession* session;
432 int call_idx;
433 int id;
460 434
461} Timer; 435} Timer;
462 436
463typedef struct _TimerHandler { 437typedef struct _TimerHandler {
464 Timer **timers; 438 Timer **timers;
465 pthread_mutex_t mutex;
466 439
467 uint32_t max_capacity; 440 uint32_t max_capacity;
468 uint32_t size; 441 uint32_t size;
469 uint64_t resolution;
470
471 _Bool running;
472
473} TimerHandler; 442} TimerHandler;
474 443
475struct timer_function_args {
476 void *arg1;
477 int arg2;
478};
479 444
480/** 445static int timer_alloc (MSISession* session , void (*func)(Timer*), int call_idx, uint32_t timeout)
481 * @brief Allocate timer in array
482 *
483 * @param timers_container Handler
484 * @param func Function to be executed
485 * @param arg Its args
486 * @param timeout Timeout in ms
487 * @return int
488 */
489static int timer_alloc ( TimerHandler *timers_container, void * (func)(void *), void *arg1, int arg2, uint32_t timeout)
490{ 446{
491 static int timer_id; 447 static int timer_id;
492 pthread_mutex_lock(&timers_container->mutex); 448 TimerHandler *timer_handler = session->timer_handler;
493 449
494 uint32_t i = 0; 450 uint32_t i = 0;
495 451
496 for (; i < timers_container->max_capacity && timers_container->timers[i]; i ++); 452 for (; i < timer_handler->max_capacity && timer_handler->timers[i]; i ++);
497 453
498 if (i == timers_container->max_capacity) { 454 if (i == timer_handler->max_capacity) {
499 LOGGER_WARNING("Maximum capacity reached!"); 455 LOGGER_WARNING("Maximum capacity reached!");
500 pthread_mutex_unlock(&timers_container->mutex);
501 return -1; 456 return -1;
502 } 457 }
503 458
504 Timer *timer = timers_container->timers[i] = calloc(sizeof(Timer), 1); 459 Timer *timer = timer_handler->timers[i] = calloc(sizeof(Timer), 1);
505 460
506 if (timer == NULL) { 461 if (timer == NULL) {
507 LOGGER_ERROR("Failed to allocate timer!"); 462 LOGGER_ERROR("Failed to allocate timer!");
508 pthread_mutex_unlock(&timers_container->mutex);
509 return -1; 463 return -1;
510 } 464 }
511 465
512 timers_container->size ++; 466 timer_handler->size ++;
513 467
514 timer->func = func; 468 timer->func = func;
515 timer->func_arg1 = arg1; 469 timer->session = session;
516 timer->func_arg2 = arg2; 470 timer->call_idx = call_idx;
517 timer->timeout = timeout + current_time_monotonic(); /* In ms */ 471 timer->timeout = timeout + current_time_monotonic(); /* In ms */
518 ++timer_id; 472 ++timer_id;
519 timer->idx = timer_id; 473 timer->id = timer_id;
520 474
521 /* reorder */ 475 /* reorder */
522 if (i) { 476 if (i) {
523 int64_t j = i - 1; 477 int64_t j = i - 1;
524 478
525 for (; j >= 0 && timeout < timers_container->timers[j]->timeout; j--) { 479 for (; j >= 0 && timeout < timer_handler->timers[j]->timeout; j--) {
526 Timer *tmp = timers_container->timers[j]; 480 Timer *tmp = timer_handler->timers[j];
527 timers_container->timers[j] = timer; 481 timer_handler->timers[j] = timer;
528 timers_container->timers[j + 1] = tmp; 482 timer_handler->timers[j + 1] = tmp;
529 } 483 }
530 } 484 }
531 485
532 pthread_mutex_unlock(&timers_container->mutex); 486 LOGGER_DEBUG("Allocated timer index: %ull timeout: %ull, current size: %ull", i, timeout, timer_handler->size);
533 487 return timer->id;
534 LOGGER_DEBUG("Allocated timer index: %ull timeout: %ull, current size: %ull", i, timeout, timers_container->size);
535 return timer->idx;
536} 488}
537 489
538/** 490static int timer_release ( TimerHandler *timers_container, int id)
539 * @brief Remove timer from array
540 *
541 * @param timers_container handler
542 * @param idx timer id
543 * @param lock_mutex (does the mutex need to be locked)
544 * @return int
545 */
546static int timer_release ( TimerHandler *timers_container, int idx , int lock_mutex)
547{ 491{
548 if (lock_mutex)
549 pthread_mutex_lock(&timers_container->mutex);
550
551 Timer **timed_events = timers_container->timers; 492 Timer **timed_events = timers_container->timers;
552 493
553 size_t i; 494 uint32_t i;
554 int rc = -1; 495 int rc = -1;
555 496
556 for (i = 0; i < timers_container->max_capacity; ++i) { 497 for (i = 0; i < timers_container->max_capacity; ++i) {
557 if (timed_events[i] && timed_events[i]->idx == idx) { 498 if (timed_events[i] && timed_events[i]->id == id) {
558 rc = i; 499 rc = i;
559 break; 500 break;
560 } 501 }
561 } 502 }
562 503
563 if (rc == -1) { 504 if (rc == -1) {
564 LOGGER_WARNING("No event with id: %d", idx); 505 LOGGER_WARNING("No event with id: %d", id);
565
566 if (lock_mutex) pthread_mutex_unlock(&timers_container->mutex);
567
568 return -1; 506 return -1;
569 } 507 }
570 508
@@ -581,133 +519,12 @@ static int timer_release ( TimerHandler *timers_container, int idx , int lock_mu
581 519
582 timers_container->size--; 520 timers_container->size--;
583 521
584 LOGGER_DEBUG("Popped id: %d, current size: %ull ", idx, timers_container->size); 522 LOGGER_DEBUG("Popped id: %d, current size: %ull ", id, timers_container->size);
585
586 if (lock_mutex) pthread_mutex_unlock(&timers_container->mutex);
587
588 return 0; 523 return 0;
589} 524}
590 525
591/** 526/**
592 * @brief Main poll for timer execution 527 * Generate _random_ alphanumerical string.
593 *
594 * @param arg ...
595 * @return void*
596 */
597static void *timer_poll( void *arg )
598{
599 TimerHandler *handler = arg;
600
601 while ( handler->running ) {
602
603 pthread_mutex_lock(&handler->mutex);
604
605 if ( handler->running ) {
606
607 uint64_t time = current_time_monotonic();
608
609 while ( handler->timers[0] && handler->timers[0]->timeout < time ) {
610 pthread_t tid;
611
612 struct timer_function_args *args = malloc(sizeof(struct timer_function_args));
613 args->arg1 = handler->timers[0]->func_arg1;
614 args->arg2 = handler->timers[0]->func_arg2;
615
616 if ( 0 != pthread_create(&tid, NULL, handler->timers[0]->func, args) ||
617 0 != pthread_detach(tid) ) {
618 LOGGER_ERROR("Failed to execute timer at: %d!", handler->timers[0]->timeout);
619 free(args);
620 } else {
621 LOGGER_DEBUG("Executed timer assigned at: %d", handler->timers[0]->timeout);
622 }
623
624 timer_release(handler, handler->timers[0]->idx, 0);
625 }
626
627 }
628
629 pthread_mutex_unlock(&handler->mutex);
630
631 usleep(handler->resolution);
632 }
633
634 size_t i = 0;
635
636 for (; i < handler->max_capacity; i ++)
637 free(handler->timers[i]);
638
639 free(handler->timers);
640
641 pthread_mutex_destroy( &handler->mutex );
642
643 free(handler);
644 pthread_exit(NULL);
645}
646
647/**
648 * @brief Start timer poll and return handler
649 *
650 * @param max_capacity capacity
651 * @param resolution ...
652 * @return TimerHandler*
653 */
654static TimerHandler *timer_init_session (int max_capacity, int resolution)
655{
656 TimerHandler *handler = calloc(1, sizeof(TimerHandler));
657
658 if (handler == NULL) {
659 LOGGER_ERROR("Failed to allocate memory, program might misbehave!");
660 return NULL;
661 }
662
663 handler->timers = calloc(max_capacity, sizeof(Timer *));
664
665 if (handler->timers == NULL) {
666 LOGGER_ERROR("Failed to allocate %d timed events!", max_capacity);
667 free(handler);
668 return NULL;
669 }
670
671 handler->max_capacity = max_capacity;
672 handler->running = 1;
673 handler->resolution = resolution;
674
675 pthread_mutex_init(&handler->mutex, NULL);
676
677
678 pthread_t _tid;
679
680 if ( 0 != pthread_create(&_tid, NULL, timer_poll, handler) || 0 != pthread_detach(_tid) ) {
681 LOGGER_ERROR("Failed to start timer poll thread!");
682 free(handler->timers);
683 free(handler);
684 return NULL;
685 }
686
687 return handler;
688}
689
690/**
691 * @brief Terminate timer session
692 *
693 * @param handler The timer handler
694 * @return void
695 */
696static void timer_terminate_session(TimerHandler *handler)
697{
698 pthread_mutex_lock(&handler->mutex);
699
700 handler->running = 0;
701
702 pthread_mutex_unlock(&handler->mutex);
703}
704
705/**
706 * @brief Generate _random_ alphanumerical string.
707 *
708 * @param str Destination.
709 * @param size Size of string.
710 * @return void
711 */ 528 */
712static void t_randomstr ( uint8_t *str, uint32_t size ) 529static void t_randomstr ( uint8_t *str, uint32_t size )
713{ 530{
@@ -728,7 +545,7 @@ static void t_randomstr ( uint8_t *str, uint32_t size )
728 } 545 }
729} 546}
730 547
731 548/* TODO: it would be nice to actually have some sane error codes */
732typedef enum { 549typedef enum {
733 error_none, 550 error_none,
734 error_deadcall, /* has call id but it's from old call */ 551 error_deadcall, /* has call id but it's from old call */
@@ -744,12 +561,9 @@ typedef enum {
744 561
745 562
746/** 563/**
747 * @brief Stringify error code. 564 * Stringify error code.
748 *
749 * @param error_code The code.
750 * @return const uint8_t* The string.
751 */ 565 */
752static inline__ const uint8_t *stringify_error ( MSICallError error_code ) 566static const uint8_t *stringify_error ( MSICallError error_code )
753{ 567{
754 static const uint8_t *strings[] = { 568 static const uint8_t *strings[] = {
755 ( uint8_t *) "", 569 ( uint8_t *) "",
@@ -764,16 +578,6 @@ static inline__ const uint8_t *stringify_error ( MSICallError error_code )
764 return strings[error_code]; 578 return strings[error_code];
765} 579}
766 580
767/**
768 * @brief Speaks for it self.
769 *
770 * @param session Control session.
771 * @param msg The message.
772 * @param to Where to.
773 * @return int
774 * @retval -1 Error occurred.
775 * @retval 0 Success.
776 */
777static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, uint32_t to ) 581static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, uint32_t to )
778{ 582{
779 msi_msg_set_callid ( msg, call->id ); 583 msi_msg_set_callid ( msg, call->id );
@@ -794,7 +598,7 @@ static int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, u
794 return -1; 598 return -1;
795} 599}
796 600
797inline__ int send_reponse ( MSISession *session, MSICall *call, MSIResponse response, uint32_t to ) 601static int send_reponse ( MSISession *session, MSICall *call, MSIResponse response, uint32_t to )
798{ 602{
799 MSIMessage *msg = msi_new_message ( TypeResponse, response ); 603 MSIMessage *msg = msi_new_message ( TypeResponse, response );
800 int ret = send_message ( session, call, msg, to ); 604 int ret = send_message ( session, call, msg, to );
@@ -802,14 +606,26 @@ inline__ int send_reponse ( MSISession *session, MSICall *call, MSIResponse resp
802 return ret; 606 return ret;
803} 607}
804 608
609static int send_error ( MSISession *session, MSICall *call, MSICallError errid, uint32_t to )
610{
611 if (!call) {
612 LOGGER_WARNING("Cannot handle error on 'null' call");
613 return -1;
614 }
615
616 LOGGER_DEBUG("Sending error: %d on call: %s", errid, call->id);
617
618 MSIMessage *msg_error = msi_new_message ( TypeResponse, error );
619
620 msi_msg_set_reason ( msg_error, stringify_error(errid) );
621 send_message ( session, call, msg_error, to );
622 free ( msg_error );
623
624 return 0;
625}
626
805/** 627/**
806 * @brief Determine 'bigger' call id 628 * Determine 'bigger' call id
807 *
808 * @param first duh
809 * @param second duh
810 * @return int
811 * @retval 0 it's first
812 * @retval 1 it's second
813 */ 629 */
814static int call_id_bigger( const uint8_t *first, const uint8_t *second) 630static int call_id_bigger( const uint8_t *first, const uint8_t *second)
815{ 631{
@@ -818,12 +634,7 @@ static int call_id_bigger( const uint8_t *first, const uint8_t *second)
818 634
819 635
820/** 636/**
821 * @brief Speaks for it self. 637 * Set/change peer csettings
822 *
823 * @param session Control session.
824 * @param msg The message.
825 * @param peer_id The peer.
826 * @return -1, 0
827 */ 638 */
828static int flush_peer_csettings ( MSICall *call, MSIMessage *msg, int peer_id ) 639static int flush_peer_csettings ( MSICall *call, MSIMessage *msg, int peer_id )
829{ 640{
@@ -855,39 +666,28 @@ static int flush_peer_csettings ( MSICall *call, MSIMessage *msg, int peer_id )
855 return -1; 666 return -1;
856} 667}
857 668
858static int terminate_call ( MSISession *session, MSICall *call );
859 669
860static void handle_remote_connection_change(Messenger *messenger, int friend_num, uint8_t status, void *session_p) 670/**
671 * Add peer to peer list.
672 */
673static void add_peer( MSICall *call, int peer_id )
861{ 674{
862 (void)messenger; 675 uint32_t *peers = !call->peers ? peers = calloc(sizeof(uint32_t), 1) :
863 MSISession *session = session_p; 676 realloc( call->peers, sizeof(uint32_t) * call->peer_count);
864 677
865 switch ( status ) { 678 if (!peers) {
866 case 0: { /* Went offline */ 679 LOGGER_WARNING("Allocation failed! Program might misbehave!");
867 int32_t j = 0; 680 return;
868
869 for ( ; j < session->max_calls; j ++ ) {
870
871 if ( !session->calls[j] ) continue;
872
873 uint16_t i = 0;
874
875 for ( ; i < session->calls[j]->peer_count; i ++ )
876 if ( session->calls[j]->peers[i] == (uint32_t)friend_num ) {
877 invoke_callback(session, j, MSI_OnPeerTimeout);
878 terminate_call(session, session->calls[j]);
879 LOGGER_DEBUG("Remote: %d timed out!", friend_num);
880 return; /* TODO: On group calls change behaviour */
881 }
882 }
883 }
884 break;
885
886 default:
887 break;
888 } 681 }
682
683 call->peer_count ++;
684 call->peers = peers;
685 call->peers[call->peer_count - 1] = peer_id;
686
687 LOGGER_DEBUG("Added peer: %d", peer_id);
889} 688}
890 689
690
891static MSICall *find_call ( MSISession *session, uint8_t *call_id ) 691static MSICall *find_call ( MSISession *session, uint8_t *call_id )
892{ 692{
893 if ( call_id == NULL ) return NULL; 693 if ( call_id == NULL ) return NULL;
@@ -902,68 +702,6 @@ static MSICall *find_call ( MSISession *session, uint8_t *call_id )
902 return NULL; 702 return NULL;
903} 703}
904 704
905/**
906 * @brief Sends error response to peer.
907 *
908 * @param session The session.
909 * @param errid The id.
910 * @param to Where to?
911 * @return int
912 * @retval -1/0 It's usually always success.
913 */
914static int send_error ( MSISession *session, MSICall *call, MSICallError errid, uint32_t to )
915{
916 if (!call) {
917 LOGGER_WARNING("Cannot handle error on 'null' call");
918 return -1;
919 }
920
921 LOGGER_DEBUG("Sending error: %d on call: %s", errid, call->id);
922
923 MSIMessage *msg_error = msi_new_message ( TypeResponse, error );
924
925 msi_msg_set_reason ( msg_error, stringify_error(errid) );
926 send_message ( session, call, msg_error, to );
927 free ( msg_error );
928
929 return 0;
930}
931
932
933
934/**
935 * @brief Add peer to peer list.
936 *
937 * @param call What call.
938 * @param peer_id Its id.
939 * @return void
940 */
941static void add_peer( MSICall *call, int peer_id )
942{
943 uint32_t *peers = !call->peers ? peers = calloc(sizeof(uint32_t), 1) :
944 realloc( call->peers, sizeof(uint32_t) * call->peer_count);
945
946 if (!peers) {
947 LOGGER_WARNING("Allocation failed! Program might misbehave!");
948 return;
949 }
950
951 call->peer_count ++;
952 call->peers = peers;
953 call->peers[call->peer_count - 1] = peer_id;
954
955 LOGGER_DEBUG("Added peer: %d", peer_id);
956}
957
958
959/**
960 * @brief Speaks for it self.
961 *
962 * @param session Control session.
963 * @param peers Amount of peers. (Currently it only supports 1)
964 * @param ringing_timeout Ringing timeout.
965 * @return MSICall* The created call.
966 */
967static MSICall *init_call ( MSISession *session, int peers, int ringing_timeout ) 705static MSICall *init_call ( MSISession *session, int peers, int ringing_timeout )
968{ 706{
969 707
@@ -1009,21 +747,10 @@ static MSICall *init_call ( MSISession *session, int peers, int ringing_timeout
1009 747
1010 call->ringing_tout_ms = ringing_timeout; 748 call->ringing_tout_ms = ringing_timeout;
1011 749
1012 pthread_mutex_init ( &call->mutex, NULL );
1013
1014 LOGGER_DEBUG("Started new call with index: %u", call_idx); 750 LOGGER_DEBUG("Started new call with index: %u", call_idx);
1015 return call; 751 return call;
1016} 752}
1017 753
1018
1019/**
1020 * @brief Terminate the call.
1021 *
1022 * @param session Control session.
1023 * @return int
1024 * @retval -1 Error occurred.
1025 * @retval 0 Success.
1026 */
1027static int terminate_call ( MSISession *session, MSICall *call ) 754static int terminate_call ( MSISession *session, MSICall *call )
1028{ 755{
1029 if ( !call ) { 756 if ( !call ) {
@@ -1031,67 +758,71 @@ static int terminate_call ( MSISession *session, MSICall *call )
1031 return -1; 758 return -1;
1032 } 759 }
1033 760
1034 LOGGER_DEBUG("Terminated call id: %d", call->call_idx);
1035 /* Check event loop and cancel timed events if there are any 761 /* Check event loop and cancel timed events if there are any
1036 * NOTE: This has to be done before possibly
1037 * locking the mutex the second time
1038 */ 762 */
1039 timer_release ( session->timer_handler, call->request_timer_id, 1); 763 timer_release ( session->timer_handler, call->request_timer_id);
1040 timer_release ( session->timer_handler, call->ringing_timer_id, 1); 764 timer_release ( session->timer_handler, call->ringing_timer_id);
1041
1042 /* Get a handle */
1043 pthread_mutex_lock ( &call->mutex );
1044 765
1045 session->calls[call->call_idx] = NULL; 766 session->calls[call->call_idx] = NULL;
1046 767
768 LOGGER_DEBUG("Terminated call id: %d", call->call_idx);
769
1047 free ( call->csettings_peer ); 770 free ( call->csettings_peer );
1048 free ( call->peers); 771 free ( call->peers );
1049
1050 /* Release handle */
1051 pthread_mutex_unlock ( &call->mutex );
1052
1053 pthread_mutex_destroy ( &call->mutex );
1054
1055 free ( call ); 772 free ( call );
1056 773
1057 return 0; 774 return 0;
1058} 775}
1059 776
777static void handle_remote_connection_change(Messenger *messenger, int friend_num, uint8_t status, void *session_p)
778{
779 (void)messenger;
780 MSISession *session = session_p;
781
782 switch ( status ) {
783 case 0: { /* Went offline */
784 int32_t j = 0;
785
786 for ( ; j < session->max_calls; j ++ ) {
787
788 if ( !session->calls[j] ) continue;
789
790 uint16_t i = 0;
791
792 for ( ; i < session->calls[j]->peer_count; i ++ )
793 if ( session->calls[j]->peers[i] == (uint32_t)friend_num ) {
794 invoke_callback(session, j, MSI_OnPeerTimeout);
795 terminate_call(session, session->calls[j]);
796 LOGGER_DEBUG("Remote: %d timed out!", friend_num);
797 return; /* TODO: On group calls change behaviour */
798 }
799 }
800 }
801 break;
802
803 default:
804 break;
805 }
806}
1060 807
1061/** 808/**
1062 * @brief Function called at request timeout. If not called in thread it might cause trouble 809 * Function called at request timeout
1063 *
1064 * @param arg Control session
1065 * @return void*
1066 */ 810 */
1067static void *handle_timeout ( void *arg ) 811static void handle_timeout ( Timer* timer )
1068{ 812{
1069 /* TODO: Cancel might not arrive there; set up 813 /* TODO: Cancel might not arrive there; set up
1070 * timers on these cancels and terminate call on 814 * timers on these cancels and terminate call on
1071 * their timeout 815 * their timeout
1072 */ 816 */
1073 struct timer_function_args *args = arg; 817 MSICall *call = timer->session->calls[timer->call_idx];
1074 int call_index = args->arg2; 818
1075 MSISession *session = args->arg1; 819
1076 MSICall *call = session->calls[call_index];
1077
1078 if (call) { 820 if (call) {
1079 LOGGER_DEBUG("[Call: %d] Request timed out!", call->call_idx); 821 LOGGER_DEBUG("[Call: %d] Request timed out!", call->call_idx);
1080 822
1081 invoke_callback(session, call_index, MSI_OnRequestTimeout); 823 invoke_callback(timer->session, timer->call_idx, MSI_OnRequestTimeout);
824 msi_cancel(timer->session, timer->call_idx, call->peers [0], "Request timed out");
1082 } 825 }
1083
1084 if ( call && call->session ) {
1085
1086 /* TODO: Cancel all? */
1087 /* uint16_t _it = 0;
1088 * for ( ; _it < _session->call->peer_count; _it++ ) */
1089 msi_cancel ( call->session, call->call_idx, call->peers [0], "Request timed out" );
1090 /*terminate_call(call->session, call);*/
1091 }
1092
1093 free(arg);
1094 pthread_exit(NULL);
1095} 826}
1096 827
1097 828
@@ -1100,12 +831,10 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *
1100{ 831{
1101 LOGGER_DEBUG("Session: %p Handling 'invite' on call: %d", session, call ? call->call_idx : -1); 832 LOGGER_DEBUG("Session: %p Handling 'invite' on call: %d", session, call ? call->call_idx : -1);
1102 833
1103 pthread_mutex_lock(&session->mutex);
1104 834
1105 if (!msg->csettings.exists) {/**/ 835 if (!msg->csettings.exists) {/**/
1106 LOGGER_WARNING("Peer sent invalid codec settings!"); 836 LOGGER_WARNING("Peer sent invalid codec settings!");
1107 send_error ( session, call, error_no_callid, msg->friend_id ); 837 send_error ( session, call, error_no_callid, msg->friend_id );
1108 pthread_mutex_unlock(&session->mutex);
1109 return 0; 838 return 0;
1110 } 839 }
1111 840
@@ -1128,13 +857,11 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *
1128 call = init_call ( session, 1, 0 ); 857 call = init_call ( session, 1, 0 );
1129 858
1130 if ( !call ) { 859 if ( !call ) {
1131 pthread_mutex_unlock(&session->mutex);
1132 LOGGER_ERROR("Starting call"); 860 LOGGER_ERROR("Starting call");
1133 return 0; 861 return 0;
1134 } 862 }
1135 863
1136 } else { 864 } else {
1137 pthread_mutex_unlock(&session->mutex);
1138 return 0; /* Wait for ringing from peer */ 865 return 0; /* Wait for ringing from peer */
1139 } 866 }
1140 } else if (call->state == call_active) { 867 } else if (call->state == call_active) {
@@ -1142,27 +869,23 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *
1142 if (flush_peer_csettings(call, msg, 0) != 0) { /**/ 869 if (flush_peer_csettings(call, msg, 0) != 0) { /**/
1143 LOGGER_WARNING("Peer sent invalid csetting!"); 870 LOGGER_WARNING("Peer sent invalid csetting!");
1144 send_error ( session, call, error_no_callid, msg->friend_id ); 871 send_error ( session, call, error_no_callid, msg->friend_id );
1145 pthread_mutex_unlock(&session->mutex);
1146 return 0; 872 return 0;
1147 } 873 }
1148 874
1149 LOGGER_DEBUG("Set new call type: %s", call->csettings_peer[0].call_type == type_audio ? "audio" : "video"); 875 LOGGER_DEBUG("Set new call type: %s", call->csettings_peer[0].call_type == type_audio ? "audio" : "video");
1150 send_reponse(session, call, starting, msg->friend_id); 876 send_reponse(session, call, starting, msg->friend_id);
1151 pthread_mutex_unlock(&session->mutex); 877 invoke_callback(session, call->call_idx, MSI_OnPeerCSChange);
1152 invoke_callback(session, call->call_idx, MSI_OnMediaChange);
1153 return 1; 878 return 1;
1154 } 879 }
1155 } else { 880 } else {
1156 send_error ( session, call, error_busy, msg->friend_id ); /* TODO: Ugh*/ 881 send_error ( session, call, error_busy, msg->friend_id ); /* TODO: Ugh*/
1157 terminate_call(session, call); 882 terminate_call(session, call);
1158 pthread_mutex_unlock(&session->mutex);
1159 return 0; 883 return 0;
1160 } 884 }
1161 } else { 885 } else {
1162 call = init_call ( session, 1, 0 ); 886 call = init_call ( session, 1, 0 );
1163 887
1164 if ( !call ) { 888 if ( !call ) {
1165 pthread_mutex_unlock(&session->mutex);
1166 LOGGER_ERROR("Starting call"); 889 LOGGER_ERROR("Starting call");
1167 return 0; 890 return 0;
1168 } 891 }
@@ -1171,7 +894,6 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *
1171 if ( !msg->callid.exists ) { 894 if ( !msg->callid.exists ) {
1172 send_error ( session, call, error_no_callid, msg->friend_id ); 895 send_error ( session, call, error_no_callid, msg->friend_id );
1173 terminate_call(session, call); 896 terminate_call(session, call);
1174 pthread_mutex_unlock(&session->mutex);
1175 return 0; 897 return 0;
1176 } 898 }
1177 899
@@ -1179,13 +901,8 @@ static int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *
1179 call->state = call_starting; 901 call->state = call_starting;
1180 902
1181 add_peer( call, msg->friend_id); 903 add_peer( call, msg->friend_id);
1182
1183 flush_peer_csettings ( call, msg, 0 ); 904 flush_peer_csettings ( call, msg, 0 );
1184
1185 send_reponse(session, call, ringing, msg->friend_id); 905 send_reponse(session, call, ringing, msg->friend_id);
1186
1187 pthread_mutex_unlock(&session->mutex);
1188
1189 invoke_callback(session, call->call_idx, MSI_OnInvite); 906 invoke_callback(session, call->call_idx, MSI_OnInvite);
1190 907
1191 return 1; 908 return 1;
@@ -1202,12 +919,7 @@ static int handle_recv_start ( MSISession *session, MSICall *call, MSIMessage *m
1202 919
1203 LOGGER_DEBUG("Session: %p Handling 'start' on call: %d, friend id: %d", session, call->call_idx, msg->friend_id ); 920 LOGGER_DEBUG("Session: %p Handling 'start' on call: %d, friend id: %d", session, call->call_idx, msg->friend_id );
1204 921
1205 pthread_mutex_lock(&session->mutex);
1206
1207 call->state = call_active; 922 call->state = call_active;
1208
1209 pthread_mutex_unlock(&session->mutex);
1210
1211 invoke_callback(session, call->call_idx, MSI_OnStart); 923 invoke_callback(session, call->call_idx, MSI_OnStart);
1212 return 1; 924 return 1;
1213} 925}
@@ -1223,13 +935,9 @@ static int handle_recv_reject ( MSISession *session, MSICall *call, MSIMessage *
1223 935
1224 invoke_callback(session, call->call_idx, MSI_OnReject); 936 invoke_callback(session, call->call_idx, MSI_OnReject);
1225 937
1226 pthread_mutex_lock(&session->mutex);
1227
1228 send_reponse(session, call, ending, msg->friend_id); 938 send_reponse(session, call, ending, msg->friend_id);
1229 terminate_call(session, call); 939 terminate_call(session, call);
1230 940
1231 pthread_mutex_unlock(&session->mutex);
1232
1233 return 1; 941 return 1;
1234} 942}
1235 943
@@ -1245,13 +953,8 @@ static int handle_recv_cancel ( MSISession *session, MSICall *call, MSIMessage *
1245 LOGGER_DEBUG("Session: %p Handling 'cancel' on call: %u", session, call->call_idx); 953 LOGGER_DEBUG("Session: %p Handling 'cancel' on call: %u", session, call->call_idx);
1246 954
1247 invoke_callback(session, call->call_idx, MSI_OnCancel); 955 invoke_callback(session, call->call_idx, MSI_OnCancel);
1248
1249 pthread_mutex_lock(&session->mutex);
1250
1251 terminate_call ( session, call ); 956 terminate_call ( session, call );
1252 957
1253 pthread_mutex_unlock(&session->mutex);
1254
1255 return 1; 958 return 1;
1256} 959}
1257 960
@@ -1265,14 +968,9 @@ static int handle_recv_end ( MSISession *session, MSICall *call, MSIMessage *msg
1265 LOGGER_DEBUG("Session: %p Handling 'end' on call: %d", session, call->call_idx); 968 LOGGER_DEBUG("Session: %p Handling 'end' on call: %d", session, call->call_idx);
1266 969
1267 invoke_callback(session, call->call_idx, MSI_OnEnd); 970 invoke_callback(session, call->call_idx, MSI_OnEnd);
1268 pthread_mutex_lock(&session->mutex);
1269
1270 send_reponse(session, call, ending, msg->friend_id); 971 send_reponse(session, call, ending, msg->friend_id);
1271 terminate_call ( session, call ); 972 terminate_call ( session, call );
1272 973
1273 pthread_mutex_unlock(&session->mutex);
1274
1275
1276 return 1; 974 return 1;
1277} 975}
1278 976
@@ -1286,21 +984,15 @@ static int handle_recv_ringing ( MSISession *session, MSICall *call, MSIMessage
1286 984
1287 (void)msg; 985 (void)msg;
1288 986
1289 pthread_mutex_lock(&session->mutex);
1290
1291 if ( call->ringing_timer_id ) { 987 if ( call->ringing_timer_id ) {
1292 LOGGER_WARNING("Call already ringing"); 988 LOGGER_WARNING("Call already ringing");
1293 pthread_mutex_unlock(&session->mutex);
1294 return 0; 989 return 0;
1295 } 990 }
1296 991
1297 LOGGER_DEBUG("Session: %p Handling 'ringing' on call: %d", session, call->call_idx ); 992 LOGGER_DEBUG("Session: %p Handling 'ringing' on call: %d", session, call->call_idx );
1298 993
1299 call->ringing_timer_id = timer_alloc ( session->timer_handler, handle_timeout, session, call->call_idx, 994 call->ringing_timer_id = timer_alloc
1300 call->ringing_tout_ms ); 995 ( session, handle_timeout, call->call_idx, call->ringing_tout_ms );
1301
1302 pthread_mutex_unlock(&session->mutex);
1303
1304 invoke_callback(session, call->call_idx, MSI_OnRinging); 996 invoke_callback(session, call->call_idx, MSI_OnRinging);
1305 return 1; 997 return 1;
1306} 998}
@@ -1311,14 +1003,11 @@ static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage
1311 return 0; 1003 return 0;
1312 } 1004 }
1313 1005
1314 pthread_mutex_lock(&session->mutex);
1315
1316 if ( call->state == call_active ) { /* Change media */ 1006 if ( call->state == call_active ) { /* Change media */
1317 1007
1318 LOGGER_DEBUG("Session: %p Changing media on call: %d", session, call->call_idx ); 1008 LOGGER_DEBUG("Session: %p Changing media on call: %d", session, call->call_idx );
1319 pthread_mutex_unlock(&session->mutex);
1320 1009
1321 invoke_callback(session, call->call_idx, MSI_OnMediaChange); 1010 invoke_callback(session, call->call_idx, MSI_OnSelfCSChange);
1322 1011
1323 } else if ( call->state == call_inviting ) { 1012 } else if ( call->state == call_inviting ) {
1324 LOGGER_DEBUG("Session: %p Handling 'starting' on call: %d", session, call->call_idx ); 1013 LOGGER_DEBUG("Session: %p Handling 'starting' on call: %d", session, call->call_idx );
@@ -1333,15 +1022,11 @@ static int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage
1333 flush_peer_csettings ( call, msg, 0 ); 1022 flush_peer_csettings ( call, msg, 0 );
1334 1023
1335 /* This is here in case of glare */ 1024 /* This is here in case of glare */
1336 timer_release ( session->timer_handler, call->ringing_timer_id, 1 ); 1025 timer_release(session->timer_handler, call->ringing_timer_id);
1337 1026 invoke_callback(session, call->call_idx, MSI_OnStart);
1338 pthread_mutex_unlock(&session->mutex);
1339
1340 invoke_callback(session, call->call_idx, MSI_OnStarting);
1341 } else { 1027 } else {
1342 LOGGER_ERROR("Invalid call state"); 1028 LOGGER_ERROR("Invalid call state");
1343 terminate_call(session, call ); 1029 terminate_call(session, call );
1344 pthread_mutex_unlock(&session->mutex);
1345 return 0; 1030 return 0;
1346 } 1031 }
1347 1032
@@ -1358,12 +1043,8 @@ static int handle_recv_ending ( MSISession *session, MSICall *call, MSIMessage *
1358 1043
1359 LOGGER_DEBUG("Session: %p Handling 'ending' on call: %d", session, call->call_idx ); 1044 LOGGER_DEBUG("Session: %p Handling 'ending' on call: %d", session, call->call_idx );
1360 1045
1361 invoke_callback(session, call->call_idx, MSI_OnEnding); 1046 invoke_callback(session, call->call_idx, MSI_OnEnd);
1362
1363 /* Terminate call */
1364 pthread_mutex_lock(&session->mutex);
1365 terminate_call ( session, call ); 1047 terminate_call ( session, call );
1366 pthread_mutex_unlock(&session->mutex);
1367 1048
1368 return 1; 1049 return 1;
1369} 1050}
@@ -1372,15 +1053,12 @@ static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *m
1372 1053
1373 if ( !call ) { 1054 if ( !call ) {
1374 LOGGER_WARNING("Handling 'error' on non-existing call!"); 1055 LOGGER_WARNING("Handling 'error' on non-existing call!");
1375 pthread_mutex_unlock(&session->mutex);
1376 return -1; 1056 return -1;
1377 } 1057 }
1378 1058
1379 LOGGER_DEBUG("Session: %p Handling 'error' on call: %d", session, call->call_idx ); 1059 LOGGER_DEBUG("Session: %p Handling 'error' on call: %d", session, call->call_idx );
1380 1060
1381 invoke_callback(session, call->call_idx, MSI_OnEnding); 1061 invoke_callback(session, call->call_idx, MSI_OnEnd);
1382
1383 pthread_mutex_lock(&session->mutex);
1384 1062
1385 /* Handle error accordingly */ 1063 /* Handle error accordingly */
1386 if ( msg->reason.exists ) { 1064 if ( msg->reason.exists ) {
@@ -1389,14 +1067,11 @@ static int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *m
1389 1067
1390 terminate_call ( session, call ); 1068 terminate_call ( session, call );
1391 1069
1392 pthread_mutex_unlock(&session->mutex);
1393
1394 return 1; 1070 return 1;
1395} 1071}
1396 1072
1397
1398/** 1073/**
1399 * @brief BASIC call flow: 1074 * BASIC call flow:
1400 * 1075 *
1401 * ALICE BOB 1076 * ALICE BOB
1402 * | invite --> | 1077 * | invite --> |
@@ -1452,7 +1127,8 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t
1452 1127
1453 msg->friend_id = source; 1128 msg->friend_id = source;
1454 1129
1455 1130 pthread_mutex_lock(&session->mutex);
1131
1456 /* Find what call */ 1132 /* Find what call */
1457 MSICall *call = msg->callid.exists ? find_call(session, msg->callid.value ) : NULL; 1133 MSICall *call = msg->callid.exists ? find_call(session, msg->callid.value ) : NULL;
1458 1134
@@ -1485,7 +1161,7 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t
1485 } else if ( msg->response.exists ) { /* Handle response */ 1161 } else if ( msg->response.exists ) { /* Handle response */
1486 1162
1487 /* Got response so cancel timer */ 1163 /* Got response so cancel timer */
1488 if ( call ) timer_release ( session->timer_handler, call->request_timer_id, 1 ); 1164 if ( call ) timer_release(session->timer_handler, call->request_timer_id);
1489 1165
1490 switch (msg->response.value) { 1166 switch (msg->response.value) {
1491 case ringing: 1167 case ringing:
@@ -1510,16 +1186,13 @@ static void msi_handle_packet ( Messenger *messenger, int source, const uint8_t
1510 } 1186 }
1511 1187
1512 free ( msg ); 1188 free ( msg );
1189
1190 pthread_mutex_unlock(&session->mutex);
1513} 1191}
1514 1192
1515 1193
1516/** 1194
1517 * @brief Callback setter. 1195/********** User functions **********/
1518 *
1519 * @param callback The callback.
1520 * @param id The id.
1521 * @return void
1522 */
1523void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata ) 1196void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata )
1524{ 1197{
1525 session->callbacks[id].function = callback; 1198 session->callbacks[id].function = callback;
@@ -1527,25 +1200,14 @@ void msi_register_callback ( MSISession *session, MSICallbackType callback, MSIC
1527} 1200}
1528 1201
1529 1202
1530/** 1203MSISession *msi_new ( Messenger *messenger, int32_t max_calls )
1531 * @brief Start the control session.
1532 *
1533 * @param messenger Tox* object.
1534 * @param max_calls Amount of calls possible
1535 * @return MSISession* The created session.
1536 * @retval NULL Error occurred.
1537 */
1538MSISession *msi_init_session ( Messenger *messenger, int32_t max_calls )
1539{ 1204{
1540 if (messenger == NULL) { 1205 if (messenger == NULL) {
1541 LOGGER_ERROR("Could not init session on empty messenger!"); 1206 LOGGER_ERROR("Could not init session on empty messenger!");
1542 return NULL; 1207 return NULL;
1543 } 1208 }
1544 1209 if ( !max_calls ) {
1545 TimerHandler *handler = timer_init_session(max_calls * 10, 10000); 1210 LOGGER_WARNING("Invalid max call treshold!");
1546
1547 if ( !max_calls || !handler ) {
1548 LOGGER_WARNING("Invalid max call treshold or timer handler initialization failed!");
1549 return NULL; 1211 return NULL;
1550 } 1212 }
1551 1213
@@ -1553,46 +1215,62 @@ MSISession *msi_init_session ( Messenger *messenger, int32_t max_calls )
1553 1215
1554 if (retu == NULL) { 1216 if (retu == NULL) {
1555 LOGGER_ERROR("Allocation failed! Program might misbehave!"); 1217 LOGGER_ERROR("Allocation failed! Program might misbehave!");
1556 timer_terminate_session(handler);
1557 return NULL; 1218 return NULL;
1558 } 1219 }
1559 1220
1560 retu->messenger_handle = messenger;
1561 retu->agent_handler = NULL;
1562 retu->timer_handler = handler;
1563
1564 if (!(retu->calls = calloc( sizeof (MSICall *), max_calls ))) { 1221 if (!(retu->calls = calloc( sizeof (MSICall *), max_calls ))) {
1565 LOGGER_ERROR("Allocation failed! Program might misbehave!"); 1222 LOGGER_ERROR("Allocation failed! Program might misbehave!");
1566 timer_terminate_session(handler); 1223 goto error;
1567 free(retu); 1224 }
1568 return NULL; 1225
1226 pthread_mutexattr_t attr;
1227
1228 if (pthread_mutexattr_init(&attr) != 0 ||
1229 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0 ||
1230 pthread_mutex_init(&retu->mutex, &attr) != 0 ) {
1231 LOGGER_ERROR("Failed to init mutex! Program might misbehave!");
1232
1233 goto error;
1234 }
1235
1236
1237 retu->timer_handler = calloc(1, sizeof(TimerHandler));
1238
1239 if (retu->timer_handler == NULL) {
1240 LOGGER_ERROR("Allocation failed! Program might misbehave!");
1241 goto error;
1569 } 1242 }
1570 1243
1244 /* Allocate space for timers */
1245 ((TimerHandler *)retu->timer_handler)->max_capacity = max_calls * 10;
1246 if (!(((TimerHandler *)retu->timer_handler)->timers = calloc(max_calls * 10, sizeof(Timer *)))) {
1247 LOGGER_ERROR("Allocation failed! Program might misbehave!");
1248 goto error;
1249 }
1250
1251 retu->messenger_handle = messenger;
1252 retu->agent_handler = NULL;
1571 retu->max_calls = max_calls; 1253 retu->max_calls = max_calls;
1572
1573 retu->frequ = 10000; /* default value? */ 1254 retu->frequ = 10000; /* default value? */
1574 retu->call_timeout = 30000; /* default value? */ 1255 retu->call_timeout = 30000; /* default value? */
1575 1256
1576
1577 m_callback_msi_packet(messenger, msi_handle_packet, retu ); 1257 m_callback_msi_packet(messenger, msi_handle_packet, retu );
1578 1258
1579 /* This is called when remote terminates session */ 1259 /* This is called when remote terminates session */
1580 m_callback_connectionstatus_internal_av(messenger, handle_remote_connection_change, retu); 1260 m_callback_connectionstatus_internal_av(messenger, handle_remote_connection_change, retu);
1581 1261
1582 pthread_mutex_init(&retu->mutex, NULL);
1583
1584 LOGGER_DEBUG("New msi session: %p max calls: %u", retu, max_calls); 1262 LOGGER_DEBUG("New msi session: %p max calls: %u", retu, max_calls);
1585 return retu; 1263 return retu;
1264
1265error:
1266 free(retu->timer_handler);
1267 free(retu->calls);
1268 free(retu);
1269 return NULL;
1586} 1270}
1587 1271
1588 1272
1589/** 1273int msi_kill ( MSISession *session )
1590 * @brief Terminate control session.
1591 *
1592 * @param session The session
1593 * @return int
1594 */
1595int msi_terminate_session ( MSISession *session )
1596{ 1274{
1597 if (session == NULL) { 1275 if (session == NULL) {
1598 LOGGER_ERROR("Tried to terminate non-existing session"); 1276 LOGGER_ERROR("Tried to terminate non-existing session");
@@ -1617,8 +1295,6 @@ int msi_terminate_session ( MSISession *session )
1617 msi_cancel ( session, idx, session->calls[idx]->peers [_it], "MSI session terminated!" ); 1295 msi_cancel ( session, idx, session->calls[idx]->peers [_it], "MSI session terminated!" );
1618 } 1296 }
1619 1297
1620 timer_terminate_session(session->timer_handler);
1621
1622 pthread_mutex_destroy(&session->mutex); 1298 pthread_mutex_destroy(&session->mutex);
1623 1299
1624 LOGGER_DEBUG("Terminated session: %p", session); 1300 LOGGER_DEBUG("Terminated session: %p", session);
@@ -1627,17 +1303,11 @@ int msi_terminate_session ( MSISession *session )
1627 return _status; 1303 return _status;
1628} 1304}
1629 1305
1630 1306int msi_invite ( MSISession* session,
1631/** 1307 int32_t* call_index,
1632 * @brief Send invite request to friend_id. 1308 const MSICSettings* csettings,
1633 * 1309 uint32_t rngsec,
1634 * @param session Control session. 1310 uint32_t friend_id )
1635 * @param call_type Type of the call. Audio or Video(both audio and video)
1636 * @param rngsec Ringing timeout.
1637 * @param friend_id The friend.
1638 * @return int
1639 */
1640int msi_invite ( MSISession *session, int32_t *call_index, MSICSettings csettings, uint32_t rngsec, uint32_t friend_id )
1641{ 1311{
1642 pthread_mutex_lock(&session->mutex); 1312 pthread_mutex_lock(&session->mutex);
1643 1313
@@ -1668,17 +1338,17 @@ int msi_invite ( MSISession *session, int32_t *call_index, MSICSettings csetting
1668 1338
1669 add_peer ( call, friend_id ); 1339 add_peer ( call, friend_id );
1670 1340
1671 call->csettings_local = csettings; 1341 call->csettings_local = *csettings;
1672 1342
1673 MSIMessage *msg_invite = msi_new_message ( TypeRequest, invite ); 1343 MSIMessage *msg_invite = msi_new_message ( TypeRequest, invite );
1674 1344
1675 msi_msg_set_csettings(msg_invite, &csettings); 1345 msi_msg_set_csettings(msg_invite, csettings);
1676 send_message ( session, call, msg_invite, friend_id ); 1346 send_message ( session, call, msg_invite, friend_id );
1677 free( msg_invite ); 1347 free( msg_invite );
1678 1348
1679 call->state = call_inviting; 1349 call->state = call_inviting;
1680 1350
1681 call->request_timer_id = timer_alloc ( session->timer_handler, handle_timeout, session, call->call_idx, m_deftout ); 1351 call->request_timer_id = timer_alloc ( session, handle_timeout, call->call_idx, m_deftout );
1682 1352
1683 LOGGER_DEBUG("Invite sent"); 1353 LOGGER_DEBUG("Invite sent");
1684 1354
@@ -1687,16 +1357,6 @@ int msi_invite ( MSISession *session, int32_t *call_index, MSICSettings csetting
1687 return 0; 1357 return 0;
1688} 1358}
1689 1359
1690
1691/**
1692 * @brief Hangup active call.
1693 *
1694 * @param session Control session.
1695 * @param call_id To which call is this action handled.
1696 * @return int
1697 * @retval -1 Error occurred.
1698 * @retval 0 Success.
1699 */
1700int msi_hangup ( MSISession *session, int32_t call_index ) 1360int msi_hangup ( MSISession *session, int32_t call_index )
1701{ 1361{
1702 pthread_mutex_lock(&session->mutex); 1362 pthread_mutex_lock(&session->mutex);
@@ -1727,22 +1387,13 @@ int msi_hangup ( MSISession *session, int32_t call_index )
1727 free ( msg_end ); 1387 free ( msg_end );
1728 1388
1729 session->calls[call_index]->request_timer_id = 1389 session->calls[call_index]->request_timer_id =
1730 timer_alloc ( session->timer_handler, handle_timeout, session, call_index, m_deftout ); 1390 timer_alloc ( session, handle_timeout, call_index, m_deftout );
1731 1391
1732 pthread_mutex_unlock(&session->mutex); 1392 pthread_mutex_unlock(&session->mutex);
1733 return 0; 1393 return 0;
1734} 1394}
1735 1395
1736 1396int msi_answer ( MSISession* session, int32_t call_index, const MSICSettings* csettings )
1737/**
1738 * @brief Answer active call request.
1739 *
1740 * @param session Control session.
1741 * @param call_id To which call is this action handled.
1742 * @param call_type Answer with Audio or Video(both).
1743 * @return int
1744 */
1745int msi_answer ( MSISession *session, int32_t call_index, MSICSettings csettings )
1746{ 1397{
1747 pthread_mutex_lock(&session->mutex); 1398 pthread_mutex_lock(&session->mutex);
1748 LOGGER_DEBUG("Session: %p Answering call: %u", session, call_index); 1399 LOGGER_DEBUG("Session: %p Answering call: %u", session, call_index);
@@ -1755,9 +1406,9 @@ int msi_answer ( MSISession *session, int32_t call_index, MSICSettings csettings
1755 1406
1756 MSIMessage *msg_starting = msi_new_message ( TypeResponse, starting ); 1407 MSIMessage *msg_starting = msi_new_message ( TypeResponse, starting );
1757 1408
1758 session->calls[call_index]->csettings_local = csettings; 1409 session->calls[call_index]->csettings_local = *csettings;
1759 1410
1760 msi_msg_set_csettings(msg_starting, &csettings); 1411 msi_msg_set_csettings(msg_starting, csettings);
1761 1412
1762 send_message ( session, session->calls[call_index], msg_starting, session->calls[call_index]->peers[0] ); 1413 send_message ( session, session->calls[call_index], msg_starting, session->calls[call_index]->peers[0] );
1763 free ( msg_starting ); 1414 free ( msg_starting );
@@ -1768,15 +1419,6 @@ int msi_answer ( MSISession *session, int32_t call_index, MSICSettings csettings
1768 return 0; 1419 return 0;
1769} 1420}
1770 1421
1771
1772/**
1773 * @brief Cancel request.
1774 *
1775 * @param session Control session.
1776 * @param call_id To which call is this action handled.
1777 * @param reason Set optional reason header. Pass NULL if none.
1778 * @return int
1779 */
1780int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason ) 1422int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason )
1781{ 1423{
1782 pthread_mutex_lock(&session->mutex); 1424 pthread_mutex_lock(&session->mutex);
@@ -1814,14 +1456,6 @@ int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const c
1814 return 0; 1456 return 0;
1815} 1457}
1816 1458
1817
1818/**
1819 * @brief Reject request.
1820 *
1821 * @param session Control session.
1822 * @param call_id To which call is this action handled.
1823 * @return int
1824 */
1825int msi_reject ( MSISession *session, int32_t call_index, const char *reason ) 1459int msi_reject ( MSISession *session, int32_t call_index, const char *reason )
1826{ 1460{
1827 pthread_mutex_lock(&session->mutex); 1461 pthread_mutex_lock(&session->mutex);
@@ -1856,24 +1490,31 @@ int msi_reject ( MSISession *session, int32_t call_index, const char *reason )
1856 1490
1857 session->calls[call_index]->state = call_hanged_up; 1491 session->calls[call_index]->state = call_hanged_up;
1858 session->calls[call_index]->request_timer_id = 1492 session->calls[call_index]->request_timer_id =
1859 timer_alloc ( session->timer_handler, handle_timeout, session, call_index, m_deftout ); 1493 timer_alloc ( session, handle_timeout, call_index, m_deftout );
1860 1494
1861 pthread_mutex_unlock(&session->mutex); 1495 pthread_mutex_unlock(&session->mutex);
1862 return 0; 1496 return 0;
1863} 1497}
1864 1498
1499int msi_stopcall ( MSISession *session, int32_t call_index )
1500{
1501 pthread_mutex_lock(&session->mutex);
1502 LOGGER_DEBUG("Session: %p Stopping call index: %u", session, call_index);
1503
1504 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1505 pthread_mutex_unlock(&session->mutex);
1506 return -1;
1507 }
1508
1509 /* just terminate it */
1510
1511 terminate_call ( session, session->calls[call_index] );
1512
1513 pthread_mutex_unlock(&session->mutex);
1514 return 0;
1515}
1865 1516
1866/** 1517int msi_change_csettings(MSISession *session, int32_t call_index, const MSICSettings* csettings)
1867 * @brief Send invite request to friend_id.
1868 *
1869 * @param session Control session.
1870 * @param call_index Call index.
1871 * @param call_type Type of the call. Audio or Video(both audio and video)
1872 * @param rngsec Ringing timeout.
1873 * @param friend_id The friend.
1874 * @return int
1875 */
1876int msi_change_csettings(MSISession *session, int32_t call_index, MSICSettings csettings)
1877{ 1518{
1878 pthread_mutex_lock(&session->mutex); 1519 pthread_mutex_lock(&session->mutex);
1879 1520
@@ -1896,20 +1537,20 @@ int msi_change_csettings(MSISession *session, int32_t call_index, MSICSettings c
1896 MSICSettings *local = &call->csettings_local; 1537 MSICSettings *local = &call->csettings_local;
1897 1538
1898 if ( 1539 if (
1899 local->call_type == csettings.call_type && 1540 local->call_type == csettings->call_type &&
1900 local->video_bitrate == csettings.video_bitrate && 1541 local->video_bitrate == csettings->video_bitrate &&
1901 local->max_video_width == csettings.max_video_width && 1542 local->max_video_width == csettings->max_video_width &&
1902 local->max_video_height == csettings.max_video_height && 1543 local->max_video_height == csettings->max_video_height &&
1903 local->audio_bitrate == csettings.audio_bitrate && 1544 local->audio_bitrate == csettings->audio_bitrate &&
1904 local->audio_frame_duration == csettings.audio_frame_duration && 1545 local->audio_frame_duration == csettings->audio_frame_duration &&
1905 local->audio_sample_rate == csettings.audio_sample_rate && 1546 local->audio_sample_rate == csettings->audio_sample_rate &&
1906 local->audio_channels == csettings.audio_channels ) { 1547 local->audio_channels == csettings->audio_channels ) {
1907 LOGGER_ERROR("Call is already set accordingly!"); 1548 LOGGER_ERROR("Call is already set accordingly!");
1908 pthread_mutex_unlock(&session->mutex); 1549 pthread_mutex_unlock(&session->mutex);
1909 return -1; 1550 return -1;
1910 } 1551 }
1911 1552
1912 *local = csettings; 1553 *local = *csettings;
1913 1554
1914 MSIMessage *msg_invite = msi_new_message ( TypeRequest, invite ); 1555 MSIMessage *msg_invite = msi_new_message ( TypeRequest, invite );
1915 1556
@@ -1924,28 +1565,24 @@ int msi_change_csettings(MSISession *session, int32_t call_index, MSICSettings c
1924 return 0; 1565 return 0;
1925} 1566}
1926 1567
1927 1568void msi_do(MSISession* session)
1928/** 1569{
1929 * @brief Terminate the current call.
1930 *
1931 * @param session Control session.
1932 * @param call_id To which call is this action handled.
1933 * @return int
1934 */
1935int msi_stopcall ( MSISession *session, int32_t call_index )
1936{
1937 pthread_mutex_lock(&session->mutex); 1570 pthread_mutex_lock(&session->mutex);
1938 LOGGER_DEBUG("Session: %p Stopping call index: %u", session, call_index); 1571
1939 1572 TimerHandler *timer = session->timer_handler;
1940 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) { 1573
1941 pthread_mutex_unlock(&session->mutex); 1574 uint64_t time = current_time_monotonic();
1942 return -1; 1575
1576 while ( timer->timers[0] && timer->timers[0]->timeout < time ) {
1577 LOGGER_DEBUG("Executing timer assigned at: %d", timer->timers[0]->timeout);
1578
1579 int id = timer->timers[0]->id;
1580 timer->timers[0]->func(timer->timers[0]);
1581
1582 /* In case function has released timer */
1583 if (timer->timers[0] && timer->timers[0]->id == id)
1584 timer_release(timer, id);
1943 } 1585 }
1944 1586
1945 /* just terminate it */
1946
1947 terminate_call ( session, session->calls[call_index] );
1948
1949 pthread_mutex_unlock(&session->mutex); 1587 pthread_mutex_unlock(&session->mutex);
1950 return 0;
1951} 1588}
diff --git a/toxav/msi.h b/toxav/msi.h
index 64fa0881..1ece8817 100644
--- a/toxav/msi.h
+++ b/toxav/msi.h
@@ -31,9 +31,8 @@ typedef uint8_t MSICallIDType[12];
31typedef uint8_t MSIReasonStrType[255]; 31typedef uint8_t MSIReasonStrType[255];
32typedef void ( *MSICallbackType ) ( void *agent, int32_t call_idx, void *arg ); 32typedef void ( *MSICallbackType ) ( void *agent, int32_t call_idx, void *arg );
33 33
34
35/** 34/**
36 * @brief Call type identifier. Also used as rtp callback prefix. 35 * Call type identifier. Also used as rtp callback prefix.
37 */ 36 */
38typedef enum { 37typedef enum {
39 type_audio = 192, 38 type_audio = 192,
@@ -42,7 +41,7 @@ typedef enum {
42 41
43 42
44/** 43/**
45 * @brief Call state identifiers. 44 * Call state identifiers.
46 */ 45 */
47typedef enum { 46typedef enum {
48 call_inviting, /* when sending call invite */ 47 call_inviting, /* when sending call invite */
@@ -55,7 +54,7 @@ typedef enum {
55 54
56 55
57/** 56/**
58 * @brief Encoding settings. 57 * Encoding settings.
59 */ 58 */
60typedef struct _MSICodecSettings { 59typedef struct _MSICodecSettings {
61 MSICallType call_type; 60 MSICallType call_type;
@@ -72,29 +71,24 @@ typedef struct _MSICodecSettings {
72 71
73 72
74/** 73/**
75 * @brief Callbacks ids that handle the states 74 * Callbacks ids that handle the states
76 */ 75 */
77typedef enum { 76typedef enum {
78 /* Requests */ 77 MSI_OnInvite, /* Incoming call */
79 MSI_OnInvite, 78 MSI_OnRinging, /* When peer is ready to accept/reject the call */
80 MSI_OnStart, 79 MSI_OnStart, /* Call (RTP transmission) started */
81 MSI_OnCancel, 80 MSI_OnCancel, /* The side that initiated call canceled invite */
82 MSI_OnReject, 81 MSI_OnReject, /* The side that was invited rejected the call */
83 MSI_OnEnd, 82 MSI_OnEnd, /* Call that was active ended */
84 83 MSI_OnRequestTimeout, /* When the requested action didn't get response in specified time */
85 /* Responses */ 84 MSI_OnPeerTimeout, /* Peer timed out; stop the call */
86 MSI_OnRinging, 85 MSI_OnPeerCSChange, /* Peer requested Csettings change */
87 MSI_OnStarting, 86 MSI_OnSelfCSChange /* Csettings change confirmation */
88 MSI_OnEnding,
89
90 /* Protocol */
91 MSI_OnRequestTimeout,
92 MSI_OnPeerTimeout,
93 MSI_OnMediaChange
94} MSICallbackID; 87} MSICallbackID;
95 88
89
96/** 90/**
97 * @brief Callbacks container 91 * Callbacks container
98 */ 92 */
99typedef struct _MSICallbackCont { 93typedef struct _MSICallbackCont {
100 MSICallbackType function; 94 MSICallbackType function;
@@ -102,16 +96,15 @@ typedef struct _MSICallbackCont {
102} MSICallbackCont; 96} MSICallbackCont;
103 97
104/** 98/**
105 * @brief The call struct. 99 * The call struct.
106 *
107 */ 100 */
108typedef struct _MSICall { /* Call info structure */ 101typedef struct _MSICall { /* Call info structure */
109 struct _MSISession *session; /* Session pointer */ 102 struct _MSISession *session; /* Session pointer */
110 103
111 MSICallState state; 104 MSICallState state;
112 105
113 MSICSettings csettings_local; /* Local call settings */ 106 MSICSettings csettings_local; /* Local call settings */
114 MSICSettings *csettings_peer; /* Peers call settings */ 107 MSICSettings *csettings_peer; /* Peers call settings */
115 108
116 MSICallIDType id; /* Random value identifying the call */ 109 MSICallIDType id; /* Random value identifying the call */
117 110
@@ -120,8 +113,6 @@ typedef struct _MSICall { /* Call info structure */
120 int request_timer_id; /* Timer id for outgoing request/action */ 113 int request_timer_id; /* Timer id for outgoing request/action */
121 int ringing_timer_id; /* Timer id for ringing timeout */ 114 int ringing_timer_id; /* Timer id for ringing timeout */
122 115
123
124 pthread_mutex_t mutex; /* */
125 uint32_t *peers; 116 uint32_t *peers;
126 uint16_t peer_count; 117 uint16_t peer_count;
127 118
@@ -130,8 +121,7 @@ typedef struct _MSICall { /* Call info structure */
130 121
131 122
132/** 123/**
133 * @brief Control session struct 124 * Control session struct
134 *
135 */ 125 */
136typedef struct _MSISession { 126typedef struct _MSISession {
137 127
@@ -143,125 +133,71 @@ typedef struct _MSISession {
143 Messenger *messenger_handle; 133 Messenger *messenger_handle;
144 134
145 uint32_t frequ; 135 uint32_t frequ;
146 uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */ 136 uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */
147 137
148 pthread_mutex_t mutex; 138 pthread_mutex_t mutex;
149 139
150 void *timer_handler; 140 void *timer_handler;
151 MSICallbackCont callbacks[11]; /* Callbacks used by this session */ 141 MSICallbackCont callbacks[10]; /* Callbacks used by this session */
152} MSISession; 142} MSISession;
153 143
154/** 144/**
155 * @brief Callback setter. 145 * Start the control session.
156 *
157 * @param session The container.
158 * @param callback The callback.
159 * @param id The id.
160 * @return void
161 */ 146 */
162void msi_register_callback(MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata); 147MSISession *msi_new ( Messenger *messenger, int32_t max_calls );
163
164 148
165/** 149/**
166 * @brief Start the control session. 150 * Terminate control session.
167 *
168 * @param messenger Tox* object.
169 * @param max_calls Amount of calls possible
170 * @return MSISession* The created session.
171 * @retval NULL Error occurred.
172 */ 151 */
173MSISession *msi_init_session ( Messenger *messenger, int32_t max_calls ); 152int msi_kill ( MSISession *session );
174
175 153
176/** 154/**
177 * @brief Terminate control session. 155 * Callback setter.
178 *
179 * @param session The session
180 * @return int
181 */ 156 */
182int msi_terminate_session ( MSISession *session ); 157void msi_register_callback(MSISession *session, MSICallbackType callback, MSICallbackID id, void *userdata);
183
184 158
185/** 159/**
186 * @brief Send invite request to friend_id. 160 * Send invite request to friend_id.
187 *
188 * @param session Control session.
189 * @param call_index Set to new call index.
190 * @param call_type Type of the call. Audio or Video(both audio and video)
191 * @param rngsec Ringing timeout.
192 * @param friend_id The friend.
193 * @return int
194 */ 161 */
195int msi_invite ( MSISession *session, int32_t *call_index, MSICSettings csettings, uint32_t rngsec, 162int msi_invite ( MSISession *session,
163 int32_t *call_index,
164 const MSICSettings* csettings,
165 uint32_t rngsec,
196 uint32_t friend_id ); 166 uint32_t friend_id );
197 167
198
199/** 168/**
200 * @brief Hangup active call. 169 * Hangup active call.
201 *
202 * @param session Control session.
203 * @param call_index To which call is this action handled.
204 * @return int
205 * @retval -1 Error occurred.
206 * @retval 0 Success.
207 */ 170 */
208int msi_hangup ( MSISession *session, int32_t call_index ); 171int msi_hangup ( MSISession *session, int32_t call_index );
209 172
210
211/** 173/**
212 * @brief Answer active call request. 174 * Answer active call request.
213 *
214 * @param session Control session.
215 * @param call_index To which call is this action handled.
216 * @param call_type Answer with Audio or Video(both).
217 * @return int
218 */ 175 */
219int msi_answer ( MSISession *session, int32_t call_index, MSICSettings csettings ); 176int msi_answer ( MSISession *session, int32_t call_index, const MSICSettings* csettings );
220
221 177
222/** 178/**
223 * @brief Cancel request. 179 * Cancel request.
224 *
225 * @param session Control session.
226 * @param call_index To which call is this action handled.
227 * @param peer To which peer.
228 * @param reason Set optional reason header. Pass NULL if none.
229 * @return int
230 */ 180 */
231int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason ); 181int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason );
232 182
233
234/** 183/**
235 * @brief Reject request. 184 * Reject incoming call.
236 *
237 * @param session Control session.
238 * @param call_index To which call is this action handled.
239 * @param reason Set optional reason header. Pass NULL if none.
240 * @return int
241 */ 185 */
242int msi_reject ( MSISession *session, int32_t call_index, const char *reason ); 186int msi_reject ( MSISession *session, int32_t call_index, const char *reason );
243 187
188/**
189 * Terminate the call.
190 */
191int msi_stopcall ( MSISession *session, int32_t call_index );
244 192
245/** 193/**
246 * @brief Send invite request to friend_id. 194 * Change codec settings of the current call.
247 *
248 * @param session Control session.
249 * @param call_index Call index.
250 * @param call_type Type of the call. Audio or Video(both audio and video)
251 * @param rngsec Ringing timeout.
252 * @param friend_id The friend.
253 * @return int
254 */ 195 */
255int msi_change_csettings ( MSISession *session, int32_t call_index, MSICSettings csettings ); 196int msi_change_csettings ( MSISession* session, int32_t call_index, const MSICSettings* csettings );
256
257 197
258/** 198/**
259 * @brief Terminate the current call. 199 * Main msi loop
260 *
261 * @param session Control session.
262 * @param call_index To which call is this action handled.
263 * @return int
264 */ 200 */
265int msi_stopcall ( MSISession *session, int32_t call_index ); 201void msi_do( MSISession* session );
266 202
267#endif /* __TOXMSI */ 203#endif /* __TOXMSI */
diff --git a/toxav/rtp.c b/toxav/rtp.c
index a4e1b12e..07547282 100644
--- a/toxav/rtp.c
+++ b/toxav/rtp.c
@@ -28,7 +28,7 @@
28 28
29#include "rtp.h" 29#include "rtp.h"
30#include <stdlib.h> 30#include <stdlib.h>
31void toxav_handle_packet(RTPSession *_session, RTPMessage *_msg); 31void queue_message(RTPSession *_session, RTPMessage *_msg);
32 32
33#define size_32 4 33#define size_32 4
34 34
@@ -47,15 +47,9 @@ void toxav_handle_packet(RTPSession *_session, RTPMessage *_msg);
47#define GET_SETTING_PAYLOAD(_h) ((_h->marker_payloadt) & 0x7f) 47#define GET_SETTING_PAYLOAD(_h) ((_h->marker_payloadt) & 0x7f)
48 48
49/** 49/**
50 * @brief Checks if message came in late. 50 * Checks if message came in late.
51 *
52 * @param session Control session.
53 * @param msg The message.
54 * @return int
55 * @retval -1 The message came in order.
56 * @retval 0 The message came late.
57 */ 51 */
58inline__ int check_late_message (RTPSession *session, RTPMessage *msg) 52static int check_late_message (RTPSession *session, RTPMessage *msg)
59{ 53{
60 /* 54 /*
61 * Check Sequence number. If this new msg has lesser number then the session->rsequnum 55 * Check Sequence number. If this new msg has lesser number then the session->rsequnum
@@ -67,12 +61,7 @@ inline__ int check_late_message (RTPSession *session, RTPMessage *msg)
67 61
68 62
69/** 63/**
70 * @brief Extracts header from payload. 64 * Extracts header from payload.
71 *
72 * @param payload The payload.
73 * @param length The size of payload.
74 * @return RTPHeader* Extracted header.
75 * @retval NULL Error occurred while extracting header.
76 */ 65 */
77RTPHeader *extract_header ( const uint8_t *payload, int length ) 66RTPHeader *extract_header ( const uint8_t *payload, int length )
78{ 67{
@@ -147,12 +136,7 @@ RTPHeader *extract_header ( const uint8_t *payload, int length )
147} 136}
148 137
149/** 138/**
150 * @brief Extracts external header from payload. Must be called AFTER extract_header()! 139 * Extracts external header from payload. Must be called AFTER extract_header()!
151 *
152 * @param payload The ITERATED payload.
153 * @param length The size of payload.
154 * @return RTPExtHeader* Extracted extension header.
155 * @retval NULL Error occurred while extracting extension header.
156 */ 140 */
157RTPExtHeader *extract_ext_header ( const uint8_t *payload, uint16_t length ) 141RTPExtHeader *extract_ext_header ( const uint8_t *payload, uint16_t length )
158{ 142{
@@ -200,11 +184,7 @@ RTPExtHeader *extract_ext_header ( const uint8_t *payload, uint16_t length )
200} 184}
201 185
202/** 186/**
203 * @brief Adds header to payload. Make sure _payload_ has enough space. 187 * Adds header to payload. Make sure _payload_ has enough space.
204 *
205 * @param header The header.
206 * @param payload The payload.
207 * @return uint8_t* Iterated position.
208 */ 188 */
209uint8_t *add_header ( RTPHeader *header, uint8_t *payload ) 189uint8_t *add_header ( RTPHeader *header, uint8_t *payload )
210{ 190{
@@ -245,11 +225,7 @@ uint8_t *add_header ( RTPHeader *header, uint8_t *payload )
245} 225}
246 226
247/** 227/**
248 * @brief Adds extension header to payload. Make sure _payload_ has enough space. 228 * Adds extension header to payload. Make sure _payload_ has enough space.
249 *
250 * @param header The header.
251 * @param payload The payload.
252 * @return uint8_t* Iterated position.
253 */ 229 */
254uint8_t *add_ext_header ( RTPExtHeader *header, uint8_t *payload ) 230uint8_t *add_ext_header ( RTPExtHeader *header, uint8_t *payload )
255{ 231{
@@ -279,10 +255,7 @@ uint8_t *add_ext_header ( RTPExtHeader *header, uint8_t *payload )
279} 255}
280 256
281/** 257/**
282 * @brief Builds header from control session values. 258 * Builds header from control session values.
283 *
284 * @param session Control session.
285 * @return RTPHeader* Created header.
286 */ 259 */
287RTPHeader *build_header ( RTPSession *session ) 260RTPHeader *build_header ( RTPSession *session )
288{ 261{
@@ -316,16 +289,8 @@ RTPHeader *build_header ( RTPSession *session )
316 289
317 290
318/** 291/**
319 * @brief Parses data into RTPMessage struct. Stores headers separately from the payload data 292 * Parses data into RTPMessage struct. Stores headers separately from the payload data
320 * and so the length variable is set accordingly. _sequnum_ argument is 293 * and so the length variable is set accordingly.
321 * passed by the handle_packet() since it's parsed already.
322 *
323 * @param session Control session.
324 * @param sequnum Sequence number that's parsed from payload in handle_packet()
325 * @param data Payload data.
326 * @param length Payload size.
327 * @return RTPMessage*
328 * @retval NULL Error occurred.
329 */ 294 */
330RTPMessage *msg_parse ( const uint8_t *data, int length ) 295RTPMessage *msg_parse ( const uint8_t *data, int length )
331{ 296{
@@ -373,15 +338,7 @@ RTPMessage *msg_parse ( const uint8_t *data, int length )
373} 338}
374 339
375/** 340/**
376 * @brief Callback for networking core. 341 * Callback for networking core.
377 *
378 * @param object RTPSession object.
379 * @param ip_port Where the message comes from.
380 * @param data Message data.
381 * @param length Message length.
382 * @return int
383 * @retval -1 Error occurred.
384 * @retval 0 Success.
385 */ 342 */
386int rtp_handle_packet ( void *object, const uint8_t *data, uint32_t length ) 343int rtp_handle_packet ( void *object, const uint8_t *data, uint32_t length )
387{ 344{
@@ -406,22 +363,13 @@ int rtp_handle_packet ( void *object, const uint8_t *data, uint32_t length )
406 _session->timestamp = _msg->header->timestamp; 363 _session->timestamp = _msg->header->timestamp;
407 } 364 }
408 365
409 toxav_handle_packet(_session, _msg); 366 queue_message(_session, _msg);
410 367
411 return 0; 368 return 0;
412} 369}
413 370
414
415
416/** 371/**
417 * @brief Stores headers and payload data in one container ( data ) 372 * Allocate message and store data there
418 * and the length is set accordingly. Returned message is used for sending _only_.
419 *
420 * @param session The control session.
421 * @param data Payload data to send ( This is what you pass ).
422 * @param length Size of the payload data.
423 * @return RTPMessage* Created message.
424 * @retval NULL Error occurred.
425 */ 373 */
426RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t length ) 374RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t length )
427{ 375{
@@ -472,28 +420,15 @@ RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t
472} 420}
473 421
474 422
475/** 423
476 * @brief Sends data to _RTPSession::dest
477 *
478 * @param session The session.
479 * @param messenger Tox* object.
480 * @param data The payload.
481 * @param length Size of the payload.
482 * @return int
483 * @retval -1 On error.
484 * @retval 0 On success.
485 */
486int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *data, uint16_t length ) 424int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *data, uint16_t length )
487{ 425{
488 RTPMessage *msg = rtp_new_message (session, data, length); 426 RTPMessage *msg = rtp_new_message (session, data, length);
489 427
490 if ( !msg ) { 428 if ( !msg ) return -1;
491 LOGGER_WARNING("No session!"); 429
492 return -1;
493 }
494
495 if ( -1 == send_custom_lossy_packet(messenger, session->dest, msg->data, msg->length) ) { 430 if ( -1 == send_custom_lossy_packet(messenger, session->dest, msg->data, msg->length) ) {
496 LOGGER_WARNING("Failed to send full packet! std error: %s", strerror(errno)); 431 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno));
497 rtp_free_msg ( session, msg ); 432 rtp_free_msg ( session, msg );
498 return -1; 433 return -1;
499 } 434 }
@@ -506,15 +441,6 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat
506 return 0; 441 return 0;
507} 442}
508 443
509
510/**
511 * @brief Speaks for it self.
512 *
513 * @param session The control session msg belongs to. You set it as NULL when freeing recved messages.
514 * Otherwise set it to session the message was created from.
515 * @param msg The message.
516 * @return void
517 */
518void rtp_free_msg ( RTPSession *session, RTPMessage *msg ) 444void rtp_free_msg ( RTPSession *session, RTPMessage *msg )
519{ 445{
520 if ( !session ) { 446 if ( !session ) {
@@ -533,17 +459,7 @@ void rtp_free_msg ( RTPSession *session, RTPMessage *msg )
533 free ( msg ); 459 free ( msg );
534} 460}
535 461
536/** 462RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num )
537 * @brief Must be called before calling any other rtp function. It's used
538 * to initialize RTP control session.
539 *
540 * @param payload_type Type of payload used to send. You can use values in toxmsi.h::MSICallType
541 * @param messenger Tox* object.
542 * @param friend_num Friend id.
543 * @return RTPSession* Created control session.
544 * @retval NULL Error occurred.
545 */
546RTPSession *rtp_init_session ( int payload_type, Messenger *messenger, int friend_num )
547{ 463{
548 RTPSession *_retu = calloc(1, sizeof(RTPSession)); 464 RTPSession *_retu = calloc(1, sizeof(RTPSession));
549 465
@@ -593,17 +509,7 @@ RTPSession *rtp_init_session ( int payload_type, Messenger *messenger, int frien
593 return _retu; 509 return _retu;
594} 510}
595 511
596 512void rtp_kill ( RTPSession *session, Messenger *messenger )
597/**
598 * @brief Terminate the session.
599 *
600 * @param session The session.
601 * @param messenger The messenger who owns the session
602 * @return int
603 * @retval -1 Error occurred.
604 * @retval 0 Success.
605 */
606void rtp_terminate_session ( RTPSession *session, Messenger *messenger )
607{ 513{
608 if ( !session ) return; 514 if ( !session ) return;
609 515
diff --git a/toxav/rtp.h b/toxav/rtp.h
index d57c5ef7..0b481eb8 100644
--- a/toxav/rtp.h
+++ b/toxav/rtp.h
@@ -24,19 +24,15 @@
24 24
25#define RTP_VERSION 2 25#define RTP_VERSION 2
26#include <inttypes.h> 26#include <inttypes.h>
27#include <pthread.h> 27// #include <pthread.h>
28 28
29#include "../toxcore/util.h"
30#include "../toxcore/network.h"
31#include "../toxcore/net_crypto.h"
32#include "../toxcore/Messenger.h" 29#include "../toxcore/Messenger.h"
33 30
34#define MAX_SEQU_NUM 65535 31#define MAX_SEQU_NUM 65535
35#define MAX_RTP_SIZE 65535 32#define MAX_RTP_SIZE 65535
36 33
37/** 34/**
38 * @brief Standard rtp header 35 * Standard rtp header
39 *
40 */ 36 */
41 37
42typedef struct _RTPHeader { 38typedef struct _RTPHeader {
@@ -52,8 +48,7 @@ typedef struct _RTPHeader {
52 48
53 49
54/** 50/**
55 * @brief Standard rtp extension header. 51 * Standard rtp extension header.
56 *
57 */ 52 */
58typedef struct _RTPExtHeader { 53typedef struct _RTPExtHeader {
59 uint16_t type; /* Extension profile */ 54 uint16_t type; /* Extension profile */
@@ -64,8 +59,7 @@ typedef struct _RTPExtHeader {
64 59
65 60
66/** 61/**
67 * @brief Standard rtp message. 62 * Standard rtp message.
68 *
69 */ 63 */
70typedef struct _RTPMessage { 64typedef struct _RTPMessage {
71 RTPHeader *header; 65 RTPHeader *header;
@@ -79,11 +73,11 @@ typedef struct _RTPMessage {
79 73
80 74
81/** 75/**
82 * @brief Our main session descriptor. 76 * Our main session descriptor.
83 * It measures the session variables and controls 77 * It measures the session variables and controls
84 * the entire session. There are functions for manipulating 78 * the entire session. There are functions for manipulating
85 * the session so tend to use those instead of directly modifying 79 * the session so tend to use those instead of directly modifying
86 * session parameters. 80 * session parameters.
87 * 81 *
88 */ 82 */
89typedef struct _RTPSession { 83typedef struct _RTPSession {
@@ -109,88 +103,31 @@ typedef struct _RTPSession {
109 uint8_t prefix; 103 uint8_t prefix;
110 104
111 int dest; 105 int dest;
112 int32_t call_index;
113 struct _ToxAv *av;
114 106
107 struct _CSSession *cs;
108
115} RTPSession; 109} RTPSession;
116 110
117
118/**
119 * @brief Release all messages held by session.
120 *
121 * @param session The session.
122 * @return int
123 * @retval -1 Error occurred.
124 * @retval 0 Success.
125 */
126int rtp_release_session_recv ( RTPSession *session );
127
128
129/** 111/**
130 * @brief Call this to change queue limit 112 * Must be called before calling any other rtp function.
131 *
132 * @param session The session
133 * @param limit new limit
134 * @return void
135 */ 113 */
136void rtp_queue_adjust_limit ( RTPSession *session, uint64_t limit ); 114RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num );
137 115
138/** 116/**
139 * @brief Get's oldest message in the list. 117 * Terminate the session.
140 *
141 * @param session Where the list is.
142 * @return RTPMessage* The message. You need to call rtp_msg_free() to free it.
143 * @retval NULL No messages in the list, or no list.
144 */ 118 */
145RTPMessage *rtp_recv_msg ( RTPSession *session ); 119void rtp_kill ( RTPSession *session, Messenger *messenger );
146
147 120
148/** 121/**
149 * @brief Sends msg to _RTPSession::dest 122 * Sends msg to _RTPSession::dest
150 *
151 * @param session The session.
152 * @param msg The message
153 * @param messenger Tox* object.
154 * @return int
155 * @retval -1 On error.
156 * @retval 0 On success.
157 */ 123 */
158int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *data, uint16_t length ); 124int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *data, uint16_t length );
159 125
160
161/** 126/**
162 * @brief Speaks for it self. 127 * Dealloc msg.
163 *
164 * @param session The control session msg belongs to. It can be NULL.
165 * @param msg The message.
166 * @return void
167 */ 128 */
168void rtp_free_msg ( RTPSession *session, RTPMessage *msg ); 129void rtp_free_msg ( RTPSession *session, RTPMessage *msg );
169 130
170/**
171 * @brief Must be called before calling any other rtp function. It's used
172 * to initialize RTP control session.
173 *
174 * @param payload_type Type of payload used to send. You can use values in toxmsi.h::MSICallType
175 * @param messenger Tox* object.
176 * @param friend_num Friend id.
177 * @return RTPSession* Created control session.
178 * @retval NULL Error occurred.
179 */
180RTPSession *rtp_init_session ( int payload_type, Messenger *messenger, int friend_num );
181
182
183/**
184 * @brief Terminate the session.
185 *
186 * @param session The session.
187 * @param messenger The messenger who owns the session
188 * @return int
189 * @retval -1 Error occurred.
190 * @retval 0 Success.
191 */
192void rtp_terminate_session ( RTPSession *session, Messenger *messenger );
193
194 131
195 132
196#endif /* __TOXRTP */ 133#endif /* __TOXRTP */
diff --git a/toxav/toxav.c b/toxav/toxav.c
index 24e42572..88e24bce 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -28,13 +28,12 @@ typedef struct Messenger Tox;
28 28
29#define _GNU_SOURCE /* implicit declaration warning */ 29#define _GNU_SOURCE /* implicit declaration warning */
30 30
31#include "rtp.h"
32#include "codec.h" 31#include "codec.h"
33#include "msi.h" 32#include "msi.h"
34#include "toxav.h"
35#include "group.h" 33#include "group.h"
36 34
37#include "../toxcore/logger.h" 35#include "../toxcore/logger.h"
36#include "../toxcore/util.h"
38 37
39#include <assert.h> 38#include <assert.h>
40#include <stdlib.h> 39#include <stdlib.h>
@@ -42,21 +41,13 @@ typedef struct Messenger Tox;
42 41
43/* Assume 24 fps*/ 42/* Assume 24 fps*/
44#define MAX_ENCODE_TIME_US ((1000 / 24) * 1000) 43#define MAX_ENCODE_TIME_US ((1000 / 24) * 1000)
45#define MAX_DECODE_TIME_US 0
46
47#define MAX_VIDEOFRAME_SIZE 0x40000 /* 256KiB */
48#define VIDEOFRAME_PIECE_SIZE 0x500 /* 1.25 KiB*/
49#define VIDEOFRAME_HEADER_SIZE 0x2
50
51
52#define inline__ inline __attribute__((always_inline))
53 44
54/* call index invalid: true if invalid */ 45/* call index invalid: true if invalid */
55#define cii(c_idx, session) (c_idx < 0 || c_idx >= session->max_calls) 46#define cii(c_idx, session) (c_idx < 0 || c_idx >= session->max_calls)
56 47
57 48
58const ToxAvCSettings av_DefaultSettings = { 49const ToxAvCSettings av_DefaultSettings = {
59 TypeAudio, 50 av_TypeAudio,
60 51
61 500, 52 500,
62 1280, 53 1280,
@@ -68,108 +59,49 @@ const ToxAvCSettings av_DefaultSettings = {
68 1 59 1
69}; 60};
70 61
71const uint32_t av_jbufdc = 3; 62static const uint32_t jbuf_capacity = 6;
72const uint32_t av_VADd = 40;
73
74
75static const uint8_t audio_index = 0, video_index = 1; 63static const uint8_t audio_index = 0, video_index = 1;
76 64
77typedef struct {
78 uint32_t size;
79 uint8_t data[0];
80} DECODE_PACKET;
81
82#define VIDEO_DECODE_QUEUE_SIZE 2
83#define AUDIO_DECODE_QUEUE_SIZE 16
84
85typedef struct _CallSpecific { 65typedef struct _CallSpecific {
86 RTPSession *crtps[2]; /** Audio is first and video is second */ 66 RTPSession *crtps[2]; /** Audio is first and video is second */
87 CodecState *cs;/** Each call have its own encoders and decoders. 67 CSSession *cs;/** Each call have its own encoders and decoders.
88 * You can, but don't have to, reuse encoders for 68 * You can, but don't have to, reuse encoders for
89 * multiple calls. If you choose to reuse encoders, 69 * multiple calls. If you choose to reuse encoders,
90 * make sure to also reuse encoded payload for every call. 70 * make sure to also reuse encoded payload for every call.
91 * Decoders have to be unique for each call. FIXME: Now add refcounted encoders and 71 * Decoders have to be unique for each call.
92 * reuse them really.
93 */ 72 */
94 JitterBuffer *j_buf; /** Jitter buffer for audio */ 73
95
96 uint32_t frame_limit; /* largest address written to in frame_buf for current input frame*/
97 uint8_t frame_id, frame_outid; /* id of input and output video frame */
98 void *frame_buf; /* buffer for split video payloads */
99
100 _Bool call_active; 74 _Bool call_active;
101 pthread_mutex_t mutex; 75 pthread_mutex_t mutex;
102
103 /* used in the "decode on another thread" system */
104 volatile _Bool exit, decoding;
105 uint8_t video_decode_read, video_decode_write, audio_decode_read, audio_decode_write;
106 pthread_mutex_t decode_cond_mutex;
107 pthread_cond_t decode_cond;
108 DECODE_PACKET *volatile video_decode_queue[VIDEO_DECODE_QUEUE_SIZE];
109 DECODE_PACKET *volatile audio_decode_queue[AUDIO_DECODE_QUEUE_SIZE];
110} CallSpecific; 76} CallSpecific;
111 77
112struct _ToxAv { 78struct _ToxAv {
113 Messenger *messenger; 79 Messenger *messenger;
114 MSISession *msi_session; /** Main msi session */ 80 MSISession *msi_session; /** Main msi session */
115 CallSpecific *calls; /** Per-call params */ 81 CallSpecific *calls; /** Per-call params */
116
117 void (*audio_callback)(ToxAv *, int32_t, int16_t *, int, void *);
118 void (*video_callback)(ToxAv *, int32_t, vpx_image_t *, void *);
119
120 void *audio_callback_userdata;
121 void *video_callback_userdata;
122
123 uint32_t max_calls; 82 uint32_t max_calls;
83
84 /* Decode time measure */
85 int32_t dectmsscount; /** Measure count */
86 int32_t dectmsstotal; /** Last cycle total */
87 int32_t avgdectms; /** Average decoding time in ms */
124}; 88};
125 89
126static void *toxav_decoding(void *arg);
127 90
128static MSICSettings msicsettings_cast (const ToxAvCSettings *from) 91static const MSICSettings *msicsettings_cast (const ToxAvCSettings *from)
129{ 92{
130 MSICSettings csettings; 93 assert(sizeof(MSICSettings) == sizeof(ToxAvCSettings));
131 csettings.call_type = from->call_type; 94 return (const MSICSettings *) from;
132
133 csettings.video_bitrate = from->video_bitrate;
134 csettings.max_video_width = from->max_video_width;
135 csettings.max_video_height = from->max_video_height;
136
137 csettings.audio_bitrate = from->audio_bitrate;
138 csettings.audio_frame_duration = from->audio_frame_duration;
139 csettings.audio_sample_rate = from->audio_sample_rate;
140 csettings.audio_channels = from->audio_channels;
141
142 return csettings;
143} 95}
144 96
145static ToxAvCSettings toxavcsettings_cast (const MSICSettings *from) 97static const ToxAvCSettings* toxavcsettings_cast (const MSICSettings *from)
146{ 98{
147 ToxAvCSettings csettings; 99 assert(sizeof(MSICSettings) == sizeof(ToxAvCSettings));
148 csettings.call_type = from->call_type; 100 return (const ToxAvCSettings *) from;
149 101
150 csettings.video_bitrate = from->video_bitrate;
151 csettings.max_video_width = from->max_video_width;
152 csettings.max_video_height = from->max_video_height;
153
154 csettings.audio_bitrate = from->audio_bitrate;
155 csettings.audio_frame_duration = from->audio_frame_duration;
156 csettings.audio_sample_rate = from->audio_sample_rate;
157 csettings.audio_channels = from->audio_channels;
158
159 return csettings;
160} 102}
161 103
162/** 104
163 * @brief Start new A/V session. There can only be one session at the time. If you register more
164 * it will result in undefined behaviour.
165 *
166 * @param messenger The messenger handle.
167 * @param userdata The agent handling A/V session (i.e. phone).
168 * @param video_width Width of video frame.
169 * @param video_height Height of video frame.
170 * @return ToxAv*
171 * @retval NULL On error.
172 */
173ToxAv *toxav_new( Tox *messenger, int32_t max_calls) 105ToxAv *toxav_new( Tox *messenger, int32_t max_calls)
174{ 106{
175 ToxAv *av = calloc ( sizeof(ToxAv), 1); 107 ToxAv *av = calloc ( sizeof(ToxAv), 1);
@@ -180,7 +112,7 @@ ToxAv *toxav_new( Tox *messenger, int32_t max_calls)
180 } 112 }
181 113
182 av->messenger = (Messenger *)messenger; 114 av->messenger = (Messenger *)messenger;
183 av->msi_session = msi_init_session(av->messenger, max_calls); 115 av->msi_session = msi_new(av->messenger, max_calls);
184 av->msi_session->agent_handler = av; 116 av->msi_session->agent_handler = av;
185 av->calls = calloc(sizeof(CallSpecific), max_calls); 117 av->calls = calloc(sizeof(CallSpecific), max_calls);
186 av->max_calls = max_calls; 118 av->max_calls = max_calls;
@@ -188,355 +120,242 @@ ToxAv *toxav_new( Tox *messenger, int32_t max_calls)
188 return av; 120 return av;
189} 121}
190 122
191/**
192 * @brief Remove A/V session.
193 *
194 * @param av Handler.
195 * @return void
196 */
197void toxav_kill ( ToxAv *av ) 123void toxav_kill ( ToxAv *av )
198{ 124{
199 uint32_t i; 125 uint32_t i;
200 126
201 for (i = 0; i < av->max_calls; i ++) { 127 for (i = 0; i < av->max_calls; i ++) {
202 if ( av->calls[i].crtps[audio_index] ) 128 if ( av->calls[i].crtps[audio_index] )
203 rtp_terminate_session(av->calls[i].crtps[audio_index], av->msi_session->messenger_handle); 129 rtp_kill(av->calls[i].crtps[audio_index], av->msi_session->messenger_handle);
204 130
205 131
206 if ( av->calls[i].crtps[video_index] ) 132 if ( av->calls[i].crtps[video_index] )
207 rtp_terminate_session(av->calls[i].crtps[video_index], av->msi_session->messenger_handle); 133 rtp_kill(av->calls[i].crtps[video_index], av->msi_session->messenger_handle);
208 134
209 135 if ( av->calls[i].cs ) cs_kill(av->calls[i].cs);
210
211 if ( av->calls[i].j_buf ) terminate_queue(av->calls[i].j_buf);
212
213 if ( av->calls[i].cs ) codec_terminate_session(av->calls[i].cs);
214 } 136 }
215 137
216 msi_terminate_session(av->msi_session); 138 msi_kill(av->msi_session);
217 139
218 free(av->calls); 140 free(av->calls);
219 free(av); 141 free(av);
220} 142}
221 143
222/** 144uint32_t toxav_do_interval(ToxAv* av)
223 * @brief Register callback for call state.
224 *
225 * @param av Handler.
226 * @param callback The callback
227 * @param id One of the ToxAvCallbackID values
228 * @return void
229 */
230void toxav_register_callstate_callback ( ToxAv *av, ToxAVCallback callback, ToxAvCallbackID id, void *userdata )
231{ 145{
232 msi_register_callback(av->msi_session, (MSICallbackType)callback, (MSICallbackID) id, userdata); 146 int i = 0;
147 uint32_t rc = 200 + av->avgdectms; /* Return 200 if no call is active */
148
149 for (; i < av->max_calls; i ++) if (av->calls[i].call_active) {
150 /* This should work. Video payload will always come in greater intervals */
151 rc = MIN(av->calls[i].cs->audio_decoder_frame_duration, rc);
152 }
153
154 return rc - av->avgdectms;
233} 155}
234 156
235/** 157void toxav_do(ToxAv* av)
236 * @brief Register callback for receiving audio data
237 *
238 * @param callback The callback
239 * @return void
240 */
241void toxav_register_audio_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, int16_t *, int, void *),
242 void *user_data)
243{ 158{
244 av->audio_callback = callback; 159 msi_do(av->msi_session);
245 av->audio_callback_userdata = user_data; 160
161 uint64_t start = current_time_monotonic();
162
163 uint32_t i = 0;
164 for(;i < av->max_calls; i ++)
165 if (av->calls[i].call_active) cs_do(av->calls[i].cs);
166
167 uint64_t end = current_time_monotonic();
168
169 /* TODO maybe use variable for sizes */
170 av->dectmsstotal += end - start;
171 if (++av->dectmsscount == 3) {
172 av->avgdectms = av->dectmsstotal / 3 + 2 /* NOTE Magic Offset */;
173 av->dectmsscount = 0;
174 av->dectmsstotal = 0;
175 }
246} 176}
247 177
248/** 178void toxav_register_callstate_callback ( ToxAv* av, ToxAVCallback cb, ToxAvCallbackID id, void* userdata )
249 * @brief Register callback for receiving video data
250 *
251 * @param callback The callback
252 * @return void
253 */
254void toxav_register_video_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, vpx_image_t *, void *),
255 void *user_data)
256{ 179{
257 av->video_callback = callback; 180 msi_register_callback(av->msi_session, (MSICallbackType)cb, (MSICallbackID) id, userdata);
258 av->video_callback_userdata = user_data;
259} 181}
260 182
261/** 183void toxav_register_audio_callback(ToxAvAudioCallback cb, void* userdata)
262 * @brief Call user. Use its friend_id. 184{
263 * 185 cs_register_audio_callback(cb, userdata);
264 * @param av Handler. 186}
265 * @param user The user. 187
266 * @param call_type Call type. 188void toxav_register_video_callback(ToxAvVideoCallback cb, void* userdata)
267 * @param ringing_seconds Ringing timeout. 189{
268 * @return int 190 cs_register_video_callback(cb, userdata);
269 * @retval 0 Success. 191}
270 * @retval ToxAvError On error. 192
271 */ 193int toxav_call (ToxAv *av,
272int toxav_call (ToxAv *av, int32_t *call_index, int user, const ToxAvCSettings *csettings, int ringing_seconds ) 194 int32_t *call_index,
195 int user,
196 const ToxAvCSettings *csettings,
197 int ringing_seconds )
273{ 198{
274 return msi_invite(av->msi_session, call_index, msicsettings_cast(csettings), ringing_seconds * 1000, user); 199 return msi_invite(av->msi_session, call_index, msicsettings_cast(csettings), ringing_seconds * 1000, user);
275} 200}
276 201
277/**
278 * @brief Hangup active call.
279 *
280 * @param av Handler.
281 * @return int
282 * @retval 0 Success.
283 * @retval ToxAvError On error.
284 */
285int toxav_hangup ( ToxAv *av, int32_t call_index ) 202int toxav_hangup ( ToxAv *av, int32_t call_index )
286{ 203{
287 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) { 204 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
288 return ErrorNoCall; 205 return av_ErrorNoCall;
289 } 206 }
290 207
291 if ( av->msi_session->calls[call_index]->state != call_active ) { 208 if ( av->msi_session->calls[call_index]->state != call_active ) {
292 return ErrorInvalidState; 209 return av_ErrorInvalidState;
293 } 210 }
294 211
295 return msi_hangup(av->msi_session, call_index); 212 return msi_hangup(av->msi_session, call_index);
296} 213}
297 214
298/**
299 * @brief Answer incomming call.
300 *
301 * @param av Handler.
302 * @param call_type Answer with...
303 * @return int
304 * @retval 0 Success.
305 * @retval ToxAvError On error.
306 */
307int toxav_answer ( ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings ) 215int toxav_answer ( ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings )
308{ 216{
309 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) { 217 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
310 return ErrorNoCall; 218 return av_ErrorNoCall;
311 } 219 }
312 220
313 if ( av->msi_session->calls[call_index]->state != call_starting ) { 221 if ( av->msi_session->calls[call_index]->state != call_starting ) {
314 return ErrorInvalidState; 222 return av_ErrorInvalidState;
315 } 223 }
316 224
317 return msi_answer(av->msi_session, call_index, msicsettings_cast(csettings)); 225 return msi_answer(av->msi_session, call_index, msicsettings_cast(csettings));
318} 226}
319 227
320/**
321 * @brief Reject incomming call.
322 *
323 * @param av Handler.
324 * @param reason Optional reason. Set NULL if none.
325 * @return int
326 * @retval 0 Success.
327 * @retval ToxAvError On error.
328 */
329int toxav_reject ( ToxAv *av, int32_t call_index, const char *reason ) 228int toxav_reject ( ToxAv *av, int32_t call_index, const char *reason )
330{ 229{
331 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) { 230 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
332 return ErrorNoCall; 231 return av_ErrorNoCall;
333 } 232 }
334 233
335 if ( av->msi_session->calls[call_index]->state != call_starting ) { 234 if ( av->msi_session->calls[call_index]->state != call_starting ) {
336 return ErrorInvalidState; 235 return av_ErrorInvalidState;
337 } 236 }
338 237
339 return msi_reject(av->msi_session, call_index, reason); 238 return msi_reject(av->msi_session, call_index, reason);
340} 239}
341 240
342/**
343 * @brief Cancel outgoing request.
344 *
345 * @param av Handler.
346 * @param reason Optional reason.
347 * @param peer_id peer friend_id
348 * @return int
349 * @retval 0 Success.
350 * @retval ToxAvError On error.
351 */
352int toxav_cancel ( ToxAv *av, int32_t call_index, int peer_id, const char *reason ) 241int toxav_cancel ( ToxAv *av, int32_t call_index, int peer_id, const char *reason )
353{ 242{
354 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) { 243 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
355 return ErrorNoCall; 244 return av_ErrorNoCall;
356 } 245 }
357 246
358 if ( av->msi_session->calls[call_index]->state != call_inviting ) { 247 if ( av->msi_session->calls[call_index]->state != call_inviting ) {
359 return ErrorInvalidState; 248 return av_ErrorInvalidState;
360 } 249 }
361 250
362 return msi_cancel(av->msi_session, call_index, peer_id, reason); 251 return msi_cancel(av->msi_session, call_index, peer_id, reason);
363} 252}
364 253
365/**
366 * @brief Notify peer that we are changing call type
367 *
368 * @param av Handler.
369 * @return int
370 * @param call_type Change to...
371 * @retval 0 Success.
372 * @retval ToxAvError On error.
373 */
374int toxav_change_settings(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings) 254int toxav_change_settings(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings)
375{ 255{
376 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) { 256 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
377 return ErrorNoCall; 257 return av_ErrorNoCall;
378 } 258 }
379 259
380 return msi_change_csettings(av->msi_session, call_index, msicsettings_cast(csettings)); 260 return msi_change_csettings(av->msi_session, call_index, msicsettings_cast(csettings));
381} 261}
382 262
383/**
384 * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer.
385 *
386 * @param av Handler.
387 * @return int
388 * @retval 0 Success.
389 * @retval ToxAvError On error.
390 */
391int toxav_stop_call ( ToxAv *av, int32_t call_index ) 263int toxav_stop_call ( ToxAv *av, int32_t call_index )
392{ 264{
393 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) { 265 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) {
394 return ErrorNoCall; 266 return av_ErrorNoCall;
395 } 267 }
396 268
397 return msi_stopcall(av->msi_session, call_index); 269 return msi_stopcall(av->msi_session, call_index);
398} 270}
399 271
400/** 272int toxav_prepare_transmission ( ToxAv* av, int32_t call_index, int support_video )
401 * @brief Must be call before any RTP transmission occurs.
402 *
403 * @param av Handler.
404 * @return int
405 * @retval 0 Success.
406 * @retval ToxAvError On error.
407 */
408int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, uint32_t jbuf_capacity, uint32_t VAD_treshold,
409 int support_video )
410{ 273{
411 if ( !av->msi_session || cii(call_index, av->msi_session) || 274 if ( !av->msi_session || cii(call_index, av->msi_session) ||
412 !av->msi_session->calls[call_index] || !av->msi_session->calls[call_index]->csettings_peer || 275 !av->msi_session->calls[call_index] || !av->msi_session->calls[call_index]->csettings_peer ||
413 av->calls[call_index].call_active) { 276 av->calls[call_index].call_active) {
414 LOGGER_ERROR("Error while starting RTP session: invalid call!\n"); 277 LOGGER_ERROR("Error while starting RTP session: invalid call!\n");
415 return ErrorInternal; 278 return av_ErrorInternal;
416 } 279 }
417 280
418 CallSpecific *call = &av->calls[call_index]; 281 CallSpecific *call = &av->calls[call_index];
419 282
283 if ( pthread_mutex_init(&call->mutex, NULL) != 0 ) {
284 LOGGER_WARNING("Failed to init call mutex!");
285 return av_ErrorInternal;
286 }
287
288 const ToxAvCSettings* c_peer = toxavcsettings_cast
289 (&av->msi_session->calls[call_index]->csettings_peer[0]);
290 const ToxAvCSettings* c_self = toxavcsettings_cast
291 (&av->msi_session->calls[call_index]->csettings_local);
292
293 LOGGER_DEBUG(
294 "Type: %u(s) %u(p)\n"
295 "Video bitrate: %u(s) %u(p)\n"
296 "Video height: %u(s) %u(p)\n"
297 "Video width: %u(s) %u(p)\n"
298 "Audio bitrate: %u(s) %u(p)\n"
299 "Audio framedur: %u(s) %u(p)\n"
300 "Audio sample rate: %u(s) %u(p)\n"
301 "Audio channels: %u(s) %u(p)\n",
302 c_self->call_type, c_peer->call_type,
303 c_self->video_bitrate, c_peer->video_bitrate,
304 c_self->max_video_height, c_peer->max_video_height,
305 c_self->max_video_width, c_peer->max_video_width,
306 c_self->audio_bitrate, c_peer->audio_bitrate,
307 c_self->audio_frame_duration, c_peer->audio_frame_duration,
308 c_self->audio_sample_rate, c_peer->audio_sample_rate,
309 c_self->audio_channels, c_peer->audio_channels );
310
311 if ( !(call->cs = cs_new(c_self, c_peer, jbuf_capacity, support_video)) ){
312 pthread_mutex_destroy(&call->mutex);
313 LOGGER_ERROR("Error while starting Codec State!\n");
314 return av_ErrorInternal;
315 }
316
317 call->cs->agent = av;
318 call->cs->call_idx = call_index;
319
420 call->crtps[audio_index] = 320 call->crtps[audio_index] =
421 rtp_init_session(type_audio, av->messenger, av->msi_session->calls[call_index]->peers[0]); 321 rtp_new(type_audio, av->messenger, av->msi_session->calls[call_index]->peers[0]);
422
423 322
424 if ( !call->crtps[audio_index] ) { 323 if ( !call->crtps[audio_index] ) {
425 LOGGER_ERROR("Error while starting audio RTP session!\n"); 324 LOGGER_ERROR("Error while starting audio RTP session!\n");
426 return ErrorInternal; 325 return av_ErrorInternal;
427 } 326 }
428 327
429 call->crtps[audio_index]->call_index = call_index; 328 call->crtps[audio_index]->cs = call->cs;
430 call->crtps[audio_index]->av = av;
431 329
432 if ( support_video ) { 330 if ( support_video ) {
433 call->crtps[video_index] = 331 call->crtps[video_index] =
434 rtp_init_session(type_video, av->messenger, av->msi_session->calls[call_index]->peers[0]); 332 rtp_new(type_video, av->messenger, av->msi_session->calls[call_index]->peers[0]);
435 333
436 if ( !call->crtps[video_index] ) { 334 if ( !call->crtps[video_index] ) {
437 LOGGER_ERROR("Error while starting video RTP session!\n"); 335 LOGGER_ERROR("Error while starting video RTP session!\n");
438 goto error; 336 goto error;
439 } 337 }
440 338
441 call->crtps[video_index]->call_index = call_index; 339 call->crtps[video_index]->cs = call->cs;
442 call->crtps[video_index]->av = av;
443
444 call->frame_limit = 0;
445 call->frame_id = 0;
446 call->frame_outid = 0;
447
448 call->frame_buf = calloc(MAX_VIDEOFRAME_SIZE, 1);
449
450 if (!call->frame_buf) {
451 LOGGER_WARNING("Frame buffer allocation failed!");
452 goto error;
453 }
454
455 }
456
457 if ( !(call->j_buf = create_queue(jbuf_capacity)) ) {
458 LOGGER_WARNING("Jitter buffer creaton failed!");
459 goto error;
460 }
461
462 ToxAvCSettings csettings_peer = toxavcsettings_cast(&av->msi_session->calls[call_index]->csettings_peer[0]);
463 ToxAvCSettings csettings_local = toxavcsettings_cast(&av->msi_session->calls[call_index]->csettings_local);
464 LOGGER_DEBUG(
465 "Type: %u \n"
466 "Video bitrate: %u \n"
467 "Video height: %u \n"
468 "Video width: %u \n"
469 "Audio bitrate: %u \n"
470 "Audio framedur: %u \n"
471 "Audio sample rate: %u \n"
472 "Audio channels: %u \n",
473 csettings_peer.call_type,
474 csettings_peer.video_bitrate,
475 csettings_peer.max_video_height,
476 csettings_peer.max_video_width,
477 csettings_peer.audio_bitrate,
478 csettings_peer.audio_frame_duration,
479 csettings_peer.audio_sample_rate,
480 csettings_peer.audio_channels );
481
482 if ( (call->cs = codec_init_session(csettings_local.audio_bitrate,
483 csettings_local.audio_frame_duration,
484 csettings_local.audio_sample_rate,
485 csettings_local.audio_channels,
486 csettings_peer.audio_channels,
487 VAD_treshold,
488 csettings_local.max_video_width,
489 csettings_local.max_video_height,
490 csettings_local.video_bitrate) )) {
491
492 if ( pthread_mutex_init(&call->mutex, NULL) != 0 ) goto error;
493
494 //todo: add error checks
495 pthread_mutex_init(&call->decode_cond_mutex, NULL);
496 pthread_cond_init(&call->decode_cond, NULL);
497
498 void **arg = malloc(2 * sizeof(void *));
499 arg[0] = av;
500 arg[1] = call;
501
502 pthread_t temp;
503 pthread_attr_t attr;
504
505 pthread_attr_init(&attr);
506 pthread_attr_setstacksize(&attr, 1 << 18);
507 pthread_create(&temp, &attr, toxav_decoding, arg);
508 pthread_attr_destroy(&attr);
509
510
511 LOGGER_WARNING("Got here");
512 call->call_active = 1;
513
514 return ErrorNone;
515 } 340 }
516 341
342 call->call_active = 1;
343 return av_ErrorNone;
517error: 344error:
518 rtp_terminate_session(call->crtps[audio_index], av->messenger); 345 rtp_kill(call->crtps[audio_index], av->messenger);
519 rtp_terminate_session(call->crtps[video_index], av->messenger); 346 rtp_kill(call->crtps[video_index], av->messenger);
520 free(call->frame_buf); 347 cs_kill(call->cs);
521 terminate_queue(call->j_buf); 348 pthread_mutex_destroy(&call->mutex);
522 codec_terminate_session(call->cs); 349 memset(call, 0, sizeof(CallSpecific));
523 350
524 return ErrorInternal; 351 return av_ErrorInternal;
525} 352}
526 353
527/**
528 * @brief Call this at the end of the transmission.
529 *
530 * @param av Handler.
531 * @return int
532 * @retval 0 Success.
533 * @retval ToxAvError On error.
534 */
535int toxav_kill_transmission ( ToxAv *av, int32_t call_index ) 354int toxav_kill_transmission ( ToxAv *av, int32_t call_index )
536{ 355{
537 if (cii(call_index, av->msi_session)) { 356 if (cii(call_index, av->msi_session)) {
538 LOGGER_WARNING("Invalid call index: %d", call_index); 357 LOGGER_WARNING("Invalid call index: %d", call_index);
539 return ErrorNoCall; 358 return av_ErrorNoCall;
540 } 359 }
541 360
542 CallSpecific *call = &av->calls[call_index]; 361 CallSpecific *call = &av->calls[call_index];
@@ -546,234 +365,110 @@ int toxav_kill_transmission ( ToxAv *av, int32_t call_index )
546 if (!call->call_active) { 365 if (!call->call_active) {
547 pthread_mutex_unlock(&call->mutex); 366 pthread_mutex_unlock(&call->mutex);
548 LOGGER_WARNING("Action on inactive call: %d", call_index); 367 LOGGER_WARNING("Action on inactive call: %d", call_index);
549 return ErrorNoCall; 368 return av_ErrorNoCall;
550 } 369 }
551 370
552 371 rtp_kill(call->crtps[audio_index], av->messenger); call->crtps[audio_index] = NULL;
372 rtp_kill(call->crtps[video_index], av->messenger); call->crtps[video_index] = NULL;
373 cs_kill(call->cs); call->cs = NULL;
374
553 call->call_active = 0; 375 call->call_active = 0;
554 376
555 rtp_terminate_session(call->crtps[audio_index], av->messenger);
556 call->crtps[audio_index] = NULL;
557 rtp_terminate_session(call->crtps[video_index], av->messenger);
558 call->crtps[video_index] = NULL;
559 terminate_queue(call->j_buf);
560 call->j_buf = NULL;
561
562 int i;
563 DECODE_PACKET *p;
564
565 call->exit = 1;
566 pthread_mutex_lock(&call->decode_cond_mutex);
567 pthread_cond_signal(&call->decode_cond);
568 pthread_cond_wait(&call->decode_cond, &call->decode_cond_mutex);
569 pthread_mutex_unlock(&call->decode_cond_mutex);
570 pthread_mutex_destroy(&call->decode_cond_mutex);
571 pthread_cond_destroy(&call->decode_cond);
572
573 for (i = 0; i != VIDEO_DECODE_QUEUE_SIZE; i++) {
574 p = call->video_decode_queue[i];
575 call->video_decode_queue[i] = NULL;
576
577 if (p) {
578 free(p);
579 }
580 }
581
582 for (i = 0; i != AUDIO_DECODE_QUEUE_SIZE; i++) {
583 p = call->audio_decode_queue[i];
584 call->audio_decode_queue[i] = NULL;
585
586 if (p) {
587 free(p);
588 }
589 }
590
591 codec_terminate_session(call->cs);
592 call->cs = NULL;
593
594 free(call->frame_buf);
595
596 pthread_mutex_unlock(&call->mutex); 377 pthread_mutex_unlock(&call->mutex);
597 pthread_mutex_destroy(&call->mutex); 378 pthread_mutex_destroy(&call->mutex);
598 379
599 memset(call, 0, sizeof(CallSpecific)); 380 return av_ErrorNone;
600 return ErrorNone;
601} 381}
602 382
603 383static int toxav_send_rtp_payload(ToxAv *av,
604/** 384 CallSpecific *call,
605 * @brief Send RTP payload. 385 ToxAvCallType type,
606 * 386 const uint8_t *payload,
607 * @param av Handler.
608 * @param type Type of payload.
609 * @param payload The payload.
610 * @param length Size of it.
611 * @return int
612 * @retval 0 Success.
613 * @retval -1 Failure.
614 */
615static int toxav_send_rtp_payload(ToxAv *av, int32_t call_index, ToxAvCallType type, const uint8_t *payload,
616 unsigned int length) 387 unsigned int length)
617{ 388{
618 CallSpecific *call = &av->calls[call_index]; 389 if (call->crtps[type - av_TypeAudio]) {
619 390
620 if (call->crtps[type - TypeAudio]) { 391 /* Audio */
621 392 if (type == av_TypeAudio)
622 if (type == TypeAudio) { 393 return rtp_send_msg(call->crtps[audio_index], av->messenger, payload, length);
623 return rtp_send_msg(call->crtps[type - TypeAudio], av->messenger, payload, length); 394
624 } else { 395 /* Video */
625 if (length == 0 || length > MAX_VIDEOFRAME_SIZE) { 396 int parts = cs_split_video_payload(call->cs, payload, length);
626 LOGGER_ERROR("Invalid video frame size: %u\n", length); 397 if (parts == -1) return av_ErrorInternal;
627 return ErrorInternal; 398
628 } 399 uint16_t part_size;
629 400 const uint8_t* iter;
630 /* number of pieces - 1*/ 401
631 uint8_t numparts = (length - 1) / VIDEOFRAME_PIECE_SIZE; 402 int i;
632 403 for (i = 0; i < parts; i++) {
633 uint8_t load[2 + VIDEOFRAME_PIECE_SIZE]; 404 iter = cs_get_split_video_frame(call->cs, &part_size);
634 load[0] = call->frame_outid++; 405 if (rtp_send_msg(call->crtps[video_index], av->messenger, iter, part_size) != 0)
635 load[1] = 0; 406 return av_ErrorInternal;
636
637 int i;
638
639 for (i = 0; i < numparts; i++) {
640 memcpy(load + VIDEOFRAME_HEADER_SIZE, payload, VIDEOFRAME_PIECE_SIZE);
641 payload += VIDEOFRAME_PIECE_SIZE;
642
643 if (rtp_send_msg(call->crtps[type - TypeAudio], av->messenger,
644 load, VIDEOFRAME_HEADER_SIZE + VIDEOFRAME_PIECE_SIZE) != 0) {
645
646 return ErrorInternal;
647 }
648
649 load[1]++;
650 }
651
652 /* remainder = length % VIDEOFRAME_PIECE_SIZE, VIDEOFRAME_PIECE_SIZE if = 0 */
653 length = ((length - 1) % VIDEOFRAME_PIECE_SIZE) + 1;
654 memcpy(load + VIDEOFRAME_HEADER_SIZE, payload, length);
655
656 return rtp_send_msg(call->crtps[type - TypeAudio], av->messenger, load, VIDEOFRAME_HEADER_SIZE + length);
657 } 407 }
658 } else { 408
659 return ErrorNoRtpSession; 409 return av_ErrorNone;
660 } 410
661} 411 } else return av_ErrorNoRtpSession;
662
663/**
664 * @brief Encode and send video packet.
665 *
666 * @param av Handler.
667 * @param input The packet.
668 * @return int
669 * @retval 0 Success.
670 * @retval ToxAvError On error.
671 */
672int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int frame_size)
673{
674
675 if (cii(call_index, av->msi_session)) {
676 LOGGER_WARNING("Invalid call index: %d", call_index);
677 return ErrorNoCall;
678 }
679
680 CallSpecific *call = &av->calls[call_index];
681 pthread_mutex_lock(&call->mutex);
682
683
684 if (!call->call_active) {
685 pthread_mutex_unlock(&call->mutex);
686 LOGGER_WARNING("Action on inactive call: %d", call_index);
687 return ErrorNoCall;
688 }
689
690 int rc = toxav_send_rtp_payload(av, call_index, TypeVideo, frame, frame_size);
691 pthread_mutex_unlock(&call->mutex);
692
693 return rc;
694} 412}
695 413
696/** 414int toxav_prepare_video_frame ( ToxAv* av, int32_t call_index, uint8_t* dest, int dest_max, vpx_image_t* input)
697 * @brief Encode video frame
698 *
699 * @param av Handler
700 * @param dest Where to
701 * @param dest_max Max size
702 * @param input What to encode
703 * @return int
704 * @retval ToxAvError On error.
705 * @retval >0 On success
706 */
707int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input)
708{ 415{
709 if (cii(call_index, av->msi_session)) { 416 if (cii(call_index, av->msi_session)) {
710 LOGGER_WARNING("Invalid call index: %d", call_index); 417 LOGGER_WARNING("Invalid call index: %d", call_index);
711 return ErrorNoCall; 418 return av_ErrorNoCall;
712 } 419 }
713 420
714 421
715 CallSpecific *call = &av->calls[call_index]; 422 CallSpecific *call = &av->calls[call_index];
716 pthread_mutex_lock(&call->mutex); 423 pthread_mutex_lock(&call->mutex);
717 424
718 if (!call->call_active) { 425 if (!call->call_active) {
719 pthread_mutex_unlock(&call->mutex); 426 pthread_mutex_unlock(&call->mutex);
720 LOGGER_WARNING("Action on inactive call: %d", call_index); 427 LOGGER_WARNING("Action on inactive call: %d", call_index);
721 return ErrorNoCall; 428 return av_ErrorNoCall;
722 } 429 }
723 430
724 if (reconfigure_video_encoder_resolution(call->cs, input->d_w, input->d_h) != 0) { 431 if (cs_set_video_encoder_resolution(call->cs, input->d_w, input->d_h) != 0) {
725 pthread_mutex_unlock(&call->mutex); 432 pthread_mutex_unlock(&call->mutex);
726 return ErrorInternal; 433 return av_ErrorInternal;
727 } 434 }
728 435
729 int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US); 436 int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US);
730 437
731 if ( rc != VPX_CODEC_OK) { 438 if ( rc != VPX_CODEC_OK) {
732 LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(rc)); 439 LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(rc));
733 pthread_mutex_unlock(&call->mutex); 440 pthread_mutex_unlock(&call->mutex);
734 return ErrorInternal; 441 return av_ErrorInternal;
735 } 442 }
736 443
737 ++call->cs->frame_counter; 444 ++call->cs->frame_counter;
738 445
739 vpx_codec_iter_t iter = NULL; 446 vpx_codec_iter_t iter = NULL;
740 const vpx_codec_cx_pkt_t *pkt; 447 const vpx_codec_cx_pkt_t *pkt;
741 int copied = 0; 448 int copied = 0;
742 449
743 while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) { 450 while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) {
744 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { 451 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
745 if ( copied + pkt->data.frame.sz > dest_max ) { 452 if ( copied + pkt->data.frame.sz > dest_max ) {
746 pthread_mutex_unlock(&call->mutex); 453 pthread_mutex_unlock(&call->mutex);
747 return ErrorPacketTooLarge; 454 return av_ErrorPacketTooLarge;
748 } 455 }
749 456
750 memcpy(dest + copied, pkt->data.frame.buf, pkt->data.frame.sz); 457 memcpy(dest + copied, pkt->data.frame.buf, pkt->data.frame.sz);
751 copied += pkt->data.frame.sz; 458 copied += pkt->data.frame.sz;
752 } 459 }
753 } 460 }
754 461
755 pthread_mutex_unlock(&call->mutex); 462 pthread_mutex_unlock(&call->mutex);
756 return copied; 463 return copied;
757} 464}
758 465
759/** 466int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int frame_size)
760 * @brief Send audio frame.
761 *
762 * @param av Handler.
763 * @param data The audio data encoded with toxav_prepare_audio_frame().
764 * @param size Its size in number of bytes.
765 * @return int
766 * @retval 0 Success.
767 * @retval ToxAvError On error.
768 */
769int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *data, unsigned int size)
770{ 467{
771 if (size > MAX_CRYPTO_DATA_SIZE)
772 return ErrorInternal;
773 468
774 if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) { 469 if (cii(call_index, av->msi_session)) {
775 LOGGER_WARNING("Action on inactive call: %d", call_index); 470 LOGGER_WARNING("Invalid call index: %d", call_index);
776 return ErrorNoCall; 471 return av_ErrorNoCall;
777 } 472 }
778 473
779 CallSpecific *call = &av->calls[call_index]; 474 CallSpecific *call = &av->calls[call_index];
@@ -783,100 +478,93 @@ int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *data, unsig
783 if (!call->call_active) { 478 if (!call->call_active) {
784 pthread_mutex_unlock(&call->mutex); 479 pthread_mutex_unlock(&call->mutex);
785 LOGGER_WARNING("Action on inactive call: %d", call_index); 480 LOGGER_WARNING("Action on inactive call: %d", call_index);
786 return ErrorNoCall; 481 return av_ErrorNoCall;
787 } 482 }
788 483
789 int rc = toxav_send_rtp_payload(av, call_index, TypeAudio, data, size); 484 int rc = toxav_send_rtp_payload(av, call, av_TypeVideo, frame, frame_size);
790 pthread_mutex_unlock(&call->mutex); 485 pthread_mutex_unlock(&call->mutex);
791 486
792 return rc; 487 return rc;
793} 488}
794 489
795/** 490int toxav_prepare_audio_frame ( ToxAv *av,
796 * @brief Encode audio frame 491 int32_t call_index,
797 * 492 uint8_t *dest,
798 * @param av Handler 493 int dest_max,
799 * @param dest dest 494 const int16_t *frame,
800 * @param dest_max Max dest size
801 * @param frame The frame
802 * @param frame_size The frame size
803 * @return int
804 * @retval ToxAvError On error.
805 * @retval >0 On success
806 */
807int toxav_prepare_audio_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, const int16_t *frame,
808 int frame_size) 495 int frame_size)
809{ 496{
810 if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) { 497 if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) {
811 LOGGER_WARNING("Action on inactive call: %d", call_index); 498 LOGGER_WARNING("Action on inactive call: %d", call_index);
812 return ErrorNoCall; 499 return av_ErrorNoCall;
813 } 500 }
814 501
815 CallSpecific *call = &av->calls[call_index]; 502 CallSpecific *call = &av->calls[call_index];
816 pthread_mutex_lock(&call->mutex); 503 pthread_mutex_lock(&call->mutex);
817 504
818 505
819 if (!call->call_active) { 506 if (!call->call_active) {
820 pthread_mutex_unlock(&call->mutex); 507 pthread_mutex_unlock(&call->mutex);
821 LOGGER_WARNING("Action on inactive call: %d", call_index); 508 LOGGER_WARNING("Action on inactive call: %d", call_index);
822 return ErrorNoCall; 509 return av_ErrorNoCall;
823 } 510 }
824 511
825 int32_t rc = opus_encode(call->cs->audio_encoder, frame, frame_size, dest, dest_max); 512 int32_t rc = opus_encode(call->cs->audio_encoder, frame, frame_size, dest, dest_max);
826 pthread_mutex_unlock(&call->mutex); 513 pthread_mutex_unlock(&call->mutex);
827 514
828 if (rc < 0) { 515 if (rc < 0) {
829 LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc)); 516 LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc));
830 return ErrorInternal; 517 return av_ErrorInternal;
831 } 518 }
519
520 return rc;
521}
522
523int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *data, unsigned int size)
524{
525 if (size > MAX_CRYPTO_DATA_SIZE)
526 return av_ErrorInternal;
527
528 if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) {
529 LOGGER_WARNING("Action on inactive call: %d", call_index);
530 return av_ErrorNoCall;
531 }
532
533 CallSpecific *call = &av->calls[call_index];
534 pthread_mutex_lock(&call->mutex);
535
536
537 if (!call->call_active) {
538 pthread_mutex_unlock(&call->mutex);
539 LOGGER_WARNING("Action on inactive call: %d", call_index);
540 return av_ErrorNoCall;
541 }
542
543 int rc = toxav_send_rtp_payload(av, call, av_TypeAudio, data, size);
544 pthread_mutex_unlock(&call->mutex);
832 545
833 return rc; 546 return rc;
834} 547}
835 548
836/**
837 * @brief Get peer transmission type. It can either be audio or video.
838 *
839 * @param av Handler.
840 * @param peer The peer
841 * @return int
842 * @retval ToxAvCallType On success.
843 * @retval ToxAvError On error.
844 */
845int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSettings *dest ) 549int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSettings *dest )
846{ 550{
847 if ( peer < 0 || cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] 551 if ( peer < 0 || cii(call_index, av->msi_session) || !av->msi_session->calls[call_index]
848 || av->msi_session->calls[call_index]->peer_count <= peer ) 552 || av->msi_session->calls[call_index]->peer_count <= peer )
849 return ErrorInternal; 553 return av_ErrorInternal;
850 554
851 *dest = toxavcsettings_cast(&av->msi_session->calls[call_index]->csettings_peer[peer]); 555 *dest = *toxavcsettings_cast(&av->msi_session->calls[call_index]->csettings_peer[peer]);
852 return ErrorNone; 556 return av_ErrorNone;
853} 557}
854 558
855/**
856 * @brief Get id of peer participating in conversation
857 *
858 * @param av Handler
859 * @param peer peer index
860 * @return int
861 * @retval ToxAvError No peer id
862 */
863int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer ) 559int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer )
864{ 560{
865 if ( peer < 0 || cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] 561 if ( peer < 0 || cii(call_index, av->msi_session) || !av->msi_session->calls[call_index]
866 || av->msi_session->calls[call_index]->peer_count <= peer ) 562 || av->msi_session->calls[call_index]->peer_count <= peer )
867 return ErrorInternal; 563 return av_ErrorInternal;
868 564
869 return av->msi_session->calls[call_index]->peers[peer]; 565 return av->msi_session->calls[call_index]->peers[peer];
870} 566}
871 567
872/**
873 * @brief Get id of peer participating in conversation
874 *
875 * @param av Handler
876 * @param peer peer index
877 * @return int
878 * @retval ToxAvError No peer id
879 */
880ToxAvCallState toxav_get_call_state(ToxAv *av, int32_t call_index) 568ToxAvCallState toxav_get_call_state(ToxAv *av, int32_t call_index)
881{ 569{
882 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) 570 if ( cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] )
@@ -886,270 +574,40 @@ ToxAvCallState toxav_get_call_state(ToxAv *av, int32_t call_index)
886 574
887} 575}
888 576
889/** 577int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability )
890 * @brief Is certain capability supported
891 *
892 * @param av Handler
893 * @return int
894 * @retval 1 Yes.
895 * @retval 0 No.
896 */
897inline__ int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability )
898{ 578{
899 return av->calls[call_index].cs ? av->calls[call_index].cs->capabilities & (Capabilities) capability : 0; 579 return av->calls[call_index].cs ? av->calls[call_index].cs->capabilities & (CsCapabilities) capability : 0;
900 /* 0 is error here */ 580 /* 0 is error here */
901} 581}
902 582
903inline__ Tox *toxav_get_tox(ToxAv *av) 583Tox *toxav_get_tox(ToxAv *av)
904{ 584{
905 return (Tox *)av->messenger; 585 return (Tox *)av->messenger;
906} 586}
907 587
908int toxav_has_activity(ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t frame_size, float ref_energy) 588int toxav_set_vad_treshold(ToxAv* av, int32_t call_index, uint32_t treshold)
909{
910 if ( !av->calls[call_index].cs ) return ErrorInvalidCodecState;
911
912 return energy_VAD(av->calls[call_index].cs, PCM, frame_size, ref_energy);
913}
914
915
916static void decode_video(ToxAv *av, CallSpecific *call, DECODE_PACKET *p)
917{
918 int32_t call_index = call - av->calls;
919
920 int rc = vpx_codec_decode(&call->cs->v_decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US);
921
922 if (rc != VPX_CODEC_OK) {
923 LOGGER_ERROR("Error decoding video: %s\n", vpx_codec_err_to_string(rc));
924 }
925
926 vpx_codec_iter_t iter = NULL;
927 vpx_image_t *img;
928 img = vpx_codec_get_frame(&call->cs->v_decoder, &iter);
929
930 if (img && av->video_callback) {
931 av->video_callback(av, call_index, img, av->video_callback_userdata);
932 } else {
933 LOGGER_WARNING("Video packet dropped due to missing callback or no image!");
934 }
935
936 free(p);
937}
938
939static void decode_audio(ToxAv *av, CallSpecific *call, DECODE_PACKET *p)
940{ 589{
941 int32_t call_index = call - av->calls; 590 if ( !av->calls[call_index].cs ) return av_ErrorInvalidCodecState;
942 591 /* TODO on't use default framedur... */
943 // ToxAvCSettings csettings; 592 cs_set_vad_treshold(av->calls[call_index].cs, treshold, av_DefaultSettings.audio_frame_duration);
944 // toxav_get_peer_csettings(av, call_index, 0, &csettings); 593
945 594 return av_ErrorNone;
946 int frame_size = 10000; /* FIXME: not static? */
947 int16_t dest[frame_size];
948
949 int dec_size = opus_decode(call->cs->audio_decoder, p->data, p->size, dest, frame_size, (p->size == 0));
950 free(p);
951
952 if (dec_size < 0) {
953 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
954 return;
955 }
956
957 if ( av->audio_callback )
958 av->audio_callback(av, call_index, dest, dec_size, av->audio_callback_userdata);
959 else
960 LOGGER_WARNING("Audio packet dropped due to missing callback!");
961} 595}
962 596
963static void *toxav_decoding(void *arg) 597int toxav_has_activity(ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t frame_size, float ref)
964{ 598{
965 void **pp = arg; 599 if ( !av->calls[call_index].cs ) return av_ErrorInvalidCodecState;
966 ToxAv *av = pp[0];
967 CallSpecific *call = pp[1];
968 free(pp);
969 600
970 while (1) { 601 return cs_calculate_vad(av->calls[call_index].cs, PCM, frame_size, ref);
971 DECODE_PACKET *p;
972 _Bool video = 0;
973
974 pthread_mutex_lock(&call->decode_cond_mutex);
975
976 if (call->exit) {
977 break;
978 }
979
980 uint8_t r;
981
982 /* first check for available packets, otherwise wait for condition*/
983 r = call->audio_decode_read;
984 p = call->audio_decode_queue[r];
985
986 if (!p) {
987 r = call->video_decode_read;
988 p = call->video_decode_queue[r];
989
990 if (!p) {
991 pthread_cond_wait(&call->decode_cond, &call->decode_cond_mutex);
992 r = call->audio_decode_read;
993 p = call->audio_decode_queue[r];
994
995 if (!p) {
996 r = call->video_decode_read;
997 p = call->video_decode_queue[r];
998 video = 1;
999 }
1000 } else {
1001 video = 1;
1002 }
1003 }
1004
1005 if (video) {
1006 if (p) {
1007 call->video_decode_queue[r] = NULL;
1008 call->video_decode_read = (r + 1) % VIDEO_DECODE_QUEUE_SIZE;
1009 }
1010 } else {
1011 call->audio_decode_queue[r] = NULL;
1012 call->audio_decode_read = (r + 1) % AUDIO_DECODE_QUEUE_SIZE;
1013 }
1014
1015 pthread_mutex_unlock(&call->decode_cond_mutex);
1016
1017 if (p) {
1018 if (video) {
1019 decode_video(av, call, p);
1020 } else {
1021 decode_audio(av, call, p);
1022 }
1023 }
1024 }
1025
1026 call->exit = 0;
1027 pthread_cond_signal(&call->decode_cond);
1028 pthread_mutex_unlock(&call->decode_cond_mutex);
1029
1030 return NULL;
1031} 602}
1032 603
1033void toxav_handle_packet(RTPSession *_session, RTPMessage *_msg) 604int toxav_get_active_count(ToxAv* av)
1034{ 605{
1035 ToxAv *av = _session->av; 606 if (!av) return av_ErrorInternal;
1036 int32_t call_index = _session->call_index; 607
1037 CallSpecific *call = &av->calls[call_index]; 608 int rc = 0, i = 0;
1038 609 for (; i < av->max_calls; i ++) if (av->calls[i].call_active) rc++;
1039 if (!call->call_active) return; 610 return rc;
1040
1041 if (_session->payload_type == type_audio % 128) {
1042 queue(call->j_buf, _msg);
1043
1044 int success = 0;
1045
1046 while ((_msg = dequeue(call->j_buf, &success)) || success == 2) {
1047 DECODE_PACKET *p;
1048
1049 if (success == 2) {
1050 p = malloc(sizeof(DECODE_PACKET));
1051
1052 if (p) {
1053 p->size = 0;
1054 }
1055 } else {
1056 p = malloc(sizeof(DECODE_PACKET) + _msg->length);
1057
1058 if (p) {
1059 p->size = _msg->length;
1060 memcpy(p->data, _msg->data, _msg->length);
1061 }
1062
1063 rtp_free_msg(NULL, _msg);
1064 }
1065
1066 if (p) {
1067 /* do the decoding on another thread */
1068 pthread_mutex_lock(&call->decode_cond_mutex);
1069 uint8_t w = call->audio_decode_write;
1070
1071 if (call->audio_decode_queue[w] == NULL) {
1072 call->audio_decode_queue[w] = p;
1073 call->audio_decode_write = (w + 1) % AUDIO_DECODE_QUEUE_SIZE;
1074 pthread_cond_signal(&call->decode_cond);
1075 } else {
1076 LOGGER_DEBUG("Dropped audio frame\n");
1077 free(p);
1078 }
1079
1080 pthread_mutex_unlock(&call->decode_cond_mutex);
1081 } else {
1082 //malloc failed
1083 }
1084 }
1085
1086 } else {
1087 uint8_t *packet = _msg->data;
1088 int recved_size = _msg->length;
1089
1090 if (recved_size < VIDEOFRAME_HEADER_SIZE) {
1091 goto end;
1092 }
1093
1094 uint8_t i = packet[0] - call->frame_id;
1095
1096 if (i == 0) {
1097 /* piece of current frame */
1098 } else if (i > 0 && i < 128) {
1099 /* received a piece of a frame ahead, flush current frame and start reading this new frame */
1100 DECODE_PACKET *p = malloc(sizeof(DECODE_PACKET) + call->frame_limit);
1101
1102 if (p) {
1103 p->size = call->frame_limit;
1104 memcpy(p->data, call->frame_buf, call->frame_limit);
1105
1106 /* do the decoding on another thread */
1107 pthread_mutex_lock(&call->decode_cond_mutex);
1108 uint8_t w = call->video_decode_write;
1109
1110 if (call->video_decode_queue[w] == NULL) {
1111 call->video_decode_queue[w] = p;
1112 call->video_decode_write = (w + 1) % VIDEO_DECODE_QUEUE_SIZE;
1113 pthread_cond_signal(&call->decode_cond);
1114 } else {
1115 LOGGER_DEBUG("Dropped video frame\n");
1116 free(p);
1117 }
1118
1119 pthread_mutex_unlock(&call->decode_cond_mutex);
1120 } else {
1121 //malloc failed
1122 }
1123
1124 call->frame_id = packet[0];
1125 memset(call->frame_buf, 0, call->frame_limit);
1126 call->frame_limit = 0;
1127 } else {
1128 /* old packet, dont read */
1129 LOGGER_DEBUG("Old packet: %u\n", i);
1130 goto end;
1131 }
1132
1133 if (packet[1] > (MAX_VIDEOFRAME_SIZE - VIDEOFRAME_PIECE_SIZE + 1) /
1134 VIDEOFRAME_PIECE_SIZE) { //TODO, fix this check? not sure
1135 /* packet out of buffer range */
1136 goto end;
1137 }
1138
1139 LOGGER_DEBUG("Video Packet: %u %u\n", packet[0], packet[1]);
1140 memcpy(call->frame_buf + packet[1] * VIDEOFRAME_PIECE_SIZE, packet + VIDEOFRAME_HEADER_SIZE,
1141 recved_size - VIDEOFRAME_HEADER_SIZE);
1142 uint32_t limit = packet[1] * VIDEOFRAME_PIECE_SIZE + recved_size - VIDEOFRAME_HEADER_SIZE;
1143
1144 if (limit > call->frame_limit) {
1145 call->frame_limit = limit;
1146 LOGGER_DEBUG("Limit: %u\n", call->frame_limit);
1147 }
1148
1149end:
1150 ;
1151 rtp_free_msg(NULL, _msg);
1152 }
1153} 611}
1154 612
1155 613
diff --git a/toxav/toxav.h b/toxav/toxav.h
index 77afda81..71ee32fb 100644
--- a/toxav/toxav.h
+++ b/toxav/toxav.h
@@ -28,11 +28,11 @@
28extern "C" { 28extern "C" {
29#endif 29#endif
30 30
31/* vpx_image_t */
32#include <vpx/vpx_image.h>
33
34typedef void ( *ToxAVCallback ) ( void *agent, int32_t call_idx, void *arg );
35typedef struct _ToxAv ToxAv; 31typedef struct _ToxAv ToxAv;
32typedef struct vpx_image vpx_image_t;
33typedef void ( *ToxAVCallback ) ( void *agent, int32_t call_idx, void *arg );
34typedef void ( *ToxAvAudioCallback ) (void* agent, int32_t call_idx, const int16_t* PCM, uint16_t size, void* data);
35typedef void ( *ToxAvVideoCallback ) (void* agent, int32_t call_idx, const vpx_image_t* img, void* data);
36 36
37#ifndef __TOX_DEFINED__ 37#ifndef __TOX_DEFINED__
38#define __TOX_DEFINED__ 38#define __TOX_DEFINED__
@@ -43,34 +43,28 @@ typedef struct Tox Tox;
43 43
44 44
45/** 45/**
46 * @brief Callbacks ids that handle the call states. 46 * Callbacks ids that handle the call states.
47 */ 47 */
48typedef enum { 48typedef enum {
49 /* Requests */ 49 av_OnInvite, /* Incoming call */
50 av_OnInvite, 50 av_OnRinging, /* When peer is ready to accept/reject the call */
51 av_OnStart, 51 av_OnStart, /* Call (RTP transmission) started */
52 av_OnCancel, 52 av_OnCancel, /* The side that initiated call canceled invite */
53 av_OnReject, 53 av_OnReject, /* The side that was invited rejected the call */
54 av_OnEnd, 54 av_OnEnd, /* Call that was active ended */
55 55 av_OnRequestTimeout, /* When the requested action didn't get response in specified time */
56 /* Responses */ 56 av_OnPeerTimeout, /* Peer timed out; stop the call */
57 av_OnRinging, 57 av_OnPeerCSChange, /* Peer changing Csettings. Prepare for changed AV */
58 av_OnStarting, 58 av_OnSelfCSChange /* Csettings change confirmation. Once triggered peer is ready to recv changed AV */
59 av_OnEnding,
60
61 /* Protocol */
62 av_OnRequestTimeout,
63 av_OnPeerTimeout,
64 av_OnMediaChange
65} ToxAvCallbackID; 59} ToxAvCallbackID;
66 60
67 61
68/** 62/**
69 * @brief Call type identifier. 63 * Call type identifier.
70 */ 64 */
71typedef enum { 65typedef enum {
72 TypeAudio = 192, 66 av_TypeAudio = 192,
73 TypeVideo 67 av_TypeVideo
74} ToxAvCallType; 68} ToxAvCallType;
75 69
76 70
@@ -84,41 +78,35 @@ typedef enum {
84} ToxAvCallState; 78} ToxAvCallState;
85 79
86/** 80/**
87 * @brief Error indicators. 81 * Error indicators.
88 */ 82 */
89typedef enum { 83typedef enum {
90 ErrorNone = 0, 84 av_ErrorNone = 0,
91 ErrorInternal = -1, /* Internal error */ 85 av_ErrorInternal = -1, /* Internal error */
92 ErrorAlreadyInCall = -2, /* Already has an active call */ 86 av_ErrorAlreadyInCall = -2, /* Already has an active call */
93 ErrorNoCall = -3, /* Trying to perform call action while not in a call */ 87 av_ErrorNoCall = -3, /* Trying to perform call action while not in a call */
94 ErrorInvalidState = -4, /* Trying to perform call action while in invalid state*/ 88 av_ErrorInvalidState = -4, /* Trying to perform call action while in invalid state*/
95 ErrorNoRtpSession = -5, /* Trying to perform rtp action on invalid session */ 89 av_ErrorNoRtpSession = -5, /* Trying to perform rtp action on invalid session */
96 ErrorAudioPacketLost = -6, /* Indicating packet loss */ 90 av_ErrorInvalidCodecState = -6, /* Codec state not initialized */
97 ErrorStartingAudioRtp = -7, /* Error in toxav_prepare_transmission() */ 91 av_ErrorPacketTooLarge = -7, /* Split packet exceeds it's limit */
98 ErrorStartingVideoRtp = -8 , /* Error in toxav_prepare_transmission() */
99 ErrorTerminatingAudioRtp = -9, /* Returned in toxav_kill_transmission() */
100 ErrorTerminatingVideoRtp = -10, /* Returned in toxav_kill_transmission() */
101 ErrorPacketTooLarge = -11, /* Buffer exceeds size while encoding */
102 ErrorInvalidCodecState = -12, /* Codec state not initialized */
103
104} ToxAvError; 92} ToxAvError;
105 93
106 94
107/** 95/**
108 * @brief Locally supported capabilities. 96 * Locally supported capabilities.
109 */ 97 */
110typedef enum { 98typedef enum {
111 AudioEncoding = 1 << 0, 99 av_AudioEncoding = 1 << 0,
112 AudioDecoding = 1 << 1, 100 av_AudioDecoding = 1 << 1,
113 VideoEncoding = 1 << 2, 101 av_VideoEncoding = 1 << 2,
114 VideoDecoding = 1 << 3 102 av_VideoDecoding = 1 << 3
115} ToxAvCapabilities; 103} ToxAvCapabilities;
116 104
117 105
118/** 106/**
119 * @brief Encoding settings. 107 * Encoding settings.
120 */ 108 */
121typedef struct _ToxAvCodecSettings { 109typedef struct _ToxAvCSettings {
122 ToxAvCallType call_type; 110 ToxAvCallType call_type;
123 111
124 uint32_t video_bitrate; /* In kbits/s */ 112 uint32_t video_bitrate; /* In kbits/s */
@@ -132,256 +120,165 @@ typedef struct _ToxAvCodecSettings {
132} ToxAvCSettings; 120} ToxAvCSettings;
133 121
134extern const ToxAvCSettings av_DefaultSettings; 122extern const ToxAvCSettings av_DefaultSettings;
135extern const uint32_t av_jbufdc; /* Jitter buffer default capacity */
136extern const uint32_t av_VADd; /* VAD default treshold */
137 123
138/** 124/**
139 * @brief Start new A/V session. There can only be one session at the time. If you register more 125 * Start new A/V session. There can only be one session at the time.
140 * it will result in undefined behaviour.
141 *
142 * @param messenger The messenger handle.
143 * @param userdata The agent handling A/V session (i.e. phone).
144 * @param video_width Width of video frame.
145 * @param video_height Height of video frame.
146 * @return ToxAv*
147 * @retval NULL On error.
148 */ 126 */
149ToxAv *toxav_new(Tox *messenger, int32_t max_calls); 127ToxAv *toxav_new(Tox *messenger, int32_t max_calls);
150 128
151/** 129/**
152 * @brief Remove A/V session. 130 * Remove A/V session.
153 *
154 * @param av Handler.
155 * @return void
156 */ 131 */
157void toxav_kill(ToxAv *av); 132void toxav_kill(ToxAv *av);
158 133
159/** 134/**
160 * @brief Register callback for call state. 135 * Returns the interval in milliseconds when the next toxav_do() should be called.
161 * 136 * If no call is active at the moment returns 200.
162 * @param av Handler.
163 * @param callback The callback
164 * @param id One of the ToxAvCallbackID values
165 * @return void
166 */ 137 */
167void toxav_register_callstate_callback (ToxAv *av, ToxAVCallback callback, ToxAvCallbackID id, void *userdata); 138uint32_t toxav_do_interval(ToxAv *av);
168 139
169/** 140/**
170 * @brief Register callback for receiving audio data 141 * Main loop for the session. Best called right after tox_do();
171 *
172 * @param av Handler.
173 * @param callback The callback
174 * @return void
175 */ 142 */
176void toxav_register_audio_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, int16_t *, int, void *), 143void toxav_do(ToxAv *av);
177 void *user_data);
178 144
179/** 145/**
180 * @brief Register callback for receiving video data 146 * Register callback for call state.
181 *
182 * @param av Handler.
183 * @param callback The callback
184 * @return void
185 */ 147 */
186void toxav_register_video_recv_callback (ToxAv *av, void (*callback)(ToxAv *, int32_t, vpx_image_t *, void *), 148void toxav_register_callstate_callback (ToxAv *av, ToxAVCallback cb, ToxAvCallbackID id, void *userdata);
187 void *user_data);
188 149
189/** 150/**
190 * @brief Call user. Use its friend_id. 151 * Register callback for audio data.
191 *
192 * @param av Handler.
193 * @param user The user.
194 * @param call_type Call type.
195 * @param ringing_seconds Ringing timeout.
196 * @return int
197 * @retval 0 Success.
198 * @retval ToxAvError On error.
199 */ 152 */
200int toxav_call(ToxAv *av, int32_t *call_index, int user, const ToxAvCSettings *csettings, int ringing_seconds); 153void toxav_register_audio_callback (ToxAvAudioCallback cb, void* userdata);
201 154
202/** 155/**
203 * @brief Hangup active call. 156 * Register callback for video data.
204 * 157 */
205 * @param av Handler. 158void toxav_register_video_callback (ToxAvVideoCallback cb, void* userdata);
206 * @return int 159
207 * @retval 0 Success. 160/**
208 * @retval ToxAvError On error. 161 * Call user. Use its friend_id.
162 */
163int toxav_call(ToxAv *av,
164 int32_t *call_index,
165 int friend_id,
166 const ToxAvCSettings *csettings,
167 int ringing_seconds);
168
169/**
170 * Hangup active call.
209 */ 171 */
210int toxav_hangup(ToxAv *av, int32_t call_index); 172int toxav_hangup(ToxAv *av, int32_t call_index);
211 173
212/** 174/**
213 * @brief Answer incomming call. 175 * Answer incoming call. Pass the csettings that you will use.
214 *
215 * @param av Handler.
216 * @param call_type Answer with...
217 * @return int
218 * @retval 0 Success.
219 * @retval ToxAvError On error.
220 */ 176 */
221int toxav_answer(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings ); 177int toxav_answer(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings );
222 178
223/** 179/**
224 * @brief Reject incomming call. 180 * Reject incoming call.
225 *
226 * @param av Handler.
227 * @param reason Optional reason. Set NULL if none.
228 * @return int
229 * @retval 0 Success.
230 * @retval ToxAvError On error.
231 */ 181 */
232int toxav_reject(ToxAv *av, int32_t call_index, const char *reason); 182int toxav_reject(ToxAv *av, int32_t call_index, const char *reason);
233 183
234/** 184/**
235 * @brief Cancel outgoing request. 185 * Cancel outgoing request.
236 *
237 * @param av Handler.
238 * @param reason Optional reason.
239 * @param peer_id peer friend_id
240 * @return int
241 * @retval 0 Success.
242 * @retval ToxAvError On error.
243 */ 186 */
244int toxav_cancel(ToxAv *av, int32_t call_index, int peer_id, const char *reason); 187int toxav_cancel(ToxAv *av, int32_t call_index, int peer_id, const char *reason);
245 188
246/** 189/**
247 * @brief Notify peer that we are changing call settings 190 * Notify peer that we are changing codec settings.
248 *
249 * @param av Handler.
250 * @return int
251 * @retval 0 Success.
252 * @retval ToxAvError On error.
253 */ 191 */
254int toxav_change_settings(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings); 192int toxav_change_settings(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings);
255 193
256/** 194/**
257 * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer. 195 * Terminate transmission. Note that transmission will be
258 * 196 * terminated without informing remote peer. Usually called when we can't inform peer.
259 * @param av Handler.
260 * @return int
261 * @retval 0 Success.
262 * @retval ToxAvError On error.
263 */ 197 */
264int toxav_stop_call(ToxAv *av, int32_t call_index); 198int toxav_stop_call(ToxAv *av, int32_t call_index);
265 199
266/** 200/**
267 * @brief Must be call before any RTP transmission occurs. 201 * Allocates transmission data. Must be call before calling toxav_prepare_* and toxav_send_*.
268 * 202 * Also, it must be called when call is started
269 * @param av Handler.
270 * @param support_video Is video supported ? 1 : 0
271 * @return int
272 * @retval 0 Success.
273 * @retval ToxAvError On error.
274 */ 203 */
275int toxav_prepare_transmission(ToxAv *av, int32_t call_index, uint32_t jbuf_size, uint32_t VAD_treshold, 204int toxav_prepare_transmission(ToxAv *av, int32_t call_index, int support_video);
276 int support_video);
277 205
278/** 206/**
279 * @brief Call this at the end of the transmission. 207 * Clears transmission data. Call this at the end of the transmission.
280 *
281 * @param av Handler.
282 * @return int
283 * @retval 0 Success.
284 * @retval ToxAvError On error.
285 */ 208 */
286int toxav_kill_transmission(ToxAv *av, int32_t call_index); 209int toxav_kill_transmission(ToxAv *av, int32_t call_index);
287 210
288/** 211/**
289 * @brief Encode and send video packet. 212 * Encode video frame.
290 *
291 * @param av Handler.
292 * @param frame The encoded frame.
293 * @param frame_size The size of the encoded frame.
294 * @return int
295 * @retval 0 Success.
296 * @retval ToxAvError On error.
297 */ 213 */
298int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int frame_size); 214int toxav_prepare_video_frame ( ToxAv *av,
215 int32_t call_index,
216 uint8_t *dest,
217 int dest_max,
218 vpx_image_t *input);
299 219
300/** 220/**
301 * @brief Send audio frame. 221 * Send encoded video packet.
302 *
303 * @param av Handler.
304 * @param data The audio data encoded with toxav_prepare_audio_frame().
305 * @param size Its size in number of bytes.
306 * @return int
307 * @retval 0 Success.
308 * @retval ToxAvError On error.
309 */ 222 */
310int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int size); 223int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, uint32_t frame_size);
311 224
312/** 225/**
313 * @brief Encode video frame 226 * Encode audio frame.
314 *
315 * @param av Handler
316 * @param dest Where to
317 * @param dest_max Max size
318 * @param input What to encode
319 * @return int
320 * @retval ToxAvError On error.
321 * @retval >0 On success
322 */ 227 */
323int toxav_prepare_video_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input ); 228int toxav_prepare_audio_frame ( ToxAv *av,
229 int32_t call_index,
230 uint8_t *dest,
231 int dest_max,
232 const int16_t *frame,
233 int frame_size);
324 234
325/** 235/**
326 * @brief Encode audio frame 236 * Send encoded audio frame.
327 * 237 */
328 * @param av Handler 238int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int size);
329 * @param dest dest
330 * @param dest_max Max dest size
331 * @param frame The frame
332 * @param frame_size The frame size
333 * @return int
334 * @retval ToxAvError On error.
335 * @retval >0 On success
336 */
337int toxav_prepare_audio_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, const int16_t *frame,
338 int frame_size);
339 239
340/** 240/**
341 * @brief Get peer transmission type. It can either be audio or video. 241 * Get codec settings from the peer. These were exchanged during call initialization
342 * 242 * or when peer send us new csettings.
343 * @param av Handler.
344 * @param peer The peer
345 * @return int
346 * @retval ToxAvCallType On success.
347 * @retval ToxAvError On error.
348 */ 243 */
349int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSettings *dest ); 244int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSettings *dest );
350 245
351/** 246/**
352 * @brief Get id of peer participating in conversation 247 * Get friend id of peer participating in conversation.
353 *
354 * @param av Handler
355 * @param peer peer index
356 * @return int
357 * @retval ToxAvError No peer id
358 */ 248 */
359int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer ); 249int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer );
360 250
361/** 251/**
362 * @brief Get current call state 252 * Get current call state.
363 *
364 * @param av Handler
365 * @param call_index What call
366 * @return int
367 * @retval ToxAvCallState State id
368 */ 253 */
369ToxAvCallState toxav_get_call_state ( ToxAv *av, int32_t call_index ); 254ToxAvCallState toxav_get_call_state ( ToxAv *av, int32_t call_index );
255
370/** 256/**
371 * @brief Is certain capability supported 257 * Is certain capability supported. Used to determine if encoding/decoding is ready.
372 *
373 * @param av Handler
374 * @return int
375 * @retval 1 Yes.
376 * @retval 0 No.
377 */ 258 */
378int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability ); 259int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability );
379 260
261/**
262 * Returns tox reference.
263 */
264Tox *toxav_get_tox (ToxAv *av);
380 265
381Tox *toxav_get_tox(ToxAv *av); 266/**
267 * Set VAD activity treshold for calculating VAD. 40 is some middle value for treshold
268 */
269int toxav_set_vad_treshold (ToxAv* av, int32_t call_index, uint32_t treshold);
382 270
383int toxav_has_activity ( ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t frame_size, float ref_energy ); 271/**
272 * Check if there is activity in the PCM data.
273 * Activity is present if the calculated PCM energy is > ref_energy.
274 * Returns bool.
275 */
276int toxav_has_activity ( ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t frame_size, float ref);
384 277
278/**
279 * Returns number of active calls or -1 on error.
280 */
281int toxav_get_active_count (ToxAv *av);
385 282
386/* Create a new toxav group. 283/* Create a new toxav group.
387 * 284 *