Implement pausing

This commit is contained in:
mannol 2015-02-22 23:41:40 +01:00
parent 29601feb76
commit 9e65cd5337
4 changed files with 266 additions and 115 deletions

View File

@ -16,13 +16,25 @@
typedef struct { typedef struct {
bool incoming; bool incoming;
bool ringing; TOXAV_CALL_STATE state;
bool ended;
bool errored;
bool sending;
bool paused;
} CallControl; } CallControl;
const char* stringify_state(TOXAV_CALL_STATE s)
{
static const char* strings[] =
{
"NOT SENDING",
"SENDING AUDIO",
"SENDING VIDEO",
"SENDING AUDIO AND VIDEO",
"PAUSED",
"END",
"ERROR"
};
return strings [s];
};
/** /**
* Callbacks * Callbacks
@ -34,53 +46,9 @@ void t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool
} }
void t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, TOXAV_CALL_STATE state, void *user_data) void t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, TOXAV_CALL_STATE state, void *user_data)
{ {
printf("Handling CALL STATE callback: "); printf("Handling CALL STATE callback: %s\n", stringify_state(state));
if (((CallControl*)user_data)->paused) ((CallControl*)user_data)->state = state;
((CallControl*)user_data)->paused = false;
switch (state)
{
case TOXAV_CALL_STATE_NOT_SENDING: {
printf("Not sending");
((CallControl*)user_data)->sending = false;
} break;
case TOXAV_CALL_STATE_SENDING_A: {
printf("Sending Audio");
((CallControl*)user_data)->sending = true;
} break;
case TOXAV_CALL_STATE_SENDING_V: {
printf("Sending Video");
((CallControl*)user_data)->sending = true;
} break;
case TOXAV_CALL_STATE_SENDING_AV: {
printf("Sending Both");
((CallControl*)user_data)->sending = true;
} break;
case TOXAV_CALL_STATE_PAUSED: {
printf("Paused");
((CallControl*)user_data)->paused = true;
((CallControl*)user_data)->sending = false;
} break;
case TOXAV_CALL_STATE_END: {
printf("Ended");
((CallControl*)user_data)->ended = true;
((CallControl*)user_data)->sending = false;
} break;
case TOXAV_CALL_STATE_ERROR: {
printf("Error");
((CallControl*)user_data)->errored = true;
((CallControl*)user_data)->sending = false;
} break;
}
printf("\n");
} }
void t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number, void t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
uint16_t width, uint16_t height, uint16_t width, uint16_t height,
@ -211,27 +179,24 @@ int main (int argc, char** argv)
long long unsigned int start_time = time(NULL); \ long long unsigned int start_time = time(NULL); \
\ \
\ \
while (!AliceCC.ended || !BobCC.ended) { \ while (BobCC.state != TOXAV_CALL_STATE_END) { \
\ \
if (BobCC.incoming) { \ if (BobCC.incoming) { \
TOXAV_ERR_ANSWER rc; \ TOXAV_ERR_ANSWER rc; \
toxav_answer(BobAV, 0, 48, 4000, &rc); \ toxav_answer(BobAV, 0, A_BR, V_BR, &rc); \
\ \
if (rc != TOXAV_ERR_ANSWER_OK) { \ if (rc != TOXAV_ERR_ANSWER_OK) { \
printf("toxav_answer failed: %d\n", rc); \ printf("toxav_answer failed: %d\n", rc); \
exit(1); \ exit(1); \
} \ } \
BobCC.incoming = false; \ BobCC.incoming = false; \
BobCC.sending = true; /* There is no more start callback when answering */\ } else { \
} \
else if (AliceCC.sending && BobCC.sending) { \
/* TODO rtp */ \ /* TODO rtp */ \
\ \
if (time(NULL) - start_time == 5) { \ if (time(NULL) - start_time == 5) { \
\ \
TOXAV_ERR_CALL_CONTROL rc; \ TOXAV_ERR_CALL_CONTROL rc; \
toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc); \ toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc); \
AliceCC.ended = true; /* There is no more end callback when hanging up */\
\ \
if (rc != TOXAV_ERR_CALL_CONTROL_OK) { \ if (rc != TOXAV_ERR_CALL_CONTROL_OK) { \
printf("toxav_call_control failed: %d\n", rc); \ printf("toxav_call_control failed: %d\n", rc); \
@ -286,7 +251,7 @@ int main (int argc, char** argv)
} }
} }
while (!AliceCC.ended) while (AliceCC.state != TOXAV_CALL_STATE_END)
iterate(Bsn, AliceAV, BobAV); iterate(Bsn, AliceAV, BobAV);
printf("Success!\n"); printf("Success!\n");
@ -323,12 +288,102 @@ int main (int argc, char** argv)
} }
/* Alice will not receive end state */ /* Alice will not receive end state */
while (!BobCC.ended) while (BobCC.state != TOXAV_CALL_STATE_END)
iterate(Bsn, AliceAV, BobAV); iterate(Bsn, AliceAV, BobAV);
printf("Success!\n"); printf("Success!\n");
} }
{ /* Check Mute-Unmute etc */
printf("\nTrying mute functionality...\n");
memset(&AliceCC, 0, sizeof(CallControl));
memset(&BobCC, 0, sizeof(CallControl));
/* Assume sending audio and video */
{
TOXAV_ERR_CALL rc;
toxav_call(AliceAV, 0, 48, 1000, &rc);
if (rc != TOXAV_ERR_CALL_OK) {
printf("toxav_call failed: %d\n", rc);
exit(1);
}
}
while (!BobCC.incoming)
iterate(Bsn, AliceAV, BobAV);
/* At first try all stuff while in invalid state */
assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL));
assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_RESUME, NULL));
assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_MUTE_AUDIO, NULL));
assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_MUTE_VIDEO, NULL));
assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_UNMUTE_AUDIO, NULL));
assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_UNMUTE_VIDEO, NULL));
{
TOXAV_ERR_ANSWER rc;
toxav_answer(BobAV, 0, 48, 4000, &rc);
if (rc != TOXAV_ERR_ANSWER_OK) {
printf("toxav_answer failed: %d\n", rc);
exit(1);
}
}
iterate(Bsn, AliceAV, BobAV);
/* Pause and Resume */
printf("Pause and Resume\n");
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL));
iterate(Bsn, AliceAV, BobAV);
assert(BobCC.state == TOXAV_CALL_STATE_PAUSED);
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_RESUME, NULL));
iterate(Bsn, AliceAV, BobAV);
assert(BobCC.state == TOXAV_CALL_STATE_SENDING_AV);
/* Mute/Unmute single */
printf("Mute/Unmute single\n");
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_MUTE_AUDIO, NULL));
iterate(Bsn, AliceAV, BobAV);
assert(BobCC.state == TOXAV_CALL_CONTROL_MUTE_AUDIO);
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_UNMUTE_AUDIO, NULL));
iterate(Bsn, AliceAV, BobAV);
assert(BobCC.state == TOXAV_CALL_CONTROL_UNMUTE_AUDIO);
/* Mute/Unmute both */
printf("Mute/Unmute both\n");
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_MUTE_AUDIO, NULL));
iterate(Bsn, AliceAV, BobAV);
assert(BobCC.state == TOXAV_CALL_STATE_SENDING_V);
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_MUTE_VIDEO, NULL));
iterate(Bsn, AliceAV, BobAV);
assert(BobCC.state == TOXAV_CALL_STATE_NOT_SENDING);
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_UNMUTE_AUDIO, NULL));
iterate(Bsn, AliceAV, BobAV);
assert(BobCC.state == TOXAV_CALL_STATE_SENDING_A);
assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_UNMUTE_VIDEO, NULL));
iterate(Bsn, AliceAV, BobAV);
assert(BobCC.state == TOXAV_CALL_STATE_SENDING_AV);
{
TOXAV_ERR_CALL_CONTROL rc;
toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
if (rc != TOXAV_ERR_CALL_CONTROL_OK) {
printf("toxav_call_control failed: %d\n", rc);
exit(1);
}
}
iterate(Bsn, AliceAV, BobAV);
assert(BobCC.state == TOXAV_CALL_STATE_END);
printf("Success!\n");
}
printf("\nTest successful!\n"); printf("\nTest successful!\n");
return 0; return 0;
} }

