diff options
Diffstat (limited to 'toxav/toxav_new.c')
-rw-r--r-- | toxav/toxav_new.c | 250 |
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 | ||
38 | enum { | 39 | enum { |
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 | ||
176 | uint32_t toxav_iteration_interval(const ToxAV* av) | 180 | uint32_t toxav_iteration_interval(const ToxAV* av) |
177 | { | 181 | { |
178 | 182 | return av->interval; | |
179 | } | 183 | } |
180 | 184 | ||
181 | void toxav_iteration(ToxAV* av) | 185 | void 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 | ||
186 | bool toxav_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error) | 210 | bool 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 | ||
262 | bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL control, TOXAV_ERR_CALL_CONTROL* error) | 286 | bool 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 | |||
335 | END: | ||
336 | if (error) | ||
337 | *error = rc; | ||
338 | |||
339 | return rc == TOXAV_ERR_CALL_CONTROL_OK; | ||
265 | } | 340 | } |
266 | 341 | ||
267 | bool toxav_set_audio_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, TOXAV_ERR_BIT_RATE* error) | 342 | bool 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 | ||
272 | bool toxav_set_video_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t video_bit_rate, TOXAV_ERR_BIT_RATE* error) | 347 | bool 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 | ||
277 | void toxav_callback_request_video_frame(ToxAV* av, toxav_request_video_frame_cb* function, void* user_data) | 352 | void 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 | ||
282 | bool 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) | 357 | bool 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 | |||
442 | END: | ||
443 | if (error) | ||
444 | *error = rc; | ||
445 | |||
446 | return rc == TOXAV_ERR_SEND_FRAME_OK; | ||
285 | } | 447 | } |
286 | 448 | ||
287 | void toxav_callback_request_audio_frame(ToxAV* av, toxav_request_audio_frame_cb* function, void* user_data) | 449 | void 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 | ||
292 | bool 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) | 454 | bool 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 | |||
504 | END: | ||
505 | if (error) | ||
506 | *error = rc; | ||
507 | |||
508 | return rc == TOXAV_ERR_SEND_FRAME_OK; | ||
295 | } | 509 | } |
296 | 510 | ||
297 | void toxav_callback_receive_video_frame(ToxAV* av, toxav_receive_video_frame_cb* function, void* user_data) | 511 | void 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 | ||
302 | void toxav_callback_receive_audio_frame(ToxAV* av, toxav_receive_audio_frame_cb* function, void* user_data) | 517 | void 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]); |