summaryrefslogtreecommitdiff
path: root/toxav/codec.c
diff options
context:
space:
mode:
authorirungentoo <irungentoo@gmail.com>2014-11-24 20:24:59 -0500
committerirungentoo <irungentoo@gmail.com>2014-11-24 20:24:59 -0500
commit279c33c01a9ca721b986aabf72fa982936b20c9e (patch)
tree4c0d289c6d74788989024485d44a4f5c7fec6efc /toxav/codec.c
parentc67bc3399faae541d64309412326ae92262b1282 (diff)
parent386c9748d48d3bb4513e8e5c32e2b30a4d6a00d4 (diff)
Merge branch 'master' of https://github.com/mannol/toxcore
Diffstat (limited to 'toxav/codec.c')
-rw-r--r--toxav/codec.c606
1 files changed, 506 insertions, 100 deletions
diff --git a/toxav/codec.c b/toxav/codec.c
index 2f00319f..e0b004a4 100644
--- a/toxav/codec.c
+++ b/toxav/codec.c
@@ -32,11 +32,107 @@
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)
69{
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
83 if (b->end == b->start) b->start = (b->start + 1) % b->size; /* full, overwrite */
84}
85
86static void buffer_read(PayloadBuffer *b, Payload **p)
87{
88 *p = b->packets[b->start];
89 b->start = (b->start + 1) % b->size;
90}
91
92static void buffer_clear(PayloadBuffer *b)
93{
94 while (!buffer_empty(b)) {
95 Payload *p;
96 buffer_read(b, &p);
97 free(p);
98 }
99}
100
101static PayloadBuffer *buffer_new(int size)
102{
103 PayloadBuffer *buf = calloc(sizeof(PayloadBuffer), 1);
104
105 if (!buf) return NULL;
106
107 buf->size = size + 1; /* include empty elem */
108
109 if (!(buf->packets = calloc(buf->size, sizeof(Payload *)))) {
110 free(buf);
111 return NULL;
112 }
113
114 return buf;
115}
116
117static void buffer_free(PayloadBuffer *b)
118{
119 if (b) {
120 buffer_clear(b);
121 free(b->packets);
122 free(b);
123 }
124}
125
126/* JITTER BUFFER WORK */
127typedef struct _JitterBuffer {
128 RTPMessage **queue;
129 uint32_t size;
130 uint32_t capacity;
131 uint16_t bottom;
132 uint16_t top;
133} JitterBuffer;
134
135static JitterBuffer *jbuf_new(uint32_t capacity)
40{ 136{
41 unsigned int size = 1; 137 unsigned int size = 1;
42 138
@@ -58,7 +154,7 @@ JitterBuffer *create_queue(unsigned int capacity)
58 return q; 154 return q;
59} 155}
60 156
61static void clear_queue(JitterBuffer *q) 157static void jbuf_clear(JitterBuffer *q)
62{ 158{
63 for (; q->bottom != q->top; ++q->bottom) { 159 for (; q->bottom != q->top; ++q->bottom) {
64 if (q->queue[q->bottom % q->size]) { 160 if (q->queue[q->bottom % q->size]) {
@@ -68,25 +164,25 @@ static void clear_queue(JitterBuffer *q)
68 } 164 }
69} 165}
70 166
71void terminate_queue(JitterBuffer *q) 167static void jbuf_free(JitterBuffer *q)
72{ 168{
73 if (!q) return; 169 if (!q) return;
74 170
75 clear_queue(q); 171 jbuf_clear(q);
76 free(q->queue); 172 free(q->queue);
77 free(q); 173 free(q);
78} 174}
79 175
80void queue(JitterBuffer *q, RTPMessage *pk) 176static void jbuf_write(JitterBuffer *q, RTPMessage *m)
81{ 177{
82 uint16_t sequnum = pk->header->sequnum; 178 uint16_t sequnum = m->header->sequnum;
83 179
84 unsigned int num = sequnum % q->size; 180 unsigned int num = sequnum % q->size;
85 181
86 if ((uint32_t)(sequnum - q->bottom) > q->size) { 182 if ((uint32_t)(sequnum - q->bottom) > q->size) {
87 clear_queue(q); 183 jbuf_clear(q);
88 q->bottom = sequnum; 184 q->bottom = sequnum;
89 q->queue[num] = pk; 185 q->queue[num] = m;
90 q->top = sequnum + 1; 186 q->top = sequnum + 1;
91 return; 187 return;
92 } 188 }
@@ -94,14 +190,16 @@ void queue(JitterBuffer *q, RTPMessage *pk)
94 if (q->queue[num]) 190 if (q->queue[num])
95 return; 191 return;
96 192
97 q->queue[num] = pk; 193 q->queue[num] = m;
98 194
99 if ((sequnum - q->bottom) >= (q->top - q->bottom)) 195 if ((sequnum - q->bottom) >= (q->top - q->bottom))
100 q->top = sequnum + 1; 196 q->top = sequnum + 1;
101} 197}
102 198
103/* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */ 199/* Success is 0 when there is nothing to dequeue,
104RTPMessage *dequeue(JitterBuffer *q, int *success) 200 * 1 when there's a good packet,
201 * 2 when there's a lost packet */
202static RTPMessage *jbuf_read(JitterBuffer *q, int32_t *success)
105{ 203{
106 if (q->top == q->bottom) { 204 if (q->top == q->bottom) {
107 *success = 0; 205 *success = 0;
@@ -128,8 +226,7 @@ RTPMessage *dequeue(JitterBuffer *q, int *success)
128 return NULL; 226 return NULL;
129} 227}
130 228
131 229static int init_video_decoder(CSSession *cs)
132int init_video_decoder(CodecState *cs)
133{ 230{
134 int rc = vpx_codec_dec_init_ver(&cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0, VPX_DECODER_ABI_VERSION); 231 int rc = vpx_codec_dec_init_ver(&cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0, VPX_DECODER_ABI_VERSION);
135 232
@@ -141,63 +238,20 @@ int init_video_decoder(CodecState *cs)
141 return 0; 238 return 0;
142} 239}
143 240
144int init_audio_decoder(CodecState *cs, uint32_t audio_channels) 241static int init_audio_decoder(CSSession *cs)
145{ 242{
146 int rc; 243 int rc;
147 cs->audio_decoder = opus_decoder_create(cs->audio_sample_rate, audio_channels, &rc ); 244 cs->audio_decoder = opus_decoder_create(cs->audio_decoder_sample_rate, cs->audio_decoder_channels, &rc );
148 245
149 if ( rc != OPUS_OK ) { 246 if ( rc != OPUS_OK ) {
150 LOGGER_ERROR("Error while starting audio decoder: %s", opus_strerror(rc)); 247 LOGGER_ERROR("Error while starting audio decoder: %s", opus_strerror(rc));
151 return -1; 248 return -1;
152 } 249 }
153 250
154 cs->audio_decoder_channels = audio_channels;
155 return 0; 251 return 0;
156} 252}
157 253
158int reconfigure_video_encoder_resolution(CodecState *cs, uint16_t width, uint16_t height) 254static 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{ 255{
202 vpx_codec_enc_cfg_t cfg; 256 vpx_codec_enc_cfg_t cfg;
203 int rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0); 257 int rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0);
@@ -219,7 +273,6 @@ int init_video_encoder(CodecState *cs, uint16_t max_width, uint16_t max_height,
219 273
220 cs->max_width = max_width; 274 cs->max_width = max_width;
221 cs->max_height = max_height; 275 cs->max_height = max_height;
222 cs->bitrate = video_bitrate;
223 276
224 rc = vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION); 277 rc = vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION);
225 278
@@ -238,17 +291,18 @@ int init_video_encoder(CodecState *cs, uint16_t max_width, uint16_t max_height,
238 return 0; 291 return 0;
239} 292}
240 293
241int init_audio_encoder(CodecState *cs, uint32_t audio_channels) 294static int init_audio_encoder(CSSession *cs)
242{ 295{
243 int rc = OPUS_OK; 296 int rc = OPUS_OK;
244 cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, audio_channels, OPUS_APPLICATION_AUDIO, &rc); 297 cs->audio_encoder = opus_encoder_create(cs->audio_encoder_sample_rate,
298 cs->audio_encoder_channels, OPUS_APPLICATION_AUDIO, &rc);
245 299
246 if ( rc != OPUS_OK ) { 300 if ( rc != OPUS_OK ) {
247 LOGGER_ERROR("Error while starting audio encoder: %s", opus_strerror(rc)); 301 LOGGER_ERROR("Error while starting audio encoder: %s", opus_strerror(rc));
248 return -1; 302 return -1;
249 } 303 }
250 304
251 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate)); 305 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_encoder_bitrate));
252 306
253 if ( rc != OPUS_OK ) { 307 if ( rc != OPUS_OK ) {
254 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc)); 308 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc));
@@ -262,57 +316,309 @@ int init_audio_encoder(CodecState *cs, uint32_t audio_channels)
262 return -1; 316 return -1;
263 } 317 }
264 318
265 cs->audio_encoder_channels = audio_channels;
266 return 0; 319 return 0;
267} 320}
268 321
322static float calculate_sum_sq (int16_t *n, uint16_t k)
323{
324 float result = 0;
325 uint16_t i = 0;
326
327 for ( ; i < k; i ++) result += (float) (n[i] * n[i]);
269 328
270CodecState *codec_init_session ( uint32_t audio_bitrate, 329 return result;
271 uint16_t audio_frame_duration, 330}
272 uint32_t audio_sample_rate, 331
273 uint32_t encoder_audio_channels, 332
274 uint32_t decoder_audio_channels, 333
275 uint32_t audio_VAD_tolerance_ms, 334/* PUBLIC */
276 uint16_t max_video_width, 335int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length)
277 uint16_t max_video_height,
278 uint32_t video_bitrate )
279{ 336{
280 CodecState *retu = calloc(sizeof(CodecState), 1); 337 if (!cs || !length || length > cs->max_video_frame_size) {
338 LOGGER_ERROR("Invalid CodecState or video frame size: %u", length);
339 return -1;
340 }
281 341
282 if (!retu) return NULL; 342 cs->split_video_frame[0] = cs->frameid_out++;
343 cs->split_video_frame[1] = 0;
344 cs->processing_video_frame = payload;
345 cs->processing_video_frame_size = length;
283 346
284 retu->audio_bitrate = audio_bitrate; 347 return ((length - 1) / cs->video_frame_piece_size) + 1;
285 retu->audio_sample_rate = audio_sample_rate; 348}
286 349
287 /* Encoders */ 350const uint8_t *cs_get_split_video_frame(CSSession *cs, uint16_t *size)
288 if (!max_video_width || !max_video_height) { /* Disable video */ 351{
289 /*video_width = 320; 352 if (!cs || !size) return NULL;
290 video_height = 240; */ 353
354 if (cs->processing_video_frame_size > cs->video_frame_piece_size) {
355 memcpy(cs->split_video_frame + VIDEOFRAME_HEADER_SIZE,
356 cs->processing_video_frame,
357 cs->video_frame_piece_size);
358
359 cs->processing_video_frame += cs->video_frame_piece_size;
360 cs->processing_video_frame_size -= cs->video_frame_piece_size;
361
362 *size = cs->video_frame_piece_size + VIDEOFRAME_HEADER_SIZE;
291 } else { 363 } else {
292 retu->capabilities |= ( 0 == init_video_encoder(retu, max_video_width, max_video_height, 364 memcpy(cs->split_video_frame + VIDEOFRAME_HEADER_SIZE,
293 video_bitrate) ) ? v_encoding : 0; 365 cs->processing_video_frame,
294 retu->capabilities |= ( 0 == init_video_decoder(retu) ) ? v_decoding : 0; 366 cs->processing_video_frame_size);
367
368 *size = cs->processing_video_frame_size + VIDEOFRAME_HEADER_SIZE;
369 }
370
371 cs->split_video_frame[1]++;
372
373 return cs->split_video_frame;
374}
375
376void cs_do(CSSession *cs)
377{
378 if (!cs) return;
379
380 pthread_mutex_lock(cs->queue_mutex);
381 /*
382 if (!cs->active) {
383 pthread_mutex_unlock(cs->queue_mutex);
384 return;
385 }
386
387 /* Iterate over whole buffers and call playback callback * /
388 if (cs->abuf_ready) while (!DecodedAudioBuffer_empty(cs->abuf_ready)) {
389 DecodedAudio* p;
390 DecodedAudioBuffer_read(cs->abuf_ready, &p);
391 if (apcallback.first)
392 apcallback.first(cs->agent, cs->call_idx, p->data, p->size, apcallback.second);
393
394 free(p);
395 }
396
397 if (cs->vbuf_ready) while (!DecodedVideoBuffer_empty(cs->vbuf_ready)) {
398 vpx_image_t* p;
399 DecodedVideoBuffer_read(cs->vbuf_ready, &p);
400 if (vpcallback.first)
401 vpcallback.first(cs->agent, cs->call_idx, p, vpcallback.second);
402
403 vpx_img_free(p);
404 }
405 */
406
407 Payload *p;
408 int rc;
409
410 if (cs->abuf_raw && !buffer_empty(cs->abuf_raw)) {
411 /* Decode audio */
412 buffer_read(cs->abuf_raw, &p);
413
414 uint16_t fsize = (cs->audio_decoder_channels *
415 (cs->audio_decoder_sample_rate * cs->audio_decoder_frame_duration) / 1000);
416 int16_t tmp[fsize];
417
418 rc = opus_decode(cs->audio_decoder, p->data, p->size, tmp, fsize, (p->size == 0));
419 free(p);
420
421 if (rc < 0)
422 LOGGER_WARNING("Decoding error: %s", opus_strerror(rc));
423 else
424 /* Play */
425 apcallback.first(cs->agent, cs->call_idx, tmp, rc, apcallback.second);
426 }
427
428 if (cs->vbuf_raw && !buffer_empty(cs->vbuf_raw)) {
429 /* Decode video */
430 buffer_read(cs->vbuf_raw, &p);
431
432 rc = vpx_codec_decode(&cs->v_decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US);
433 free(p);
434
435 if (rc != VPX_CODEC_OK) {
436 LOGGER_ERROR("Error decoding video: %s", vpx_codec_err_to_string(rc));
437 } else {
438 vpx_codec_iter_t iter = NULL;
439 vpx_image_t *dest = vpx_codec_get_frame(&cs->v_decoder, &iter);
440
441 /* Play decoded images */
442 for (; dest; dest = vpx_codec_get_frame(&cs->v_decoder, &iter)) {
443 vpcallback.first(cs->agent, cs->call_idx, dest, vpcallback.second);
444 vpx_img_free(dest);
445 }
446 }
447 }
448
449 pthread_mutex_unlock(cs->queue_mutex);
450}
451
452void cs_register_audio_callback(CSAudioCallback cb, void *data)
453{
454 apcallback.first = cb;
455 apcallback.second = data;
456}
457
458void cs_register_video_callback(CSVideoCallback cb, void *data)
459{
460 vpcallback.first = cb;
461 vpcallback.second = data;
462}
463
464int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height)
465{
466 vpx_codec_enc_cfg_t cfg = *cs->v_encoder.config.enc;
467
468 if (cfg.g_w == width && cfg.g_h == height)
469 return 0;
470
471 if (width * height > cs->max_width * cs->max_height)
472 return -1;
473
474 LOGGER_DEBUG("New video resolution: %u %u", width, height);
475 cfg.g_w = width;
476 cfg.g_h = height;
477 int rc = vpx_codec_enc_config_set(&cs->v_encoder, &cfg);
478
479 if ( rc != VPX_CODEC_OK) {
480 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
481 return -1;
482 }
483
484 return 0;
485}
486
487int cs_set_video_encoder_bitrate(CSSession *cs, uint32_t video_bitrate)
488{
489 vpx_codec_enc_cfg_t cfg = *cs->v_encoder.config.enc;
490
491 if (cfg.rc_target_bitrate == video_bitrate)
492 return 0;
493
494 LOGGER_DEBUG("New video bitrate: %u", video_bitrate);
495 cfg.rc_target_bitrate = video_bitrate;
496 int rc = vpx_codec_enc_config_set(&cs->v_encoder, &cfg);
497
498 if ( rc != VPX_CODEC_OK) {
499 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
500 return -1;
295 } 501 }
296 502
297 retu->capabilities |= ( 0 == init_audio_encoder(retu, encoder_audio_channels) ) ? a_encoding : 0; 503 return 0;
298 retu->capabilities |= ( 0 == init_audio_decoder(retu, decoder_audio_channels) ) ? a_decoding : 0; 504}
505
506CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer, uint32_t jbuf_size, int has_video)
507{
508 CSSession *cs = calloc(sizeof(CSSession), 1);
299 509
300 if ( retu->capabilities == 0 ) { /* everything failed */ 510 if (!cs) {
301 free (retu); 511 LOGGER_WARNING("Allocation failed! Application might misbehave!");
302 return NULL; 512 return NULL;
303 } 513 }
304 514
515 if ( !(cs->j_buf = jbuf_new(jbuf_size)) ) {
516 LOGGER_WARNING("Jitter buffer creaton failed!");
517 goto error;
518 }
519
520 cs->audio_encoder_bitrate = cs_self->audio_bitrate;
521 cs->audio_encoder_sample_rate = cs_self->audio_sample_rate;
522 cs->audio_encoder_channels = cs_self->audio_channels;
523 cs->audio_encoder_frame_duration = cs_self->audio_frame_duration;
524
525 cs->audio_decoder_bitrate = cs_peer->audio_bitrate;
526 cs->audio_decoder_sample_rate = cs_peer->audio_sample_rate;
527 cs->audio_decoder_channels = cs_peer->audio_channels;
528 cs->audio_decoder_frame_duration = cs_peer->audio_frame_duration;
305 529
306 retu->EVAD_tolerance = audio_VAD_tolerance_ms > audio_frame_duration ?
307 audio_VAD_tolerance_ms / audio_frame_duration : audio_frame_duration;
308 530
309 return retu; 531 cs->capabilities |= ( 0 == init_audio_encoder(cs) ) ? a_encoding : 0;
532 cs->capabilities |= ( 0 == init_audio_decoder(cs) ) ? a_decoding : 0;
533
534 if ( !(cs->capabilities & a_encoding) || !(cs->capabilities & a_decoding) ) goto error;
535
536 if ( !(cs->abuf_raw = buffer_new(jbuf_size)) ) goto error;
537
538 pthread_mutexattr_t attr;
539
540 if (pthread_mutexattr_init(&attr) != 0) goto error;
541
542 if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) {
543 if (pthread_mutexattr_destroy(&attr) != 0)
544 LOGGER_WARNING("Failed to destroy mutex attribute!");
545
546 goto error;
547 }
548
549 if (pthread_mutex_init(cs->queue_mutex, &attr) != 0) {
550 pthread_mutexattr_destroy(&attr);
551 goto error;
552 }
553
554 if ((cs->support_video = has_video)) {
555 cs->max_video_frame_size = MAX_VIDEOFRAME_SIZE;
556 cs->video_frame_piece_size = VIDEOFRAME_PIECE_SIZE;
557
558 cs->capabilities |= ( 0 == init_video_encoder(cs, cs_self->max_video_width,
559 cs_self->max_video_height, cs_self->video_bitrate) ) ? v_encoding : 0;
560 cs->capabilities |= ( 0 == init_video_decoder(cs) ) ? v_decoding : 0;
561
562 if ( !(cs->capabilities & v_encoding) || !(cs->capabilities & v_decoding) ) goto error;
563
564 if ( !(cs->frame_buf = calloc(cs->max_video_frame_size, 1)) ) goto error;
565
566 if ( !(cs->split_video_frame = calloc(cs->video_frame_piece_size + VIDEOFRAME_HEADER_SIZE, 1)) )
567 goto error;
568
569 if ( !(cs->vbuf_raw = buffer_new(VIDEO_DECODE_BUFFER_SIZE)) ) goto error;
570 }
571
572 if (pthread_mutexattr_destroy(&attr) != 0)
573 LOGGER_WARNING("Failed to destroy mutex attribute!");
574
575
576 cs->active = 1;
577 return cs;
578
579error:
580 LOGGER_WARNING("Error initializing codec session! Application might misbehave!");
581
582 buffer_free(cs->abuf_raw);
583
584 if ( cs->audio_encoder ) opus_encoder_destroy(cs->audio_encoder);
585
586 if ( cs->audio_decoder ) opus_decoder_destroy(cs->audio_decoder);
587
588
589 if (has_video) {
590 if ( cs->capabilities & v_decoding ) vpx_codec_destroy(&cs->v_decoder);
591
592 if ( cs->capabilities & v_encoding ) vpx_codec_destroy(&cs->v_encoder);
593
594 buffer_free(cs->vbuf_raw);
595
596 free(cs->frame_buf);
597 free(cs->split_video_frame);
598 }
599
600 jbuf_free(cs->j_buf);
601 free(cs);
602
603 return NULL;
310} 604}
311 605
312void codec_terminate_session ( CodecState *cs ) 606void cs_kill(CSSession *cs)
313{ 607{
314 if (!cs) return; 608 if (!cs) return;
315 609
610 /* Lock running mutex and signal that cs is no longer active */
611 pthread_mutex_lock(cs->queue_mutex);
612 cs->active = 0;
613
614 /* Wait threads to close */
615 pthread_mutex_unlock(cs->queue_mutex);
616 pthread_mutex_lock(cs->queue_mutex);
617 pthread_mutex_unlock(cs->queue_mutex);
618
619 pthread_mutex_destroy(cs->queue_mutex);
620
621
316 if ( cs->audio_encoder ) 622 if ( cs->audio_encoder )
317 opus_encoder_destroy(cs->audio_encoder); 623 opus_encoder_destroy(cs->audio_encoder);
318 624
@@ -325,21 +631,21 @@ void codec_terminate_session ( CodecState *cs )
325 if ( cs->capabilities & v_encoding ) 631 if ( cs->capabilities & v_encoding )
326 vpx_codec_destroy(&cs->v_encoder); 632 vpx_codec_destroy(&cs->v_encoder);
327 633
634 jbuf_free(cs->j_buf);
635 buffer_free(cs->abuf_raw);
636 buffer_free(cs->vbuf_raw);
637 free(cs->frame_buf);
638
328 LOGGER_DEBUG("Terminated codec state: %p", cs); 639 LOGGER_DEBUG("Terminated codec state: %p", cs);
329 free(cs); 640 free(cs);
330} 641}
331 642
332static float calculate_sum_sq (int16_t *n, uint16_t k) 643void cs_set_vad_treshold(CSSession *cs, uint32_t treshold, uint16_t frame_duration)
333{ 644{
334 float result = 0; 645 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} 646}
341 647
342int energy_VAD(CodecState *cs, int16_t *PCM, uint16_t frame_size, float energy) 648int cs_calculate_vad(CSSession *cs, int16_t *PCM, uint16_t frame_size, float energy)
343{ 649{
344 float frame_energy = sqrt(calculate_sum_sq(PCM, frame_size)) / frame_size; 650 float frame_energy = sqrt(calculate_sum_sq(PCM, frame_size)) / frame_size;
345 651
@@ -355,3 +661,103 @@ int energy_VAD(CodecState *cs, int16_t *PCM, uint16_t frame_size, float energy)
355 661
356 return 0; 662 return 0;
357} 663}
664
665
666
667
668/* Called from RTP */
669void queue_message(RTPSession *session, RTPMessage *msg)
670{
671 CSSession *cs = session->cs;
672
673 if (!cs || !cs->active) return;
674
675 /* Audio */
676 if (session->payload_type == type_audio % 128) {
677 jbuf_write(cs->j_buf, msg);
678
679 pthread_mutex_lock(cs->queue_mutex);
680 int success = 0;
681
682 while ((msg = jbuf_read(cs->j_buf, &success)) || success == 2) {
683 Payload *p;
684
685 if (success == 2) {
686 p = malloc(sizeof(Payload));
687
688 if (p) p->size = 0;
689
690 } else {
691 p = malloc(sizeof(Payload) + msg->length);
692
693 if (p) {
694 p->size = msg->length;
695 memcpy(p->data, msg->data, msg->length);
696 }
697
698 rtp_free_msg(NULL, msg);
699 }
700
701 if (p) {
702 buffer_write(cs->abuf_raw, p);
703 } else {
704 LOGGER_WARNING("Allocation failed! Program might misbehave!");
705 }
706 }
707
708 pthread_mutex_unlock(cs->queue_mutex);
709 }
710 /* Video */
711 else {
712 uint8_t *packet = msg->data;
713 uint32_t packet_size = msg->length;
714
715 if (packet_size < VIDEOFRAME_HEADER_SIZE)
716 goto end;
717
718 if (packet[0] > cs->frameid_in || (msg->header->timestamp > cs->last_timestamp)) { /* New frame */
719 /* Flush last frames' data and get ready for this frame */
720 Payload *p = malloc(sizeof(Payload) + cs->frame_size);
721
722 if (p) {
723 pthread_mutex_lock(cs->queue_mutex);
724
725 if (buffer_full(cs->vbuf_raw)) {
726 LOGGER_DEBUG("Dropped video frame");
727 Payload *tp;
728 buffer_read(cs->vbuf_raw, &tp);
729 free(tp);
730 } else {
731 p->size = cs->frame_size;
732 memcpy(p->data, cs->frame_buf, cs->frame_size);
733 }
734
735 buffer_write(cs->vbuf_raw, p);
736 pthread_mutex_unlock(cs->queue_mutex);
737 } else {
738 LOGGER_WARNING("Allocation failed! Program might misbehave!");
739 goto end;
740 }
741
742 cs->last_timestamp = msg->header->timestamp;
743 cs->frameid_in = packet[0];
744 memset(cs->frame_buf, 0, cs->frame_size);
745 cs->frame_size = 0;
746
747 } else if (packet[0] < cs->frameid_in) { /* Old frame; drop */
748 LOGGER_DEBUG("Old packet: %u", packet[0]);
749 goto end;
750 }
751
752 /* Otherwise it's part of the frame so just process */
753 /* LOGGER_DEBUG("Video Packet: %u %u", packet[0], packet[1]); */
754 memcpy(cs->frame_buf + cs->frame_size,
755 packet + VIDEOFRAME_HEADER_SIZE,
756 packet_size - VIDEOFRAME_HEADER_SIZE);
757
758 cs->frame_size += packet_size - VIDEOFRAME_HEADER_SIZE;
759
760end:
761 rtp_free_msg(NULL, msg);
762 }
763} \ No newline at end of file