summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--toxav/codec.c594
-rw-r--r--toxav/codec.h60
-rw-r--r--toxav/rtp.c4
-rw-r--r--toxav/rtp.h2
-rw-r--r--toxav/toxav.c16
-rw-r--r--toxav/toxav_new.c250
-rw-r--r--toxav/toxav_new.h8
7 files changed, 587 insertions, 347 deletions
diff --git a/toxav/codec.c b/toxav/codec.c
index fd2f9f93..43120e0f 100644
--- a/toxav/codec.c
+++ b/toxav/codec.c
@@ -229,271 +229,127 @@ static RTPMessage *jbuf_read(JitterBuffer *q, int32_t *success)
229 return NULL; 229 return NULL;
230} 230}
231 231
232 232static int convert_bw_to_sampling_rate(int bw)
233
234
235
236/* PUBLIC */
237int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length)
238{ 233{
239 if (!cs || !length || length > cs->max_video_frame_size) { 234 switch(bw)
240 LOGGER_ERROR("Invalid CodecState or video frame size: %u", length); 235 {
241 return cs_ErrorSplittingVideoPayload; 236 case OPUS_BANDWIDTH_NARROWBAND: return 8000;
237 case OPUS_BANDWIDTH_MEDIUMBAND: return 12000;
238 case OPUS_BANDWIDTH_WIDEBAND: return 16000;
239 case OPUS_BANDWIDTH_SUPERWIDEBAND: return 24000;
240 case OPUS_BANDWIDTH_FULLBAND: return 48000;
241 default: return -1;
242 } 242 }
243
244 cs->split_video_frame[0] = cs->frameid_out++;
245 cs->split_video_frame[1] = 0;
246 cs->processing_video_frame = payload;
247 cs->processing_video_frame_size = length;
248
249 return ((length - 1) / cs->video_frame_piece_size) + 1;
250} 243}
251 244
252const uint8_t *cs_get_split_video_frame(CSSession *cs, uint16_t *size)
253{
254 if (!cs || !size) return NULL;
255
256 if (cs->processing_video_frame_size > cs->video_frame_piece_size) {
257 memcpy(cs->split_video_frame + VIDEOFRAME_HEADER_SIZE,
258 cs->processing_video_frame,
259 cs->video_frame_piece_size);
260
261 cs->processing_video_frame += cs->video_frame_piece_size;
262 cs->processing_video_frame_size -= cs->video_frame_piece_size;
263
264 *size = cs->video_frame_piece_size + VIDEOFRAME_HEADER_SIZE;
265 } else {
266 memcpy(cs->split_video_frame + VIDEOFRAME_HEADER_SIZE,
267 cs->processing_video_frame,
268 cs->processing_video_frame_size);
269
270 *size = cs->processing_video_frame_size + VIDEOFRAME_HEADER_SIZE;
271 }
272 245
273 cs->split_video_frame[1]++;
274 246
275 return cs->split_video_frame; 247/* PUBLIC */
276}
277 248
278void cs_do(CSSession *cs) 249void cs_do(CSSession *cs)
279{ 250{
280 /* Codec session should always be protected by call mutex so no need to check for cs validity 251 /* Codec session should always be protected by call mutex so no need to check for cs validity
281 */ 252 */
282 253
283 if (!cs) return; 254 if (!cs)
284 255 return;
256
285 Payload *p; 257 Payload *p;
286 int rc; 258 int rc;
287 259
288 int success = 0; 260 int success = 0;
289 261
290 pthread_mutex_lock(cs->queue_mutex); 262 pthread_mutex_lock(cs->queue_mutex);
291 RTPMessage *msg; 263 RTPMessage *msg;
292 264
265 uint16_t fsize = 5760; /* Max frame size for 48 kHz */
266 int16_t tmp[fsize * 2];
267
293 while ((msg = jbuf_read(cs->j_buf, &success)) || success == 2) { 268 while ((msg = jbuf_read(cs->j_buf, &success)) || success == 2) {
294 pthread_mutex_unlock(cs->queue_mutex); 269 pthread_mutex_unlock(cs->queue_mutex);
295 270
296 uint16_t fsize = ((cs->audio_decoder_sample_rate * cs->audio_decoder_frame_duration) / 1000);
297 int16_t tmp[fsize * cs->audio_decoder_channels];
298
299 if (success == 2) { 271 if (success == 2) {
300 rc = opus_decode(cs->audio_decoder, 0, 0, tmp, fsize, 1); 272 rc = opus_decode(cs->audio_decoder, 0, 0, tmp, fsize, 1);
301 } else { 273 } else {
274 /* Get values from packet and decode.
275 * It also checks for validity of an opus packet
276 */
277 rc = convert_bw_to_sampling_rate(opus_packet_get_bandwidth(msg->data));
278 if (rc != -1) {
279 cs->last_packet_sampling_rate = rc;
280 cs->last_pack_channels = opus_packet_get_nb_channels(msg->data);
281
282 cs->last_packet_frame_duration =
283 ( opus_packet_get_samples_per_frame(msg->data, cs->last_packet_sampling_rate) * 1000 )
284 / cs->last_packet_sampling_rate;
285
286 } else {
287 LOGGER_WARNING("Failed to load packet values!");
288 rtp_free_msg(NULL, msg);
289 continue;
290 }
291
302 rc = opus_decode(cs->audio_decoder, msg->data, msg->length, tmp, fsize, 0); 292 rc = opus_decode(cs->audio_decoder, msg->data, msg->length, tmp, fsize, 0);
303 rtp_free_msg(NULL, msg); 293 rtp_free_msg(NULL, msg);
304 } 294 }
305 295
306 if (rc < 0) { 296 if (rc < 0) {
307 LOGGER_WARNING("Decoding error: %s", opus_strerror(rc)); 297 LOGGER_WARNING("Decoding error: %s", opus_strerror(rc));
308 } else if (cs->acb.first) { 298 } else if (((ToxAV*)cs->agent)->acb.first) {
309 /* Play */ 299 /* Play */
310 cs->acb.first(cs->agent, cs->call_idx, tmp, rc, cs->acb.second); 300 ((ToxAV*)cs->agent)->acb.first(cs->agent, cs->call_idx, tmp, rc,
301 ((ToxAV*)cs->agent)->acb.second);
311 } 302 }
312 303
313 pthread_mutex_lock(cs->queue_mutex); 304 pthread_mutex_lock(cs->queue_mutex);
314 } 305 }
315 306
316 if (cs->vbuf_raw && !buffer_empty(cs->vbuf_raw)) { 307 if (cs->vbuf_raw && !buffer_empty(cs->vbuf_raw)) {
317 /* Decode video */ 308 /* Decode video */
318 buffer_read(cs->vbuf_raw, &p); 309 buffer_read(cs->vbuf_raw, &p);
319 310
320 /* Leave space for (possibly) other thread to queue more data after we read it here */ 311 /* Leave space for (possibly) other thread to queue more data after we read it here */
321 pthread_mutex_unlock(cs->queue_mutex); 312 pthread_mutex_unlock(cs->queue_mutex);
322 313
323 rc = vpx_codec_decode(cs->v_decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US); 314 rc = vpx_codec_decode(cs->v_decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US);
324 free(p); 315 free(p);
325 316
326 if (rc != VPX_CODEC_OK) { 317 if (rc != VPX_CODEC_OK) {
327 LOGGER_ERROR("Error decoding video: %s", vpx_codec_err_to_string(rc)); 318 LOGGER_ERROR("Error decoding video: %s", vpx_codec_err_to_string(rc));
328 } else { 319 } else {
329 vpx_codec_iter_t iter = NULL; 320 vpx_codec_iter_t iter = NULL;
330 vpx_image_t *dest = vpx_codec_get_frame(cs->v_decoder, &iter); 321 vpx_image_t *dest = vpx_codec_get_frame(cs->v_decoder, &iter);
331 322
332 /* Play decoded images */ 323 /* Play decoded images */
333 for (; dest; dest = vpx_codec_get_frame(cs->v_decoder, &iter)) { 324 for (; dest; dest = vpx_codec_get_frame(cs->v_decoder, &iter)) {
334 if (cs->vcb.first) 325 if (((ToxAV*)cs->agent)->vcb.first)
335 cs->vcb.first(cs->agent, cs->call_idx, dest, cs->vcb.second); 326 ((ToxAV*)cs->agent)->vcb.first(cs->agent, cs->call_idx, dest,
336 327 ((ToxAV*)cs->agent)->vcb.second);
337 vpx_img_free(dest); 328
329 vpx_img_free(dest);
338 } 330 }
339 } 331 }
340
341 return;
342 }
343
344 pthread_mutex_unlock(cs->queue_mutex);
345}
346
347int cs_set_sending_video_resolution(CSSession *cs, uint16_t width, uint16_t height)
348{
349 if (!cs->v_encoding)
350 return -1;
351
352 /* TODO FIXME reference is safe? */
353 vpx_codec_enc_cfg_t cfg = *cs->v_encoder[0].config.enc;
354
355 if (cfg.g_w == width && cfg.g_h == height)
356 return 0;
357/*
358 if (width * height > cs->max_width * cs->max_height) {
359 vpx_codec_ctx_t v_encoder = cs->v_encoder;
360
361 if (init_video_encoder(cs, width, height, cs->video_bitrate) == -1) {
362 cs->v_encoder = v_encoder;
363 return cs_ErrorSettingVideoResolution;
364 }
365
366 vpx_codec_destroy(&v_encoder);
367 return 0;
368 }*/
369
370 LOGGER_DEBUG("New video resolution: %u %u", width, height);
371 cfg.g_w = width;
372 cfg.g_h = height;
373 int rc = vpx_codec_enc_config_set(cs->v_encoder, &cfg);
374
375 if ( rc != VPX_CODEC_OK) {
376 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
377 return cs_ErrorSettingVideoResolution;
378 }
379
380 return 0;
381}
382
383int cs_set_sending_video_bitrate(CSSession *cs, uint32_t bitrate)
384{
385 if (!cs->v_encoding)
386 return -1;
387
388 /* TODO FIXME reference is safe? */
389 vpx_codec_enc_cfg_t cfg = *cs->v_encoder[0].config.enc;
390 if (cfg.rc_target_bitrate == bitrate)
391 return 0;
392
393 LOGGER_DEBUG("New video bitrate: %u", video_bitrate);
394 cfg.rc_target_bitrate = bitrate;
395
396 int rc = vpx_codec_enc_config_set(cs->v_encoder, &cfg);
397 if ( rc != VPX_CODEC_OK) {
398 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
399 return cs_ErrorSettingVideoBitrate;
400 }
401
402 return 0;
403}
404
405int cs_set_sending_audio_bitrate(CSSession *cs, int32_t rate)
406{
407 if (cs->audio_encoder == NULL)
408 return -1;
409
410 int rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(rate));
411
412 if ( rc != OPUS_OK ) {
413 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc));
414 return -1;
415 }
416
417 return 0;
418}
419
420int cs_set_sending_audio_sampling_rate(CSSession* cs, int32_t rate)
421{
422 /* TODO Find a better way? */
423 if (cs->audio_encoder == NULL)
424 return -1;
425
426 int rc = OPUS_OK;
427 int last_rate = 0;
428
429 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(&last_rate));
430
431 if ( rc != OPUS_OK ) {
432 LOGGER_ERROR("Error while getting encoder ctl: %s", opus_strerror(rc));
433 return -1;
434 }
435
436 if (rate == last_rate)
437 return 0;
438 332
439 OpusEncoder* new_enc = opus_encoder_create(rate, cs->channels, OPUS_APPLICATION_AUDIO, &rc); 333 return;
440
441 if ( rc != OPUS_OK ) {
442 LOGGER_ERROR("Error while starting audio encoder: %s", opus_strerror(rc));
443 return -1;
444 }
445
446 opus_encoder_destroy(cs->audio_encoder);
447 cs->audio_encoder = new_enc;
448 return 0;
449}
450
451int cs_set_sending_audio_channels(CSSession* cs, int32_t count)
452{
453 /* TODO Find a better way? */
454 if (cs->audio_encoder == NULL)
455 return -1;
456
457 if (cs->channels == count)
458 return 0;
459
460 int rc = OPUS_OK;
461 int bitrate = 0;
462
463 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(&bitrate));
464
465 if ( rc != OPUS_OK ) {
466 LOGGER_ERROR("Error while getting encoder ctl: %s", opus_strerror(rc));
467 return -1;
468 }
469
470 cs->channels = count;
471 OpusEncoder* new_enc = opus_encoder_create(bitrate, cs->channels, OPUS_APPLICATION_AUDIO, &rc);
472
473 if ( rc != OPUS_OK ) {
474 LOGGER_ERROR("Error while starting audio encoder: %s", opus_strerror(rc));
475 return -1;
476 } 334 }
477 335
478 opus_encoder_destroy(cs->audio_encoder); 336 pthread_mutex_unlock(cs->queue_mutex);
479 cs->audio_encoder = new_enc;
480 return 0;
481} 337}
482 338
483CSSession *cs_new(uint32_t s_audio_b, uint32_t p_audio_b, uint32_t s_video_b, uint32_t p_video_b) 339CSSession *cs_new(uint32_t s_audio_b, uint32_t p_audio_b, uint32_t s_video_b, uint32_t p_video_b)
484{ 340{
485 CSSession *cs = calloc(sizeof(CSSession), 1); 341 CSSession *cs = calloc(sizeof(CSSession), 1);
486 342
487 if (!cs) { 343 if (!cs) {
488 LOGGER_WARNING("Allocation failed! Application might misbehave!"); 344 LOGGER_WARNING("Allocation failed! Application might misbehave!");
489 return NULL; 345 return NULL;
490 } 346 }
491 347
492 /* TODO this has to be exchanged in msi */ 348 /* TODO this has to be exchanged in msi */
493 cs->max_video_frame_size = MAX_VIDEOFRAME_SIZE; 349 cs->max_video_frame_size = MAX_VIDEOFRAME_SIZE;
494 cs->video_frame_piece_size = VIDEOFRAME_PIECE_SIZE; 350 cs->video_frame_piece_size = VIDEOFRAME_PIECE_SIZE;
495 351
496 if (s_audio_b > 0 && 0 != cs_enable_audio_sending(cs, s_audio_b)) { /* Sending audio enabled */ 352 if (s_audio_b > 0 && 0 != cs_enable_audio_sending(cs, s_audio_b, 2)) { /* Sending audio enabled */
497 LOGGER_WARNING("Failed to enable audio sending!"); 353 LOGGER_WARNING("Failed to enable audio sending!");
498 goto FAILURE; 354 goto FAILURE;
499 } 355 }
@@ -502,29 +358,29 @@ CSSession *cs_new(uint32_t s_audio_b, uint32_t p_audio_b, uint32_t s_video_b, ui
502 LOGGER_WARNING("Failed to enable audio receiving!"); 358 LOGGER_WARNING("Failed to enable audio receiving!");
503 goto FAILURE; 359 goto FAILURE;
504 } 360 }
505 361
506 if (s_video_b > 0 && 0 != cs_enable_video_sending(cs, s_video_b)) { /* Sending video enabled */ 362 if (s_video_b > 0 && 0 != cs_enable_video_sending(cs, s_video_b)) { /* Sending video enabled */
507 LOGGER_WARNING("Failed to enable video sending!"); 363 LOGGER_WARNING("Failed to enable video sending!");
508 goto FAILURE; 364 goto FAILURE;
509 } 365 }
510 366
511 if (p_video_b > 0 && 0 != cs_enable_video_receiving(cs)) { /* Receiving video enabled */ 367 if (p_video_b > 0 && 0 != cs_enable_video_receiving(cs)) { /* Receiving video enabled */
512 LOGGER_WARNING("Failed to enable video receiving!"); 368 LOGGER_WARNING("Failed to enable video receiving!");
513 goto FAILURE; 369 goto FAILURE;
514 } 370 }
515 371
516 return cs; 372 return cs;
517 373
518FAILURE: 374 FAILURE:
519 LOGGER_WARNING("Error initializing codec session! Application might misbehave!"); 375 LOGGER_WARNING("Error initializing codec session! Application might misbehave!");
520 376
521 cs_disable_audio_sending(cs); 377 cs_disable_audio_sending(cs);
522 cs_disable_audio_receiving(cs); 378 cs_disable_audio_receiving(cs);
523 cs_disable_video_sending(cs); 379 cs_disable_video_sending(cs);
524 cs_disable_video_receiving(cs); 380 cs_disable_video_receiving(cs);
525 381
526 free(cs); 382 free(cs);
527 383
528 return NULL; 384 return NULL;
529} 385}
530 386
@@ -532,7 +388,7 @@ void cs_kill(CSSession *cs)
532{ 388{
533 if (!cs) 389 if (!cs)
534 return; 390 return;
535 391
536 /* NOTE: queue_message() will not be called since 392 /* NOTE: queue_message() will not be called since
537 * the callback is unregistered before cs_kill is called. 393 * the callback is unregistered before cs_kill is called.
538 */ 394 */
@@ -541,78 +397,110 @@ void cs_kill(CSSession *cs)
541 cs_disable_audio_receiving(cs); 397 cs_disable_audio_receiving(cs);
542 cs_disable_video_sending(cs); 398 cs_disable_video_sending(cs);
543 cs_disable_video_receiving(cs); 399 cs_disable_video_receiving(cs);
544 400
545 LOGGER_DEBUG("Terminated codec state: %p", cs); 401 LOGGER_DEBUG("Terminated codec state: %p", cs);
546 free(cs); 402 free(cs);
547} 403}
548 404
549int cs_enable_audio_sending(CSSession* cs, uint32_t bitrate) 405
406
407void cs_init_video_splitter_cycle(CSSession* cs)
550{ 408{
551 if (cs->audio_encoder) 409 cs->split_video_frame[0] = cs->frameid_out++;
552 return 0; 410 cs->split_video_frame[1] = 0;
553 411}
554 /** 412
555 * Encoder is initialized with default values. These values (Sampling rate, channel count) 413int cs_update_video_splitter_cycle(CSSession *cs, const uint8_t *payload, uint16_t length)
556 * change on the fly from toxav. 414{
557 */ 415 cs->processing_video_frame = payload;
558 416 cs->processing_video_frame_size = length;
559 int rc = OPUS_OK;
560 cs->audio_encoder = opus_encoder_create(48000, 2, OPUS_APPLICATION_AUDIO, &rc);
561
562 if ( rc != OPUS_OK ) {
563 LOGGER_ERROR("Error while starting audio encoder: %s", opus_strerror(rc));
564 return -1;
565 }
566
567 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(bitrate));
568 417
569 if ( rc != OPUS_OK ) { 418 return ((length - 1) / cs->video_frame_piece_size) + 1;
570 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc)); 419}
571 goto FAILURE; 420
421const uint8_t *cs_iterate_split_video_frame(CSSession *cs, uint16_t *size)
422{
423 if (!cs || !size) return NULL;
424
425 if (cs->processing_video_frame_size > cs->video_frame_piece_size) {
426 memcpy(cs->split_video_frame + VIDEOFRAME_HEADER_SIZE,
427 cs->processing_video_frame,
428 cs->video_frame_piece_size);
429
430 cs->processing_video_frame += cs->video_frame_piece_size;
431 cs->processing_video_frame_size -= cs->video_frame_piece_size;
432
433 *size = cs->video_frame_piece_size + VIDEOFRAME_HEADER_SIZE;
434 } else {
435 memcpy(cs->split_video_frame + VIDEOFRAME_HEADER_SIZE,
436 cs->processing_video_frame,
437 cs->processing_video_frame_size);
438
439 *size = cs->processing_video_frame_size + VIDEOFRAME_HEADER_SIZE;
572 } 440 }
441
442 cs->split_video_frame[1]++;
443
444 return cs->split_video_frame;
445}
446
447
448
449int cs_set_sending_video_resolution(CSSession *cs, uint16_t width, uint16_t height)
450{
451 if (!cs->v_encoding)
452 return -1;
573 453
574 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10)); 454 /* TODO FIXME reference is safe? */
455 vpx_codec_enc_cfg_t cfg = *cs->v_encoder[0].config.enc;
575 456
576 if ( rc != OPUS_OK ) { 457 if (cfg.g_w == width && cfg.g_h == height)
577 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc)); 458 return 0;
578 goto FAILURE; 459/*
460 if (width * height > cs->max_width * cs->max_height) {
461 vpx_codec_ctx_t v_encoder = cs->v_encoder;
462
463 if (init_video_encoder(cs, width, height, cs->video_bitrate) == -1) {
464 cs->v_encoder = v_encoder;
465 return cs_ErrorSettingVideoResolution;
466 }
467
468 vpx_codec_destroy(&v_encoder);
469 return 0;
470 }*/
471
472 LOGGER_DEBUG("New video resolution: %u %u", width, height);
473 cfg.g_w = width;
474 cfg.g_h = height;
475 int rc = vpx_codec_enc_config_set(cs->v_encoder, &cfg);
476
477 if ( rc != VPX_CODEC_OK) {
478 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
479 return cs_ErrorSettingVideoResolution;
579 } 480 }
580 481
581 cs->channels = 2;
582 return 0; 482 return 0;
583
584FAILURE:
585 cs_disable_audio_sending(cs);
586 return -1;
587} 483}
588 484
589int cs_enable_audio_receiving(CSSession* cs) 485int cs_set_sending_video_bitrate(CSSession *cs, uint32_t bitrate)
590{ 486{
591 if (cs->audio_decoder) 487 if (!cs->v_encoding)
592 return 0;
593
594 /**
595 * Decoder is initialized with default values. These values (Sampling rate, channel count)
596 * change on the fly from toxav.
597 */
598
599 int rc;
600 cs->audio_decoder = opus_decoder_create(48000, 2, &rc );
601
602 if ( rc != OPUS_OK ) {
603 LOGGER_ERROR("Error while starting audio decoder: %s", opus_strerror(rc));
604 return -1; 488 return -1;
605 }
606 489
490 /* TODO FIXME reference is safe? */
491 vpx_codec_enc_cfg_t cfg = *cs->v_encoder[0].config.enc;
492 if (cfg.rc_target_bitrate == bitrate)
493 return 0;
494
495 LOGGER_DEBUG("New video bitrate: %u", video_bitrate);
496 cfg.rc_target_bitrate = bitrate;
607 497
608 if ( !(cs->j_buf = jbuf_new(DEFAULT_JBUF)) ) { 498 int rc = vpx_codec_enc_config_set(cs->v_encoder, &cfg);
609 LOGGER_WARNING("Jitter buffer creaton failed!"); 499 if ( rc != VPX_CODEC_OK) {
610 opus_decoder_destroy(cs->audio_decoder); 500 LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
611 cs->audio_decoder = NULL; 501 return cs_ErrorSettingVideoBitrate;
612 return -1;
613 } 502 }
614 503
615
616 return 0; 504 return 0;
617} 505}
618 506
@@ -704,25 +592,6 @@ FAILURE:
704 return -1; 592 return -1;
705} 593}
706 594
707void cs_disable_audio_sending(CSSession* cs)
708{
709 if ( cs->audio_encoder ) {
710 opus_encoder_destroy(cs->audio_encoder);
711 cs->audio_encoder = NULL;
712 cs->channels = 0;
713 }
714}
715
716void cs_disable_audio_receiving(CSSession* cs)
717{
718 if ( cs->audio_decoder ) {
719 opus_decoder_destroy(cs->audio_decoder);
720 cs->audio_decoder = NULL;
721 jbuf_free(cs->j_buf);
722 cs->j_buf = NULL;
723 }
724}
725
726void cs_disable_video_sending(CSSession* cs) 595void cs_disable_video_sending(CSSession* cs)
727{ 596{
728 if (cs->v_encoding) { 597 if (cs->v_encoding) {
@@ -752,6 +621,163 @@ void cs_disable_video_receiving(CSSession* cs)
752 621
753 622
754 623
624int cs_set_sending_audio_bitrate(CSSession *cs, int32_t rate)
625{
626 if (cs->audio_encoder == NULL)
627 return -1;
628
629 int rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(rate));
630
631 if ( rc != OPUS_OK ) {
632 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc));
633 return -1;
634 }
635
636 return 0;
637}
638
639int cs_set_sending_audio_sampling_rate(CSSession* cs, int32_t rate)
640{
641 /* TODO Find a better way? */
642 if (cs->audio_encoder == NULL)
643 return -1;
644
645 int rc = OPUS_OK;
646 int bitrate = 0;
647 int channels = cs->encoder_channels;
648
649 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_GET_BITRATE(&bitrate));
650
651 if ( rc != OPUS_OK ) {
652 LOGGER_ERROR("Error while getting encoder ctl: %s", opus_strerror(rc));
653 return -1;
654 }
655
656 cs_disable_audio_sending(cs);
657 return cs_enable_audio_sending(cs, bitrate, channels);
658}
659
660int cs_set_sending_audio_channels(CSSession* cs, int32_t count)
661{
662 /* TODO Find a better way? */
663 if (cs->audio_encoder == NULL)
664 return -1;
665
666 if (cs->encoder_channels == count)
667 return 0;
668
669 int rc = OPUS_OK;
670 int bitrate = 0;
671
672 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_GET_BITRATE(&bitrate));
673
674 if ( rc != OPUS_OK ) {
675 LOGGER_ERROR("Error while getting encoder ctl: %s", opus_strerror(rc));
676 return -1;
677 }
678
679 cs_disable_audio_sending(cs);
680 return cs_enable_audio_sending(cs, bitrate, count);
681}
682
683void cs_disable_audio_sending(CSSession* cs)
684{
685 if ( cs->audio_encoder ) {
686 opus_encoder_destroy(cs->audio_encoder);
687 cs->audio_encoder = NULL;
688 cs->encoder_channels = 0;
689 }
690}
691
692void cs_disable_audio_receiving(CSSession* cs)
693{
694 if ( cs->audio_decoder ) {
695 opus_decoder_destroy(cs->audio_decoder);
696 cs->audio_decoder = NULL;
697 jbuf_free(cs->j_buf);
698 cs->j_buf = NULL;
699
700 /* It's used for measuring iteration interval so this has to be some value.
701 * To avoid unecessary checking we set this to 500
702 */
703 cs->last_packet_frame_duration = 500;
704 }
705}
706
707int cs_enable_audio_sending(CSSession* cs, uint32_t bitrate, int channels)
708{
709 if (cs->audio_encoder)
710 return 0;
711
712 /**
713 * Encoder is initialized with default values. These values (Sampling rate, channel count)
714 * change on the fly from toxav.
715 */
716
717 int rc = OPUS_OK;
718 cs->audio_encoder = opus_encoder_create(48000, channels, OPUS_APPLICATION_AUDIO, &rc);
719
720 if ( rc != OPUS_OK ) {
721 LOGGER_ERROR("Error while starting audio encoder: %s", opus_strerror(rc));
722 return -1;
723 }
724
725 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(bitrate));
726
727 if ( rc != OPUS_OK ) {
728 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc));
729 goto FAILURE;
730 }
731
732 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10));
733
734 if ( rc != OPUS_OK ) {
735 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc));
736 goto FAILURE;
737 }
738
739 cs->encoder_channels = channels;
740 return 0;
741
742FAILURE:
743 cs_disable_audio_sending(cs);
744 return -1;
745}
746
747int cs_enable_audio_receiving(CSSession* cs)
748{
749 if (cs->audio_decoder)
750 return 0;
751
752 /**
753 * Decoder is initialized with default values. These values (Sampling rate, channel count)
754 * change on the fly from toxav.
755 */
756
757 int rc;
758 cs->audio_decoder = opus_decoder_create(48000, 2, &rc );
759
760 if ( rc != OPUS_OK ) {
761 LOGGER_ERROR("Error while starting audio decoder: %s", opus_strerror(rc));
762 return -1;
763 }
764
765
766 if ( !(cs->j_buf = jbuf_new(DEFAULT_JBUF)) ) {
767 LOGGER_WARNING("Jitter buffer creaton failed!");
768 opus_decoder_destroy(cs->audio_decoder);
769 cs->audio_decoder = NULL;
770 return -1;
771 }
772
773 /* It's used for measuring iteration interval so this has to be some value.
774 * To avoid unecessary checking we set this to 500
775 */
776 cs->last_packet_frame_duration = 500;
777 return 0;
778}
779
780
755 781
756/* Called from RTP */ 782/* Called from RTP */
757void queue_message(RTPSession *session, RTPMessage *msg) 783void queue_message(RTPSession *session, RTPMessage *msg)
diff --git a/toxav/codec.h b/toxav/codec.h
index 92262ef8..951d6d2f 100644
--- a/toxav/codec.h
+++ b/toxav/codec.h
@@ -96,7 +96,7 @@ typedef struct _CSSession {
96 uint32_t video_frame_piece_size; 96 uint32_t video_frame_piece_size;
97 uint32_t max_video_frame_size; 97 uint32_t max_video_frame_size;
98 98
99 /* Reassembling */ 99 /* Splitting */
100 uint8_t *split_video_frame; 100 uint8_t *split_video_frame;
101 const uint8_t *processing_video_frame; 101 const uint8_t *processing_video_frame;
102 uint16_t processing_video_frame_size; 102 uint16_t processing_video_frame_size;
@@ -110,10 +110,13 @@ typedef struct _CSSession {
110 110
111 /* audio encoding */ 111 /* audio encoding */
112 OpusEncoder *audio_encoder; 112 OpusEncoder *audio_encoder;
113 int32_t channels; 113 int32_t encoder_channels;
114 114
115 /* audio decoding */ 115 /* audio decoding */
116 OpusDecoder *audio_decoder; 116 OpusDecoder *audio_decoder;
117 int32_t last_pack_channels;
118 int32_t last_packet_sampling_rate;
119 int32_t last_packet_frame_duration;
117 struct _JitterBuffer *j_buf; 120 struct _JitterBuffer *j_buf;
118 121
119 122
@@ -127,54 +130,55 @@ typedef struct _CSSession {
127 * 130 *
128 * 131 *
129 */ 132 */
130 133 void *agent; /* Pointer to ToxAV TODO make this pointer to ToxAV*/
131 /* Callbacks */
132 PAIR(CSAudioCallback, void *) acb;
133 PAIR(CSVideoCallback, void *) vcb;
134
135 void *agent; /* Pointer to ToxAv */
136 int32_t call_idx; 134 int32_t call_idx;
137 135
138 pthread_mutex_t queue_mutex[1]; 136 pthread_mutex_t queue_mutex[1];
139} CSSession; 137} CSSession;
140 138
141int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length);
142const uint8_t *cs_get_split_video_frame(CSSession *cs, uint16_t *size);
143 139
144/** 140/**
145 * Call playback callbacks 141 * Generic
146 */ 142 */
147void cs_do(CSSession *cs); 143void cs_do(CSSession *cs);
148 144
149/** 145/* Make sure to be called BEFORE corresponding rtp_new */
150 * Reconfigure video settings; return 0 on success or -1 on failure. 146CSSession *cs_new(uint32_t s_audio_b, uint32_t p_audio_b, uint32_t s_video_b, uint32_t p_video_b);
147/* Make sure to be called AFTER corresponding rtp_kill */
148void cs_kill(CSSession *cs);
149
150
151/**
152 * VIDEO HANDLING
151 */ 153 */
154void cs_init_video_splitter_cycle(CSSession *cs);
155int cs_update_video_splitter_cycle(CSSession* cs, const uint8_t* payload, uint16_t length);
156const uint8_t *cs_iterate_split_video_frame(CSSession *cs, uint16_t *size);
157
152int cs_set_sending_video_resolution(CSSession *cs, uint16_t width, uint16_t height); 158int cs_set_sending_video_resolution(CSSession *cs, uint16_t width, uint16_t height);
153int cs_set_sending_video_bitrate(CSSession *cs, uint32_t bitrate); 159int cs_set_sending_video_bitrate(CSSession *cs, uint32_t bitrate);
154 160
161int cs_enable_video_sending(CSSession* cs, uint32_t bitrate);
162int cs_enable_video_receiving(CSSession* cs);
163
164void cs_disable_video_sending(CSSession* cs);
165void cs_disable_video_receiving(CSSession* cs);
166
167/**
168 * AUDIO HANDLING
169 */
155int cs_set_sending_audio_bitrate(CSSession* cs, int32_t rate); 170int cs_set_sending_audio_bitrate(CSSession* cs, int32_t rate);
156/* NOTE: Try not to call these a lot */
157int cs_set_sending_audio_sampling_rate(CSSession* cs, int32_t rate); 171int cs_set_sending_audio_sampling_rate(CSSession* cs, int32_t rate);
158int cs_set_sending_audio_channels(CSSession* cs, int32_t count); 172int cs_set_sending_audio_channels(CSSession* cs, int32_t count);
159 173
160/** 174int cs_enable_audio_sending(CSSession* cs, uint32_t bitrate, int channels);
161 * Make sure to be called BEFORE corresponding rtp_new
162 */
163CSSession *cs_new(uint32_t s_audio_b, uint32_t p_audio_b, uint32_t s_video_b, uint32_t p_video_b);
164/**
165 * Make sure to be called AFTER corresponding rtp_kill
166 */
167void cs_kill(CSSession *cs);
168
169int cs_enable_audio_sending(CSSession* cs, uint32_t bitrate);
170int cs_enable_audio_receiving(CSSession* cs); 175int cs_enable_audio_receiving(CSSession* cs);
171int cs_enable_video_sending(CSSession* cs, uint32_t bitrate);
172int cs_enable_video_receiving(CSSession* cs);
173 176
174void cs_disable_audio_sending(CSSession* cs); 177void cs_disable_audio_sending(CSSession* cs);
175void cs_disable_audio_receiving(CSSession* cs); 178void cs_disable_audio_receiving(CSSession* cs);
176void cs_disable_video_sending(CSSession* cs); 179
177void cs_disable_video_receiving(CSSession* cs); 180
181
178 182
179/* Internal. Called from rtp_handle_message */ 183/* Internal. Called from rtp_handle_message */
180void queue_message(RTPSession *session, RTPMessage *msg); 184void queue_message(RTPSession *session, RTPMessage *msg);
diff --git a/toxav/rtp.c b/toxav/rtp.c
index ba93e781..a50dd7ce 100644
--- a/toxav/rtp.c
+++ b/toxav/rtp.c
@@ -488,13 +488,13 @@ int rtp_register_for_receiving(RTPSession* session)
488 rtp_handle_packet, session); 488 rtp_handle_packet, session);
489} 489}
490 490
491int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *data, uint16_t length ) 491int rtp_send_msg ( RTPSession *session, const uint8_t *data, uint16_t length )
492{ 492{
493 RTPMessage *msg = rtp_new_message (session, data, length); 493 RTPMessage *msg = rtp_new_message (session, data, length);
494 494
495 if ( !msg ) return -1; 495 if ( !msg ) return -1;
496 496
497 if ( -1 == send_custom_lossy_packet(messenger, session->dest, msg->data, msg->length) ) { 497 if ( -1 == send_custom_lossy_packet(session->m, session->dest, msg->data, msg->length) ) {
498 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno)); 498 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno));
499 rtp_free_msg ( session, msg ); 499 rtp_free_msg ( session, msg );
500 return rtp_ErrorSending; 500 return rtp_ErrorSending;
diff --git a/toxav/rtp.h b/toxav/rtp.h
index b25b13ba..03b44719 100644
--- a/toxav/rtp.h
+++ b/toxav/rtp.h
@@ -121,7 +121,7 @@ int rtp_register_for_receiving (RTPSession *session);
121/** 121/**
122 * Sends msg to _RTPSession::dest 122 * Sends msg to _RTPSession::dest
123 */ 123 */
124int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *data, uint16_t length ); 124int rtp_send_msg ( RTPSession* session, const uint8_t* data, uint16_t length );
125 125
126/** 126/**
127 * Dealloc msg. 127 * Dealloc msg.
diff --git a/toxav/toxav.c b/toxav/toxav.c
index 68402020..ee7f49a6 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -176,14 +176,14 @@ uint32_t toxav_do_interval(ToxAv *av)
176void toxav_do(ToxAv *av) 176void toxav_do(ToxAv *av)
177{ 177{
178 msi_do(av->msi_session); 178 msi_do(av->msi_session);
179 179
180 uint64_t start = current_time_monotonic(); 180 uint64_t start = current_time_monotonic();
181 181
182 uint32_t i = 0; 182 uint32_t i = 0;
183 183
184 for (; i < av->max_calls; i ++) { 184 for (; i < av->max_calls; i ++) {
185 pthread_mutex_lock(av->calls[i].mutex_control); 185 pthread_mutex_lock(av->calls[i].mutex_control);
186 186
187 if (av->calls[i].active) { 187 if (av->calls[i].active) {
188 pthread_mutex_lock(av->calls[i].mutex_do); 188 pthread_mutex_lock(av->calls[i].mutex_do);
189 pthread_mutex_unlock(av->calls[i].mutex_control); 189 pthread_mutex_unlock(av->calls[i].mutex_control);
@@ -193,12 +193,12 @@ void toxav_do(ToxAv *av)
193 pthread_mutex_unlock(av->calls[i].mutex_control); 193 pthread_mutex_unlock(av->calls[i].mutex_control);
194 } 194 }
195 } 195 }
196 196
197 uint64_t end = current_time_monotonic(); 197 uint64_t end = current_time_monotonic();
198 198
199 /* TODO maybe use variable for sizes */ 199 /* TODO maybe use variable for sizes */
200 av->dectmsstotal += end - start; 200 av->dectmsstotal += end - start;
201 201
202 if (++av->dectmsscount == 3) { 202 if (++av->dectmsscount == 3) {
203 av->avgdectms = av->dectmsstotal / 3 + 2 /* NOTE Magic Offset */; 203 av->avgdectms = av->dectmsstotal / 3 + 2 /* NOTE Magic Offset */;
204 av->dectmsscount = 0; 204 av->dectmsscount = 0;
@@ -432,7 +432,7 @@ static int toxav_send_rtp_payload(ToxAv *av,
432 int i; 432 int i;
433 433
434 for (i = 0; i < parts; i++) { 434 for (i = 0; i < parts; i++) {
435 iter = cs_get_split_video_frame(call->cs, &part_size); 435 iter = cs_iterate_split_video_frame(call->cs, &part_size);
436 436
437 if (rtp_send_msg(call->crtps[video_index], av->messenger, iter, part_size) < 0) 437 if (rtp_send_msg(call->crtps[video_index], av->messenger, iter, part_size) < 0)
438 return av_ErrorSendingPayload; 438 return av_ErrorSendingPayload;
diff --git a/toxav/toxav_new.c b/toxav/toxav_new.c
index d6c1872c..857d5a83 100644
--- a/toxav/toxav_new.c
+++ b/toxav/toxav_new.c
@@ -34,6 +34,7 @@
34#include <stdlib.h> 34#include <stdlib.h>
35#include <string.h> 35#include <string.h>
36 36
37#define MAX_ENCODE_TIME_US ((1000 / 24) * 1000)
37 38
38enum { 39enum {
39 audio_index, 40 audio_index,
@@ -75,6 +76,8 @@ struct toxAV
75 int32_t dmssc; /** Measure count */ 76 int32_t dmssc; /** Measure count */
76 int32_t dmsst; /** Last cycle total */ 77 int32_t dmsst; /** Last cycle total */
77 int32_t dmssa; /** Average decoding time in ms */ 78 int32_t dmssa; /** Average decoding time in ms */
79
80 uint32_t interval; /** Calculated interval */
78}; 81};
79 82
80 83
@@ -130,6 +133,7 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error)
130 goto FAILURE; 133 goto FAILURE;
131 } 134 }
132 135
136 av->interval = 200;
133 av->msi->agent_handler = av; 137 av->msi->agent_handler = av;
134 138
135 msi_register_callback(av->msi, i_toxav_msi_callback_invite, msi_OnInvite, NULL); 139 msi_register_callback(av->msi, i_toxav_msi_callback_invite, msi_OnInvite, NULL);
@@ -144,7 +148,7 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error)
144 msi_register_callback(av->msi, i_toxav_msi_callback_state_change, msi_OnSelfCSChange, NULL); 148 msi_register_callback(av->msi, i_toxav_msi_callback_state_change, msi_OnSelfCSChange, NULL);
145 149
146 150
147 if (error) 151 if (error)
148 *error = rc; 152 *error = rc;
149 153
150 return av; 154 return av;
@@ -175,12 +179,32 @@ Tox* toxav_get_tox(ToxAV* av)
175 179
176uint32_t toxav_iteration_interval(const ToxAV* av) 180uint32_t toxav_iteration_interval(const ToxAV* av)
177{ 181{
178 182 return av->interval;
179} 183}
180 184
181void toxav_iteration(ToxAV* av) 185void toxav_iteration(ToxAV* av)
182{ 186{
183 187 msi_do(av->msi);
188
189 uint64_t start = current_time_monotonic();
190 uint32_t rc = 200 + av->dmssa; /* If no call is active interval is 200 */
191
192 IToxAVCall* i = av->calls[av->calls_head];
193 for (; i; i = i->next) {
194 if (i->active) {
195 cs_do(i->cs);
196 rc = MIN(i->cs->last_packet_frame_duration, rc);
197 }
198 }
199
200 av->interval = rc < av->dmssa ? 0 : rc - av->dmssa;
201 av->dmsst += current_time_monotonic() - start;
202
203 if (++av->dmssc == 3) {
204 av->dmssa = av->dmsst / 3 + 2 /* NOTE Magic Offset for precission */;
205 av->dmssc = 0;
206 av->dmsst = 0;
207 }
184} 208}
185 209
186bool toxav_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error) 210bool toxav_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error)
@@ -261,52 +285,244 @@ void toxav_callback_call_state(ToxAV* av, toxav_call_state_cb* function, void* u
261 285
262bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL control, TOXAV_ERR_CALL_CONTROL* error) 286bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL control, TOXAV_ERR_CALL_CONTROL* error)
263{ 287{
264 288 TOXAV_ERR_CALL_CONTROL rc = TOXAV_ERR_CALL_CONTROL_OK;
289
290 if (m_friend_exists(av->m, friend_number)) {
291 rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_FOUND;
292 goto END;
293 }
294
295
296 IToxAVCall* call = i_toxav_get_call(av, friend_number);
297 if (call == NULL) {
298 rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
299 goto END;
300 }
301
302 /* TODO rest of these */
303 switch (control)
304 {
305 case TOXAV_CALL_CONTROL_RESUME: {
306
307 } break;
308
309 case TOXAV_CALL_CONTROL_PAUSE: {
310
311 } break;
312
313 case TOXAV_CALL_CONTROL_CANCEL: {
314 if (av->msi->calls[call->call_idx]->state == msi_CallActive) {
315 /* Hang up */
316 msi_hangup(av->msi, call->call_idx);
317 } else if (av->msi->calls[call->call_idx]->state == msi_CallRequested) {
318 /* Reject the call */
319 msi_reject(av->msi, call->call_idx);
320 } else if (av->msi->calls[call->call_idx]->state == msi_CallRequesting) {
321 /* Cancel the call */
322 msi_cancel(av->msi, call->call_idx);
323 }
324 } break;
325
326 case TOXAV_CALL_CONTROL_MUTE_AUDIO: {
327
328 } break;
329
330 case TOXAV_CALL_CONTROL_MUTE_VIDEO: {
331
332 } break;
333 }
334
335END:
336 if (error)
337 *error = rc;
338
339 return rc == TOXAV_ERR_CALL_CONTROL_OK;
265} 340}
266 341
267bool toxav_set_audio_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, TOXAV_ERR_BIT_RATE* error) 342bool toxav_set_audio_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, TOXAV_ERR_BIT_RATE* error)
268{ 343{
269 344 /* TODO */
270} 345}
271 346
272bool toxav_set_video_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t video_bit_rate, TOXAV_ERR_BIT_RATE* error) 347bool toxav_set_video_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t video_bit_rate, TOXAV_ERR_BIT_RATE* error)
273{ 348{
274 349 /* TODO */
275} 350}
276 351
277void toxav_callback_request_video_frame(ToxAV* av, toxav_request_video_frame_cb* function, void* user_data) 352void toxav_callback_request_video_frame(ToxAV* av, toxav_request_video_frame_cb* function, void* user_data)
278{ 353{
279 354 /* TODO */
280} 355}
281 356
282bool toxav_send_video_frame(ToxAV* av, uint32_t friend_number, uint16_t width, uint16_t height, const uint8_t* y, const uint8_t* u, const uint8_t* v, const uint8_t* a, TOXAV_ERR_SEND_FRAME* error) 357bool toxav_send_video_frame(ToxAV* av, uint32_t friend_number, uint16_t width, uint16_t height, const uint8_t* y, const uint8_t* u, const uint8_t* v, TOXAV_ERR_SEND_FRAME* error)
283{ 358{
284 359 TOXAV_ERR_SEND_FRAME rc = TOXAV_ERR_SEND_FRAME_OK;
360 IToxAVCall* call;
361
362 if (m_friend_exists(av->m, friend_number)) {
363 rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_FOUND;
364 goto END;
365 }
366
367 call = i_toxav_get_call(av, friend_number);
368 if (call == NULL) {
369 rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL;
370 goto END;
371 }
372
373 if (av->msi->calls[call->call_idx]->state != msi_CallActive) {
374 /* TODO */
375 rc = TOXAV_ERR_SEND_FRAME_NOT_REQUESTED;
376 goto END;
377 }
378
379 if ( y == NULL || u == NULL || v == NULL ) {
380 rc = TOXAV_ERR_SEND_FRAME_NULL;
381 goto END;
382 }
383
384 if ( cs_set_sending_video_resolution(call->cs, width, height) != 0 ) {
385 rc = TOXAV_ERR_SEND_FRAME_INVALID;
386 goto END;
387 }
388
389 { /* Encode */
390 vpx_image_t img;
391 img.w = img.h = img.d_w = img.d_h = 0;
392 vpx_img_alloc(&img, VPX_IMG_FMT_VPXI420, width, height, 1);
393
394 /* I420 "It comprises an NxM Y plane followed by (N/2)x(M/2) V and U planes."
395 * http://fourcc.org/yuv.php#IYUV
396 */
397 memcpy(img.planes[VPX_PLANE_Y], y, width * height);
398 memcpy(img.planes[VPX_PLANE_U], u, (width/2) * (height/2));
399 memcpy(img.planes[VPX_PLANE_V], v, (width/2) * (height/2));
400
401 int vrc = vpx_codec_encode(call->cs->v_encoder, &img,
402 call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US);
403
404 vpx_img_free(&img); /* FIXME don't free? */
405 if ( vrc != VPX_CODEC_OK) {
406 LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(vrc));
407 rc = TOXAV_ERR_SEND_FRAME_INVALID;
408 goto END;
409 }
410 }
411
412 ++call->cs->frame_counter;
413
414 { /* Split and send */
415 vpx_codec_iter_t iter = NULL;
416 const vpx_codec_cx_pkt_t *pkt;
417
418 cs_init_video_splitter_cycle(call->cs);
419
420 while ( (pkt = vpx_codec_get_cx_data(call->cs->v_encoder, &iter)) ) {
421 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
422 int parts = cs_update_video_splitter_cycle(call->cs, pkt->data.frame.buf,
423 pkt->data.frame.sz);
424
425 if (parts < 0) /* Should never happen though */
426 continue;
427
428 uint16_t part_size;
429 const uint8_t *iter;
430
431 int i;
432 for (i = 0; i < parts; i++) {
433 iter = cs_iterate_split_video_frame(call->cs, &part_size);
434
435 if (rtp_send_msg(call->rtps[video_index], iter, part_size) < 0)
436 goto END;
437 }
438 }
439 }
440 }
441
442END:
443 if (error)
444 *error = rc;
445
446 return rc == TOXAV_ERR_SEND_FRAME_OK;
285} 447}
286 448
287void toxav_callback_request_audio_frame(ToxAV* av, toxav_request_audio_frame_cb* function, void* user_data) 449void toxav_callback_request_audio_frame(ToxAV* av, toxav_request_audio_frame_cb* function, void* user_data)
288{ 450{
289 451 /* TODO */
290} 452}
291 453
292bool toxav_send_audio_frame(ToxAV* av, uint32_t friend_number, const int16_t* pcm, size_t sample_count, uint8_t channels, uint32_t sampling_rate, TOXAV_ERR_SEND_FRAME* error) 454bool toxav_send_audio_frame(ToxAV* av, uint32_t friend_number, const int16_t* pcm, size_t sample_count, uint8_t channels, uint32_t sampling_rate, TOXAV_ERR_SEND_FRAME* error)
293{ 455{
294 456 TOXAV_ERR_SEND_FRAME rc = TOXAV_ERR_SEND_FRAME_OK;
457 IToxAVCall* call;
458
459 if (m_friend_exists(av->m, friend_number)) {
460 rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_FOUND;
461 goto END;
462 }
463
464 call = i_toxav_get_call(av, friend_number);
465 if (call == NULL) {
466 rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL;
467 goto END;
468 }
469
470 if (av->msi->calls[call->call_idx]->state != msi_CallActive) {
471 /* TODO */
472 rc = TOXAV_ERR_SEND_FRAME_NOT_REQUESTED;
473 goto END;
474 }
475
476 if ( pcm == NULL ) {
477 rc = TOXAV_ERR_SEND_FRAME_NULL;
478 goto END;
479 }
480
481 if ( channels != 1 || channels != 2 ) {
482 rc = TOXAV_ERR_SEND_FRAME_INVALID;
483 goto END;
484 }
485
486 { /* Encode and send */
487 /* TODO redundant? */
488 cs_set_sending_audio_channels(call->cs, channels);
489 cs_set_sending_audio_sampling_rate(call->cs, sampling_rate);
490
491 uint8_t dest[sample_count * channels * 2 /* sizeof(uint16_t) */];
492 int vrc = opus_encode(call->cs->audio_encoder, pcm, sample_count, dest, sizeof (dest));
493
494 if (vrc < 0) {
495 LOGGER_WARNING("Failed to encode frame");
496 rc = TOXAV_ERR_SEND_FRAME_INVALID;
497 goto END;
498 }
499
500 vrc = rtp_send_msg(call->rtps[audio_index], dest, vrc);
501 /* TODO check for error? */
502 }
503
504END:
505 if (error)
506 *error = rc;
507
508 return rc == TOXAV_ERR_SEND_FRAME_OK;
295} 509}
296 510
297void toxav_callback_receive_video_frame(ToxAV* av, toxav_receive_video_frame_cb* function, void* user_data) 511void toxav_callback_receive_video_frame(ToxAV* av, toxav_receive_video_frame_cb* function, void* user_data)
298{ 512{
299 513 av->vcb.first = function;
514 av->vcb.second = user_data;
300} 515}
301 516
302void toxav_callback_receive_audio_frame(ToxAV* av, toxav_receive_audio_frame_cb* function, void* user_data) 517void toxav_callback_receive_audio_frame(ToxAV* av, toxav_receive_audio_frame_cb* function, void* user_data)
303{ 518{
304 519 av->acb.first = function;
520 av->acb.second = user_data;
305} 521}
306 522
307 523
308/******************************************************************************* 524/*******************************************************************************
309 * 525 *
310 * :: Internal 526 * :: Internal
311 * 527 *
312 ******************************************************************************/ 528 ******************************************************************************/
@@ -616,12 +832,6 @@ bool i_toxav_prepare_transmission(ToxAV* av, IToxAVCall* call)
616 call->cs->agent = av; 832 call->cs->agent = av;
617 call->cs->call_idx = call->call_idx; 833 call->cs->call_idx = call->call_idx;
618 834
619 call->cs->acb.first = av->acb.first;
620 call->cs->acb.second = av->acb.second;
621
622 call->cs->vcb.first = av->vcb.first;
623 call->cs->vcb.second = av->vcb.second;
624
625 835
626 if (c_self->audio_bitrate > 0 || c_peer->audio_bitrate > 0) { /* Prepare audio rtp */ 836 if (c_self->audio_bitrate > 0 || c_peer->audio_bitrate > 0) { /* Prepare audio rtp */
627 call->rtps[audio_index] = rtp_new(msi_TypeAudio, av->m, av->msi->calls[call->call_idx]->peers[0]); 837 call->rtps[audio_index] = rtp_new(msi_TypeAudio, av->m, av->msi->calls[call->call_idx]->peers[0]);
diff --git a/toxav/toxav_new.h b/toxav/toxav_new.h
index 78e79357..038ee99a 100644
--- a/toxav/toxav_new.h
+++ b/toxav/toxav_new.h
@@ -374,8 +374,9 @@ void toxav_callback_request_video_frame(ToxAV *av, toxav_request_video_frame_cb
374 * 374 *
375 * This is called in response to receiving the `request_video_frame` event. 375 * This is called in response to receiving the `request_video_frame` event.
376 * 376 *
377 * Each plane should contain (width * height) pixels. The Alpha plane can be 377 * Y - plane should be of size: height * width
378 * NULL, in which case every pixel is assumed fully opaque. 378 * U - plane should be of size: (height/2) * (width/2)
379 * V - plane should be of size: (height/2) * (width/2)
379 * 380 *
380 * @param friend_number The friend number of the friend to which to send a video 381 * @param friend_number The friend number of the friend to which to send a video
381 * frame. 382 * frame.
@@ -384,11 +385,10 @@ void toxav_callback_request_video_frame(ToxAV *av, toxav_request_video_frame_cb
384 * @param y Y (Luminance) plane data. 385 * @param y Y (Luminance) plane data.
385 * @param u U (Chroma) plane data. 386 * @param u U (Chroma) plane data.
386 * @param v V (Chroma) plane data. 387 * @param v V (Chroma) plane data.
387 * @param a A (Alpha) plane data.
388 */ 388 */
389bool toxav_send_video_frame(ToxAV *av, uint32_t friend_number, 389bool toxav_send_video_frame(ToxAV *av, uint32_t friend_number,
390 uint16_t width, uint16_t height, 390 uint16_t width, uint16_t height,
391 uint8_t const *y, uint8_t const *u, uint8_t const *v, uint8_t const *a, 391 uint8_t const *y, uint8_t const *u, uint8_t const *v,
392 TOXAV_ERR_SEND_FRAME *error); 392 TOXAV_ERR_SEND_FRAME *error);
393/** 393/**
394 * The function type for the `request_audio_frame` callback. 394 * The function type for the `request_audio_frame` callback.