View File

@ -41,8 +41,8 @@ typedef enum {
msi_InvalidState, msi_InvalidState,
msi_StrayMessage, msi_StrayMessage,
msi_SystemError, msi_SystemError,
msi_ErrUndisclosed,
msi_HandleError, msi_HandleError,
msi_ErrUndisclosed, /* NOTE: must be last enum otherwise parsing wont work */
} MSIError; } MSIError;
/** /**

View File

@ -235,6 +235,8 @@ bool toxav_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint
return false; return false;
} }
call->msi_call->av_call = call;
return true; return true;
} }
@ -310,12 +312,22 @@ bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL co
switch (control) switch (control)
{ {
case TOXAV_CALL_CONTROL_RESUME: { case TOXAV_CALL_CONTROL_RESUME: {
if (!call->active) {
rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
goto END;
}
/* Only act if paused and had media transfer active before */
if (call->msi_call->self_capabilities == 0 && if (call->msi_call->self_capabilities == 0 &&
call->last_capabilities ) { call->last_capabilities ) {
/* Only act if paused and had media transfer active before */
if (msi_change_capabilities(call->msi_call, call->last_capabilities) == -1) if (msi_change_capabilities(call->msi_call,
return false; call->last_capabilities) == -1) {
/* The only reason for this function to fail is invalid state
* ( not active ) */
rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
goto END;
}
rtp_start_receiving(call->rtps[audio_index]); rtp_start_receiving(call->rtps[audio_index]);
rtp_start_receiving(call->rtps[video_index]); 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
} break; } break;
case TOXAV_CALL_CONTROL_PAUSE: { case TOXAV_CALL_CONTROL_PAUSE: {
if (call->msi_call->self_capabilities) { if (!call->active) {
/* Only act if not already paused */ rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
goto END;
}
/* Only act if not already paused */
if (call->msi_call->self_capabilities) {
call->last_capabilities = call->msi_call->self_capabilities; call->last_capabilities = call->msi_call->self_capabilities;
if (msi_change_capabilities(call->msi_call, 0) == -1 ) if (msi_change_capabilities(call->msi_call, 0) == -1 ) {
return false; /* The only reason for this function to fail is invalid state
* ( not active ) */
rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
goto END;
}
rtp_stop_receiving(call->rtps[audio_index]); rtp_stop_receiving(call->rtps[audio_index]);
rtp_stop_receiving(call->rtps[video_index]); 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
msi_hangup(call->msi_call); msi_hangup(call->msi_call);
/* No mather the case, terminate the call */ /* No mather the case, terminate the call */
call_kill_transmission(call);
call_remove(call); call_remove(call);
} break; } break;
case TOXAV_CALL_CONTROL_MUTE_AUDIO: { case TOXAV_CALL_CONTROL_MUTE_AUDIO: {
if (call->msi_call->self_capabilities & msi_CapRAudio || if (!call->active) {
call->msi_call->self_capabilities & msi_CapSAudio) { rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
goto END;
}
uint8_t capabilities = call->msi_call->self_capabilities; if (call->msi_call->self_capabilities & msi_CapRAudio) {
capabilities ^= msi_CapRAudio; if (msi_change_capabilities(call->msi_call, call->
capabilities ^= msi_CapRAudio; msi_call->self_capabilities ^ msi_CapRAudio) == -1) {
/* The only reason for this function to fail is invalid state
if (msi_change_capabilities(call->msi_call, call->msi_call->self_capabilities) == -1) * ( not active ) */
return false; rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
goto END;
}
rtp_stop_receiving(call->rtps[audio_index]); rtp_stop_receiving(call->rtps[audio_index]);
} }
} break; } break;
case TOXAV_CALL_CONTROL_MUTE_VIDEO: { case TOXAV_CALL_CONTROL_MUTE_VIDEO: {
if (!call->active) {
rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
goto END;
}
if (call->msi_call->self_capabilities & msi_CapRVideo) {
if (msi_change_capabilities(call->msi_call, call->
msi_call->self_capabilities ^ msi_CapRVideo) == -1) {
/* The only reason for this function to fail is invalid state
* ( not active ) */
rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
goto END;
}
rtp_stop_receiving(call->rtps[video_index]);
}
} break;
case TOXAV_CALL_CONTROL_UNMUTE_AUDIO: {
if (!call->active) {
rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
goto END;
}
if (call->msi_call->self_capabilities & ~msi_CapRAudio) {
if (msi_change_capabilities(call->msi_call, call->
msi_call->self_capabilities | msi_CapRAudio) == -1) {
/* The only reason for this function to fail is invalid state
* ( not active ) */
rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
goto END;
}
rtp_start_receiving(call->rtps[audio_index]);
}
} break;
case TOXAV_CALL_CONTROL_UNMUTE_VIDEO: {
if (!call->active) {
rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
goto END;
}
if (call->msi_call->self_capabilities & ~msi_CapRVideo) {
if (msi_change_capabilities(call->msi_call, call->
msi_call->self_capabilities | msi_CapRVideo) == -1) {
/* The only reason for this function to fail is invalid state
* ( not active ) */
rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL;
goto END;
}
rtp_start_receiving(call->rtps[video_index]);
}
} break; } break;
} }
@ -558,8 +636,6 @@ void toxav_callback_receive_audio_frame(ToxAV* av, toxav_receive_audio_frame_cb*
* :: Internal * :: Internal
* *
******************************************************************************/ ******************************************************************************/
/** TODO:
*/
int callback_invite(void* toxav_inst, MSICall* call) int callback_invite(void* toxav_inst, MSICall* call)
{ {
ToxAV* toxav = toxav_inst; ToxAV* toxav = toxav_inst;
@ -586,15 +662,20 @@ int callback_start(void* toxav_inst, MSICall* call)
ToxAVCall* av_call = call_get(toxav, call->friend_id); ToxAVCall* av_call = call_get(toxav, call->friend_id);
if (av_call == NULL || !call_prepare_transmission(av_call)) { if (av_call == NULL) {
/* Should this ever happen? */
return -1;
}
if (!call_prepare_transmission(av_call)) {
callback_error(toxav_inst, call);
call_remove(av_call); call_remove(av_call);
return -1; return -1;
} }
TOXAV_CALL_STATE state = capabilities_to_state(av_call->msi_call->peer_capabilities);
if (toxav->scb.first) if (toxav->scb.first)
toxav->scb.first(toxav, call->friend_id, state, toxav->scb.second); toxav->scb.first(toxav, call->friend_id,
capabilities_to_state(call->peer_capabilities), toxav->scb.second);
return 0; return 0;
} }
@ -603,18 +684,19 @@ int callback_end(void* toxav_inst, MSICall* call)
{ {
ToxAV* toxav = toxav_inst; ToxAV* toxav = toxav_inst;
call_kill_transmission(call->av_call);
call_remove(call->av_call);
if (toxav->scb.first) if (toxav->scb.first)
toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_END, toxav->scb.second); toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_END, toxav->scb.second);
call_kill_transmission(call->av_call);
call_remove(call->av_call);
return 0; return 0;
} }
int callback_error(void* toxav_inst, MSICall* call) int callback_error(void* toxav_inst, MSICall* call)
{ {
ToxAV* toxav = toxav_inst; ToxAV* toxav = toxav_inst;
if (toxav->scb.first) if (toxav->scb.first)
toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_ERROR, toxav->scb.second); toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_ERROR, toxav->scb.second);
@ -633,14 +715,16 @@ int callback_capabilites(void* toxav_inst, MSICall* call)
TOXAV_CALL_STATE capabilities_to_state(uint8_t capabilities) TOXAV_CALL_STATE capabilities_to_state(uint8_t capabilities)
{ {
if ((capabilities & msi_CapSAudio) && (capabilities & msi_CapSVideo)) if (capabilities == 0)
return TOXAV_CALL_STATE_PAUSED;
else if ((capabilities & msi_CapSAudio) && (capabilities & msi_CapSVideo))
return TOXAV_CALL_STATE_SENDING_AV; return TOXAV_CALL_STATE_SENDING_AV;
else if (capabilities & msi_CapSAudio) else if (capabilities & msi_CapSAudio)
return TOXAV_CALL_STATE_SENDING_A; return TOXAV_CALL_STATE_SENDING_A;
else if (capabilities & msi_CapSVideo) else if (capabilities & msi_CapSVideo)
return TOXAV_CALL_STATE_SENDING_V; return TOXAV_CALL_STATE_SENDING_V;
else
return TOXAV_CALL_STATE_PAUSED; return TOXAV_CALL_STATE_NOT_SENDING;
} }
bool audio_bitrate_invalid(uint32_t bitrate) bool audio_bitrate_invalid(uint32_t bitrate)
@ -798,8 +882,6 @@ bool call_prepare_transmission(ToxAVCall* call)
goto MUTEX_INIT_ERROR; goto MUTEX_INIT_ERROR;
} }
uint8_t capabilities = call->msi_call->self_capabilities;
call->cs = cs_new(call->msi_call->peer_vfpsz); call->cs = cs_new(call->msi_call->peer_vfpsz);
if ( !call->cs ) { if ( !call->cs ) {
@ -813,8 +895,7 @@ bool call_prepare_transmission(ToxAVCall* call)
memcpy(&call->cs->acb, &av->acb, sizeof(av->acb)); memcpy(&call->cs->acb, &av->acb, sizeof(av->acb));
memcpy(&call->cs->vcb, &av->vcb, sizeof(av->vcb)); memcpy(&call->cs->vcb, &av->vcb, sizeof(av->vcb));
if (capabilities & msi_CapSAudio || capabilities & msi_CapRAudio) { /* Prepare audio sending */ { /* Prepare audio */
call->rtps[audio_index] = rtp_new(rtp_TypeAudio, av->m, call->friend_id); call->rtps[audio_index] = rtp_new(rtp_TypeAudio, av->m, call->friend_id);
if ( !call->rtps[audio_index] ) { if ( !call->rtps[audio_index] ) {
@ -824,12 +905,12 @@ bool call_prepare_transmission(ToxAVCall* call)
call->rtps[audio_index]->cs = call->cs; call->rtps[audio_index]->cs = call->cs;
if (cs_enable_audio_sending(call->cs, call->s_audio_b, 2) != 0) { /* Only enable sending if bitrate is defined */
if (call->s_audio_b > 0 && cs_enable_audio_sending(call->cs, call->s_audio_b, 2) != 0) {
LOGGER_WARNING("Failed to enable audio sending!"); LOGGER_WARNING("Failed to enable audio sending!");
goto FAILURE; goto FAILURE;
} }
if (capabilities & msi_CapRAudio) {
if (cs_enable_audio_receiving(call->cs) != 0) { if (cs_enable_audio_receiving(call->cs) != 0) {
LOGGER_WARNING("Failed to enable audio receiving!"); LOGGER_WARNING("Failed to enable audio receiving!");
goto FAILURE; goto FAILURE;
@ -837,9 +918,8 @@ bool call_prepare_transmission(ToxAVCall* call)
rtp_start_receiving(call->rtps[audio_index]); rtp_start_receiving(call->rtps[audio_index]);
} }
}
if (capabilities & msi_CapSVideo || capabilities & msi_CapRVideo) { /* Prepare video rtp */ { /* Prepare video */
call->rtps[video_index] = rtp_new(rtp_TypeVideo, av->m, call->friend_id); call->rtps[video_index] = rtp_new(rtp_TypeVideo, av->m, call->friend_id);
if ( !call->rtps[video_index] ) { if ( !call->rtps[video_index] ) {
@ -849,12 +929,13 @@ bool call_prepare_transmission(ToxAVCall* call)
call->rtps[video_index]->cs = call->cs; call->rtps[video_index]->cs = call->cs;
if (cs_enable_video_sending(call->cs, call->s_video_b) != 0) { /* Only enable sending if bitrate is defined */
if (call->s_video_b > 0 && cs_enable_video_sending(call->cs, call->s_video_b) != 0) {
LOGGER_WARNING("Failed to enable video sending!"); LOGGER_WARNING("Failed to enable video sending!");
goto FAILURE; goto FAILURE;
} }
if (capabilities & msi_CapRVideo) {
if (cs_enable_video_receiving(call->cs) != 0) { if (cs_enable_video_receiving(call->cs) != 0) {
LOGGER_WARNING("Failed to enable video receiving!"); LOGGER_WARNING("Failed to enable video receiving!");
goto FAILURE; goto FAILURE;
@ -862,7 +943,6 @@ bool call_prepare_transmission(ToxAVCall* call)
rtp_start_receiving(call->rtps[audio_index]); rtp_start_receiving(call->rtps[audio_index]);
} }
}
call->active = 1; call->active = 1;
pthread_mutex_unlock(call->mutex_control); pthread_mutex_unlock(call->mutex_control);

View File

@ -246,7 +246,7 @@ void toxav_callback_call_state(ToxAV *av, toxav_call_state_cb *function, void *u
typedef enum TOXAV_CALL_CONTROL { typedef enum TOXAV_CALL_CONTROL {
/** /**
* Resume a previously paused call. Only valid if the pause was caused by this * Resume a previously paused call. Only valid if the pause was caused by this
* client. Not valid before the call is accepted. * client, if not, this control is ignored. Not valid before the call is accepted.
*/ */
TOXAV_CALL_CONTROL_RESUME, TOXAV_CALL_CONTROL_RESUME,
/** /**
@ -269,7 +269,19 @@ typedef enum TOXAV_CALL_CONTROL {
* compliance, this will cause the `receive_video_frame` event to stop being * compliance, this will cause the `receive_video_frame` event to stop being
* triggered on receiving an video frame from the friend. * triggered on receiving an video frame from the friend.
*/ */
TOXAV_CALL_CONTROL_MUTE_VIDEO TOXAV_CALL_CONTROL_MUTE_VIDEO,
/**
* Notify the friend that we are AGAIN ready to handle incoming audio.
* This control will not work if the call is not started with audio
* initiated.
*/
TOXAV_CALL_CONTROL_UNMUTE_AUDIO,
/**
* Notify the friend that we are AGAIN ready to handle incoming video.
* This control will not work if the call is not started with video
* initiated.
*/
TOXAV_CALL_CONTROL_UNMUTE_VIDEO
} TOXAV_CALL_CONTROL; } TOXAV_CALL_CONTROL;
typedef enum TOXAV_ERR_CALL_CONTROL { typedef enum TOXAV_ERR_CALL_CONTROL {
TOXAV_ERR_CALL_CONTROL_OK, TOXAV_ERR_CALL_CONTROL_OK,
@ -296,7 +308,11 @@ typedef enum TOXAV_ERR_CALL_CONTROL {
* other party paused the call. The call will resume after both parties sent * other party paused the call. The call will resume after both parties sent
* the RESUME control. * the RESUME control.
*/ */
TOXAV_ERR_CALL_CONTROL_ALREADY_PAUSED TOXAV_ERR_CALL_CONTROL_ALREADY_PAUSED,
/**
* Tried to unmute a call that was not already muted.
*/
TOXAV_ERR_CALL_CONTROL_NOT_MUTED
} TOXAV_ERR_CALL_CONTROL; } TOXAV_ERR_CALL_CONTROL;
/** /**
* Sends a call control command to a friend. * Sends a call control command to a friend.