From 29601feb7656d1a75b4ab7cdb161f232f0ec92dc Mon Sep 17 00:00:00 2001 From: mannol Date: Sat, 21 Feb 2015 01:07:22 +0100 Subject: New msi protocol --- toxav/av_test.c | 20 +-- toxav/msi.c | 486 +++++++++++++++++++++----------------------------------- toxav/msi.h | 17 +- toxav/rtp.c | 14 +- toxav/rtp.h | 7 +- toxav/toxav.c | 432 ++++++++++++++++++++++++++----------------------- toxav/toxav.h | 5 - 7 files changed, 445 insertions(+), 536 deletions(-) (limited to 'toxav') diff --git a/toxav/av_test.c b/toxav/av_test.c index 3270f39c..594e7232 100644 --- a/toxav/av_test.c +++ b/toxav/av_test.c @@ -36,19 +36,11 @@ void t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, TOXAV_CALL_STATE s { printf("Handling CALL STATE callback: "); - if (((CallControl*)user_data)->ringing) - ((CallControl*)user_data)->ringing = false; - if (((CallControl*)user_data)->paused) ((CallControl*)user_data)->paused = false; switch (state) - { - case TOXAV_CALL_STATE_RINGING: { - printf("Ringing"); - ((CallControl*)user_data)->ringing = true; - } break; - + { case TOXAV_CALL_STATE_NOT_SENDING: { printf("Not sending"); ((CallControl*)user_data)->sending = false; @@ -230,6 +222,7 @@ int main (int argc, char** argv) exit(1); \ } \ BobCC.incoming = false; \ + BobCC.sending = true; /* There is no more start callback when answering */\ } \ else if (AliceCC.sending && BobCC.sending) { \ /* TODO rtp */ \ @@ -238,6 +231,7 @@ int main (int argc, char** argv) \ TOXAV_ERR_CALL_CONTROL 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) { \ printf("toxav_call_control failed: %d\n", rc); \ @@ -252,13 +246,13 @@ int main (int argc, char** argv) } printf("\nTrying regular call (Audio and Video)...\n"); - REGULAR_CALL_FLOW(48, 4000); +// REGULAR_CALL_FLOW(48, 4000); printf("\nTrying regular call (Audio only)...\n"); - REGULAR_CALL_FLOW(48, 0); +// REGULAR_CALL_FLOW(48, 0); printf("\nTrying regular call (Video only)...\n"); - REGULAR_CALL_FLOW(0, 4000); +// REGULAR_CALL_FLOW(0, 4000); #undef REGULAR_CALL_FLOW @@ -292,7 +286,7 @@ int main (int argc, char** argv) } } - while (!AliceCC.ended || !BobCC.ended) + while (!AliceCC.ended) iterate(Bsn, AliceAV, BobAV); printf("Success!\n"); diff --git a/toxav/msi.c b/toxav/msi.c index 16476364..f179a7ab 100644 --- a/toxav/msi.c +++ b/toxav/msi.c @@ -37,8 +37,6 @@ #define MSI_MAXMSG_SIZE 256 -/* TODO send error on any calloc or etc */ - /** * Protocol: * @@ -47,24 +45,17 @@ typedef enum { IDRequest = 1, - IDResponse, IDError, IDCapabilities, IDVFPSZ, } MSIHeaderID; -typedef enum { - requ_invite, - requ_start, - requ_reject, - requ_end, -} MSIRequest; typedef enum { - resp_ringing, - resp_starting, -} MSIResponse; + requ_push, + requ_pop, +} MSIRequest; #define GENERIC_HEADER(header, val_type) \ @@ -75,7 +66,6 @@ typedef struct { \ GENERIC_HEADER ( Request, MSIRequest ); -GENERIC_HEADER ( Response, MSIResponse ); GENERIC_HEADER ( Error, MSIError ); GENERIC_HEADER ( Capabilities, uint8_t ); GENERIC_HEADER ( VFPSZ, uint16_t ); @@ -83,29 +73,24 @@ GENERIC_HEADER ( VFPSZ, uint16_t ); typedef struct { MSIHeaderRequest request; - MSIHeaderResponse response; MSIHeaderError error; MSIHeaderCapabilities capabilities; MSIHeaderVFPSZ vfpsz; /* Video frame piece size. NOTE: Value must be in network b-order */ } MSIMessage; +void msg_init (MSIMessage *dest, MSIRequest request); int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length ); uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length ); int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg ); int send_error ( Messenger* m, uint32_t friend_id, MSIError error ); -static void invoke_callback(MSICall* call, MSICallbackID cb); +static int invoke_callback(MSICall* call, MSICallbackID cb); static MSICall *get_call ( MSISession *session, uint32_t friend_id ); MSICall *new_call ( MSISession *session, uint32_t friend_id ); void kill_call ( MSICall *call ); void on_peer_status(Messenger *m, int friend_id, uint8_t status, void *data); -int handle_recv_invite ( MSICall *call, const MSIMessage *msg ); -int handle_recv_start ( MSICall *call, const MSIMessage *msg ); -int handle_recv_reject ( MSICall *call, const MSIMessage *msg ); -int handle_recv_end ( MSICall *call, const MSIMessage *msg ); -int handle_recv_ringing ( MSICall *call, const MSIMessage *msg ); -int handle_recv_starting ( MSICall *call, const MSIMessage *msg ); -int handle_recv_error ( MSICall *call, const MSIMessage *msg ); +void handle_push ( MSICall *call, const MSIMessage *msg ); +void handle_pop ( MSICall *call, const MSIMessage *msg ); void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint16_t length, void *object ); @@ -157,13 +142,12 @@ int msi_kill ( MSISession *session ) pthread_mutex_lock(session->mutex); if (session->calls) { - MSIMessage msg_end; - msg_end.request.exists = true; - msg_end.request.value = requ_end; + MSIMessage msg; + msg_init(&msg, requ_pop); MSICall* it = get_call(session, session->calls_head); for (; it; it = it->next) { - send_message(session->messenger, it->friend_id, &msg_end); + send_message(session->messenger, it->friend_id, &msg); kill_call(it); /* This will eventually free session->calls */ } } @@ -191,17 +175,16 @@ int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_ (*call)->self_capabilities = capabilities; - MSIMessage msg_invite; - msg_invite.request.exists = true; - msg_invite.request.value = requ_invite; + MSIMessage msg; + msg_init(&msg, requ_push); - msg_invite.capabilities.exists = true; - msg_invite.capabilities.value = capabilities; + msg.capabilities.exists = true; + msg.capabilities.value = capabilities; - msg_invite.vfpsz.exists = true; - msg_invite.vfpsz.value = htons(VIDEOFRAME_PIECE_SIZE); + msg.vfpsz.exists = true; + msg.vfpsz.value = htons(VIDEOFRAME_PIECE_SIZE); - send_message ( (*call)->session->messenger, (*call)->friend_id, &msg_invite ); + send_message ( (*call)->session->messenger, (*call)->friend_id, &msg ); (*call)->state = msi_CallRequesting; @@ -212,10 +195,10 @@ int msi_hangup ( MSICall* call ) { LOGGER_DEBUG("Session: %p Hanging up call with friend: %u", call->session, call->friend_id); - MSIMessage msg_end; - msg_end.request.exists = true; - msg_end.request.value = requ_end; - send_message ( call->session->messenger, call->friend_id, &msg_end ); + MSIMessage msg; + msg_init(&msg, requ_pop); + + send_message ( call->session->messenger, call->friend_id, &msg ); kill_call(call); return 0; @@ -225,65 +208,68 @@ int msi_answer ( MSICall* call, uint8_t capabilities ) LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_id); if ( call->state != msi_CallRequested ) { + /* Though sending in invalid state will not cause anything wierd + * Its better to not do it like a maniac */ LOGGER_ERROR("Call is in invalid state!"); return -1; } call->self_capabilities = capabilities; - MSIMessage msg_starting; - msg_starting.response.exists = true; - msg_starting.response.value = resp_starting; + MSIMessage msg; + msg_init(&msg, requ_push); - msg_starting.capabilities.exists = true; - msg_starting.capabilities.value = capabilities; + msg.capabilities.exists = true; + msg.capabilities.value = capabilities; - msg_starting.vfpsz.exists = true; - msg_starting.vfpsz.value = htons(VIDEOFRAME_PIECE_SIZE); + msg.vfpsz.exists = true; + msg.vfpsz.value = htons(VIDEOFRAME_PIECE_SIZE); - send_message ( call->session->messenger, call->friend_id, &msg_starting ); + send_message ( call->session->messenger, call->friend_id, &msg ); + + call->state = msi_CallActive; return 0; } -int msi_reject ( MSICall* call ) +int msi_change_capabilities( MSICall* call, uint8_t capabilities ) { - LOGGER_DEBUG("Session: %p Rejecting call with friend: %u", call->session, call->friend_id); - - if ( call->state != msi_CallRequested ) { + LOGGER_DEBUG("Session: %p Trying to change capabilities to friend %u", call->session, call->friend_id); + + if ( call->state != msi_CallActive ) { + /* Sending capabilities change can cause error on other side if + * the call is not active since we don't send header 'vfpsz'. + * If we were to send 'vfpsz' while call is active it would be + * ignored. However, if call is not active peer will expect + * the said header on 'push' so that it could handle the call + * like new. TODO: explain this better + */ LOGGER_ERROR("Call is in invalid state!"); return -1; } - MSIMessage msg_reject; - msg_reject.request.exists = true; - msg_reject.request.value = requ_reject; - - send_message ( call->session->messenger, call->friend_id, &msg_reject ); - - return 0; -} -int msi_change_csettings( MSICall* call, uint8_t capabilities ) -{ call->self_capabilities = capabilities; - MSIMessage msg_invite; - msg_invite.request.exists = true; - msg_invite.request.value = requ_invite; + MSIMessage msg; + msg_init(&msg, requ_push); - msg_invite.capabilities.exists = true; - msg_invite.capabilities.value = capabilities; + msg.capabilities.exists = true; + msg.capabilities.value = capabilities; - send_message ( call->session->messenger, call->friend_id, &msg_invite ); + send_message ( call->session->messenger, call->friend_id, &msg ); return 0; } - /** * Private functions */ - +void msg_init(MSIMessage* dest, MSIRequest request) +{ + memset(dest, 0, sizeof(*dest)); + dest->request.exists = true; + dest->request.value = request; +} int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length ) { /* Parse raw data received from socket into MSIMessage struct */ @@ -314,7 +300,9 @@ int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length ) LOGGER_ERROR("Invalid end byte"); return -1; } - + + memset(dest, 0, sizeof(*dest)); + const uint8_t *it = data; int size_constraint = length; @@ -322,17 +310,10 @@ int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length ) switch (*it) { case IDRequest: CHECK_SIZE(it, size_constraint, 1); - CHECK_ENUM_HIGH(it, requ_end); + CHECK_ENUM_HIGH(it, requ_pop); SET_UINT8(it, dest->request); break; - case IDResponse: - CHECK_SIZE(it, size_constraint, 1); - CHECK_ENUM_HIGH(it, resp_starting); - SET_UINT8(it, dest->response); - it += 3; - break; - case IDError: CHECK_SIZE(it, size_constraint, 1); CHECK_ENUM_HIGH(it, msi_ErrUndisclosed); @@ -356,6 +337,11 @@ int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length ) } } + if (dest->request.exists == false) { + LOGGER_ERROR("Invalid request field!"); + return -1; + } + return 0; #undef CHECK_SIZE @@ -395,17 +381,15 @@ int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg ) uint8_t cast = msg->request.value; it = msg_parse_header_out(IDRequest, it, &cast, sizeof(cast), &size); - } - - if (msg->response.exists) { - uint8_t cast = msg->response.value; - it = msg_parse_header_out(IDResponse, it, &cast, - sizeof(cast), &size); + } else { + LOGGER_DEBUG("Must have request field"); + return -1; } if (msg->error.exists) { - it = msg_parse_header_out(IDError, it, &msg->error.value, - sizeof(msg->error.value), &size); + uint8_t cast = msg->error.value; + it = msg_parse_header_out(IDError, it, &cast, + sizeof(cast), &size); } if (msg->capabilities.exists) { @@ -418,14 +402,14 @@ int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg ) sizeof(msg->vfpsz.value), &size); } - *it = 0; - size ++; - if ( it == parsed ) { LOGGER_WARNING("Parsing message failed; empty message"); return -1; } + *it = 0; + size ++; + if ( m_msi_packet(m, friend_id, parsed, size) ) { LOGGER_DEBUG("Sent message"); return 0; @@ -440,22 +424,36 @@ int send_error ( Messenger* m, uint32_t friend_id, MSIError error ) LOGGER_DEBUG("Sending error: %d to friend: %d", error, friend_id); - MSIMessage msg_error; + MSIMessage msg; + msg_init(&msg, requ_pop); - msg_error.error.exists = true; - msg_error.error.value = error; + msg.error.exists = true; + msg.error.value = error; - send_message ( m, friend_id, &msg_error ); + send_message ( m, friend_id, &msg ); return 0; } -static void invoke_callback(MSICall* call, MSICallbackID cb) +int invoke_callback(MSICall* call, MSICallbackID cb) { assert(call); if ( call->session->callbacks[cb] ) { LOGGER_DEBUG("Invoking callback function: %d", cb); - call->session->callbacks[cb] ( call->session->av, call ); + if ( call->session->callbacks[cb] ( call->session->av, call ) != 0 ) { + LOGGER_WARNING("Callback handling failed, sending error"); + goto FAILURE; + } + + return 0; } + +FAILURE: + /* If no callback present or error happened while handling, + * an error message will be send to friend + */ + + call->error = msi_HandleError; + return -1; } static MSICall *get_call ( MSISession *session, uint32_t friend_id ) { @@ -563,7 +561,7 @@ void on_peer_status(Messenger *m, int friend_id, uint8_t status, void *data) if (call == NULL) return; - invoke_callback(call, msi_OnPeerTimeout); + invoke_callback(call, msi_OnPeerTimeout); /* Failure is ignored */ kill_call(call); } break; @@ -572,205 +570,120 @@ void on_peer_status(Messenger *m, int friend_id, uint8_t status, void *data) break; } } -int handle_recv_invite ( MSICall *call, const MSIMessage *msg ) +void handle_push ( MSICall *call, const MSIMessage *msg ) { assert(call); MSISession* session = call->session; - LOGGER_DEBUG("Session: %p Handling 'invite' friend: %d", call->session, call->friend_id); + LOGGER_DEBUG("Session: %p Handling 'push' friend: %d", call->session, call->friend_id); if (!msg->capabilities.exists) { - LOGGER_WARNING("Session: %p Invalid capabilities on 'invite'"); + LOGGER_WARNING("Session: %p Invalid capabilities on 'push'"); call->error = msi_InvalidMessage; - return -1; + goto FAILURE; } - MSIMessage response; - response.response.exists = true; - - if ( call->state == msi_CallRequesting ) { - /* The rare glare case. - * Send starting and wait for starting by the other side. - * The peer will do the same. - * When you receive starting from peer send started. - * Don't notice the app until the start is received. - */ - - LOGGER_DEBUG("Glare detected!"); - + if (call->state != msi_CallActive) { if (!msg->vfpsz.exists) { - LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'"); + LOGGER_WARNING("Session: %p Invalid vfpsz on 'push'"); call->error = msi_InvalidMessage; - return -1; + goto FAILURE; } - call->peer_capabilities = msg->capabilities.value; + /* Sending video frame piece size is ignored when call is active */ call->peer_vfpsz = ntohs(msg->vfpsz.value); + } + + + switch (call->state) { + case msi_CallInactive: { + LOGGER_INFO("Friend is calling us"); + + /* Call requested */ + call->peer_capabilities = msg->capabilities.value; + call->state = msi_CallRequested; + + if ( invoke_callback(call, msi_OnInvite) == -1 ) + goto FAILURE; + + } break; - /* Send response */ - response.response.value = resp_starting; - send_message ( call->session->messenger, call->friend_id, &response ); - - return 0; - } else if ( call->state == msi_CallActive ) { - /* Changing capabilities. - * We send starting but no response is expected. - * WARNING: if start is sent call is terminated with an error - */ - LOGGER_DEBUG("Peer is changing capabilities"); - - /* Send response */ - response.response.value = resp_starting; - send_message ( call->session->messenger, call->friend_id, &response ); + case msi_CallActive: { + /* Only act if capabilities changed */ + if ( call->peer_capabilities != msg->capabilities.value) { + LOGGER_INFO("Friend is changing capabilities"); + + call->peer_capabilities = msg->capabilities.value; + if ( invoke_callback(call, msi_OnCapabilities) == -1 ) + goto FAILURE; + } + } break; - if ( call->peer_capabilities != msg->capabilities.value) { - /* Only invoke callback if capabilities changed */ + case msi_CallRequesting: { + LOGGER_INFO("Friend answered our call"); + + /* Call started */ call->peer_capabilities = msg->capabilities.value; - invoke_callback(call, msi_OnCapabilities); - } + call->state = msi_CallActive; + + if ( invoke_callback(call, msi_OnStart) == -1 ) + goto FAILURE; + } break; - return 0; - } - - if (!msg->vfpsz.exists) { - LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'"); - call->error = msi_InvalidMessage; - return -1; + case msi_CallRequested: { + /* Consecutive pushes during initialization state are ignored */ + LOGGER_WARNING("Consecutive push"); + } break; } - call->peer_capabilities = msg->capabilities.value; - call->peer_vfpsz = ntohs(msg->vfpsz.value); - call->state = msi_CallRequested; - - /* Send response */ - response.response.value = resp_ringing; - send_message ( call->session->messenger, call->friend_id, &response ); - - - invoke_callback(call, msi_OnInvite); - return 0; -} -int handle_recv_start ( MSICall *call, const MSIMessage *msg ) -{ - assert(call); - - if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) { - LOGGER_WARNING("Session: %p Invalid call state on 'start'"); - call->error = msi_InvalidState; - return -1; - } - - (void)msg; - - LOGGER_DEBUG("Session: %p Handling 'start', friend id: %d", call->session, call->friend_id ); - - call->state = msi_CallActive; - invoke_callback(call, msi_OnStart); - - return 0; -} -int handle_recv_reject ( MSICall *call, const MSIMessage *msg ) -{ - assert(call); - - (void)msg; - - if ( call->state != msi_CallRequesting ) { - LOGGER_WARNING("Session: %p Invalid call state on 'reject'"); - call->error = msi_InvalidState; - return -1; - } + return; - LOGGER_DEBUG("Session: %p Handling 'reject', friend id: %u", call->session, call->friend_id); - - invoke_callback(call, msi_OnReject); +FAILURE: + send_error(call->session->messenger, call->friend_id, call->error); kill_call(call); - - return 0; -} -int handle_recv_end ( MSICall *call, const MSIMessage *msg ) -{ - assert(call); - - (void)msg; - - LOGGER_DEBUG("Session: %p Handling 'end', friend id: %d", call->session, call->friend_id); - - invoke_callback(call, msi_OnEnd); - kill_call ( call ); - - return 0; } -int handle_recv_ringing ( MSICall *call, const MSIMessage *msg ) +void handle_pop ( MSICall *call, const MSIMessage *msg ) { assert(call); - (void)msg; - - if ( call->state != msi_CallRequesting ) { - LOGGER_WARNING("Session: %p Invalid call state on 'ringing'"); - call->error = msi_InvalidState; - return -1; - } - - LOGGER_DEBUG("Session: %p Handling 'ringing' friend id: %d", call->session, call->friend_id ); - - invoke_callback(call, msi_OnRinging); - return 0; -} -int handle_recv_starting ( MSICall *call, const MSIMessage *msg ) -{ - assert(call); + LOGGER_DEBUG("Session: %p Handling 'pop', friend id: %d", call->session, call->friend_id); - if ( call->state == msi_CallActive ) { - LOGGER_DEBUG("Capabilities change confirmed"); - return 0; - } else if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) { - LOGGER_WARNING("Session: %p Invalid call state on 'starting'"); - call->error = msi_InvalidState; - return -1; - } + /* callback errors are ignored */ - if (call->state == msi_CallRequesting) { - if (!msg->capabilities.exists) { - LOGGER_WARNING("Session: %p Invalid capabilities on 'starting'"); - call->error = msi_InvalidParam; - return -1; - } + if (msg->error.exists) { + LOGGER_WARNING("Friend detected an error: %d", msg->error.value); + call->error = msg->error.value; + invoke_callback(call, msi_OnError); - if (!msg->vfpsz.exists) { - LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'"); - call->error = msi_InvalidParam; - return -1; - } + } else switch (call->state) { + case msi_CallInactive: { + LOGGER_ERROR("Handling what should be impossible case"); + abort(); + } break; - call->peer_capabilities = msg->capabilities.value; - call->peer_vfpsz = ntohs(msg->vfpsz.value); - call->state = msi_CallActive; + case msi_CallActive: { + /* Hangup */ + LOGGER_INFO("Friend hung up on us"); + invoke_callback(call, msi_OnEnd); + } break; - invoke_callback(call, msi_OnStart); + case msi_CallRequesting: { + /* Reject */ + LOGGER_INFO("Friend rejected our call"); + invoke_callback(call, msi_OnEnd); + } break; + + case msi_CallRequested: { + /* Cancel */ + LOGGER_INFO("Friend canceled call invite"); + invoke_callback(call, msi_OnEnd); + } break; } - /* Otherwise it's a glare case so don't start until 'start' is recved */ - - /* Send start in either case (glare or normal) */ - MSIMessage msg_start; - msg_start.request.exists = true; - msg_start.request.value = requ_start; - send_message ( call->session->messenger, call->friend_id, &msg_start ); - return 0; -} -int handle_recv_error ( MSICall *call, const MSIMessage *msg ) -{ - assert(call); - - LOGGER_DEBUG("Session: %p Handling 'error' friend id: %d", call->session, call->friend_id ); - - call->error = msg->error.value; - invoke_callback(call, msi_OnError); + kill_call ( call ); - return 0; + return; } void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint16_t length, void *object ) { @@ -779,8 +692,6 @@ void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint1 MSISession *session = object; MSIMessage msg; - int rc = 0; - if ( msg_parse_in ( &msg, data, length ) == -1 ) { LOGGER_WARNING("Error parsing message"); send_error(m, friend_id, msi_InvalidMessage); @@ -792,7 +703,7 @@ void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint1 MSICall *call = get_call(session, friend_id); if (call == NULL) { - if (msg.request.value != requ_invite) { + if (msg.request.value != requ_push) { send_error(m, friend_id, msi_StrayMessage); return; } @@ -805,49 +716,8 @@ void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint1 } - /* Now handle message */ - if ( msg.request.exists ) { /* Handle request */ - switch (msg.request.value) { - case requ_invite: - rc = handle_recv_invite ( call, &msg ); - break; - - case requ_start: - rc = handle_recv_start ( call, &msg ); - break; - - case requ_reject: - rc = handle_recv_reject ( call, &msg ); - break; - - case requ_end: - rc = handle_recv_end ( call, &msg ); - break; - } - } else if ( msg.response.exists ) { /* Handle response */ - switch (msg.response.value) { - case resp_ringing: - rc = handle_recv_ringing ( call, &msg ); - break; - - case resp_starting: - rc = handle_recv_starting ( call, &msg ); - break; - } - } else if (msg.error.exists) { - handle_recv_error ( call, &msg ); - rc = -1; - } else { - LOGGER_WARNING("Invalid message; none of the request, response or error!"); - call->error = msi_InvalidMessage; - rc = -1; - } - - - if (rc == -1) { - if (call->error != msi_ErrorNone) - send_error(m, friend_id, call->error); - - kill_call(call); - } -} + if (msg.request.value == requ_push) + handle_push(call, &msg); + else + handle_pop(call, &msg); /* always kills the call */ +} \ No newline at end of file diff --git a/toxav/msi.h b/toxav/msi.h index a55d8567..783d3928 100644 --- a/toxav/msi.h +++ b/toxav/msi.h @@ -42,6 +42,7 @@ typedef enum { msi_StrayMessage, msi_SystemError, msi_ErrUndisclosed, + msi_HandleError, } MSIError; /** @@ -70,9 +71,7 @@ typedef enum { */ typedef enum { msi_OnInvite, /* Incoming call */ - msi_OnRinging, /* When peer is ready to accept/reject the call */ msi_OnStart, /* Call (RTP transmission) started */ - msi_OnReject, /* The side that was invited rejected the call */ msi_OnEnd, /* Call that was active ended */ msi_OnError, /* On protocol error */ msi_OnPeerTimeout, /* Peer timed out; stop the call */ @@ -100,9 +99,12 @@ typedef struct MSICall_s { /** - * Msi callback type. 'agent' is a pointer to ToxAv + * Msi callback type. 'agent' is a pointer to ToxAv. + * Expected return on success is 0, if any other number is + * returned the call is considered errored and will be handled + * as such which means it will be terminated without any notice. */ -typedef void ( *MSICallbackType ) ( void *agent, MSICall* call); +typedef int ( *MSICallbackType ) ( void *agent, MSICall* call); /** * Control session struct. Please do not modify outside msi.c @@ -117,7 +119,7 @@ typedef struct MSISession_s { Messenger *messenger; pthread_mutex_t mutex[1]; - MSICallbackType callbacks[8]; + MSICallbackType callbacks[7]; } MSISession; /** @@ -150,11 +152,6 @@ int msi_hangup ( MSICall* call ); */ int msi_answer ( MSICall* call, uint8_t capabilities ); -/** - * Reject incoming call. NOTE: 'call' will be freed - */ -int msi_reject ( MSICall* call ); - /** * Change capabilities of the call. */ diff --git a/toxav/rtp.c b/toxav/rtp.c index 396e0202..8319c7dc 100644 --- a/toxav/rtp.c +++ b/toxav/rtp.c @@ -478,12 +478,24 @@ void rtp_kill ( RTPSession *session ) free ( session ); } -int rtp_register_for_receiving(RTPSession* session) +int rtp_start_receiving(RTPSession* session) { + if (session == NULL) + return 0; + return custom_lossy_packet_registerhandler(session->m, session->dest, session->prefix, rtp_handle_packet, session); } +int rtp_stop_receiving(RTPSession* session) +{ + if (session == NULL) + return 0; + + return custom_lossy_packet_registerhandler(session->m, session->dest, session->prefix, + NULL, NULL); +} + int rtp_send_msg ( RTPSession *session, const uint8_t *data, uint16_t length ) { RTPMessage *msg = rtp_new_message (session, data, length); diff --git a/toxav/rtp.h b/toxav/rtp.h index e3b38a8e..2950941b 100644 --- a/toxav/rtp.h +++ b/toxav/rtp.h @@ -119,7 +119,12 @@ void rtp_kill ( RTPSession* session ); /** * By default rtp is not in receiving state */ -int rtp_register_for_receiving (RTPSession *session); +int rtp_start_receiving (RTPSession *session); + +/** + * Pause rtp receiving mode. + */ +int rtp_stop_receiving (RTPSession *session); /** * Sends msg to RTPSession::dest diff --git a/toxav/toxav.c b/toxav/toxav.c index 584b3898..5054d399 100644 --- a/toxav/toxav.c +++ b/toxav/toxav.c @@ -42,6 +42,7 @@ enum { typedef struct ToxAVCall_s { + ToxAV* av; pthread_mutex_t mutex_control[1]; pthread_mutex_t mutex_encoding_audio[1]; pthread_mutex_t mutex_encoding_video[1]; @@ -55,6 +56,8 @@ typedef struct ToxAVCall_s uint32_t s_audio_b; /* Sending audio bitrate */ uint32_t s_video_b; /* Sending video bitrate */ + uint8_t last_capabilities; + struct ToxAVCall_s *prev; struct ToxAVCall_s *next; } ToxAVCall; @@ -83,22 +86,20 @@ struct toxAV }; -void i_callback_invite(void* toxav_inst, MSICall* call); -void i_callback_ringing(void* toxav_inst, MSICall* call); -void i_callback_start(void* toxav_inst, MSICall* call); -void i_callback_end(void* toxav_inst, MSICall* call); -void i_callback_error(void* toxav_inst, MSICall* call); -void i_callback_capabilites(void* toxav_inst, MSICall* call); +int callback_invite(void* toxav_inst, MSICall* call); +int callback_start(void* toxav_inst, MSICall* call); +int callback_end(void* toxav_inst, MSICall* call); +int callback_error(void* toxav_inst, MSICall* call); +int callback_capabilites(void* toxav_inst, MSICall* call); TOXAV_CALL_STATE capabilities_to_state(uint8_t capabilities); -ToxAVCall* i_toxav_get_call(ToxAV* av, uint32_t friend_number); -ToxAVCall* i_toxav_add_call(ToxAV* av, uint32_t friend_number); -void i_toxav_remove_call(ToxAV* av, uint32_t friend_number); -ToxAVCall* i_toxav_init_call(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error); -bool i_toxav_audio_bitrate_invalid(uint32_t bitrate); -bool i_toxav_video_bitrate_invalid(uint32_t bitrate); -bool i_toxav_prepare_transmission(ToxAV* av, ToxAVCall* call); -void i_toxav_kill_transmission(ToxAV* av, uint32_t friend_number); +ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error); +ToxAVCall* call_get(ToxAV* av, uint32_t friend_number); +void call_remove(ToxAVCall* call); +bool audio_bitrate_invalid(uint32_t bitrate); +bool video_bitrate_invalid(uint32_t bitrate); +bool call_prepare_transmission(ToxAVCall* call); +void call_kill_transmission(ToxAVCall* call); @@ -136,14 +137,12 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error) av->interval = 200; av->msi->av = av; - msi_register_callback(av->msi, i_callback_invite, msi_OnInvite); - msi_register_callback(av->msi, i_callback_ringing, msi_OnRinging); - msi_register_callback(av->msi, i_callback_start, msi_OnStart); - msi_register_callback(av->msi, i_callback_end, msi_OnReject); - msi_register_callback(av->msi, i_callback_end, msi_OnEnd); - msi_register_callback(av->msi, i_callback_error, msi_OnError); - msi_register_callback(av->msi, i_callback_error, msi_OnPeerTimeout); - msi_register_callback(av->msi, i_callback_capabilites, msi_OnCapabilities); + msi_register_callback(av->msi, callback_invite, msi_OnInvite); + msi_register_callback(av->msi, callback_start, msi_OnStart); + msi_register_callback(av->msi, callback_end, msi_OnEnd); + msi_register_callback(av->msi, callback_error, msi_OnError); + msi_register_callback(av->msi, callback_error, msi_OnPeerTimeout); + msi_register_callback(av->msi, callback_capabilites, msi_OnCapabilities); if (error) @@ -166,7 +165,16 @@ void toxav_kill(ToxAV* av) return; msi_kill(av->msi); - /* TODO iterate over calls */ + + /* Msi kill will hang up all calls so just clean these calls */ + if (av->calls) { + ToxAVCall* it = call_get(av, av->calls_head); + for (; it; it = it->next) { + call_kill_transmission(it); + call_remove(it); /* This will eventually free av->calls */ + } + } + free(av); } @@ -208,20 +216,20 @@ void toxav_iteration(ToxAV* av) bool toxav_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error) { - ToxAVCall* call = i_toxav_init_call(av, friend_number, error); + ToxAVCall* call = call_new(av, friend_number, error); if (call == NULL) return false; call->s_audio_b = audio_bit_rate; call->s_video_b = video_bit_rate; - uint8_t capabilities = 0; + call->last_capabilities = msi_CapRAudio | msi_CapRVideo; - capabilities |= audio_bit_rate > 0 ? msi_CapSAudio : 0; - capabilities |= video_bit_rate > 0 ? msi_CapSVideo : 0; + call->last_capabilities |= audio_bit_rate > 0 ? msi_CapSAudio : 0; + call->last_capabilities |= video_bit_rate > 0 ? msi_CapSVideo : 0; - if (msi_invite(av->msi, &call->msi_call, friend_number, capabilities) != 0) { - i_toxav_remove_call(av, friend_number); + if (msi_invite(av->msi, &call->msi_call, friend_number, call->last_capabilities) != 0) { + call_remove(call); if (error) *error = TOXAV_ERR_CALL_MALLOC; return false; @@ -244,14 +252,14 @@ bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, ui goto END; } - if ((audio_bit_rate && i_toxav_audio_bitrate_invalid(audio_bit_rate)) - ||(video_bit_rate && i_toxav_video_bitrate_invalid(video_bit_rate)) + if ((audio_bit_rate && audio_bitrate_invalid(audio_bit_rate)) + ||(video_bit_rate && video_bitrate_invalid(video_bit_rate)) ) { rc = TOXAV_ERR_CALL_INVALID_BIT_RATE; goto END; } - ToxAVCall* call = i_toxav_get_call(av, friend_number); + ToxAVCall* call = call_get(av, friend_number); if (call == NULL) { rc = TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING; goto END; @@ -260,12 +268,12 @@ bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, ui call->s_audio_b = audio_bit_rate; call->s_video_b = video_bit_rate; - uint8_t capabilities = 0; + call->last_capabilities = msi_CapRAudio | msi_CapRVideo; - capabilities |= audio_bit_rate > 0 ? msi_CapSAudio : 0; - capabilities |= video_bit_rate > 0 ? msi_CapSVideo : 0; + call->last_capabilities |= audio_bit_rate > 0 ? msi_CapSAudio : 0; + call->last_capabilities |= video_bit_rate > 0 ? msi_CapSVideo : 0; - if (msi_answer(call->msi_call, capabilities) != 0) + if (msi_answer(call->msi_call, call->last_capabilities) != 0) rc = TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING; /* the only reason for msi_answer to fail */ @@ -292,7 +300,7 @@ bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL co } - ToxAVCall* call = i_toxav_get_call(av, friend_number); + ToxAVCall* call = call_get(av, friend_number); if (call == NULL) { rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL; goto END; @@ -302,29 +310,53 @@ bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL co switch (control) { case TOXAV_CALL_CONTROL_RESUME: { - + if (call->msi_call->self_capabilities == 0 && + call->last_capabilities ) { + /* Only act if paused and had media transfer active before */ + + if (msi_change_capabilities(call->msi_call, call->last_capabilities) == -1) + return false; + + rtp_start_receiving(call->rtps[audio_index]); + rtp_start_receiving(call->rtps[video_index]); + } } break; case TOXAV_CALL_CONTROL_PAUSE: { - + if (call->msi_call->self_capabilities) { + /* Only act if not already paused */ + + call->last_capabilities = call->msi_call->self_capabilities; + + if (msi_change_capabilities(call->msi_call, 0) == -1 ) + return false; + + rtp_stop_receiving(call->rtps[audio_index]); + rtp_stop_receiving(call->rtps[video_index]); + } } break; case TOXAV_CALL_CONTROL_CANCEL: { - if (call->msi_call->state == msi_CallActive - || call->msi_call->state == msi_CallRequesting) { - /* Hang up */ - msi_hangup(call->msi_call); - } else if (call->msi_call->state == msi_CallRequested) { - /* Reject the call */ - msi_reject(call->msi_call); - } + /* Hang up */ + msi_hangup(call->msi_call); - // No mather the case, terminate the call - i_toxav_remove_call(av, friend_number); + /* No mather the case, terminate the call */ + call_remove(call); } break; case TOXAV_CALL_CONTROL_MUTE_AUDIO: { - + if (call->msi_call->self_capabilities & msi_CapRAudio || + call->msi_call->self_capabilities & msi_CapSAudio) { + + uint8_t capabilities = call->msi_call->self_capabilities; + capabilities ^= msi_CapRAudio; + capabilities ^= msi_CapRAudio; + + if (msi_change_capabilities(call->msi_call, call->msi_call->self_capabilities) == -1) + return false; + + rtp_stop_receiving(call->rtps[audio_index]); + } } break; case TOXAV_CALL_CONTROL_MUTE_VIDEO: { @@ -364,7 +396,7 @@ bool toxav_send_video_frame(ToxAV* av, uint32_t friend_number, uint16_t width, u goto END; } - call = i_toxav_get_call(av, friend_number); + call = call_get(av, friend_number); if (call == NULL) { rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL; goto END; @@ -461,7 +493,7 @@ bool toxav_send_audio_frame(ToxAV* av, uint32_t friend_number, const int16_t* pc goto END; } - call = i_toxav_get_call(av, friend_number); + call = call_get(av, friend_number); if (call == NULL) { rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL; goto END; @@ -526,19 +558,16 @@ void toxav_callback_receive_audio_frame(ToxAV* av, toxav_receive_audio_frame_cb* * :: Internal * ******************************************************************************/ -/** TODO: - * - If crutial callback not present send error. - * - Error handling by return values from callbacks and setting 'error'. +/** TODO: */ -void i_callback_invite(void* toxav_inst, MSICall* call) +int callback_invite(void* toxav_inst, MSICall* call) { ToxAV* toxav = toxav_inst; - ToxAVCall* av_call = i_toxav_init_call(toxav, call->friend_id, NULL); + ToxAVCall* av_call = call_new(toxav, call->friend_id, NULL); if (av_call == NULL) { - LOGGER_WARNING("Failed to start call, rejecting..."); - msi_reject(call); - return; + LOGGER_WARNING("Failed to initialize call..."); + return -1; } call->av_call = av_call; @@ -547,55 +576,59 @@ void i_callback_invite(void* toxav_inst, MSICall* call) if (toxav->ccb.first) toxav->ccb.first(toxav, call->friend_id, call->peer_capabilities & msi_CapSAudio, call->peer_capabilities & msi_CapSVideo, toxav->ccb.second); + + return 0; } -void i_callback_ringing(void* toxav_inst, MSICall* call) -{ - ToxAV* toxav = toxav_inst; - if (toxav->scb.first) - toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_RINGING, toxav->scb.second); -} - -void i_callback_start(void* toxav_inst, MSICall* call) +int callback_start(void* toxav_inst, MSICall* call) { ToxAV* toxav = toxav_inst; - ToxAVCall* av_call = i_toxav_get_call(toxav, call->friend_id); + ToxAVCall* av_call = call_get(toxav, call->friend_id); - if (av_call == NULL || !i_toxav_prepare_transmission(toxav, av_call)) { - /* TODO send error */ - i_toxav_remove_call(toxav, call->friend_id); - return; + if (av_call == NULL || !call_prepare_transmission(av_call)) { + call_remove(av_call); + return -1; } TOXAV_CALL_STATE state = capabilities_to_state(av_call->msi_call->peer_capabilities); if (toxav->scb.first) toxav->scb.first(toxav, call->friend_id, state, toxav->scb.second); + + return 0; } -void i_callback_end(void* toxav_inst, MSICall* call) +int callback_end(void* toxav_inst, MSICall* call) { ToxAV* toxav = toxav_inst; - i_toxav_kill_transmission(toxav, call->friend_id); - i_toxav_remove_call(toxav, call->friend_id); + call_kill_transmission(call->av_call); + call_remove(call->av_call); if (toxav->scb.first) toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_END, toxav->scb.second); + + return 0; } -void i_callback_error(void* toxav_inst, MSICall* call) +int callback_error(void* toxav_inst, MSICall* call) { ToxAV* toxav = toxav_inst; if (toxav->scb.first) toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_ERROR, toxav->scb.second); + + return 0; } -void i_callback_capabilites(void* toxav_inst, MSICall* call) +int callback_capabilites(void* toxav_inst, MSICall* call) { ToxAV* toxav = toxav_inst; - /* TODO handle this */ + if (toxav->scb.first) + toxav->scb.first(toxav, call->friend_id, + capabilities_to_state(call->peer_capabilities), toxav->scb.second); + + return 0; } TOXAV_CALL_STATE capabilities_to_state(uint8_t capabilities) @@ -610,32 +643,64 @@ TOXAV_CALL_STATE capabilities_to_state(uint8_t capabilities) return TOXAV_CALL_STATE_PAUSED; } -ToxAVCall* i_toxav_get_call(ToxAV* av, uint32_t friend_number) +bool audio_bitrate_invalid(uint32_t bitrate) { - if (av->calls == NULL || av->calls_tail < friend_number) - return NULL; - - return av->calls[friend_number]; + /* Opus RFC 6716 section-2.1.1 dictates the following: + * Opus supports all bitrates from 6 kbit/s to 510 kbit/s. + */ + return bitrate < 6 || bitrate > 510; } -ToxAVCall* i_toxav_add_call(ToxAV* av, uint32_t friend_number) +bool video_bitrate_invalid(uint32_t bitrate) { - ToxAVCall* rc = calloc(sizeof(ToxAVCall), 1); + /* TODO: If anyone knows the answer to this one please fill it up */ + return false; +} + +ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error) +{ + TOXAV_ERR_CALL rc = TOXAV_ERR_CALL_OK; + ToxAVCall* call = NULL; - if (rc == NULL) - return NULL; + if (m_friend_exists(av->m, friend_number) == 0) { + rc = TOXAV_ERR_CALL_FRIEND_NOT_FOUND; + goto END; + } - rc->friend_id = friend_number; + if (m_get_friend_connectionstatus(av->m, friend_number) != 1) { + rc = TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED; + goto END; + } - if (create_recursive_mutex(rc->mutex_control) != 0) { - free(rc); - return NULL; + if (call_get(av, friend_number) != NULL) { + rc = TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL; + goto END; } - if (create_recursive_mutex(rc->mutex_do) != 0) { - pthread_mutex_destroy(rc->mutex_control); - free(rc); - return NULL; + + call = calloc(sizeof(ToxAVCall), 1); + + if (call == NULL) { + rc = TOXAV_ERR_CALL_MALLOC; + goto END; + } + + call->av = av; + call->friend_id = friend_number; + + if (create_recursive_mutex(call->mutex_control) != 0) { + free(call); + call = NULL; + rc = TOXAV_ERR_CALL_MALLOC; + goto END; + } + + if (create_recursive_mutex(call->mutex_do) != 0) { + pthread_mutex_destroy(call->mutex_control); + free(call); + call = NULL; + rc = TOXAV_ERR_CALL_MALLOC; + goto END; } @@ -643,10 +708,12 @@ ToxAVCall* i_toxav_add_call(ToxAV* av, uint32_t friend_number) av->calls = calloc (sizeof(ToxAVCall*), friend_number + 1); if (av->calls == NULL) { - pthread_mutex_destroy(rc->mutex_control); - pthread_mutex_destroy(rc->mutex_do); - free(rc); - return NULL; + pthread_mutex_destroy(call->mutex_control); + pthread_mutex_destroy(call->mutex_do); + free(call); + call = NULL; + rc = TOXAV_ERR_CALL_MALLOC; + goto END; } av->calls_tail = av->calls_head = friend_number; @@ -655,10 +722,12 @@ ToxAVCall* i_toxav_add_call(ToxAV* av, uint32_t friend_number) void* tmp = realloc(av->calls, sizeof(ToxAVCall*) * friend_number + 1); if (tmp == NULL) { - pthread_mutex_destroy(rc->mutex_control); - pthread_mutex_destroy(rc->mutex_do); - free(rc); - return NULL; + pthread_mutex_destroy(call->mutex_control); + pthread_mutex_destroy(call->mutex_do); + free(call); + call = NULL; + rc = TOXAV_ERR_CALL_MALLOC; + goto END; } av->calls = tmp; @@ -668,105 +737,41 @@ ToxAVCall* i_toxav_add_call(ToxAV* av, uint32_t friend_number) for (; i < friend_number; i ++) av->calls[i] = NULL; - rc->prev = av->calls[av->calls_tail]; - av->calls[av->calls_tail]->next = rc; + call->prev = av->calls[av->calls_tail]; + av->calls[av->calls_tail]->next = call; av->calls_tail = friend_number; } else if (av->calls_head > friend_number) { /* Inserting at front */ - rc->next = av->calls[av->calls_head]; - av->calls[av->calls_head]->prev = rc; + call->next = av->calls[av->calls_head]; + av->calls[av->calls_head]->prev = call; av->calls_head = friend_number; } - av->calls[friend_number] = rc; - return rc; -} - -void i_toxav_remove_call(ToxAV* av, uint32_t friend_number) -{ - ToxAVCall* tc = i_toxav_get_call(av, friend_number); - - if (tc == NULL) - return; - - ToxAVCall* prev = tc->prev; - ToxAVCall* next = tc->next; - - pthread_mutex_destroy(tc->mutex_control); - pthread_mutex_destroy(tc->mutex_do); - - free(tc); - - if (prev) - prev->next = next; - else if (next) - av->calls_head = next->friend_id; - else goto CLEAR; + av->calls[friend_number] = call; - if (next) - next->prev = prev; - else if (prev) - av->calls_tail = prev->friend_id; - else goto CLEAR; - - av->calls[friend_number] = NULL; - return; - -CLEAR: - av->calls_head = av->calls_tail = 0; - free(av->calls); - av->calls = NULL; -} - -ToxAVCall* i_toxav_init_call(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error) -{ - TOXAV_ERR_CALL rc = TOXAV_ERR_CALL_OK; - ToxAVCall* call = NULL; - - if (m_friend_exists(av->m, friend_number) == 0) { - rc = TOXAV_ERR_CALL_FRIEND_NOT_FOUND; - goto END; - } - - if (m_get_friend_connectionstatus(av->m, friend_number) != 1) { - rc = TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED; - goto END; - } - - if (i_toxav_get_call(av, friend_number) != NULL) { - rc = TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL; - goto END; - } - - call = i_toxav_add_call(av, friend_number); - if (call == NULL) { - rc = TOXAV_ERR_CALL_MALLOC; - } - - END: +END: if (error) *error = rc; return call; } -bool i_toxav_audio_bitrate_invalid(uint32_t bitrate) +ToxAVCall* call_get(ToxAV* av, uint32_t friend_number) { - /* Opus RFC 6716 section-2.1.1 dictates the following: - * Opus supports all bitrates from 6 kbit/s to 510 kbit/s. - */ - return bitrate < 6 || bitrate > 510; -} - -bool i_toxav_video_bitrate_invalid(uint32_t bitrate) -{ - /* TODO: If anyone knows the answer to this one please fill it up */ - return false; + if (av->calls == NULL || av->calls_tail < friend_number) + return NULL; + + return av->calls[friend_number]; } -bool i_toxav_prepare_transmission(ToxAV* av, ToxAVCall* call) +bool call_prepare_transmission(ToxAVCall* call) { + if (call == NULL) + return false; + + ToxAV* av = call->av; + if (!av->acb.first && !av->vcb.first) /* It makes no sense to have CSession without callbacks */ return false; @@ -830,7 +835,7 @@ bool i_toxav_prepare_transmission(ToxAV* av, ToxAVCall* call) goto FAILURE; } - rtp_register_for_receiving(call->rtps[audio_index]); + rtp_start_receiving(call->rtps[audio_index]); } } @@ -854,8 +859,8 @@ bool i_toxav_prepare_transmission(ToxAV* av, ToxAVCall* call) LOGGER_WARNING("Failed to enable video receiving!"); goto FAILURE; } - - rtp_register_for_receiving(call->rtps[audio_index]); + + rtp_start_receiving(call->rtps[audio_index]); } } @@ -863,7 +868,7 @@ bool i_toxav_prepare_transmission(ToxAV* av, ToxAVCall* call) pthread_mutex_unlock(call->mutex_control); return true; -FAILURE: + FAILURE: rtp_kill(call->rtps[audio_index]); call->rtps[audio_index] = NULL; rtp_kill(call->rtps[video_index]); @@ -878,25 +883,19 @@ FAILURE: pthread_mutex_unlock(call->mutex_control); return false; -MUTEX_INIT_ERROR: + MUTEX_INIT_ERROR: pthread_mutex_unlock(call->mutex_control); LOGGER_ERROR("Mutex initialization failed!\n"); return false; } -void i_toxav_kill_transmission(ToxAV* av, uint32_t friend_number) +void call_kill_transmission(ToxAVCall* call) { - ToxAVCall* call = i_toxav_get_call(av, friend_number); - if (!call) + if (call == NULL || call->active == 0) return; pthread_mutex_lock(call->mutex_control); - if (!call->active) { - pthread_mutex_unlock(call->mutex_control); - return; - } - call->active = 0; pthread_mutex_lock(call->mutex_encoding_audio); @@ -918,4 +917,41 @@ void i_toxav_kill_transmission(ToxAV* av, uint32_t friend_number) pthread_mutex_destroy(call->mutex_do); pthread_mutex_unlock(call->mutex_control); +} + +void call_remove(ToxAVCall* call) +{ + if (call == NULL) + return; + + uint32_t friend_id = call->friend_id; + ToxAV* av = call->av; + + ToxAVCall* prev = call->prev; + ToxAVCall* next = call->next; + + pthread_mutex_destroy(call->mutex_control); + pthread_mutex_destroy(call->mutex_do); + + free(call); + + if (prev) + prev->next = next; + else if (next) + av->calls_head = next->friend_id; + else goto CLEAR; + + if (next) + next->prev = prev; + else if (prev) + av->calls_tail = prev->friend_id; + else goto CLEAR; + + av->calls[friend_id] = NULL; + return; + +CLEAR: + av->calls_head = av->calls_tail = 0; + free(av->calls); + av->calls = NULL; } \ No newline at end of file diff --git a/toxav/toxav.h b/toxav/toxav.h index c1c6019c..5e82faa6 100644 --- a/toxav/toxav.h +++ b/toxav/toxav.h @@ -186,11 +186,6 @@ bool toxav_answer(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, ui * ******************************************************************************/ typedef enum TOXAV_CALL_STATE { - /** - * The friend's client is aware of the call. This happens after calling - * toxav_call and the initial call request has been received. - */ - TOXAV_CALL_STATE_RINGING, /** * Not sending anything. Either the friend requested that this client stops * sending anything, or the client turned off both audio and video by setting -- cgit v1.2.3