summaryrefslogtreecommitdiff
path: root/toxav
diff options
context:
space:
mode:
authoriphydf <iphydf@users.noreply.github.com>2018-08-12 22:01:42 +0000
committeriphydf <iphydf@users.noreply.github.com>2018-08-14 21:59:27 +0000
commit475f01bc1aaffc2a6b0a04909dc1b81d38573d04 (patch)
treef40ba06680f04233920db7d3b2a2daa80c50e414 /toxav
parentfc34fee59abbd79bd530b57fcbc030bde45df00a (diff)
Fix style in toxav.c.
* Use Camel_Snake_Case for type names. * Use at least 4 characters for constant names. I.e. `END` is a type name, but `RETURN` is a constant name. This is because `DHT` is a type name (yay consistency). * Using `min_*` functions instead of MIN, we can avoid a cast. * Use `for`-loops for for-each-frame semantics instead of `while`. * Don't use assignments as expressions. * `++i` instead of `i++`. * Function pointers are dereferenced automatically, so no need to manually do so. * Avoid void pointers that lie about not being spaghetti code. Toxcore and toxav are both spaghetti and shouldn't pretend anything else. * Don't use empty statements (e.g. no `;;` anywhere in the code).
Diffstat (limited to 'toxav')
-rw-r--r--toxav/toxav.api.h23
-rw-r--r--toxav/toxav.c295
-rw-r--r--toxav/toxav.h22
3 files changed, 191 insertions, 149 deletions
diff --git a/toxav/toxav.api.h b/toxav/toxav.api.h
index 9e6cea68..29a61f16 100644
--- a/toxav/toxav.api.h
+++ b/toxav/toxav.api.h
@@ -605,6 +605,10 @@ namespace video {
605%{ 605%{
606/** 606/**
607 * NOTE Compatibility with old toxav group calls. TODO(iphydf): remove 607 * NOTE Compatibility with old toxav group calls. TODO(iphydf): remove
608 *
609 * TODO(iphydf): Use proper new API guidelines for these. E.g. don't use inline
610 * function types, don't have per-callback userdata, especially don't have one
611 * userdata per group.
608 */ 612 */
609/* Create a new toxav group. 613/* Create a new toxav group.
610 * 614 *
@@ -616,8 +620,9 @@ namespace video {
616 * 620 *
617 * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). 621 * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)).
618 */ 622 */
619int toxav_add_av_groupchat(Tox *tox, void (*audio_callback)(void *, uint32_t, uint32_t, const int16_t *, unsigned int, uint8_t, 623int toxav_add_av_groupchat(Tox *tox,
620 uint32_t, void *), void *userdata); 624 void (*audio_callback)(void *, uint32_t, uint32_t, const int16_t *, unsigned int, uint8_t, uint32_t, void *),
625 void *userdata);
621 626
622/* Join a AV group (you need to have been invited first.) 627/* Join a AV group (you need to have been invited first.)
623 * 628 *
@@ -630,7 +635,8 @@ int toxav_add_av_groupchat(Tox *tox, void (*audio_callback)(void *, uint32_t, ui
630 * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). 635 * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)).
631 */ 636 */
632int toxav_join_av_groupchat(Tox *tox, uint32_t friendnumber, const uint8_t *data, uint16_t length, 637int toxav_join_av_groupchat(Tox *tox, uint32_t friendnumber, const uint8_t *data, uint16_t length,
633 void (*audio_callback)(void *, uint32_t, uint32_t, const int16_t *, unsigned int, uint8_t, uint32_t, void *), void *userdata); 638 void (*audio_callback)(void *, uint32_t, uint32_t, const int16_t *, unsigned int, uint8_t, uint32_t, void *),
639 void *userdata);
634 640
635/* Send audio to the group chat. 641/* Send audio to the group chat.
636 * 642 *
@@ -651,5 +657,16 @@ int toxav_group_send_audio(Tox *tox, uint32_t groupnumber, const int16_t *pcm, u
651#ifdef __cplusplus 657#ifdef __cplusplus
652} 658}
653#endif 659#endif
660
661typedef void toxav_group_audio_cb(Tox *tox, uint32_t groupnumber, uint32_t peernumber, const int16_t *pcm, uint32_t samples, uint8_t channels, uint32_t sample_rate, void *user_data);
662
663typedef TOXAV_ERR_CALL Toxav_Err_Call;
664typedef TOXAV_ERR_NEW Toxav_Err_New;
665typedef TOXAV_ERR_ANSWER Toxav_Err_Answer;
666typedef TOXAV_ERR_CALL_CONTROL Toxav_Err_Call_Control;
667typedef TOXAV_ERR_BIT_RATE_SET Toxav_Err_Bit_Rate_Set;
668typedef TOXAV_ERR_SEND_FRAME Toxav_Err_Send_Frame;
669typedef TOXAV_CALL_CONTROL Toxav_Call_Control;
670
654#endif /* TOXAV_H */ 671#endif /* TOXAV_H */
655%} 672%}
diff --git a/toxav/toxav.c b/toxav/toxav.c
index 6f47a0bc..84e67858 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -128,20 +128,20 @@ int callback_capabilites(void *toxav_inst, MSICall *call);
128bool audio_bit_rate_invalid(uint32_t bit_rate); 128bool audio_bit_rate_invalid(uint32_t bit_rate);
129bool video_bit_rate_invalid(uint32_t bit_rate); 129bool video_bit_rate_invalid(uint32_t bit_rate);
130bool invoke_call_state_callback(ToxAV *av, uint32_t friend_number, uint32_t state); 130bool invoke_call_state_callback(ToxAV *av, uint32_t friend_number, uint32_t state);
131ToxAVCall *call_new(ToxAV *av, uint32_t friend_number, TOXAV_ERR_CALL *error); 131ToxAVCall *call_new(ToxAV *av, uint32_t friend_number, Toxav_Err_Call *error);
132ToxAVCall *call_get(ToxAV *av, uint32_t friend_number); 132ToxAVCall *call_get(ToxAV *av, uint32_t friend_number);
133ToxAVCall *call_remove(ToxAVCall *call); 133ToxAVCall *call_remove(ToxAVCall *call);
134bool call_prepare_transmission(ToxAVCall *call); 134bool call_prepare_transmission(ToxAVCall *call);
135void call_kill_transmission(ToxAVCall *call); 135void call_kill_transmission(ToxAVCall *call);
136 136
137ToxAV *toxav_new(Tox *tox, TOXAV_ERR_NEW *error) 137ToxAV *toxav_new(Tox *tox, Toxav_Err_New *error)
138{ 138{
139 TOXAV_ERR_NEW rc = TOXAV_ERR_NEW_OK; 139 Toxav_Err_New rc = TOXAV_ERR_NEW_OK;
140 ToxAV *av = nullptr; 140 ToxAV *av = nullptr;
141 141
142 if (tox == nullptr) { 142 if (tox == nullptr) {
143 rc = TOXAV_ERR_NEW_NULL; 143 rc = TOXAV_ERR_NEW_NULL;
144 goto END; 144 goto RETURN;
145 } 145 }
146 146
147 // TODO(iphydf): Don't rely on toxcore internals. 147 // TODO(iphydf): Don't rely on toxcore internals.
@@ -150,7 +150,7 @@ ToxAV *toxav_new(Tox *tox, TOXAV_ERR_NEW *error)
150 150
151 if (m->msi_packet) { 151 if (m->msi_packet) {
152 rc = TOXAV_ERR_NEW_MULTIPLE; 152 rc = TOXAV_ERR_NEW_MULTIPLE;
153 goto END; 153 goto RETURN;
154 } 154 }
155 155
156 av = (ToxAV *)calloc(sizeof(ToxAV), 1); 156 av = (ToxAV *)calloc(sizeof(ToxAV), 1);
@@ -158,13 +158,13 @@ ToxAV *toxav_new(Tox *tox, TOXAV_ERR_NEW *error)
158 if (av == nullptr) { 158 if (av == nullptr) {
159 LOGGER_WARNING(m->log, "Allocation failed!"); 159 LOGGER_WARNING(m->log, "Allocation failed!");
160 rc = TOXAV_ERR_NEW_MALLOC; 160 rc = TOXAV_ERR_NEW_MALLOC;
161 goto END; 161 goto RETURN;
162 } 162 }
163 163
164 if (create_recursive_mutex(av->mutex) != 0) { 164 if (create_recursive_mutex(av->mutex) != 0) {
165 LOGGER_WARNING(m->log, "Mutex creation failed!"); 165 LOGGER_WARNING(m->log, "Mutex creation failed!");
166 rc = TOXAV_ERR_NEW_MALLOC; 166 rc = TOXAV_ERR_NEW_MALLOC;
167 goto END; 167 goto RETURN;
168 } 168 }
169 169
170 av->tox = tox; 170 av->tox = tox;
@@ -174,7 +174,7 @@ ToxAV *toxav_new(Tox *tox, TOXAV_ERR_NEW *error)
174 if (av->msi == nullptr) { 174 if (av->msi == nullptr) {
175 pthread_mutex_destroy(av->mutex); 175 pthread_mutex_destroy(av->mutex);
176 rc = TOXAV_ERR_NEW_MALLOC; 176 rc = TOXAV_ERR_NEW_MALLOC;
177 goto END; 177 goto RETURN;
178 } 178 }
179 179
180 av->interval = 200; 180 av->interval = 200;
@@ -187,7 +187,7 @@ ToxAV *toxav_new(Tox *tox, TOXAV_ERR_NEW *error)
187 msi_register_callback(av->msi, callback_error, MSI_ON_PEERTIMEOUT); 187 msi_register_callback(av->msi, callback_error, MSI_ON_PEERTIMEOUT);
188 msi_register_callback(av->msi, callback_capabilites, MSI_ON_CAPABILITIES); 188 msi_register_callback(av->msi, callback_capabilites, MSI_ON_CAPABILITIES);
189 189
190END: 190RETURN:
191 191
192 if (error) { 192 if (error) {
193 *error = rc; 193 *error = rc;
@@ -268,7 +268,7 @@ void toxav_iterate(ToxAV *av)
268 268
269 if (i->msi_call->self_capabilities & MSI_CAP_R_VIDEO && 269 if (i->msi_call->self_capabilities & MSI_CAP_R_VIDEO &&
270 i->msi_call->peer_capabilities & MSI_CAP_S_VIDEO) { 270 i->msi_call->peer_capabilities & MSI_CAP_S_VIDEO) {
271 rc = min_u32(i->video->lcfd, (uint32_t) rc); 271 rc = min_u32(i->video->lcfd, rc);
272 } 272 }
273 273
274 uint32_t fid = i->friend_number; 274 uint32_t fid = i->friend_number;
@@ -295,9 +295,9 @@ void toxav_iterate(ToxAV *av)
295 } 295 }
296} 296}
297bool toxav_call(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, 297bool toxav_call(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate,
298 TOXAV_ERR_CALL *error) 298 Toxav_Err_Call *error)
299{ 299{
300 TOXAV_ERR_CALL rc = TOXAV_ERR_CALL_OK; 300 Toxav_Err_Call rc = TOXAV_ERR_CALL_OK;
301 ToxAVCall *call; 301 ToxAVCall *call;
302 302
303 pthread_mutex_lock(av->mutex); 303 pthread_mutex_lock(av->mutex);
@@ -305,13 +305,13 @@ bool toxav_call(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, uint
305 if ((audio_bit_rate && audio_bit_rate_invalid(audio_bit_rate)) 305 if ((audio_bit_rate && audio_bit_rate_invalid(audio_bit_rate))
306 || (video_bit_rate && video_bit_rate_invalid(video_bit_rate))) { 306 || (video_bit_rate && video_bit_rate_invalid(video_bit_rate))) {
307 rc = TOXAV_ERR_CALL_INVALID_BIT_RATE; 307 rc = TOXAV_ERR_CALL_INVALID_BIT_RATE;
308 goto END; 308 goto RETURN;
309 } 309 }
310 310
311 call = call_new(av, friend_number, &rc); 311 call = call_new(av, friend_number, &rc);
312 312
313 if (call == nullptr) { 313 if (call == nullptr) {
314 goto END; 314 goto RETURN;
315 } 315 }
316 316
317 call->audio_bit_rate = audio_bit_rate; 317 call->audio_bit_rate = audio_bit_rate;
@@ -325,12 +325,12 @@ bool toxav_call(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, uint
325 if (msi_invite(av->msi, &call->msi_call, friend_number, call->previous_self_capabilities) != 0) { 325 if (msi_invite(av->msi, &call->msi_call, friend_number, call->previous_self_capabilities) != 0) {
326 call_remove(call); 326 call_remove(call);
327 rc = TOXAV_ERR_CALL_SYNC; 327 rc = TOXAV_ERR_CALL_SYNC;
328 goto END; 328 goto RETURN;
329 } 329 }
330 330
331 call->msi_call->av_call = call; 331 call->msi_call->av_call = call;
332 332
333END: 333RETURN:
334 pthread_mutex_unlock(av->mutex); 334 pthread_mutex_unlock(av->mutex);
335 335
336 if (error) { 336 if (error) {
@@ -347,35 +347,35 @@ void toxav_callback_call(ToxAV *av, toxav_call_cb *callback, void *user_data)
347 pthread_mutex_unlock(av->mutex); 347 pthread_mutex_unlock(av->mutex);
348} 348}
349bool toxav_answer(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, 349bool toxav_answer(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate,
350 TOXAV_ERR_ANSWER *error) 350 Toxav_Err_Answer *error)
351{ 351{
352 pthread_mutex_lock(av->mutex); 352 pthread_mutex_lock(av->mutex);
353 353
354 TOXAV_ERR_ANSWER rc = TOXAV_ERR_ANSWER_OK; 354 Toxav_Err_Answer rc = TOXAV_ERR_ANSWER_OK;
355 ToxAVCall *call; 355 ToxAVCall *call;
356 356
357 if (m_friend_exists(av->m, friend_number) == 0) { 357 if (m_friend_exists(av->m, friend_number) == 0) {
358 rc = TOXAV_ERR_ANSWER_FRIEND_NOT_FOUND; 358 rc = TOXAV_ERR_ANSWER_FRIEND_NOT_FOUND;
359 goto END; 359 goto RETURN;
360 } 360 }
361 361
362 if ((audio_bit_rate && audio_bit_rate_invalid(audio_bit_rate)) 362 if ((audio_bit_rate && audio_bit_rate_invalid(audio_bit_rate))
363 || (video_bit_rate && video_bit_rate_invalid(video_bit_rate)) 363 || (video_bit_rate && video_bit_rate_invalid(video_bit_rate))
364 ) { 364 ) {
365 rc = TOXAV_ERR_ANSWER_INVALID_BIT_RATE; 365 rc = TOXAV_ERR_ANSWER_INVALID_BIT_RATE;
366 goto END; 366 goto RETURN;
367 } 367 }
368 368
369 call = call_get(av, friend_number); 369 call = call_get(av, friend_number);
370 370
371 if (call == nullptr) { 371 if (call == nullptr) {
372 rc = TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING; 372 rc = TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING;
373 goto END; 373 goto RETURN;
374 } 374 }
375 375
376 if (!call_prepare_transmission(call)) { 376 if (!call_prepare_transmission(call)) {
377 rc = TOXAV_ERR_ANSWER_CODEC_INITIALIZATION; 377 rc = TOXAV_ERR_ANSWER_CODEC_INITIALIZATION;
378 goto END; 378 goto RETURN;
379 } 379 }
380 380
381 call->audio_bit_rate = audio_bit_rate; 381 call->audio_bit_rate = audio_bit_rate;
@@ -390,7 +390,7 @@ bool toxav_answer(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, ui
390 rc = TOXAV_ERR_ANSWER_SYNC; 390 rc = TOXAV_ERR_ANSWER_SYNC;
391 } 391 }
392 392
393END: 393RETURN:
394 pthread_mutex_unlock(av->mutex); 394 pthread_mutex_unlock(av->mutex);
395 395
396 if (error) { 396 if (error) {
@@ -406,22 +406,22 @@ void toxav_callback_call_state(ToxAV *av, toxav_call_state_cb *callback, void *u
406 av->scb_user_data = user_data; 406 av->scb_user_data = user_data;
407 pthread_mutex_unlock(av->mutex); 407 pthread_mutex_unlock(av->mutex);
408} 408}
409bool toxav_call_control(ToxAV *av, uint32_t friend_number, TOXAV_CALL_CONTROL control, TOXAV_ERR_CALL_CONTROL *error) 409bool toxav_call_control(ToxAV *av, uint32_t friend_number, Toxav_Call_Control control, Toxav_Err_Call_Control *error)
410{ 410{
411 pthread_mutex_lock(av->mutex); 411 pthread_mutex_lock(av->mutex);
412 TOXAV_ERR_CALL_CONTROL rc = TOXAV_ERR_CALL_CONTROL_OK; 412 Toxav_Err_Call_Control rc = TOXAV_ERR_CALL_CONTROL_OK;
413 ToxAVCall *call; 413 ToxAVCall *call;
414 414
415 if (m_friend_exists(av->m, friend_number) == 0) { 415 if (m_friend_exists(av->m, friend_number) == 0) {
416 rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_FOUND; 416 rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_FOUND;
417 goto END; 417 goto RETURN;
418 } 418 }
419 419
420 call = call_get(av, friend_number); 420 call = call_get(av, friend_number);
421 421
422 if (call == nullptr || (!call->active && control != TOXAV_CALL_CONTROL_CANCEL)) { 422 if (call == nullptr || (!call->active && control != TOXAV_CALL_CONTROL_CANCEL)) {
423 rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL; 423 rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
424 goto END; 424 goto RETURN;
425 } 425 }
426 426
427 switch (control) { 427 switch (control) {
@@ -433,14 +433,14 @@ bool toxav_call_control(ToxAV *av, uint32_t friend_number, TOXAV_CALL_CONTROL co
433 if (msi_change_capabilities(call->msi_call, 433 if (msi_change_capabilities(call->msi_call,
434 call->previous_self_capabilities) == -1) { 434 call->previous_self_capabilities) == -1) {
435 rc = TOXAV_ERR_CALL_CONTROL_SYNC; 435 rc = TOXAV_ERR_CALL_CONTROL_SYNC;
436 goto END; 436 goto RETURN;
437 } 437 }
438 438
439 rtp_allow_receiving(call->audio_rtp); 439 rtp_allow_receiving(call->audio_rtp);
440 rtp_allow_receiving(call->video_rtp); 440 rtp_allow_receiving(call->video_rtp);
441 } else { 441 } else {
442 rc = TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION; 442 rc = TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION;
443 goto END; 443 goto RETURN;
444 } 444 }
445 } 445 }
446 break; 446 break;
@@ -452,14 +452,14 @@ bool toxav_call_control(ToxAV *av, uint32_t friend_number, TOXAV_CALL_CONTROL co
452 452
453 if (msi_change_capabilities(call->msi_call, 0) == -1) { 453 if (msi_change_capabilities(call->msi_call, 0) == -1) {
454 rc = TOXAV_ERR_CALL_CONTROL_SYNC; 454 rc = TOXAV_ERR_CALL_CONTROL_SYNC;
455 goto END; 455 goto RETURN;
456 } 456 }
457 457
458 rtp_stop_receiving(call->audio_rtp); 458 rtp_stop_receiving(call->audio_rtp);
459 rtp_stop_receiving(call->video_rtp); 459 rtp_stop_receiving(call->video_rtp);
460 } else { 460 } else {
461 rc = TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION; 461 rc = TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION;
462 goto END; 462 goto RETURN;
463 } 463 }
464 } 464 }
465 break; 465 break;
@@ -471,7 +471,7 @@ bool toxav_call_control(ToxAV *av, uint32_t friend_number, TOXAV_CALL_CONTROL co
471 if (msi_hangup(call->msi_call) != 0) { 471 if (msi_hangup(call->msi_call) != 0) {
472 rc = TOXAV_ERR_CALL_CONTROL_SYNC; 472 rc = TOXAV_ERR_CALL_CONTROL_SYNC;
473 pthread_mutex_unlock(call->mutex); 473 pthread_mutex_unlock(call->mutex);
474 goto END; 474 goto RETURN;
475 } 475 }
476 476
477 call->msi_call = nullptr; 477 call->msi_call = nullptr;
@@ -488,13 +488,13 @@ bool toxav_call_control(ToxAV *av, uint32_t friend_number, TOXAV_CALL_CONTROL co
488 if (msi_change_capabilities(call->msi_call, call-> 488 if (msi_change_capabilities(call->msi_call, call->
489 msi_call->self_capabilities ^ MSI_CAP_R_AUDIO) == -1) { 489 msi_call->self_capabilities ^ MSI_CAP_R_AUDIO) == -1) {
490 rc = TOXAV_ERR_CALL_CONTROL_SYNC; 490 rc = TOXAV_ERR_CALL_CONTROL_SYNC;
491 goto END; 491 goto RETURN;
492 } 492 }
493 493
494 rtp_stop_receiving(call->audio_rtp); 494 rtp_stop_receiving(call->audio_rtp);
495 } else { 495 } else {
496 rc = TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION; 496 rc = TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION;
497 goto END; 497 goto RETURN;
498 } 498 }
499 } 499 }
500 break; 500 break;
@@ -504,13 +504,13 @@ bool toxav_call_control(ToxAV *av, uint32_t friend_number, TOXAV_CALL_CONTROL co
504 if (msi_change_capabilities(call->msi_call, call-> 504 if (msi_change_capabilities(call->msi_call, call->
505 msi_call->self_capabilities | MSI_CAP_R_AUDIO) == -1) { 505 msi_call->self_capabilities | MSI_CAP_R_AUDIO) == -1) {
506 rc = TOXAV_ERR_CALL_CONTROL_SYNC; 506 rc = TOXAV_ERR_CALL_CONTROL_SYNC;
507 goto END; 507 goto RETURN;
508 } 508 }
509 509
510 rtp_allow_receiving(call->audio_rtp); 510 rtp_allow_receiving(call->audio_rtp);
511 } else { 511 } else {
512 rc = TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION; 512 rc = TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION;
513 goto END; 513 goto RETURN;
514 } 514 }
515 } 515 }
516 break; 516 break;
@@ -520,13 +520,13 @@ bool toxav_call_control(ToxAV *av, uint32_t friend_number, TOXAV_CALL_CONTROL co
520 if (msi_change_capabilities(call->msi_call, call-> 520 if (msi_change_capabilities(call->msi_call, call->
521 msi_call->self_capabilities ^ MSI_CAP_R_VIDEO) == -1) { 521 msi_call->self_capabilities ^ MSI_CAP_R_VIDEO) == -1) {
522 rc = TOXAV_ERR_CALL_CONTROL_SYNC; 522 rc = TOXAV_ERR_CALL_CONTROL_SYNC;
523 goto END; 523 goto RETURN;
524 } 524 }
525 525
526 rtp_stop_receiving(call->video_rtp); 526 rtp_stop_receiving(call->video_rtp);
527 } else { 527 } else {
528 rc = TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION; 528 rc = TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION;
529 goto END; 529 goto RETURN;
530 } 530 }
531 } 531 }
532 break; 532 break;
@@ -536,19 +536,19 @@ bool toxav_call_control(ToxAV *av, uint32_t friend_number, TOXAV_CALL_CONTROL co
536 if (msi_change_capabilities(call->msi_call, call-> 536 if (msi_change_capabilities(call->msi_call, call->
537 msi_call->self_capabilities | MSI_CAP_R_VIDEO) == -1) { 537 msi_call->self_capabilities | MSI_CAP_R_VIDEO) == -1) {
538 rc = TOXAV_ERR_CALL_CONTROL_SYNC; 538 rc = TOXAV_ERR_CALL_CONTROL_SYNC;
539 goto END; 539 goto RETURN;
540 } 540 }
541 541
542 rtp_allow_receiving(call->video_rtp); 542 rtp_allow_receiving(call->video_rtp);
543 } else { 543 } else {
544 rc = TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION; 544 rc = TOXAV_ERR_CALL_CONTROL_INVALID_TRANSITION;
545 goto END; 545 goto RETURN;
546 } 546 }
547 } 547 }
548 break; 548 break;
549 } 549 }
550 550
551END: 551RETURN:
552 pthread_mutex_unlock(av->mutex); 552 pthread_mutex_unlock(av->mutex);
553 553
554 if (error) { 554 if (error) {
@@ -558,19 +558,19 @@ END:
558 return rc == TOXAV_ERR_CALL_CONTROL_OK; 558 return rc == TOXAV_ERR_CALL_CONTROL_OK;
559} 559}
560bool toxav_audio_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, 560bool toxav_audio_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate,
561 TOXAV_ERR_BIT_RATE_SET *error) 561 Toxav_Err_Bit_Rate_Set *error)
562{ 562{
563 TOXAV_ERR_BIT_RATE_SET rc = TOXAV_ERR_BIT_RATE_SET_OK; 563 Toxav_Err_Bit_Rate_Set rc = TOXAV_ERR_BIT_RATE_SET_OK;
564 ToxAVCall *call; 564 ToxAVCall *call;
565 565
566 if (m_friend_exists(av->m, friend_number) == 0) { 566 if (m_friend_exists(av->m, friend_number) == 0) {
567 rc = TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_FOUND; 567 rc = TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_FOUND;
568 goto END; 568 goto RETURN;
569 } 569 }
570 570
571 if (audio_bit_rate > 0 && audio_bit_rate_invalid(audio_bit_rate)) { 571 if (audio_bit_rate > 0 && audio_bit_rate_invalid(audio_bit_rate)) {
572 rc = TOXAV_ERR_BIT_RATE_SET_INVALID_BIT_RATE; 572 rc = TOXAV_ERR_BIT_RATE_SET_INVALID_BIT_RATE;
573 goto END; 573 goto RETURN;
574 } 574 }
575 575
576 pthread_mutex_lock(av->mutex); 576 pthread_mutex_lock(av->mutex);
@@ -579,7 +579,7 @@ bool toxav_audio_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t audio_
579 if (call == nullptr || !call->active || call->msi_call->state != MSI_CALL_ACTIVE) { 579 if (call == nullptr || !call->active || call->msi_call->state != MSI_CALL_ACTIVE) {
580 pthread_mutex_unlock(av->mutex); 580 pthread_mutex_unlock(av->mutex);
581 rc = TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_IN_CALL; 581 rc = TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_IN_CALL;
582 goto END; 582 goto RETURN;
583 } 583 }
584 584
585 LOGGER_DEBUG(av->m->log, "Setting new audio bitrate to: %d", audio_bit_rate); 585 LOGGER_DEBUG(av->m->log, "Setting new audio bitrate to: %d", audio_bit_rate);
@@ -593,7 +593,7 @@ bool toxav_audio_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t audio_
593 self_capabilities ^ MSI_CAP_S_AUDIO) != 0) { 593 self_capabilities ^ MSI_CAP_S_AUDIO) != 0) {
594 pthread_mutex_unlock(av->mutex); 594 pthread_mutex_unlock(av->mutex);
595 rc = TOXAV_ERR_BIT_RATE_SET_SYNC; 595 rc = TOXAV_ERR_BIT_RATE_SET_SYNC;
596 goto END; 596 goto RETURN;
597 } 597 }
598 598
599 /* Audio sending is turned off; notify peer */ 599 /* Audio sending is turned off; notify peer */
@@ -610,7 +610,7 @@ bool toxav_audio_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t audio_
610 pthread_mutex_unlock(call->mutex); 610 pthread_mutex_unlock(call->mutex);
611 pthread_mutex_unlock(av->mutex); 611 pthread_mutex_unlock(av->mutex);
612 rc = TOXAV_ERR_BIT_RATE_SET_SYNC; 612 rc = TOXAV_ERR_BIT_RATE_SET_SYNC;
613 goto END; 613 goto RETURN;
614 } 614 }
615 } else { 615 } else {
616 LOGGER_DEBUG(av->m->log, "Set new audio bit rate %d", audio_bit_rate); 616 LOGGER_DEBUG(av->m->log, "Set new audio bit rate %d", audio_bit_rate);
@@ -621,7 +621,7 @@ bool toxav_audio_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t audio_
621 } 621 }
622 622
623 pthread_mutex_unlock(av->mutex); 623 pthread_mutex_unlock(av->mutex);
624END: 624RETURN:
625 625
626 if (error) { 626 if (error) {
627 *error = rc; 627 *error = rc;
@@ -630,19 +630,19 @@ END:
630 return rc == TOXAV_ERR_BIT_RATE_SET_OK; 630 return rc == TOXAV_ERR_BIT_RATE_SET_OK;
631} 631}
632bool toxav_video_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, 632bool toxav_video_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate,
633 TOXAV_ERR_BIT_RATE_SET *error) 633 Toxav_Err_Bit_Rate_Set *error)
634{ 634{
635 TOXAV_ERR_BIT_RATE_SET rc = TOXAV_ERR_BIT_RATE_SET_OK; 635 Toxav_Err_Bit_Rate_Set rc = TOXAV_ERR_BIT_RATE_SET_OK;
636 ToxAVCall *call; 636 ToxAVCall *call;
637 637
638 if (m_friend_exists(av->m, friend_number) == 0) { 638 if (m_friend_exists(av->m, friend_number) == 0) {
639 rc = TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_FOUND; 639 rc = TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_FOUND;
640 goto END; 640 goto RETURN;
641 } 641 }
642 642
643 if (video_bit_rate > 0 && video_bit_rate_invalid(video_bit_rate)) { 643 if (video_bit_rate > 0 && video_bit_rate_invalid(video_bit_rate)) {
644 rc = TOXAV_ERR_BIT_RATE_SET_INVALID_BIT_RATE; 644 rc = TOXAV_ERR_BIT_RATE_SET_INVALID_BIT_RATE;
645 goto END; 645 goto RETURN;
646 } 646 }
647 647
648 pthread_mutex_lock(av->mutex); 648 pthread_mutex_lock(av->mutex);
@@ -651,7 +651,7 @@ bool toxav_video_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_
651 if (call == nullptr || !call->active || call->msi_call->state != MSI_CALL_ACTIVE) { 651 if (call == nullptr || !call->active || call->msi_call->state != MSI_CALL_ACTIVE) {
652 pthread_mutex_unlock(av->mutex); 652 pthread_mutex_unlock(av->mutex);
653 rc = TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_IN_CALL; 653 rc = TOXAV_ERR_BIT_RATE_SET_FRIEND_NOT_IN_CALL;
654 goto END; 654 goto RETURN;
655 } 655 }
656 656
657 LOGGER_DEBUG(av->m->log, "Setting new video bitrate to: %d", video_bit_rate); 657 LOGGER_DEBUG(av->m->log, "Setting new video bitrate to: %d", video_bit_rate);
@@ -666,7 +666,7 @@ bool toxav_video_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_
666 self_capabilities ^ MSI_CAP_S_VIDEO) != 0) { 666 self_capabilities ^ MSI_CAP_S_VIDEO) != 0) {
667 pthread_mutex_unlock(av->mutex); 667 pthread_mutex_unlock(av->mutex);
668 rc = TOXAV_ERR_BIT_RATE_SET_SYNC; 668 rc = TOXAV_ERR_BIT_RATE_SET_SYNC;
669 goto END; 669 goto RETURN;
670 } 670 }
671 671
672 call->video_bit_rate = 0; 672 call->video_bit_rate = 0;
@@ -682,7 +682,7 @@ bool toxav_video_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_
682 pthread_mutex_unlock(call->mutex); 682 pthread_mutex_unlock(call->mutex);
683 pthread_mutex_unlock(av->mutex); 683 pthread_mutex_unlock(av->mutex);
684 rc = TOXAV_ERR_BIT_RATE_SET_SYNC; 684 rc = TOXAV_ERR_BIT_RATE_SET_SYNC;
685 goto END; 685 goto RETURN;
686 } 686 }
687 } else { 687 } else {
688 LOGGER_DEBUG(av->m->log, "Set new video bit rate %d", video_bit_rate); 688 LOGGER_DEBUG(av->m->log, "Set new video bit rate %d", video_bit_rate);
@@ -693,7 +693,7 @@ bool toxav_video_set_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_
693 } 693 }
694 694
695 pthread_mutex_unlock(av->mutex); 695 pthread_mutex_unlock(av->mutex);
696END: 696RETURN:
697 697
698 if (error) { 698 if (error) {
699 *error = rc; 699 *error = rc;
@@ -716,19 +716,19 @@ void toxav_callback_video_bit_rate(ToxAV *av, toxav_video_bit_rate_cb *callback,
716 pthread_mutex_unlock(av->mutex); 716 pthread_mutex_unlock(av->mutex);
717} 717}
718bool toxav_audio_send_frame(ToxAV *av, uint32_t friend_number, const int16_t *pcm, size_t sample_count, 718bool toxav_audio_send_frame(ToxAV *av, uint32_t friend_number, const int16_t *pcm, size_t sample_count,
719 uint8_t channels, uint32_t sampling_rate, TOXAV_ERR_SEND_FRAME *error) 719 uint8_t channels, uint32_t sampling_rate, Toxav_Err_Send_Frame *error)
720{ 720{
721 TOXAV_ERR_SEND_FRAME rc = TOXAV_ERR_SEND_FRAME_OK; 721 Toxav_Err_Send_Frame rc = TOXAV_ERR_SEND_FRAME_OK;
722 ToxAVCall *call; 722 ToxAVCall *call;
723 723
724 if (m_friend_exists(av->m, friend_number) == 0) { 724 if (m_friend_exists(av->m, friend_number) == 0) {
725 rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_FOUND; 725 rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_FOUND;
726 goto END; 726 goto RETURN;
727 } 727 }
728 728
729 if (pthread_mutex_trylock(av->mutex) != 0) { 729 if (pthread_mutex_trylock(av->mutex) != 0) {
730 rc = TOXAV_ERR_SEND_FRAME_SYNC; 730 rc = TOXAV_ERR_SEND_FRAME_SYNC;
731 goto END; 731 goto RETURN;
732 } 732 }
733 733
734 call = call_get(av, friend_number); 734 call = call_get(av, friend_number);
@@ -736,7 +736,7 @@ bool toxav_audio_send_frame(ToxAV *av, uint32_t friend_number, const int16_t *pc
736 if (call == nullptr || !call->active || call->msi_call->state != MSI_CALL_ACTIVE) { 736 if (call == nullptr || !call->active || call->msi_call->state != MSI_CALL_ACTIVE) {
737 pthread_mutex_unlock(av->mutex); 737 pthread_mutex_unlock(av->mutex);
738 rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL; 738 rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL;
739 goto END; 739 goto RETURN;
740 } 740 }
741 741
742 if (call->audio_bit_rate == 0 || 742 if (call->audio_bit_rate == 0 ||
@@ -744,7 +744,7 @@ bool toxav_audio_send_frame(ToxAV *av, uint32_t friend_number, const int16_t *pc
744 !(call->msi_call->peer_capabilities & MSI_CAP_R_AUDIO)) { 744 !(call->msi_call->peer_capabilities & MSI_CAP_R_AUDIO)) {
745 pthread_mutex_unlock(av->mutex); 745 pthread_mutex_unlock(av->mutex);
746 rc = TOXAV_ERR_SEND_FRAME_PAYLOAD_TYPE_DISABLED; 746 rc = TOXAV_ERR_SEND_FRAME_PAYLOAD_TYPE_DISABLED;
747 goto END; 747 goto RETURN;
748 } 748 }
749 749
750 pthread_mutex_lock(call->mutex_audio); 750 pthread_mutex_lock(call->mutex_audio);
@@ -753,20 +753,20 @@ bool toxav_audio_send_frame(ToxAV *av, uint32_t friend_number, const int16_t *pc
753 if (pcm == nullptr) { 753 if (pcm == nullptr) {
754 pthread_mutex_unlock(call->mutex_audio); 754 pthread_mutex_unlock(call->mutex_audio);
755 rc = TOXAV_ERR_SEND_FRAME_NULL; 755 rc = TOXAV_ERR_SEND_FRAME_NULL;
756 goto END; 756 goto RETURN;
757 } 757 }
758 758
759 if (channels > 2) { 759 if (channels > 2) {
760 pthread_mutex_unlock(call->mutex_audio); 760 pthread_mutex_unlock(call->mutex_audio);
761 rc = TOXAV_ERR_SEND_FRAME_INVALID; 761 rc = TOXAV_ERR_SEND_FRAME_INVALID;
762 goto END; 762 goto RETURN;
763 } 763 }
764 764
765 { /* Encode and send */ 765 { /* Encode and send */
766 if (ac_reconfigure_encoder(call->audio, call->audio_bit_rate * 1000, sampling_rate, channels) != 0) { 766 if (ac_reconfigure_encoder(call->audio, call->audio_bit_rate * 1000, sampling_rate, channels) != 0) {
767 pthread_mutex_unlock(call->mutex_audio); 767 pthread_mutex_unlock(call->mutex_audio);
768 rc = TOXAV_ERR_SEND_FRAME_INVALID; 768 rc = TOXAV_ERR_SEND_FRAME_INVALID;
769 goto END; 769 goto RETURN;
770 } 770 }
771 771
772 VLA(uint8_t, dest, sample_count + sizeof(sampling_rate)); /* This is more than enough always */ 772 VLA(uint8_t, dest, sample_count + sizeof(sampling_rate)); /* This is more than enough always */
@@ -780,7 +780,7 @@ bool toxav_audio_send_frame(ToxAV *av, uint32_t friend_number, const int16_t *pc
780 LOGGER_WARNING(av->m->log, "Failed to encode frame %s", opus_strerror(vrc)); 780 LOGGER_WARNING(av->m->log, "Failed to encode frame %s", opus_strerror(vrc));
781 pthread_mutex_unlock(call->mutex_audio); 781 pthread_mutex_unlock(call->mutex_audio);
782 rc = TOXAV_ERR_SEND_FRAME_INVALID; 782 rc = TOXAV_ERR_SEND_FRAME_INVALID;
783 goto END; 783 goto RETURN;
784 } 784 }
785 785
786 if (rtp_send_data(call->audio_rtp, dest, vrc + sizeof(sampling_rate), false, av->m->log) != 0) { 786 if (rtp_send_data(call->audio_rtp, dest, vrc + sizeof(sampling_rate), false, av->m->log) != 0) {
@@ -791,7 +791,7 @@ bool toxav_audio_send_frame(ToxAV *av, uint32_t friend_number, const int16_t *pc
791 791
792 pthread_mutex_unlock(call->mutex_audio); 792 pthread_mutex_unlock(call->mutex_audio);
793 793
794END: 794RETURN:
795 795
796 if (error) { 796 if (error) {
797 *error = rc; 797 *error = rc;
@@ -800,22 +800,60 @@ END:
800 return rc == TOXAV_ERR_SEND_FRAME_OK; 800 return rc == TOXAV_ERR_SEND_FRAME_OK;
801} 801}
802 802
803static Toxav_Err_Send_Frame send_frames(const Logger *log, ToxAVCall *call)
804{
805 vpx_codec_iter_t iter = nullptr;
806
807 for (const vpx_codec_cx_pkt_t *pkt = vpx_codec_get_cx_data(call->video->encoder, &iter);
808 pkt != nullptr;
809 pkt = vpx_codec_get_cx_data(call->video->encoder, &iter)) {
810 if (pkt->kind != VPX_CODEC_CX_FRAME_PKT) {
811 continue;
812 }
813
814 const bool is_keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
815
816 // https://www.webmproject.org/docs/webm-sdk/structvpx__codec__cx__pkt.html
817 // pkt->data.frame.sz -> size_t
818 const uint32_t frame_length_in_bytes = pkt->data.frame.sz;
819
820 const int res = rtp_send_data(
821 call->video_rtp,
822 (const uint8_t *)pkt->data.frame.buf,
823 frame_length_in_bytes,
824 is_keyframe,
825 log);
826
827 LOGGER_DEBUG(log, "+ _sending_FRAME_TYPE_==%s bytes=%d frame_len=%d", is_keyframe ? "K" : ".",
828 (int)pkt->data.frame.sz, (int)frame_length_in_bytes);
829 const uint8_t *const buf = (const uint8_t *)pkt->data.frame.buf;
830 LOGGER_DEBUG(log, "+ _sending_FRAME_ b0=%d b1=%d", buf[0], buf[1]);
831
832 if (res < 0) {
833 LOGGER_WARNING(log, "Could not send video frame: %s", strerror(errno));
834 return TOXAV_ERR_SEND_FRAME_RTP_FAILED;
835 }
836 }
837
838 return TOXAV_ERR_SEND_FRAME_OK;
839}
840
803bool toxav_video_send_frame(ToxAV *av, uint32_t friend_number, uint16_t width, uint16_t height, const uint8_t *y, 841bool toxav_video_send_frame(ToxAV *av, uint32_t friend_number, uint16_t width, uint16_t height, const uint8_t *y,
804 const uint8_t *u, const uint8_t *v, TOXAV_ERR_SEND_FRAME *error) 842 const uint8_t *u, const uint8_t *v, Toxav_Err_Send_Frame *error)
805{ 843{
806 TOXAV_ERR_SEND_FRAME rc = TOXAV_ERR_SEND_FRAME_OK; 844 Toxav_Err_Send_Frame rc = TOXAV_ERR_SEND_FRAME_OK;
807 ToxAVCall *call; 845 ToxAVCall *call;
808 846
809 int vpx_encode_flags = 0; 847 int vpx_encode_flags = 0;
810 848
811 if (m_friend_exists(av->m, friend_number) == 0) { 849 if (m_friend_exists(av->m, friend_number) == 0) {
812 rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_FOUND; 850 rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_FOUND;
813 goto END; 851 goto RETURN;
814 } 852 }
815 853
816 if (pthread_mutex_trylock(av->mutex) != 0) { 854 if (pthread_mutex_trylock(av->mutex) != 0) {
817 rc = TOXAV_ERR_SEND_FRAME_SYNC; 855 rc = TOXAV_ERR_SEND_FRAME_SYNC;
818 goto END; 856 goto RETURN;
819 } 857 }
820 858
821 call = call_get(av, friend_number); 859 call = call_get(av, friend_number);
@@ -823,7 +861,7 @@ bool toxav_video_send_frame(ToxAV *av, uint32_t friend_number, uint16_t width, u
823 if (call == nullptr || !call->active || call->msi_call->state != MSI_CALL_ACTIVE) { 861 if (call == nullptr || !call->active || call->msi_call->state != MSI_CALL_ACTIVE) {
824 pthread_mutex_unlock(av->mutex); 862 pthread_mutex_unlock(av->mutex);
825 rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL; 863 rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL;
826 goto END; 864 goto RETURN;
827 } 865 }
828 866
829 if (call->video_bit_rate == 0 || 867 if (call->video_bit_rate == 0 ||
@@ -831,7 +869,7 @@ bool toxav_video_send_frame(ToxAV *av, uint32_t friend_number, uint16_t width, u
831 !(call->msi_call->peer_capabilities & MSI_CAP_R_VIDEO)) { 869 !(call->msi_call->peer_capabilities & MSI_CAP_R_VIDEO)) {
832 pthread_mutex_unlock(av->mutex); 870 pthread_mutex_unlock(av->mutex);
833 rc = TOXAV_ERR_SEND_FRAME_PAYLOAD_TYPE_DISABLED; 871 rc = TOXAV_ERR_SEND_FRAME_PAYLOAD_TYPE_DISABLED;
834 goto END; 872 goto RETURN;
835 } 873 }
836 874
837 pthread_mutex_lock(call->mutex_video); 875 pthread_mutex_lock(call->mutex_video);
@@ -840,13 +878,13 @@ bool toxav_video_send_frame(ToxAV *av, uint32_t friend_number, uint16_t width, u
840 if (y == nullptr || u == nullptr || v == nullptr) { 878 if (y == nullptr || u == nullptr || v == nullptr) {
841 pthread_mutex_unlock(call->mutex_video); 879 pthread_mutex_unlock(call->mutex_video);
842 rc = TOXAV_ERR_SEND_FRAME_NULL; 880 rc = TOXAV_ERR_SEND_FRAME_NULL;
843 goto END; 881 goto RETURN;
844 } 882 }
845 883
846 if (vc_reconfigure_encoder(call->video, call->video_bit_rate * 1000, width, height, -1) != 0) { 884 if (vc_reconfigure_encoder(call->video, call->video_bit_rate * 1000, width, height, -1) != 0) {
847 pthread_mutex_unlock(call->mutex_video); 885 pthread_mutex_unlock(call->mutex_video);
848 rc = TOXAV_ERR_SEND_FRAME_INVALID; 886 rc = TOXAV_ERR_SEND_FRAME_INVALID;
849 goto END; 887 goto RETURN;
850 } 888 }
851 889
852 if (call->video_rtp->ssrc < VIDEO_SEND_X_KEYFRAMES_FIRST) { 890 if (call->video_rtp->ssrc < VIDEO_SEND_X_KEYFRAMES_FIRST) {
@@ -854,20 +892,23 @@ bool toxav_video_send_frame(ToxAV *av, uint32_t friend_number, uint16_t width, u
854 vpx_encode_flags = VPX_EFLAG_FORCE_KF; 892 vpx_encode_flags = VPX_EFLAG_FORCE_KF;
855 LOGGER_INFO(av->m->log, "I_FRAME_FLAG:%d only-i-frame mode", call->video_rtp->ssrc); 893 LOGGER_INFO(av->m->log, "I_FRAME_FLAG:%d only-i-frame mode", call->video_rtp->ssrc);
856 894
857 call->video_rtp->ssrc++; 895 ++call->video_rtp->ssrc;
858 } else if (call->video_rtp->ssrc == VIDEO_SEND_X_KEYFRAMES_FIRST) { 896 } else if (call->video_rtp->ssrc == VIDEO_SEND_X_KEYFRAMES_FIRST) {
859 // normal keyframe placement 897 // normal keyframe placement
860 vpx_encode_flags = 0; 898 vpx_encode_flags = 0;
861 LOGGER_INFO(av->m->log, "I_FRAME_FLAG:%d normal mode", call->video_rtp->ssrc); 899 LOGGER_INFO(av->m->log, "I_FRAME_FLAG:%d normal mode", call->video_rtp->ssrc);
862 900
863 call->video_rtp->ssrc++; 901 ++call->video_rtp->ssrc;
864 } 902 }
865 903
866 // we start with I-frames (full frames) and then switch to normal mode later 904 // we start with I-frames (full frames) and then switch to normal mode later
867 905
868 { /* Encode */ 906 { /* Encode */
869 vpx_image_t img; 907 vpx_image_t img;
870 img.w = img.h = img.d_w = img.d_h = 0; 908 img.w = 0;
909 img.h = 0;
910 img.d_w = 0;
911 img.d_h = 0;
871 vpx_img_alloc(&img, VPX_IMG_FMT_I420, width, height, 0); 912 vpx_img_alloc(&img, VPX_IMG_FMT_I420, width, height, 0);
872 913
873 /* I420 "It comprises an NxM Y plane followed by (N/2)x(M/2) V and U planes." 914 /* I420 "It comprises an NxM Y plane followed by (N/2)x(M/2) V and U planes."
@@ -886,49 +927,17 @@ bool toxav_video_send_frame(ToxAV *av, uint32_t friend_number, uint16_t width, u
886 pthread_mutex_unlock(call->mutex_video); 927 pthread_mutex_unlock(call->mutex_video);
887 LOGGER_ERROR(av->m->log, "Could not encode video frame: %s\n", vpx_codec_err_to_string(vrc)); 928 LOGGER_ERROR(av->m->log, "Could not encode video frame: %s\n", vpx_codec_err_to_string(vrc));
888 rc = TOXAV_ERR_SEND_FRAME_INVALID; 929 rc = TOXAV_ERR_SEND_FRAME_INVALID;
889 goto END; 930 goto RETURN;
890 } 931 }
891 } 932 }
892 933
893 ++call->video->frame_counter; 934 ++call->video->frame_counter;
894 935
895 { /* Send frames */ 936 rc = send_frames(av->m->log, call);
896 vpx_codec_iter_t iter = nullptr;
897 const vpx_codec_cx_pkt_t *pkt;
898
899 while ((pkt = vpx_codec_get_cx_data(call->video->encoder, &iter)) != nullptr) {
900 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
901 const bool is_keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
902
903 // https://www.webmproject.org/docs/webm-sdk/structvpx__codec__cx__pkt.html
904 // pkt->data.frame.sz -> size_t
905 const uint32_t frame_length_in_bytes = pkt->data.frame.sz;
906
907 const int res = rtp_send_data(
908 call->video_rtp,
909 (const uint8_t *)pkt->data.frame.buf,
910 frame_length_in_bytes,
911 is_keyframe,
912 av->m->log);
913
914 LOGGER_DEBUG(av->m->log, "+ _sending_FRAME_TYPE_==%s bytes=%d frame_len=%d", is_keyframe ? "K" : ".",
915 (int)pkt->data.frame.sz, (int)frame_length_in_bytes);
916 LOGGER_DEBUG(av->m->log, "+ _sending_FRAME_ b0=%d b1=%d", ((const uint8_t *)pkt->data.frame.buf)[0],
917 ((const uint8_t *)pkt->data.frame.buf)[1]);
918
919 if (res < 0) {
920 pthread_mutex_unlock(call->mutex_video);
921 LOGGER_WARNING(av->m->log, "Could not send video frame: %s", strerror(errno));
922 rc = TOXAV_ERR_SEND_FRAME_RTP_FAILED;
923 goto END;
924 }
925 }
926 }
927 }
928 937
929 pthread_mutex_unlock(call->mutex_video); 938 pthread_mutex_unlock(call->mutex_video);
930 939
931END: 940RETURN:
932 941
933 if (error) { 942 if (error) {
934 *error = rc; 943 *error = rc;
@@ -986,9 +995,9 @@ void callback_bwc(BWController *bwc, uint32_t friend_number, float loss, void *u
986 return; 995 return;
987 } 996 }
988 997
989 (*call->av->vbcb)(call->av, friend_number, 998 call->av->vbcb(call->av, friend_number,
990 call->video_bit_rate - (call->video_bit_rate * loss), 999 call->video_bit_rate - (call->video_bit_rate * loss),
991 call->av->vbcb_user_data); 1000 call->av->vbcb_user_data);
992 } else if (call->audio_bit_rate) { 1001 } else if (call->audio_bit_rate) {
993 if (!call->av->abcb) { 1002 if (!call->av->abcb) {
994 pthread_mutex_unlock(call->av->mutex); 1003 pthread_mutex_unlock(call->av->mutex);
@@ -996,9 +1005,9 @@ void callback_bwc(BWController *bwc, uint32_t friend_number, float loss, void *u
996 return; 1005 return;
997 } 1006 }
998 1007
999 (*call->av->abcb)(call->av, friend_number, 1008 call->av->abcb(call->av, friend_number,
1000 call->audio_bit_rate - (call->audio_bit_rate * loss), 1009 call->audio_bit_rate - (call->audio_bit_rate * loss),
1001 call->av->abcb_user_data); 1010 call->av->abcb_user_data);
1002 } 1011 }
1003 1012
1004 pthread_mutex_unlock(call->av->mutex); 1013 pthread_mutex_unlock(call->av->mutex);
@@ -1067,8 +1076,8 @@ int callback_end(void *toxav_inst, MSICall *call)
1067 invoke_call_state_callback(toxav, call->friend_number, TOXAV_FRIEND_CALL_STATE_FINISHED); 1076 invoke_call_state_callback(toxav, call->friend_number, TOXAV_FRIEND_CALL_STATE_FINISHED);
1068 1077
1069 if (call->av_call) { 1078 if (call->av_call) {
1070 call_kill_transmission((ToxAVCall *)call->av_call); 1079 call_kill_transmission(call->av_call);
1071 call_remove((ToxAVCall *)call->av_call); 1080 call_remove(call->av_call);
1072 } 1081 }
1073 1082
1074 pthread_mutex_unlock(toxav->mutex); 1083 pthread_mutex_unlock(toxav->mutex);
@@ -1082,8 +1091,8 @@ int callback_error(void *toxav_inst, MSICall *call)
1082 invoke_call_state_callback(toxav, call->friend_number, TOXAV_FRIEND_CALL_STATE_ERROR); 1091 invoke_call_state_callback(toxav, call->friend_number, TOXAV_FRIEND_CALL_STATE_ERROR);
1083 1092
1084 if (call->av_call) { 1093 if (call->av_call) {
1085 call_kill_transmission((ToxAVCall *)call->av_call); 1094 call_kill_transmission(call->av_call);
1086 call_remove((ToxAVCall *)call->av_call); 1095 call_remove(call->av_call);
1087 } 1096 }
1088 1097
1089 pthread_mutex_unlock(toxav->mutex); 1098 pthread_mutex_unlock(toxav->mutex);
@@ -1095,15 +1104,15 @@ int callback_capabilites(void *toxav_inst, MSICall *call)
1095 pthread_mutex_lock(toxav->mutex); 1104 pthread_mutex_lock(toxav->mutex);
1096 1105
1097 if (call->peer_capabilities & MSI_CAP_S_AUDIO) { 1106 if (call->peer_capabilities & MSI_CAP_S_AUDIO) {
1098 rtp_allow_receiving(((ToxAVCall *)call->av_call)->audio_rtp); 1107 rtp_allow_receiving(call->av_call->audio_rtp);
1099 } else { 1108 } else {
1100 rtp_stop_receiving(((ToxAVCall *)call->av_call)->audio_rtp); 1109 rtp_stop_receiving(call->av_call->audio_rtp);
1101 } 1110 }
1102 1111
1103 if (call->peer_capabilities & MSI_CAP_S_VIDEO) { 1112 if (call->peer_capabilities & MSI_CAP_S_VIDEO) {
1104 rtp_allow_receiving(((ToxAVCall *)call->av_call)->video_rtp); 1113 rtp_allow_receiving(call->av_call->video_rtp);
1105 } else { 1114 } else {
1106 rtp_stop_receiving(((ToxAVCall *)call->av_call)->video_rtp); 1115 rtp_stop_receiving(call->av_call->video_rtp);
1107 } 1116 }
1108 1117
1109 invoke_call_state_callback(toxav, call->friend_number, call->peer_capabilities); 1118 invoke_call_state_callback(toxav, call->friend_number, call->peer_capabilities);
@@ -1140,32 +1149,32 @@ bool invoke_call_state_callback(ToxAV *av, uint32_t friend_number, uint32_t stat
1140 return true; 1149 return true;
1141} 1150}
1142 1151
1143ToxAVCall *call_new(ToxAV *av, uint32_t friend_number, TOXAV_ERR_CALL *error) 1152ToxAVCall *call_new(ToxAV *av, uint32_t friend_number, Toxav_Err_Call *error)
1144{ 1153{
1145 /* Assumes mutex locked */ 1154 /* Assumes mutex locked */
1146 TOXAV_ERR_CALL rc = TOXAV_ERR_CALL_OK; 1155 Toxav_Err_Call rc = TOXAV_ERR_CALL_OK;
1147 ToxAVCall *call = nullptr; 1156 ToxAVCall *call = nullptr;
1148 1157
1149 if (m_friend_exists(av->m, friend_number) == 0) { 1158 if (m_friend_exists(av->m, friend_number) == 0) {
1150 rc = TOXAV_ERR_CALL_FRIEND_NOT_FOUND; 1159 rc = TOXAV_ERR_CALL_FRIEND_NOT_FOUND;
1151 goto END; 1160 goto RETURN;
1152 } 1161 }
1153 1162
1154 if (m_get_friend_connectionstatus(av->m, friend_number) < 1) { 1163 if (m_get_friend_connectionstatus(av->m, friend_number) < 1) {
1155 rc = TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED; 1164 rc = TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED;
1156 goto END; 1165 goto RETURN;
1157 } 1166 }
1158 1167
1159 if (call_get(av, friend_number) != nullptr) { 1168 if (call_get(av, friend_number) != nullptr) {
1160 rc = TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL; 1169 rc = TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL;
1161 goto END; 1170 goto RETURN;
1162 } 1171 }
1163 1172
1164 call = (ToxAVCall *)calloc(sizeof(ToxAVCall), 1); 1173 call = (ToxAVCall *)calloc(sizeof(ToxAVCall), 1);
1165 1174
1166 if (call == nullptr) { 1175 if (call == nullptr) {
1167 rc = TOXAV_ERR_CALL_MALLOC; 1176 rc = TOXAV_ERR_CALL_MALLOC;
1168 goto END; 1177 goto RETURN;
1169 } 1178 }
1170 1179
1171 call->av = av; 1180 call->av = av;
@@ -1178,10 +1187,11 @@ ToxAVCall *call_new(ToxAV *av, uint32_t friend_number, TOXAV_ERR_CALL *error)
1178 free(call); 1187 free(call);
1179 call = nullptr; 1188 call = nullptr;
1180 rc = TOXAV_ERR_CALL_MALLOC; 1189 rc = TOXAV_ERR_CALL_MALLOC;
1181 goto END; 1190 goto RETURN;
1182 } 1191 }
1183 1192
1184 av->calls_tail = av->calls_head = friend_number; 1193 av->calls_tail = friend_number;
1194 av->calls_head = friend_number;
1185 } else if (av->calls_tail < friend_number) { /* Appending */ 1195 } else if (av->calls_tail < friend_number) { /* Appending */
1186 ToxAVCall **tmp = (ToxAVCall **)realloc(av->calls, sizeof(ToxAVCall *) * (friend_number + 1)); 1196 ToxAVCall **tmp = (ToxAVCall **)realloc(av->calls, sizeof(ToxAVCall *) * (friend_number + 1));
1187 1197
@@ -1189,15 +1199,13 @@ ToxAVCall *call_new(ToxAV *av, uint32_t friend_number, TOXAV_ERR_CALL *error)
1189 free(call); 1199 free(call);
1190 call = nullptr; 1200 call = nullptr;
1191 rc = TOXAV_ERR_CALL_MALLOC; 1201 rc = TOXAV_ERR_CALL_MALLOC;
1192 goto END; 1202 goto RETURN;
1193 } 1203 }
1194 1204
1195 av->calls = tmp; 1205 av->calls = tmp;
1196 1206
1197 /* Set fields in between to null */ 1207 /* Set fields in between to null */
1198 uint32_t i = av->calls_tail + 1; 1208 for (uint32_t i = av->calls_tail + 1; i < friend_number; ++i) {
1199
1200 for (; i < friend_number; i ++) {
1201 av->calls[i] = nullptr; 1209 av->calls[i] = nullptr;
1202 } 1210 }
1203 1211
@@ -1213,7 +1221,7 @@ ToxAVCall *call_new(ToxAV *av, uint32_t friend_number, TOXAV_ERR_CALL *error)
1213 1221
1214 av->calls[friend_number] = call; 1222 av->calls[friend_number] = call;
1215 1223
1216END: 1224RETURN:
1217 1225
1218 if (error) { 1226 if (error) {
1219 *error = rc; 1227 *error = rc;
@@ -1273,7 +1281,8 @@ ToxAVCall *call_remove(ToxAVCall *call)
1273 return next; 1281 return next;
1274 1282
1275CLEAR: 1283CLEAR:
1276 av->calls_head = av->calls_tail = 0; 1284 av->calls_head = 0;
1285 av->calls_tail = 0;
1277 free(av->calls); 1286 free(av->calls);
1278 av->calls = nullptr; 1287 av->calls = nullptr;
1279 1288
@@ -1327,7 +1336,7 @@ bool call_prepare_transmission(ToxAVCall *call)
1327 call->audio, ac_queue_message); 1336 call->audio, ac_queue_message);
1328 1337
1329 if (!call->audio_rtp) { 1338 if (!call->audio_rtp) {
1330 LOGGER_ERROR(av->m->log, "Failed to create audio rtp session");; 1339 LOGGER_ERROR(av->m->log, "Failed to create audio rtp session");
1331 goto FAILURE; 1340 goto FAILURE;
1332 } 1341 }
1333 } 1342 }
diff --git a/toxav/toxav.h b/toxav/toxav.h
index 911d6b49..5b25fdeb 100644
--- a/toxav/toxav.h
+++ b/toxav/toxav.h
@@ -733,6 +733,10 @@ void toxav_callback_video_receive_frame(ToxAV *av, toxav_video_receive_frame_cb
733 733
734/** 734/**
735 * NOTE Compatibility with old toxav group calls. TODO(iphydf): remove 735 * NOTE Compatibility with old toxav group calls. TODO(iphydf): remove
736 *
737 * TODO(iphydf): Use proper new API guidelines for these. E.g. don't use inline
738 * function types, don't have per-callback userdata, especially don't have one
739 * userdata per group.
736 */ 740 */
737/* Create a new toxav group. 741/* Create a new toxav group.
738 * 742 *
@@ -744,9 +748,9 @@ void toxav_callback_video_receive_frame(ToxAV *av, toxav_video_receive_frame_cb
744 * 748 *
745 * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). 749 * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)).
746 */ 750 */
747int toxav_add_av_groupchat(Tox *tox, void (*audio_callback)(void *, uint32_t, uint32_t, const int16_t *, unsigned int, 751int toxav_add_av_groupchat(Tox *tox,
748 uint8_t, 752 void (*audio_callback)(void *, uint32_t, uint32_t, const int16_t *, unsigned int, uint8_t, uint32_t, void *),
749 uint32_t, void *), void *userdata); 753 void *userdata);
750 754
751/* Join a AV group (you need to have been invited first.) 755/* Join a AV group (you need to have been invited first.)
752 * 756 *
@@ -781,4 +785,16 @@ int toxav_group_send_audio(Tox *tox, uint32_t groupnumber, const int16_t *pcm, u
781#ifdef __cplusplus 785#ifdef __cplusplus
782} 786}
783#endif 787#endif
788
789typedef void toxav_group_audio_cb(Tox *tox, uint32_t groupnumber, uint32_t peernumber, const int16_t *pcm,
790 uint32_t samples, uint8_t channels, uint32_t sample_rate, void *user_data);
791
792typedef TOXAV_ERR_CALL Toxav_Err_Call;
793typedef TOXAV_ERR_NEW Toxav_Err_New;
794typedef TOXAV_ERR_ANSWER Toxav_Err_Answer;
795typedef TOXAV_ERR_CALL_CONTROL Toxav_Err_Call_Control;
796typedef TOXAV_ERR_BIT_RATE_SET Toxav_Err_Bit_Rate_Set;
797typedef TOXAV_ERR_SEND_FRAME Toxav_Err_Send_Frame;
798typedef TOXAV_CALL_CONTROL Toxav_Call_Control;
799
784#endif /* TOXAV_H */ 800#endif /* TOXAV_H */