summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--toxav/av_test.c173
-rw-r--r--toxav/msi.h2
-rw-r--r--toxav/toxav.c184
-rw-r--r--toxav/toxav.h22
4 files changed, 266 insertions, 115 deletions
diff --git a/toxav/av_test.c b/toxav/av_test.c
index 594e7232..41f5a758 100644
--- a/toxav/av_test.c
+++ b/toxav/av_test.c
@@ -16,13 +16,25 @@
16 16
17typedef struct { 17typedef struct {
18 bool incoming; 18 bool incoming;
19 bool ringing; 19 TOXAV_CALL_STATE state;
20 bool ended;
21 bool errored;
22 bool sending;
23 bool paused;
24} CallControl; 20} CallControl;
25 21
22const char* stringify_state(TOXAV_CALL_STATE s)
23{
24 static const char* strings[] =
25 {
26 "NOT SENDING",
27 "SENDING AUDIO",
28 "SENDING VIDEO",
29 "SENDING AUDIO AND VIDEO",
30 "PAUSED",
31 "END",
32 "ERROR"
33 };
34
35 return strings [s];
36};
37
26 38
27/** 39/**
28 * Callbacks 40 * Callbacks
@@ -34,53 +46,9 @@ void t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool
34} 46}
35void t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, TOXAV_CALL_STATE state, void *user_data) 47void t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, TOXAV_CALL_STATE state, void *user_data)
36{ 48{
37 printf("Handling CALL STATE callback: "); 49 printf("Handling CALL STATE callback: %s\n", stringify_state(state));
38
39 if (((CallControl*)user_data)->paused)
40 ((CallControl*)user_data)->paused = false;
41
42 switch (state)
43 {
44 case TOXAV_CALL_STATE_NOT_SENDING: {
45 printf("Not sending");
46 ((CallControl*)user_data)->sending = false;
47 } break;
48
49 case TOXAV_CALL_STATE_SENDING_A: {
50 printf("Sending Audio");
51 ((CallControl*)user_data)->sending = true;
52 } break;
53
54 case TOXAV_CALL_STATE_SENDING_V: {
55 printf("Sending Video");
56 ((CallControl*)user_data)->sending = true;
57 } break;
58
59 case TOXAV_CALL_STATE_SENDING_AV: {
60 printf("Sending Both");
61 ((CallControl*)user_data)->sending = true;
62 } break;
63
64 case TOXAV_CALL_STATE_PAUSED: {
65 printf("Paused");
66 ((CallControl*)user_data)->paused = true;
67 ((CallControl*)user_data)->sending = false;
68 } break;
69
70 case TOXAV_CALL_STATE_END: {
71 printf("Ended");
72 ((CallControl*)user_data)->ended = true;
73 ((CallControl*)user_data)->sending = false;
74 } break;
75
76 case TOXAV_CALL_STATE_ERROR: {
77 printf("Error");
78 ((CallControl*)user_data)->errored = true;
79 ((CallControl*)user_data)->sending = false;
80 } break;
81 }
82 50
83 printf("\n"); 51 ((CallControl*)user_data)->state = state;
84} 52}
85void t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number, 53void t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
86 uint16_t width, uint16_t height, 54 uint16_t width, uint16_t height,
@@ -211,27 +179,24 @@ int main (int argc, char** argv)
211 long long unsigned int start_time = time(NULL); \ 179 long long unsigned int start_time = time(NULL); \
212 \ 180 \
213 \ 181 \
214 while (!AliceCC.ended || !BobCC.ended) { \ 182 while (BobCC.state != TOXAV_CALL_STATE_END) { \
215 \ 183 \
216 if (BobCC.incoming) { \ 184 if (BobCC.incoming) { \
217 TOXAV_ERR_ANSWER rc; \ 185 TOXAV_ERR_ANSWER rc; \
218 toxav_answer(BobAV, 0, 48, 4000, &rc); \ 186 toxav_answer(BobAV, 0, A_BR, V_BR, &rc); \
219 \ 187 \
220 if (rc != TOXAV_ERR_ANSWER_OK) { \ 188 if (rc != TOXAV_ERR_ANSWER_OK) { \
221 printf("toxav_answer failed: %d\n", rc); \ 189 printf("toxav_answer failed: %d\n", rc); \
222 exit(1); \ 190 exit(1); \
223 } \ 191 } \
224 BobCC.incoming = false; \ 192 BobCC.incoming = false; \
225 BobCC.sending = true; /* There is no more start callback when answering */\ 193 } else { \
226 } \
227 else if (AliceCC.sending && BobCC.sending) { \
228 /* TODO rtp */ \ 194 /* TODO rtp */ \
229 \ 195 \
230 if (time(NULL) - start_time == 5) { \ 196 if (time(NULL) - start_time == 5) { \
231 \ 197 \
232 TOXAV_ERR_CALL_CONTROL rc; \ 198 TOXAV_ERR_CALL_CONTROL rc; \
233 toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc); \ 199 toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc); \
234 AliceCC.ended = true; /* There is no more end callback when hanging up */\
235 \ 200 \
236 if (rc != TOXAV_ERR_CALL_CONTROL_OK) { \ 201 if (rc != TOXAV_ERR_CALL_CONTROL_OK) { \
237 printf("toxav_call_control failed: %d\n", rc); \ 202 printf("toxav_call_control failed: %d\n", rc); \
@@ -286,7 +251,7 @@ int main (int argc, char** argv)
286 } 251 }
287 } 252 }
288 253
289 while (!AliceCC.ended) 254 while (AliceCC.state != TOXAV_CALL_STATE_END)
290 iterate(Bsn, AliceAV, BobAV); 255 iterate(Bsn, AliceAV, BobAV);
291 256
292 printf("Success!\n"); 257 printf("Success!\n");
@@ -323,9 +288,99 @@ int main (int argc, char** argv)
323 } 288 }
324 289
325 /* Alice will not receive end state */ 290 /* Alice will not receive end state */
326 while (!BobCC.ended) 291 while (BobCC.state != TOXAV_CALL_STATE_END)
292 iterate(Bsn, AliceAV, BobAV);
293
294 printf("Success!\n");
295 }
296
297 { /* Check Mute-Unmute etc */
298 printf("\nTrying mute functionality...\n");
299
300
301 memset(&AliceCC, 0, sizeof(CallControl));
302 memset(&BobCC, 0, sizeof(CallControl));
303
304 /* Assume sending audio and video */
305 {
306 TOXAV_ERR_CALL rc;
307 toxav_call(AliceAV, 0, 48, 1000, &rc);
308
309 if (rc != TOXAV_ERR_CALL_OK) {
310 printf("toxav_call failed: %d\n", rc);
311 exit(1);
312 }
313 }
314
315 while (!BobCC.incoming)
327 iterate(Bsn, AliceAV, BobAV); 316 iterate(Bsn, AliceAV, BobAV);
328 317
318 /* At first try all stuff while in invalid state */
319 assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL));
320 assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_RESUME, NULL));
321 assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_MUTE_AUDIO, NULL));
322 assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_MUTE_VIDEO, NULL));
323 assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_UNMUTE_AUDIO, NULL));
324 assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_UNMUTE_VIDEO, NULL));
325
326 {
327 TOXAV_ERR_ANSWER rc;
328 toxav_answer(BobAV, 0, 48, 4000, &rc);
329
330 if (rc != TOXAV_ERR_ANSWER_OK) {
331 printf("toxav_answer failed: %d\n", rc);
332 exit(1);
333 }
334 }
335
336 iterate(Bsn, AliceAV, BobAV);
337
338 /* Pause and Resume */
339 printf("Pause and Resume\n");
340 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL));
341 iterate(Bsn, AliceAV, BobAV);
342 assert(BobCC.state == TOXAV_CALL_STATE_PAUSED);
343 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_RESUME, NULL));
344 iterate(Bsn, AliceAV, BobAV);
345 assert(BobCC.state == TOXAV_CALL_STATE_SENDING_AV);
346
347 /* Mute/Unmute single */
348 printf("Mute/Unmute single\n");
349 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_MUTE_AUDIO, NULL));
350 iterate(Bsn, AliceAV, BobAV);
351 assert(BobCC.state == TOXAV_CALL_CONTROL_MUTE_AUDIO);
352 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_UNMUTE_AUDIO, NULL));
353 iterate(Bsn, AliceAV, BobAV);
354 assert(BobCC.state == TOXAV_CALL_CONTROL_UNMUTE_AUDIO);
355
356 /* Mute/Unmute both */
357 printf("Mute/Unmute both\n");
358 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_MUTE_AUDIO, NULL));
359 iterate(Bsn, AliceAV, BobAV);
360 assert(BobCC.state == TOXAV_CALL_STATE_SENDING_V);
361 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_MUTE_VIDEO, NULL));
362 iterate(Bsn, AliceAV, BobAV);
363 assert(BobCC.state == TOXAV_CALL_STATE_NOT_SENDING);
364 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_UNMUTE_AUDIO, NULL));
365 iterate(Bsn, AliceAV, BobAV);
366 assert(BobCC.state == TOXAV_CALL_STATE_SENDING_A);
367 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_UNMUTE_VIDEO, NULL));
368 iterate(Bsn, AliceAV, BobAV);
369 assert(BobCC.state == TOXAV_CALL_STATE_SENDING_AV);
370
371 {
372 TOXAV_ERR_CALL_CONTROL rc;
373 toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
374
375 if (rc != TOXAV_ERR_CALL_CONTROL_OK) {
376 printf("toxav_call_control failed: %d\n", rc);
377 exit(1);
378 }
379 }
380
381 iterate(Bsn, AliceAV, BobAV);
382 assert(BobCC.state == TOXAV_CALL_STATE_END);
383
329 printf("Success!\n"); 384 printf("Success!\n");
330 } 385 }
331 386
diff --git a/toxav/msi.h b/toxav/msi.h
index 783d3928..b846542d 100644
--- a/toxav/msi.h
+++ b/toxav/msi.h
@@ -41,8 +41,8 @@ typedef enum {
41 msi_InvalidState, 41 msi_InvalidState,
42 msi_StrayMessage, 42 msi_StrayMessage,
43 msi_SystemError, 43 msi_SystemError,
44 msi_ErrUndisclosed,
45 msi_HandleError, 44 msi_HandleError,
45 msi_ErrUndisclosed, /* NOTE: must be last enum otherwise parsing wont work */
46} MSIError; 46} MSIError;
47 47
48/** 48/**
diff --git a/toxav/toxav.c b/toxav/toxav.c
index 5054d399..e6b51ee4 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -235,6 +235,8 @@ bool toxav_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint
235 return false; 235 return false;
236 } 236 }
237 237
238 call->msi_call->av_call = call;
239
238 return true; 240 return true;
239} 241}
240 242
@@ -310,12 +312,22 @@ bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL co
310 switch (control) 312 switch (control)
311 { 313 {
312 case TOXAV_CALL_CONTROL_RESUME: { 314 case TOXAV_CALL_CONTROL_RESUME: {
313 if (call->msi_call->self_capabilities == 0 && 315 if (!call->active) {
316 rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
317 goto END;
318 }
319
320 /* Only act if paused and had media transfer active before */
321 if (call->msi_call->self_capabilities == 0 &&
314 call->last_capabilities ) { 322 call->last_capabilities ) {
315 /* Only act if paused and had media transfer active before */
316 323
317 if (msi_change_capabilities(call->msi_call, call->last_capabilities) == -1) 324 if (msi_change_capabilities(call->msi_call,
318 return false; 325 call->last_capabilities) == -1) {
326 /* The only reason for this function to fail is invalid state
327 * ( not active ) */
328 rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
329 goto END;
330 }
319 331
320 rtp_start_receiving(call->rtps[audio_index]); 332 rtp_start_receiving(call->rtps[audio_index]);
321 rtp_start_receiving(call->rtps[video_index]); 333 rtp_start_receiving(call->rtps[video_index]);
@@ -323,13 +335,21 @@ bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL co
323 } break; 335 } break;
324 336
325 case TOXAV_CALL_CONTROL_PAUSE: { 337 case TOXAV_CALL_CONTROL_PAUSE: {
338 if (!call->active) {
339 rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
340 goto END;
341 }
342
343 /* Only act if not already paused */
326 if (call->msi_call->self_capabilities) { 344 if (call->msi_call->self_capabilities) {
327 /* Only act if not already paused */
328
329 call->last_capabilities = call->msi_call->self_capabilities; 345 call->last_capabilities = call->msi_call->self_capabilities;
330 346
331 if (msi_change_capabilities(call->msi_call, 0) == -1 ) 347 if (msi_change_capabilities(call->msi_call, 0) == -1 ) {
332 return false; 348 /* The only reason for this function to fail is invalid state
349 * ( not active ) */
350 rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
351 goto END;
352 }
333 353
334 rtp_stop_receiving(call->rtps[audio_index]); 354 rtp_stop_receiving(call->rtps[audio_index]);
335 rtp_stop_receiving(call->rtps[video_index]); 355 rtp_stop_receiving(call->rtps[video_index]);
@@ -341,26 +361,84 @@ bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL co
341 msi_hangup(call->msi_call); 361 msi_hangup(call->msi_call);
342 362
343 /* No mather the case, terminate the call */ 363 /* No mather the case, terminate the call */
364 call_kill_transmission(call);
344 call_remove(call); 365 call_remove(call);
345 } break; 366 } break;
346 367
347 case TOXAV_CALL_CONTROL_MUTE_AUDIO: { 368 case TOXAV_CALL_CONTROL_MUTE_AUDIO: {
348 if (call->msi_call->self_capabilities & msi_CapRAudio || 369 if (!call->active) {
349 call->msi_call->self_capabilities & msi_CapSAudio) { 370 rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
350 371 goto END;
351 uint8_t capabilities = call->msi_call->self_capabilities; 372 }
352 capabilities ^= msi_CapRAudio; 373
353 capabilities ^= msi_CapRAudio; 374 if (call->msi_call->self_capabilities & msi_CapRAudio) {
354 375 if (msi_change_capabilities(call->msi_call, call->
355 if (msi_change_capabilities(call->msi_call, call->msi_call->self_capabilities) == -1) 376 msi_call->self_capabilities ^ msi_CapRAudio) == -1) {
356 return false; 377 /* The only reason for this function to fail is invalid state
378 * ( not active ) */
379 rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
380 goto END;
381 }
357 382
358 rtp_stop_receiving(call->rtps[audio_index]); 383 rtp_stop_receiving(call->rtps[audio_index]);
359 } 384 }
360 } break; 385 } break;
361 386
362 case TOXAV_CALL_CONTROL_MUTE_VIDEO: { 387 case TOXAV_CALL_CONTROL_MUTE_VIDEO: {
388 if (!call->active) {
389 rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
390 goto END;
391 }
392
393 if (call->msi_call->self_capabilities & msi_CapRVideo) {
394 if (msi_change_capabilities(call->msi_call, call->
395 msi_call->self_capabilities ^ msi_CapRVideo) == -1) {
396 /* The only reason for this function to fail is invalid state
397 * ( not active ) */
398 rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
399 goto END;
400 }
401
402 rtp_stop_receiving(call->rtps[video_index]);
403 }
404 } break;
405
406 case TOXAV_CALL_CONTROL_UNMUTE_AUDIO: {
407 if (!call->active) {
408 rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
409 goto END;
410 }
411
412 if (call->msi_call->self_capabilities & ~msi_CapRAudio) {
413 if (msi_change_capabilities(call->msi_call, call->
414 msi_call->self_capabilities | msi_CapRAudio) == -1) {
415 /* The only reason for this function to fail is invalid state
416 * ( not active ) */
417 rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
418 goto END;
419 }
420
421 rtp_start_receiving(call->rtps[audio_index]);
422 }
423 } break;
424
425 case TOXAV_CALL_CONTROL_UNMUTE_VIDEO: {
426 if (!call->active) {
427 rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
428 goto END;
429 }
363 430
431 if (call->msi_call->self_capabilities & ~msi_CapRVideo) {
432 if (msi_change_capabilities(call->msi_call, call->
433 msi_call->self_capabilities | msi_CapRVideo) == -1) {
434 /* The only reason for this function to fail is invalid state
435 * ( not active ) */
436 rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
437 goto END;
438 }
439
440 rtp_start_receiving(call->rtps[video_index]);
441 }
364 } break; 442 } break;
365 } 443 }
366 444
@@ -558,8 +636,6 @@ void toxav_callback_receive_audio_frame(ToxAV* av, toxav_receive_audio_frame_cb*
558 * :: Internal 636 * :: Internal
559 * 637 *
560 ******************************************************************************/ 638 ******************************************************************************/
561/** TODO:
562 */
563int callback_invite(void* toxav_inst, MSICall* call) 639int callback_invite(void* toxav_inst, MSICall* call)
564{ 640{
565 ToxAV* toxav = toxav_inst; 641 ToxAV* toxav = toxav_inst;
@@ -586,15 +662,20 @@ int callback_start(void* toxav_inst, MSICall* call)
586 662
587 ToxAVCall* av_call = call_get(toxav, call->friend_id); 663 ToxAVCall* av_call = call_get(toxav, call->friend_id);
588 664
589 if (av_call == NULL || !call_prepare_transmission(av_call)) { 665 if (av_call == NULL) {
590 call_remove(av_call); 666 /* Should this ever happen? */
591 return -1; 667 return -1;
592 } 668 }
593 669
594 TOXAV_CALL_STATE state = capabilities_to_state(av_call->msi_call->peer_capabilities); 670 if (!call_prepare_transmission(av_call)) {
671 callback_error(toxav_inst, call);
672 call_remove(av_call);
673 return -1;
674 }
595 675
596 if (toxav->scb.first) 676 if (toxav->scb.first)
597 toxav->scb.first(toxav, call->friend_id, state, toxav->scb.second); 677 toxav->scb.first(toxav, call->friend_id,
678 capabilities_to_state(call->peer_capabilities), toxav->scb.second);
598 679
599 return 0; 680 return 0;
600} 681}
@@ -603,18 +684,19 @@ int callback_end(void* toxav_inst, MSICall* call)
603{ 684{
604 ToxAV* toxav = toxav_inst; 685 ToxAV* toxav = toxav_inst;
605 686
606 call_kill_transmission(call->av_call);
607 call_remove(call->av_call);
608
609 if (toxav->scb.first) 687 if (toxav->scb.first)
610 toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_END, toxav->scb.second); 688 toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_END, toxav->scb.second);
611 689
690 call_kill_transmission(call->av_call);
691 call_remove(call->av_call);
692
612 return 0; 693 return 0;
613} 694}
614 695
615int callback_error(void* toxav_inst, MSICall* call) 696int callback_error(void* toxav_inst, MSICall* call)
616{ 697{
617 ToxAV* toxav = toxav_inst; 698 ToxAV* toxav = toxav_inst;
699
618 if (toxav->scb.first) 700 if (toxav->scb.first)
619 toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_ERROR, toxav->scb.second); 701 toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_ERROR, toxav->scb.second);
620 702
@@ -633,14 +715,16 @@ int callback_capabilites(void* toxav_inst, MSICall* call)
633 715
634TOXAV_CALL_STATE capabilities_to_state(uint8_t capabilities) 716TOXAV_CALL_STATE capabilities_to_state(uint8_t capabilities)
635{ 717{
636 if ((capabilities & msi_CapSAudio) && (capabilities & msi_CapSVideo)) 718 if (capabilities == 0)
719 return TOXAV_CALL_STATE_PAUSED;
720 else if ((capabilities & msi_CapSAudio) && (capabilities & msi_CapSVideo))
637 return TOXAV_CALL_STATE_SENDING_AV; 721 return TOXAV_CALL_STATE_SENDING_AV;
638 else if (capabilities & msi_CapSAudio) 722 else if (capabilities & msi_CapSAudio)
639 return TOXAV_CALL_STATE_SENDING_A; 723 return TOXAV_CALL_STATE_SENDING_A;
640 else if (capabilities & msi_CapSVideo) 724 else if (capabilities & msi_CapSVideo)
641 return TOXAV_CALL_STATE_SENDING_V; 725 return TOXAV_CALL_STATE_SENDING_V;
642 else 726
643 return TOXAV_CALL_STATE_PAUSED; 727 return TOXAV_CALL_STATE_NOT_SENDING;
644} 728}
645 729
646bool audio_bitrate_invalid(uint32_t bitrate) 730bool audio_bitrate_invalid(uint32_t bitrate)
@@ -798,8 +882,6 @@ bool call_prepare_transmission(ToxAVCall* call)
798 goto MUTEX_INIT_ERROR; 882 goto MUTEX_INIT_ERROR;
799 } 883 }
800 884
801 uint8_t capabilities = call->msi_call->self_capabilities;
802
803 call->cs = cs_new(call->msi_call->peer_vfpsz); 885 call->cs = cs_new(call->msi_call->peer_vfpsz);
804 886
805 if ( !call->cs ) { 887 if ( !call->cs ) {
@@ -813,8 +895,7 @@ bool call_prepare_transmission(ToxAVCall* call)
813 memcpy(&call->cs->acb, &av->acb, sizeof(av->acb)); 895 memcpy(&call->cs->acb, &av->acb, sizeof(av->acb));
814 memcpy(&call->cs->vcb, &av->vcb, sizeof(av->vcb)); 896 memcpy(&call->cs->vcb, &av->vcb, sizeof(av->vcb));
815 897
816 if (capabilities & msi_CapSAudio || capabilities & msi_CapRAudio) { /* Prepare audio sending */ 898 { /* Prepare audio */
817
818 call->rtps[audio_index] = rtp_new(rtp_TypeAudio, av->m, call->friend_id); 899 call->rtps[audio_index] = rtp_new(rtp_TypeAudio, av->m, call->friend_id);
819 900
820 if ( !call->rtps[audio_index] ) { 901 if ( !call->rtps[audio_index] ) {
@@ -824,22 +905,21 @@ bool call_prepare_transmission(ToxAVCall* call)
824 905
825 call->rtps[audio_index]->cs = call->cs; 906 call->rtps[audio_index]->cs = call->cs;
826 907
827 if (cs_enable_audio_sending(call->cs, call->s_audio_b, 2) != 0) { 908 /* Only enable sending if bitrate is defined */
909 if (call->s_audio_b > 0 && cs_enable_audio_sending(call->cs, call->s_audio_b, 2) != 0) {
828 LOGGER_WARNING("Failed to enable audio sending!"); 910 LOGGER_WARNING("Failed to enable audio sending!");
829 goto FAILURE; 911 goto FAILURE;
830 } 912 }
831 913
832 if (capabilities & msi_CapRAudio) { 914 if (cs_enable_audio_receiving(call->cs) != 0) {
833 if (cs_enable_audio_receiving(call->cs) != 0) { 915 LOGGER_WARNING("Failed to enable audio receiving!");
834 LOGGER_WARNING("Failed to enable audio receiving!"); 916 goto FAILURE;
835 goto FAILURE;
836 }
837
838 rtp_start_receiving(call->rtps[audio_index]);
839 } 917 }
918
919 rtp_start_receiving(call->rtps[audio_index]);
840 } 920 }
841 921
842 if (capabilities & msi_CapSVideo || capabilities & msi_CapRVideo) { /* Prepare video rtp */ 922 { /* Prepare video */
843 call->rtps[video_index] = rtp_new(rtp_TypeVideo, av->m, call->friend_id); 923 call->rtps[video_index] = rtp_new(rtp_TypeVideo, av->m, call->friend_id);
844 924
845 if ( !call->rtps[video_index] ) { 925 if ( !call->rtps[video_index] ) {
@@ -849,26 +929,26 @@ bool call_prepare_transmission(ToxAVCall* call)
849 929
850 call->rtps[video_index]->cs = call->cs; 930 call->rtps[video_index]->cs = call->cs;
851 931
852 if (cs_enable_video_sending(call->cs, call->s_video_b) != 0) { 932 /* Only enable sending if bitrate is defined */
933 if (call->s_video_b > 0 && cs_enable_video_sending(call->cs, call->s_video_b) != 0) {
853 LOGGER_WARNING("Failed to enable video sending!"); 934 LOGGER_WARNING("Failed to enable video sending!");
854 goto FAILURE; 935 goto FAILURE;
855 } 936 }
856 937
857 if (capabilities & msi_CapRVideo) { 938
858 if (cs_enable_video_receiving(call->cs) != 0) { 939 if (cs_enable_video_receiving(call->cs) != 0) {
859 LOGGER_WARNING("Failed to enable video receiving!"); 940 LOGGER_WARNING("Failed to enable video receiving!");
860 goto FAILURE; 941 goto FAILURE;
861 }
862
863 rtp_start_receiving(call->rtps[audio_index]);
864 } 942 }
943
944 rtp_start_receiving(call->rtps[audio_index]);
865 } 945 }
866 946
867 call->active = 1; 947 call->active = 1;
868 pthread_mutex_unlock(call->mutex_control); 948 pthread_mutex_unlock(call->mutex_control);
869 return true; 949 return true;
870 950
871 FAILURE: 951FAILURE:
872 rtp_kill(call->rtps[audio_index]); 952 rtp_kill(call->rtps[audio_index]);
873 call->rtps[audio_index] = NULL; 953 call->rtps[audio_index] = NULL;
874 rtp_kill(call->rtps[video_index]); 954 rtp_kill(call->rtps[video_index]);
@@ -883,7 +963,7 @@ bool call_prepare_transmission(ToxAVCall* call)
883 pthread_mutex_unlock(call->mutex_control); 963 pthread_mutex_unlock(call->mutex_control);
884 return false; 964 return false;
885 965
886 MUTEX_INIT_ERROR: 966MUTEX_INIT_ERROR:
887 pthread_mutex_unlock(call->mutex_control); 967 pthread_mutex_unlock(call->mutex_control);
888 LOGGER_ERROR("Mutex initialization failed!\n"); 968 LOGGER_ERROR("Mutex initialization failed!\n");
889 return false; 969 return false;
diff --git a/toxav/toxav.h b/toxav/toxav.h
index 5e82faa6..ec232ddd 100644
--- a/toxav/toxav.h
+++ b/toxav/toxav.h
@@ -246,7 +246,7 @@ void toxav_callback_call_state(ToxAV *av, toxav_call_state_cb *function, void *u
246typedef enum TOXAV_CALL_CONTROL { 246typedef enum TOXAV_CALL_CONTROL {
247 /** 247 /**
248 * Resume a previously paused call. Only valid if the pause was caused by this 248 * Resume a previously paused call. Only valid if the pause was caused by this
249 * client. Not valid before the call is accepted. 249 * client, if not, this control is ignored. Not valid before the call is accepted.
250 */ 250 */
251 TOXAV_CALL_CONTROL_RESUME, 251 TOXAV_CALL_CONTROL_RESUME,
252 /** 252 /**
@@ -269,7 +269,19 @@ typedef enum TOXAV_CALL_CONTROL {
269 * compliance, this will cause the `receive_video_frame` event to stop being 269 * compliance, this will cause the `receive_video_frame` event to stop being
270 * triggered on receiving an video frame from the friend. 270 * triggered on receiving an video frame from the friend.
271 */ 271 */
272 TOXAV_CALL_CONTROL_MUTE_VIDEO 272 TOXAV_CALL_CONTROL_MUTE_VIDEO,
273 /**
274 * Notify the friend that we are AGAIN ready to handle incoming audio.
275 * This control will not work if the call is not started with audio
276 * initiated.
277 */
278 TOXAV_CALL_CONTROL_UNMUTE_AUDIO,
279 /**
280 * Notify the friend that we are AGAIN ready to handle incoming video.
281 * This control will not work if the call is not started with video
282 * initiated.
283 */
284 TOXAV_CALL_CONTROL_UNMUTE_VIDEO
273} TOXAV_CALL_CONTROL; 285} TOXAV_CALL_CONTROL;
274typedef enum TOXAV_ERR_CALL_CONTROL { 286typedef enum TOXAV_ERR_CALL_CONTROL {
275 TOXAV_ERR_CALL_CONTROL_OK, 287 TOXAV_ERR_CALL_CONTROL_OK,
@@ -296,7 +308,11 @@ typedef enum TOXAV_ERR_CALL_CONTROL {
296 * other party paused the call. The call will resume after both parties sent 308 * other party paused the call. The call will resume after both parties sent
297 * the RESUME control. 309 * the RESUME control.
298 */ 310 */
299 TOXAV_ERR_CALL_CONTROL_ALREADY_PAUSED 311 TOXAV_ERR_CALL_CONTROL_ALREADY_PAUSED,
312 /**
313 * Tried to unmute a call that was not already muted.
314 */
315 TOXAV_ERR_CALL_CONTROL_NOT_MUTED
300} TOXAV_ERR_CALL_CONTROL; 316} TOXAV_ERR_CALL_CONTROL;
301/** 317/**
302 * Sends a call control command to a friend. 318 * Sends a call control command to a friend.