summaryrefslogtreecommitdiff
path: root/toxav/toxav_new.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxav/toxav_new.c')
-rw-r--r--toxav/toxav_new.c250
1 files changed, 230 insertions, 20 deletions
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]);