diff options
-rw-r--r-- | toxav/av_test.c | 53 | ||||
-rw-r--r-- | toxav/codec.c | 30 | ||||
-rw-r--r-- | toxav/msi.c | 111 | ||||
-rw-r--r-- | toxav/msi.h | 19 | ||||
-rw-r--r-- | toxav/toxav.c | 300 | ||||
-rw-r--r-- | toxav/toxav.h | 66 |
6 files changed, 334 insertions, 245 deletions
diff --git a/toxav/av_test.c b/toxav/av_test.c index 41f5a758..bb79eedc 100644 --- a/toxav/av_test.c +++ b/toxav/av_test.c | |||
@@ -16,7 +16,7 @@ | |||
16 | 16 | ||
17 | typedef struct { | 17 | typedef struct { |
18 | bool incoming; | 18 | bool incoming; |
19 | TOXAV_CALL_STATE state; | 19 | uint32_t state; |
20 | } CallControl; | 20 | } CallControl; |
21 | 21 | ||
22 | const char* stringify_state(TOXAV_CALL_STATE s) | 22 | const char* stringify_state(TOXAV_CALL_STATE s) |
@@ -44,9 +44,9 @@ void t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool | |||
44 | printf("Handling CALL callback\n"); | 44 | printf("Handling CALL callback\n"); |
45 | ((CallControl*)user_data)->incoming = true; | 45 | ((CallControl*)user_data)->incoming = true; |
46 | } | 46 | } |
47 | void t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, TOXAV_CALL_STATE state, void *user_data) | 47 | void t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data) |
48 | { | 48 | { |
49 | printf("Handling CALL STATE callback: %s\n", stringify_state(state)); | 49 | printf("Handling CALL STATE callback: %d\n", state); |
50 | 50 | ||
51 | ((CallControl*)user_data)->state = state; | 51 | ((CallControl*)user_data)->state = state; |
52 | } | 52 | } |
@@ -211,13 +211,13 @@ int main (int argc, char** argv) | |||
211 | } | 211 | } |
212 | 212 | ||
213 | printf("\nTrying regular call (Audio and Video)...\n"); | 213 | printf("\nTrying regular call (Audio and Video)...\n"); |
214 | // REGULAR_CALL_FLOW(48, 4000); | 214 | REGULAR_CALL_FLOW(48, 4000); |
215 | 215 | ||
216 | printf("\nTrying regular call (Audio only)...\n"); | 216 | printf("\nTrying regular call (Audio only)...\n"); |
217 | // REGULAR_CALL_FLOW(48, 0); | 217 | REGULAR_CALL_FLOW(48, 0); |
218 | 218 | ||
219 | printf("\nTrying regular call (Video only)...\n"); | 219 | printf("\nTrying regular call (Video only)...\n"); |
220 | // REGULAR_CALL_FLOW(0, 4000); | 220 | REGULAR_CALL_FLOW(0, 4000); |
221 | 221 | ||
222 | #undef REGULAR_CALL_FLOW | 222 | #undef REGULAR_CALL_FLOW |
223 | 223 | ||
@@ -318,10 +318,8 @@ int main (int argc, char** argv) | |||
318 | /* At first try all stuff while in invalid state */ | 318 | /* At first try all stuff while in invalid state */ |
319 | assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL)); | 319 | assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL)); |
320 | assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_RESUME, 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)); | 321 | assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL)); |
322 | assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_MUTE_VIDEO, NULL)); | 322 | assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_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 | 323 | ||
326 | { | 324 | { |
327 | TOXAV_ERR_ANSWER rc; | 325 | TOXAV_ERR_ANSWER rc; |
@@ -342,36 +340,36 @@ int main (int argc, char** argv) | |||
342 | assert(BobCC.state == TOXAV_CALL_STATE_PAUSED); | 340 | assert(BobCC.state == TOXAV_CALL_STATE_PAUSED); |
343 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_RESUME, NULL)); | 341 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_RESUME, NULL)); |
344 | iterate(Bsn, AliceAV, BobAV); | 342 | iterate(Bsn, AliceAV, BobAV); |
345 | assert(BobCC.state == TOXAV_CALL_STATE_SENDING_AV); | 343 | assert(BobCC.state & (TOXAV_CALL_STATE_SENDING_A | TOXAV_CALL_STATE_SENDING_V)); |
346 | 344 | ||
347 | /* Mute/Unmute single */ | 345 | /* Mute/Unmute single */ |
348 | printf("Mute/Unmute single\n"); | 346 | printf("Mute/Unmute single\n"); |
349 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_MUTE_AUDIO, NULL)); | 347 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL)); |
350 | iterate(Bsn, AliceAV, BobAV); | 348 | iterate(Bsn, AliceAV, BobAV); |
351 | assert(BobCC.state == TOXAV_CALL_CONTROL_MUTE_AUDIO); | 349 | assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_A); |
352 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_UNMUTE_AUDIO, NULL)); | 350 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL)); |
353 | iterate(Bsn, AliceAV, BobAV); | 351 | iterate(Bsn, AliceAV, BobAV); |
354 | assert(BobCC.state == TOXAV_CALL_CONTROL_UNMUTE_AUDIO); | 352 | assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_A); |
355 | 353 | ||
356 | /* Mute/Unmute both */ | 354 | /* Mute/Unmute both */ |
357 | printf("Mute/Unmute both\n"); | 355 | printf("Mute/Unmute both\n"); |
358 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_MUTE_AUDIO, NULL)); | 356 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL)); |
359 | iterate(Bsn, AliceAV, BobAV); | 357 | iterate(Bsn, AliceAV, BobAV); |
360 | assert(BobCC.state == TOXAV_CALL_STATE_SENDING_V); | 358 | assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_A); |
361 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_MUTE_VIDEO, NULL)); | 359 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_VIDEO, NULL)); |
362 | iterate(Bsn, AliceAV, BobAV); | 360 | iterate(Bsn, AliceAV, BobAV); |
363 | assert(BobCC.state == TOXAV_CALL_STATE_NOT_SENDING); | 361 | assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_V); |
364 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_UNMUTE_AUDIO, NULL)); | 362 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL)); |
365 | iterate(Bsn, AliceAV, BobAV); | 363 | iterate(Bsn, AliceAV, BobAV); |
366 | assert(BobCC.state == TOXAV_CALL_STATE_SENDING_A); | 364 | assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_A); |
367 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_UNMUTE_VIDEO, NULL)); | 365 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_VIDEO, NULL)); |
368 | iterate(Bsn, AliceAV, BobAV); | 366 | iterate(Bsn, AliceAV, BobAV); |
369 | assert(BobCC.state == TOXAV_CALL_STATE_SENDING_AV); | 367 | assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_V); |
370 | 368 | ||
371 | { | 369 | { |
372 | TOXAV_ERR_CALL_CONTROL rc; | 370 | TOXAV_ERR_CALL_CONTROL rc; |
373 | toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc); | 371 | toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc); |
374 | 372 | ||
375 | if (rc != TOXAV_ERR_CALL_CONTROL_OK) { | 373 | if (rc != TOXAV_ERR_CALL_CONTROL_OK) { |
376 | printf("toxav_call_control failed: %d\n", rc); | 374 | printf("toxav_call_control failed: %d\n", rc); |
377 | exit(1); | 375 | exit(1); |
@@ -384,6 +382,13 @@ int main (int argc, char** argv) | |||
384 | printf("Success!\n"); | 382 | printf("Success!\n"); |
385 | } | 383 | } |
386 | 384 | ||
385 | |||
386 | toxav_kill(BobAV); | ||
387 | toxav_kill(AliceAV); | ||
388 | tox_kill(Bob); | ||
389 | tox_kill(Alice); | ||
390 | tox_kill(Bsn); | ||
391 | |||
387 | printf("\nTest successful!\n"); | 392 | printf("\nTest successful!\n"); |
388 | return 0; | 393 | return 0; |
389 | } \ No newline at end of file | 394 | } \ No newline at end of file |
diff --git a/toxav/codec.c b/toxav/codec.c index e44387df..645f7188 100644 --- a/toxav/codec.c +++ b/toxav/codec.c | |||
@@ -343,21 +343,17 @@ CSSession *cs_new(uint32_t peer_video_frame_piece_size) | |||
343 | return NULL; | 343 | return NULL; |
344 | } | 344 | } |
345 | 345 | ||
346 | cs->peer_video_frame_piece_size = peer_video_frame_piece_size; | ||
347 | |||
348 | return cs; | ||
349 | 346 | ||
350 | FAILURE: | 347 | if (create_recursive_mutex(cs->queue_mutex) != 0) { |
351 | LOGGER_WARNING("Error initializing codec session! Application might misbehave!"); | 348 | LOGGER_WARNING("Failed to create recursive mutex!"); |
349 | free(cs); | ||
350 | return NULL; | ||
351 | } | ||
352 | 352 | ||
353 | cs_disable_audio_sending(cs); | ||
354 | cs_disable_audio_receiving(cs); | ||
355 | cs_disable_video_sending(cs); | ||
356 | cs_disable_video_receiving(cs); | ||
357 | 353 | ||
358 | free(cs); | 354 | cs->peer_video_frame_piece_size = peer_video_frame_piece_size; |
359 | 355 | ||
360 | return NULL; | 356 | return cs; |
361 | } | 357 | } |
362 | 358 | ||
363 | void cs_kill(CSSession *cs) | 359 | void cs_kill(CSSession *cs) |
@@ -374,6 +370,8 @@ void cs_kill(CSSession *cs) | |||
374 | cs_disable_video_sending(cs); | 370 | cs_disable_video_sending(cs); |
375 | cs_disable_video_receiving(cs); | 371 | cs_disable_video_receiving(cs); |
376 | 372 | ||
373 | pthread_mutex_destroy(cs->queue_mutex); | ||
374 | |||
377 | LOGGER_DEBUG("Terminated codec state: %p", cs); | 375 | LOGGER_DEBUG("Terminated codec state: %p", cs); |
378 | free(cs); | 376 | free(cs); |
379 | } | 377 | } |
@@ -536,19 +534,12 @@ int cs_enable_video_receiving(CSSession* cs) | |||
536 | { | 534 | { |
537 | if (cs->v_decoding) | 535 | if (cs->v_decoding) |
538 | return 0; | 536 | return 0; |
539 | 537 | ||
540 | if (create_recursive_mutex(cs->queue_mutex) != 0) { | ||
541 | LOGGER_WARNING("Failed to create recursive mutex!"); | ||
542 | return -1; | ||
543 | } | ||
544 | |||
545 | int rc = vpx_codec_dec_init_ver(cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, | 538 | int rc = vpx_codec_dec_init_ver(cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, |
546 | NULL, 0, VPX_DECODER_ABI_VERSION); | 539 | NULL, 0, VPX_DECODER_ABI_VERSION); |
547 | 540 | ||
548 | if ( rc != VPX_CODEC_OK) { | 541 | if ( rc != VPX_CODEC_OK) { |
549 | LOGGER_ERROR("Init video_decoder failed: %s", vpx_codec_err_to_string(rc)); | 542 | LOGGER_ERROR("Init video_decoder failed: %s", vpx_codec_err_to_string(rc)); |
550 | |||
551 | pthread_mutex_destroy(cs->queue_mutex); | ||
552 | return -1; | 543 | return -1; |
553 | } | 544 | } |
554 | 545 | ||
@@ -591,7 +582,6 @@ void cs_disable_video_receiving(CSSession* cs) | |||
591 | cs->frame_buf = NULL; | 582 | cs->frame_buf = NULL; |
592 | 583 | ||
593 | vpx_codec_destroy(cs->v_decoder); | 584 | vpx_codec_destroy(cs->v_decoder); |
594 | pthread_mutex_destroy(cs->queue_mutex); | ||
595 | } | 585 | } |
596 | } | 586 | } |
597 | 587 | ||
diff --git a/toxav/msi.c b/toxav/msi.c index f179a7ab..ac900dac 100644 --- a/toxav/msi.c +++ b/toxav/msi.c | |||
@@ -99,7 +99,9 @@ void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint1 | |||
99 | */ | 99 | */ |
100 | void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id) | 100 | void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id) |
101 | { | 101 | { |
102 | pthread_mutex_lock(session->mutex); | ||
102 | session->callbacks[id] = callback; | 103 | session->callbacks[id] = callback; |
104 | pthread_mutex_unlock(session->mutex); | ||
103 | } | 105 | } |
104 | MSISession *msi_new ( Messenger *messenger ) | 106 | MSISession *msi_new ( Messenger *messenger ) |
105 | { | 107 | { |
@@ -163,15 +165,19 @@ int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_ | |||
163 | { | 165 | { |
164 | LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id); | 166 | LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id); |
165 | 167 | ||
168 | pthread_mutex_lock(session->mutex); | ||
166 | if (get_call(session, friend_id) != NULL) { | 169 | if (get_call(session, friend_id) != NULL) { |
167 | LOGGER_ERROR("Already in a call"); | 170 | LOGGER_ERROR("Already in a call"); |
171 | pthread_mutex_unlock(session->mutex); | ||
168 | return -1; | 172 | return -1; |
169 | } | 173 | } |
170 | 174 | ||
171 | (*call) = new_call ( session, friend_id ); | 175 | (*call) = new_call ( session, friend_id ); |
172 | 176 | ||
173 | if ( *call == NULL ) | 177 | if ( *call == NULL ) { |
178 | pthread_mutex_unlock(session->mutex); | ||
174 | return -1; | 179 | return -1; |
180 | } | ||
175 | 181 | ||
176 | (*call)->self_capabilities = capabilities; | 182 | (*call)->self_capabilities = capabilities; |
177 | 183 | ||
@@ -180,7 +186,7 @@ int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_ | |||
180 | 186 | ||
181 | msg.capabilities.exists = true; | 187 | msg.capabilities.exists = true; |
182 | msg.capabilities.value = capabilities; | 188 | msg.capabilities.value = capabilities; |
183 | 189 | ||
184 | msg.vfpsz.exists = true; | 190 | msg.vfpsz.exists = true; |
185 | msg.vfpsz.value = htons(VIDEOFRAME_PIECE_SIZE); | 191 | msg.vfpsz.value = htons(VIDEOFRAME_PIECE_SIZE); |
186 | 192 | ||
@@ -189,28 +195,37 @@ int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_ | |||
189 | (*call)->state = msi_CallRequesting; | 195 | (*call)->state = msi_CallRequesting; |
190 | 196 | ||
191 | LOGGER_DEBUG("Invite sent"); | 197 | LOGGER_DEBUG("Invite sent"); |
198 | pthread_mutex_unlock(session->mutex); | ||
192 | return 0; | 199 | return 0; |
193 | } | 200 | } |
194 | int msi_hangup ( MSICall* call ) | 201 | int msi_hangup ( MSICall* call ) |
195 | { | 202 | { |
196 | LOGGER_DEBUG("Session: %p Hanging up call with friend: %u", call->session, call->friend_id); | 203 | LOGGER_DEBUG("Session: %p Hanging up call with friend: %u", call->session, call->friend_id); |
197 | 204 | ||
205 | MSISession* session = call->session; | ||
206 | pthread_mutex_lock(session->mutex); | ||
207 | |||
198 | MSIMessage msg; | 208 | MSIMessage msg; |
199 | msg_init(&msg, requ_pop); | 209 | msg_init(&msg, requ_pop); |
200 | 210 | ||
201 | send_message ( call->session->messenger, call->friend_id, &msg ); | 211 | send_message ( session->messenger, call->friend_id, &msg ); |
202 | 212 | ||
203 | kill_call(call); | 213 | kill_call(call); |
214 | pthread_mutex_unlock(session->mutex); | ||
204 | return 0; | 215 | return 0; |
205 | } | 216 | } |
206 | int msi_answer ( MSICall* call, uint8_t capabilities ) | 217 | int msi_answer ( MSICall* call, uint8_t capabilities ) |
207 | { | 218 | { |
208 | LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_id); | 219 | LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_id); |
209 | 220 | ||
221 | MSISession* session = call->session; | ||
222 | pthread_mutex_lock(session->mutex); | ||
223 | |||
210 | if ( call->state != msi_CallRequested ) { | 224 | if ( call->state != msi_CallRequested ) { |
211 | /* Though sending in invalid state will not cause anything wierd | 225 | /* Though sending in invalid state will not cause anything wierd |
212 | * Its better to not do it like a maniac */ | 226 | * Its better to not do it like a maniac */ |
213 | LOGGER_ERROR("Call is in invalid state!"); | 227 | LOGGER_ERROR("Call is in invalid state!"); |
228 | pthread_mutex_unlock(session->mutex); | ||
214 | return -1; | 229 | return -1; |
215 | } | 230 | } |
216 | 231 | ||
@@ -225,9 +240,10 @@ int msi_answer ( MSICall* call, uint8_t capabilities ) | |||
225 | msg.vfpsz.exists = true; | 240 | msg.vfpsz.exists = true; |
226 | msg.vfpsz.value = htons(VIDEOFRAME_PIECE_SIZE); | 241 | msg.vfpsz.value = htons(VIDEOFRAME_PIECE_SIZE); |
227 | 242 | ||
228 | send_message ( call->session->messenger, call->friend_id, &msg ); | 243 | send_message ( session->messenger, call->friend_id, &msg ); |
229 | 244 | ||
230 | call->state = msi_CallActive; | 245 | call->state = msi_CallActive; |
246 | pthread_mutex_unlock(session->mutex); | ||
231 | 247 | ||
232 | return 0; | 248 | return 0; |
233 | } | 249 | } |
@@ -235,6 +251,9 @@ int msi_change_capabilities( MSICall* call, uint8_t capabilities ) | |||
235 | { | 251 | { |
236 | LOGGER_DEBUG("Session: %p Trying to change capabilities to friend %u", call->session, call->friend_id); | 252 | LOGGER_DEBUG("Session: %p Trying to change capabilities to friend %u", call->session, call->friend_id); |
237 | 253 | ||
254 | MSISession* session = call->session; | ||
255 | pthread_mutex_lock(session->mutex); | ||
256 | |||
238 | if ( call->state != msi_CallActive ) { | 257 | if ( call->state != msi_CallActive ) { |
239 | /* Sending capabilities change can cause error on other side if | 258 | /* Sending capabilities change can cause error on other side if |
240 | * the call is not active since we don't send header 'vfpsz'. | 259 | * the call is not active since we don't send header 'vfpsz'. |
@@ -244,6 +263,7 @@ int msi_change_capabilities( MSICall* call, uint8_t capabilities ) | |||
244 | * like new. TODO: explain this better | 263 | * like new. TODO: explain this better |
245 | */ | 264 | */ |
246 | LOGGER_ERROR("Call is in invalid state!"); | 265 | LOGGER_ERROR("Call is in invalid state!"); |
266 | pthread_mutex_unlock(session->mutex); | ||
247 | return -1; | 267 | return -1; |
248 | } | 268 | } |
249 | 269 | ||
@@ -257,6 +277,7 @@ int msi_change_capabilities( MSICall* call, uint8_t capabilities ) | |||
257 | 277 | ||
258 | send_message ( call->session->messenger, call->friend_id, &msg ); | 278 | send_message ( call->session->messenger, call->friend_id, &msg ); |
259 | 279 | ||
280 | pthread_mutex_unlock(session->mutex); | ||
260 | return 0; | 281 | return 0; |
261 | } | 282 | } |
262 | 283 | ||
@@ -316,7 +337,7 @@ int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length ) | |||
316 | 337 | ||
317 | case IDError: | 338 | case IDError: |
318 | CHECK_SIZE(it, size_constraint, 1); | 339 | CHECK_SIZE(it, size_constraint, 1); |
319 | CHECK_ENUM_HIGH(it, msi_ErrUndisclosed); | 340 | CHECK_ENUM_HIGH(it, msi_EUndisclosed); |
320 | SET_UINT8(it, dest->error); | 341 | SET_UINT8(it, dest->error); |
321 | break; | 342 | break; |
322 | 343 | ||
@@ -440,7 +461,7 @@ int invoke_callback(MSICall* call, MSICallbackID cb) | |||
440 | if ( call->session->callbacks[cb] ) { | 461 | if ( call->session->callbacks[cb] ) { |
441 | LOGGER_DEBUG("Invoking callback function: %d", cb); | 462 | LOGGER_DEBUG("Invoking callback function: %d", cb); |
442 | if ( call->session->callbacks[cb] ( call->session->av, call ) != 0 ) { | 463 | if ( call->session->callbacks[cb] ( call->session->av, call ) != 0 ) { |
443 | LOGGER_WARNING("Callback handling failed, sending error"); | 464 | LOGGER_WARNING("Callback state handling failed, sending error"); |
444 | goto FAILURE; | 465 | goto FAILURE; |
445 | } | 466 | } |
446 | 467 | ||
@@ -449,10 +470,11 @@ int invoke_callback(MSICall* call, MSICallbackID cb) | |||
449 | 470 | ||
450 | FAILURE: | 471 | FAILURE: |
451 | /* If no callback present or error happened while handling, | 472 | /* If no callback present or error happened while handling, |
452 | * an error message will be send to friend | 473 | * an error message will be sent to friend |
453 | */ | 474 | */ |
454 | 475 | ||
455 | call->error = msi_HandleError; | 476 | if (call->error == msi_ENone) |
477 | call->error = msi_EHandle; | ||
456 | return -1; | 478 | return -1; |
457 | } | 479 | } |
458 | static MSICall *get_call ( MSISession *session, uint32_t friend_id ) | 480 | static MSICall *get_call ( MSISession *session, uint32_t friend_id ) |
@@ -517,9 +539,12 @@ MSICall *new_call ( MSISession *session, uint32_t friend_id ) | |||
517 | } | 539 | } |
518 | void kill_call ( MSICall *call ) | 540 | void kill_call ( MSICall *call ) |
519 | { | 541 | { |
542 | /* Assume that session mutex is locked */ | ||
520 | if ( call == NULL ) | 543 | if ( call == NULL ) |
521 | return; | 544 | return; |
522 | 545 | ||
546 | LOGGER_DEBUG("Killing call: %p", call); | ||
547 | |||
523 | MSISession* session = call->session; | 548 | MSISession* session = call->session; |
524 | 549 | ||
525 | MSICall* prev = call->prev; | 550 | MSICall* prev = call->prev; |
@@ -529,23 +554,23 @@ void kill_call ( MSICall *call ) | |||
529 | prev->next = next; | 554 | prev->next = next; |
530 | else if (next) | 555 | else if (next) |
531 | session->calls_head = next->friend_id; | 556 | session->calls_head = next->friend_id; |
532 | else goto CLEAR; | 557 | else goto CLEAR_CONTAINER; |
533 | 558 | ||
534 | if (next) | 559 | if (next) |
535 | next->prev = prev; | 560 | next->prev = prev; |
536 | else if (prev) | 561 | else if (prev) |
537 | session->calls_tail = prev->friend_id; | 562 | session->calls_tail = prev->friend_id; |
538 | else goto CLEAR; | 563 | else goto CLEAR_CONTAINER; |
539 | 564 | ||
540 | session->calls[call->friend_id] = NULL; | 565 | session->calls[call->friend_id] = NULL; |
541 | free(call); | 566 | free(call); |
542 | return; | 567 | return; |
543 | 568 | ||
544 | CLEAR: | 569 | CLEAR_CONTAINER: |
545 | session->calls_head = session->calls_tail = 0; | 570 | session->calls_head = session->calls_tail = 0; |
546 | free(session->calls); | 571 | free(session->calls); |
547 | session->calls = NULL; | ||
548 | free(call); | 572 | free(call); |
573 | session->calls = NULL; | ||
549 | } | 574 | } |
550 | void on_peer_status(Messenger *m, int friend_id, uint8_t status, void *data) | 575 | void on_peer_status(Messenger *m, int friend_id, uint8_t status, void *data) |
551 | { | 576 | { |
@@ -556,13 +581,17 @@ void on_peer_status(Messenger *m, int friend_id, uint8_t status, void *data) | |||
556 | case 0: { /* Friend is now offline */ | 581 | case 0: { /* Friend is now offline */ |
557 | LOGGER_DEBUG("Friend %d is now offline", friend_id); | 582 | LOGGER_DEBUG("Friend %d is now offline", friend_id); |
558 | 583 | ||
584 | pthread_mutex_lock(session->mutex); | ||
559 | MSICall* call = get_call(session, friend_id); | 585 | MSICall* call = get_call(session, friend_id); |
560 | 586 | ||
561 | if (call == NULL) | 587 | if (call == NULL) { |
588 | pthread_mutex_unlock(session->mutex); | ||
562 | return; | 589 | return; |
590 | } | ||
563 | 591 | ||
564 | invoke_callback(call, msi_OnPeerTimeout); /* Failure is ignored */ | 592 | invoke_callback(call, msi_OnPeerTimeout); /* Failure is ignored */ |
565 | kill_call(call); | 593 | kill_call(call); |
594 | pthread_mutex_unlock(session->mutex); | ||
566 | } | 595 | } |
567 | break; | 596 | break; |
568 | 597 | ||
@@ -580,18 +609,17 @@ void handle_push ( MSICall *call, const MSIMessage *msg ) | |||
580 | 609 | ||
581 | if (!msg->capabilities.exists) { | 610 | if (!msg->capabilities.exists) { |
582 | LOGGER_WARNING("Session: %p Invalid capabilities on 'push'"); | 611 | LOGGER_WARNING("Session: %p Invalid capabilities on 'push'"); |
583 | call->error = msi_InvalidMessage; | 612 | call->error = msi_EInvalidMessage; |
584 | goto FAILURE; | 613 | goto FAILURE; |
585 | } | 614 | } |
586 | 615 | ||
587 | if (call->state != msi_CallActive) { | 616 | if (call->state != msi_CallActive) { |
588 | if (!msg->vfpsz.exists) { | 617 | if (!msg->vfpsz.exists) { |
589 | LOGGER_WARNING("Session: %p Invalid vfpsz on 'push'"); | 618 | LOGGER_WARNING("Session: %p Invalid vfpsz on 'push'"); |
590 | call->error = msi_InvalidMessage; | 619 | call->error = msi_EInvalidMessage; |
591 | goto FAILURE; | 620 | goto FAILURE; |
592 | } | 621 | } |
593 | 622 | ||
594 | /* Sending video frame piece size is ignored when call is active */ | ||
595 | call->peer_vfpsz = ntohs(msg->vfpsz.value); | 623 | call->peer_vfpsz = ntohs(msg->vfpsz.value); |
596 | } | 624 | } |
597 | 625 | ||
@@ -610,6 +638,38 @@ void handle_push ( MSICall *call, const MSIMessage *msg ) | |||
610 | } break; | 638 | } break; |
611 | 639 | ||
612 | case msi_CallActive: { | 640 | case msi_CallActive: { |
641 | if (msg->vfpsz.exists) { | ||
642 | /* If peer sended video frame piece size | ||
643 | * while the call is already active it's probable | ||
644 | * that he is trying to re-call us while the call | ||
645 | * is not terminated on our side. We can assume that | ||
646 | * in this case we can automatically answer the re-call. | ||
647 | */ | ||
648 | if (call->peer_vfpsz != ntohs(msg->vfpsz.value)) { | ||
649 | LOGGER_WARNING("Friend sent invalid parameters for re-call"); | ||
650 | call->error = msi_EInvalidParam; | ||
651 | invoke_callback(call, msi_OnError); | ||
652 | goto FAILURE; | ||
653 | } | ||
654 | |||
655 | LOGGER_INFO("Friend is recalling us"); | ||
656 | |||
657 | MSIMessage msg; | ||
658 | msg_init(&msg, requ_push); | ||
659 | |||
660 | msg.capabilities.exists = true; | ||
661 | msg.capabilities.value = call->self_capabilities; | ||
662 | |||
663 | msg.vfpsz.exists = true; | ||
664 | msg.vfpsz.value = htons(VIDEOFRAME_PIECE_SIZE); | ||
665 | |||
666 | send_message ( call->session->messenger, call->friend_id, &msg ); | ||
667 | |||
668 | /* If peer changed capabilities during re-call they will | ||
669 | * be handled accordingly during the next step | ||
670 | */ | ||
671 | } | ||
672 | |||
613 | /* Only act if capabilities changed */ | 673 | /* Only act if capabilities changed */ |
614 | if ( call->peer_capabilities != msg->capabilities.value) { | 674 | if ( call->peer_capabilities != msg->capabilities.value) { |
615 | LOGGER_INFO("Friend is changing capabilities"); | 675 | LOGGER_INFO("Friend is changing capabilities"); |
@@ -629,6 +689,7 @@ void handle_push ( MSICall *call, const MSIMessage *msg ) | |||
629 | 689 | ||
630 | if ( invoke_callback(call, msi_OnStart) == -1 ) | 690 | if ( invoke_callback(call, msi_OnStart) == -1 ) |
631 | goto FAILURE; | 691 | goto FAILURE; |
692 | |||
632 | } break; | 693 | } break; |
633 | 694 | ||
634 | case msi_CallRequested: { | 695 | case msi_CallRequested: { |
@@ -646,7 +707,7 @@ FAILURE: | |||
646 | void handle_pop ( MSICall *call, const MSIMessage *msg ) | 707 | void handle_pop ( MSICall *call, const MSIMessage *msg ) |
647 | { | 708 | { |
648 | assert(call); | 709 | assert(call); |
649 | 710 | ||
650 | LOGGER_DEBUG("Session: %p Handling 'pop', friend id: %d", call->session, call->friend_id); | 711 | LOGGER_DEBUG("Session: %p Handling 'pop', friend id: %d", call->session, call->friend_id); |
651 | 712 | ||
652 | /* callback errors are ignored */ | 713 | /* callback errors are ignored */ |
@@ -682,8 +743,6 @@ void handle_pop ( MSICall *call, const MSIMessage *msg ) | |||
682 | } | 743 | } |
683 | 744 | ||
684 | kill_call ( call ); | 745 | kill_call ( call ); |
685 | |||
686 | return; | ||
687 | } | 746 | } |
688 | void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint16_t length, void *object ) | 747 | void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint16_t length, void *object ) |
689 | { | 748 | { |
@@ -694,30 +753,34 @@ void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint1 | |||
694 | 753 | ||
695 | if ( msg_parse_in ( &msg, data, length ) == -1 ) { | 754 | if ( msg_parse_in ( &msg, data, length ) == -1 ) { |
696 | LOGGER_WARNING("Error parsing message"); | 755 | LOGGER_WARNING("Error parsing message"); |
697 | send_error(m, friend_id, msi_InvalidMessage); | 756 | send_error(m, friend_id, msi_EInvalidMessage); |
698 | return; | 757 | return; |
699 | } else { | 758 | } else { |
700 | LOGGER_DEBUG("Successfully parsed message"); | 759 | LOGGER_DEBUG("Successfully parsed message"); |
701 | } | 760 | } |
702 | 761 | ||
762 | pthread_mutex_lock(session->mutex); | ||
703 | MSICall *call = get_call(session, friend_id); | 763 | MSICall *call = get_call(session, friend_id); |
704 | 764 | ||
705 | if (call == NULL) { | 765 | if (call == NULL) { |
706 | if (msg.request.value != requ_push) { | 766 | if (msg.request.value != requ_push) { |
707 | send_error(m, friend_id, msi_StrayMessage); | 767 | send_error(m, friend_id, msi_EStrayMessage); |
768 | pthread_mutex_unlock(session->mutex); | ||
708 | return; | 769 | return; |
709 | } | 770 | } |
710 | 771 | ||
711 | call = new_call(session, friend_id); | 772 | call = new_call(session, friend_id); |
712 | if (call == NULL) { | 773 | if (call == NULL) { |
713 | send_error(m, friend_id, msi_SystemError); | 774 | send_error(m, friend_id, msi_ESystem); |
775 | pthread_mutex_unlock(session->mutex); | ||
714 | return; | 776 | return; |
715 | } | 777 | } |
716 | } | 778 | } |
717 | 779 | ||
718 | 780 | if (msg.request.value == requ_push) | |
719 | if (msg.request.value == requ_push) | ||
720 | handle_push(call, &msg); | 781 | handle_push(call, &msg); |
721 | else | 782 | else |
722 | handle_pop(call, &msg); /* always kills the call */ | 783 | handle_pop(call, &msg); /* always kills the call */ |
784 | |||
785 | pthread_mutex_unlock(session->mutex); | ||
723 | } \ No newline at end of file | 786 | } \ No newline at end of file |
diff --git a/toxav/msi.h b/toxav/msi.h index b846542d..8404df19 100644 --- a/toxav/msi.h +++ b/toxav/msi.h | |||
@@ -35,14 +35,14 @@ | |||
35 | * Error codes. | 35 | * Error codes. |
36 | */ | 36 | */ |
37 | typedef enum { | 37 | typedef enum { |
38 | msi_ErrorNone, | 38 | msi_ENone, |
39 | msi_InvalidMessage, | 39 | msi_EInvalidMessage, |
40 | msi_InvalidParam, | 40 | msi_EInvalidParam, |
41 | msi_InvalidState, | 41 | msi_EInvalidState, |
42 | msi_StrayMessage, | 42 | msi_EStrayMessage, |
43 | msi_SystemError, | 43 | msi_ESystem, |
44 | msi_HandleError, | 44 | msi_EHandle, |
45 | msi_ErrUndisclosed, /* NOTE: must be last enum otherwise parsing wont work */ | 45 | msi_EUndisclosed, /* NOTE: must be last enum otherwise parsing wont work */ |
46 | } MSIError; | 46 | } MSIError; |
47 | 47 | ||
48 | /** | 48 | /** |
@@ -118,6 +118,9 @@ typedef struct MSISession_s { | |||
118 | void *av; | 118 | void *av; |
119 | Messenger *messenger; | 119 | Messenger *messenger; |
120 | 120 | ||
121 | /* The mutex controls async access from control | ||
122 | * thread(s) and core thread. | ||
123 | */ | ||
121 | pthread_mutex_t mutex[1]; | 124 | pthread_mutex_t mutex[1]; |
122 | MSICallbackType callbacks[7]; | 125 | MSICallbackType callbacks[7]; |
123 | } MSISession; | 126 | } MSISession; |
diff --git a/toxav/toxav.c b/toxav/toxav.c index e6b51ee4..78243ae6 100644 --- a/toxav/toxav.c +++ b/toxav/toxav.c | |||
@@ -40,15 +40,16 @@ enum { | |||
40 | video_index, | 40 | video_index, |
41 | }; | 41 | }; |
42 | 42 | ||
43 | typedef struct ToxAVCall_s | 43 | typedef struct ToxAVCall_s { |
44 | { | ||
45 | ToxAV* av; | 44 | ToxAV* av; |
46 | pthread_mutex_t mutex_control[1]; | ||
47 | pthread_mutex_t mutex_encoding_audio[1]; | ||
48 | pthread_mutex_t mutex_encoding_video[1]; | ||
49 | pthread_mutex_t mutex_do[1]; | ||
50 | RTPSession *rtps[2]; /* Audio is first and video is second */ | 45 | RTPSession *rtps[2]; /* Audio is first and video is second */ |
51 | CSSession *cs; | 46 | CSSession *cs; |
47 | |||
48 | pthread_mutex_t mutex_audio_sending[1]; | ||
49 | pthread_mutex_t mutex_video_sending[1]; | ||
50 | /* Only audio or video can be decoded at one time */ | ||
51 | pthread_mutex_t mutex_decoding[1]; | ||
52 | |||
52 | bool active; | 53 | bool active; |
53 | MSICall* msi_call; | 54 | MSICall* msi_call; |
54 | uint32_t friend_id; | 55 | uint32_t friend_id; |
@@ -56,14 +57,14 @@ typedef struct ToxAVCall_s | |||
56 | uint32_t s_audio_b; /* Sending audio bitrate */ | 57 | uint32_t s_audio_b; /* Sending audio bitrate */ |
57 | uint32_t s_video_b; /* Sending video bitrate */ | 58 | uint32_t s_video_b; /* Sending video bitrate */ |
58 | 59 | ||
59 | uint8_t last_capabilities; | 60 | uint8_t last_self_capabilities; |
61 | uint8_t last_peer_capabilities; | ||
60 | 62 | ||
61 | struct ToxAVCall_s *prev; | 63 | struct ToxAVCall_s *prev; |
62 | struct ToxAVCall_s *next; | 64 | struct ToxAVCall_s *next; |
63 | } ToxAVCall; | 65 | } ToxAVCall; |
64 | 66 | ||
65 | struct toxAV | 67 | struct toxAV { |
66 | { | ||
67 | Messenger* m; | 68 | Messenger* m; |
68 | MSISession* msi; | 69 | MSISession* msi; |
69 | 70 | ||
@@ -71,11 +72,14 @@ struct toxAV | |||
71 | ToxAVCall** calls; | 72 | ToxAVCall** calls; |
72 | uint32_t calls_tail; | 73 | uint32_t calls_tail; |
73 | uint32_t calls_head; | 74 | uint32_t calls_head; |
75 | pthread_mutex_t mutex[1]; | ||
74 | 76 | ||
75 | PAIR(toxav_call_cb *, void*) ccb; /* Call callback */ | 77 | PAIR(toxav_call_cb *, void*) ccb; /* Call callback */ |
76 | PAIR(toxav_call_state_cb *, void *) scb; /* Call state callback */ | 78 | PAIR(toxav_call_state_cb *, void *) scb; /* Call state callback */ |
77 | PAIR(toxav_receive_audio_frame_cb *, void *) acb; /* Audio frame receive callback */ | 79 | PAIR(toxav_receive_audio_frame_cb *, void *) acb; /* Audio frame receive callback */ |
78 | PAIR(toxav_receive_video_frame_cb *, void *) vcb; /* Video frame receive callback */ | 80 | PAIR(toxav_receive_video_frame_cb *, void *) vcb; /* Video frame receive callback */ |
81 | PAIR(toxav_request_video_frame_cb *, void *) rvcb; /* Request video callback */ | ||
82 | PAIR(toxav_request_audio_frame_cb *, void *) racb; /* Request video callback */ | ||
79 | 83 | ||
80 | /** Decode time measures */ | 84 | /** Decode time measures */ |
81 | int32_t dmssc; /** Measure count */ | 85 | int32_t dmssc; /** Measure count */ |
@@ -92,7 +96,6 @@ int callback_end(void* toxav_inst, MSICall* call); | |||
92 | int callback_error(void* toxav_inst, MSICall* call); | 96 | int callback_error(void* toxav_inst, MSICall* call); |
93 | int callback_capabilites(void* toxav_inst, MSICall* call); | 97 | int callback_capabilites(void* toxav_inst, MSICall* call); |
94 | 98 | ||
95 | TOXAV_CALL_STATE capabilities_to_state(uint8_t capabilities); | ||
96 | ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error); | 99 | ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error); |
97 | ToxAVCall* call_get(ToxAV* av, uint32_t friend_number); | 100 | ToxAVCall* call_get(ToxAV* av, uint32_t friend_number); |
98 | void call_remove(ToxAVCall* call); | 101 | void call_remove(ToxAVCall* call); |
@@ -118,7 +121,7 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error) | |||
118 | goto FAILURE; | 121 | goto FAILURE; |
119 | } | 122 | } |
120 | 123 | ||
121 | av = calloc ( sizeof(ToxAV), 1); | 124 | av = calloc (sizeof(ToxAV), 1); |
122 | 125 | ||
123 | if (av == NULL) { | 126 | if (av == NULL) { |
124 | LOGGER_WARNING("Allocation failed!"); | 127 | LOGGER_WARNING("Allocation failed!"); |
@@ -126,10 +129,17 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error) | |||
126 | goto FAILURE; | 129 | goto FAILURE; |
127 | } | 130 | } |
128 | 131 | ||
132 | if (create_recursive_mutex(av->mutex) == -1) { | ||
133 | LOGGER_WARNING("Mutex creation failed!"); | ||
134 | rc = TOXAV_ERR_NEW_MALLOC; | ||
135 | goto FAILURE; | ||
136 | } | ||
137 | |||
129 | av->m = (Messenger *)tox; | 138 | av->m = (Messenger *)tox; |
130 | av->msi = msi_new(av->m); | 139 | av->msi = msi_new(av->m); |
131 | 140 | ||
132 | if (av->msi == NULL) { | 141 | if (av->msi == NULL) { |
142 | pthread_mutex_destroy(av->mutex); | ||
133 | rc = TOXAV_ERR_NEW_MALLOC; | 143 | rc = TOXAV_ERR_NEW_MALLOC; |
134 | goto FAILURE; | 144 | goto FAILURE; |
135 | } | 145 | } |
@@ -163,6 +173,7 @@ void toxav_kill(ToxAV* av) | |||
163 | { | 173 | { |
164 | if (av == NULL) | 174 | if (av == NULL) |
165 | return; | 175 | return; |
176 | pthread_mutex_lock(av->mutex); | ||
166 | 177 | ||
167 | msi_kill(av->msi); | 178 | msi_kill(av->msi); |
168 | 179 | ||
@@ -175,6 +186,8 @@ void toxav_kill(ToxAV* av) | |||
175 | } | 186 | } |
176 | } | 187 | } |
177 | 188 | ||
189 | pthread_mutex_unlock(av->mutex); | ||
190 | pthread_mutex_destroy(av->mutex); | ||
178 | free(av); | 191 | free(av); |
179 | } | 192 | } |
180 | 193 | ||
@@ -185,6 +198,7 @@ Tox* toxav_get_tox(ToxAV* av) | |||
185 | 198 | ||
186 | uint32_t toxav_iteration_interval(const ToxAV* av) | 199 | uint32_t toxav_iteration_interval(const ToxAV* av) |
187 | { | 200 | { |
201 | /* If no call is active interval is 200 */ | ||
188 | return av->calls ? av->interval : 200; | 202 | return av->calls ? av->interval : 200; |
189 | } | 203 | } |
190 | 204 | ||
@@ -194,14 +208,28 @@ void toxav_iteration(ToxAV* av) | |||
194 | return; | 208 | return; |
195 | 209 | ||
196 | uint64_t start = current_time_monotonic(); | 210 | uint64_t start = current_time_monotonic(); |
197 | uint32_t rc = 200 + av->dmssa; /* If no call is active interval is 200 */ | 211 | uint32_t rc = 0; |
198 | 212 | ||
213 | pthread_mutex_lock(av->mutex); | ||
199 | ToxAVCall* i = av->calls[av->calls_head]; | 214 | ToxAVCall* i = av->calls[av->calls_head]; |
200 | for (; i; i = i->next) { | 215 | for (; i; i = i->next) { |
201 | if (i->active) { | 216 | if (i->active) { |
217 | pthread_mutex_lock(i->mutex_decoding); | ||
218 | |||
219 | /* TODO make AV synchronisation */ | ||
220 | if (av->racb.first) | ||
221 | av->racb.first(av, i->friend_id, av->racb.second); | ||
222 | if (av->rvcb.first) | ||
223 | av->rvcb.first(av, i->friend_id, av->rvcb.second); | ||
224 | |||
225 | pthread_mutex_unlock(av->mutex); | ||
202 | cs_do(i->cs); | 226 | cs_do(i->cs); |
203 | rc = MIN(i->cs->last_packet_frame_duration, rc); | 227 | rc = MIN(i->cs->last_packet_frame_duration, rc); |
204 | } | 228 | pthread_mutex_unlock(i->mutex_decoding); |
229 | } else | ||
230 | continue; | ||
231 | |||
232 | pthread_mutex_lock(av->mutex); | ||
205 | } | 233 | } |
206 | 234 | ||
207 | av->interval = rc < av->dmssa ? 0 : rc - av->dmssa; | 235 | av->interval = rc < av->dmssa ? 0 : rc - av->dmssa; |
@@ -216,38 +244,47 @@ void toxav_iteration(ToxAV* av) | |||
216 | 244 | ||
217 | bool toxav_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error) | 245 | bool toxav_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error) |
218 | { | 246 | { |
247 | pthread_mutex_lock(av->mutex); | ||
219 | ToxAVCall* call = call_new(av, friend_number, error); | 248 | ToxAVCall* call = call_new(av, friend_number, error); |
220 | if (call == NULL) | 249 | if (call == NULL) { |
250 | pthread_mutex_unlock(av->mutex); | ||
221 | return false; | 251 | return false; |
252 | } | ||
222 | 253 | ||
223 | call->s_audio_b = audio_bit_rate; | 254 | call->s_audio_b = audio_bit_rate; |
224 | call->s_video_b = video_bit_rate; | 255 | call->s_video_b = video_bit_rate; |
225 | 256 | ||
226 | call->last_capabilities = msi_CapRAudio | msi_CapRVideo; | 257 | call->last_self_capabilities = msi_CapRAudio | msi_CapRVideo; |
227 | 258 | ||
228 | call->last_capabilities |= audio_bit_rate > 0 ? msi_CapSAudio : 0; | 259 | call->last_self_capabilities |= audio_bit_rate > 0 ? msi_CapSAudio : 0; |
229 | call->last_capabilities |= video_bit_rate > 0 ? msi_CapSVideo : 0; | 260 | call->last_self_capabilities |= video_bit_rate > 0 ? msi_CapSVideo : 0; |
230 | 261 | ||
231 | if (msi_invite(av->msi, &call->msi_call, friend_number, call->last_capabilities) != 0) { | 262 | if (msi_invite(av->msi, &call->msi_call, friend_number, call->last_self_capabilities) != 0) { |
232 | call_remove(call); | 263 | call_remove(call); |
233 | if (error) | 264 | if (error) |
234 | *error = TOXAV_ERR_CALL_MALLOC; | 265 | *error = TOXAV_ERR_CALL_MALLOC; |
266 | pthread_mutex_unlock(av->mutex); | ||
235 | return false; | 267 | return false; |
236 | } | 268 | } |
237 | 269 | ||
238 | call->msi_call->av_call = call; | 270 | call->msi_call->av_call = call; |
271 | pthread_mutex_unlock(av->mutex); | ||
239 | 272 | ||
240 | return true; | 273 | return true; |
241 | } | 274 | } |
242 | 275 | ||
243 | void toxav_callback_call(ToxAV* av, toxav_call_cb* function, void* user_data) | 276 | void toxav_callback_call(ToxAV* av, toxav_call_cb* function, void* user_data) |
244 | { | 277 | { |
278 | pthread_mutex_lock(av->mutex); | ||
245 | av->ccb.first = function; | 279 | av->ccb.first = function; |
246 | av->ccb.second = user_data; | 280 | av->ccb.second = user_data; |
281 | pthread_mutex_unlock(av->mutex); | ||
247 | } | 282 | } |
248 | 283 | ||
249 | bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_ANSWER* error) | 284 | bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_ANSWER* error) |
250 | { | 285 | { |
286 | pthread_mutex_lock(av->mutex); | ||
287 | |||
251 | TOXAV_ERR_ANSWER rc = TOXAV_ERR_ANSWER_OK; | 288 | TOXAV_ERR_ANSWER rc = TOXAV_ERR_ANSWER_OK; |
252 | if (m_friend_exists(av->m, friend_number) == 0) { | 289 | if (m_friend_exists(av->m, friend_number) == 0) { |
253 | rc = TOXAV_ERR_ANSWER_FRIEND_NOT_FOUND; | 290 | rc = TOXAV_ERR_ANSWER_FRIEND_NOT_FOUND; |
@@ -270,16 +307,18 @@ bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, ui | |||
270 | call->s_audio_b = audio_bit_rate; | 307 | call->s_audio_b = audio_bit_rate; |
271 | call->s_video_b = video_bit_rate; | 308 | call->s_video_b = video_bit_rate; |
272 | 309 | ||
273 | call->last_capabilities = msi_CapRAudio | msi_CapRVideo; | 310 | call->last_self_capabilities = msi_CapRAudio | msi_CapRVideo; |
274 | 311 | ||
275 | call->last_capabilities |= audio_bit_rate > 0 ? msi_CapSAudio : 0; | 312 | call->last_self_capabilities |= audio_bit_rate > 0 ? msi_CapSAudio : 0; |
276 | call->last_capabilities |= video_bit_rate > 0 ? msi_CapSVideo : 0; | 313 | call->last_self_capabilities |= video_bit_rate > 0 ? msi_CapSVideo : 0; |
277 | 314 | ||
278 | if (msi_answer(call->msi_call, call->last_capabilities) != 0) | 315 | if (msi_answer(call->msi_call, call->last_self_capabilities) != 0) |
279 | rc = TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING; /* the only reason for msi_answer to fail */ | 316 | rc = TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING; /* the only reason for msi_answer to fail */ |
280 | 317 | ||
281 | 318 | ||
282 | END: | 319 | END: |
320 | pthread_mutex_unlock(av->mutex); | ||
321 | |||
283 | if (error) | 322 | if (error) |
284 | *error = rc; | 323 | *error = rc; |
285 | 324 | ||
@@ -288,12 +327,15 @@ END: | |||
288 | 327 | ||
289 | void toxav_callback_call_state(ToxAV* av, toxav_call_state_cb* function, void* user_data) | 328 | void toxav_callback_call_state(ToxAV* av, toxav_call_state_cb* function, void* user_data) |
290 | { | 329 | { |
330 | pthread_mutex_lock(av->mutex); | ||
291 | av->scb.first = function; | 331 | av->scb.first = function; |
292 | av->scb.second = user_data; | 332 | av->scb.second = user_data; |
333 | pthread_mutex_unlock(av->mutex); | ||
293 | } | 334 | } |
294 | 335 | ||
295 | bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL control, TOXAV_ERR_CALL_CONTROL* error) | 336 | bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL control, TOXAV_ERR_CALL_CONTROL* error) |
296 | { | 337 | { |
338 | pthread_mutex_lock(av->mutex); | ||
297 | TOXAV_ERR_CALL_CONTROL rc = TOXAV_ERR_CALL_CONTROL_OK; | 339 | TOXAV_ERR_CALL_CONTROL rc = TOXAV_ERR_CALL_CONTROL_OK; |
298 | 340 | ||
299 | if (m_friend_exists(av->m, friend_number) == 0) { | 341 | if (m_friend_exists(av->m, friend_number) == 0) { |
@@ -308,9 +350,7 @@ bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL co | |||
308 | goto END; | 350 | goto END; |
309 | } | 351 | } |
310 | 352 | ||
311 | /* TODO rest of these */ | 353 | switch (control) { |
312 | switch (control) | ||
313 | { | ||
314 | case TOXAV_CALL_CONTROL_RESUME: { | 354 | case TOXAV_CALL_CONTROL_RESUME: { |
315 | if (!call->active) { | 355 | if (!call->active) { |
316 | rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL; | 356 | rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL; |
@@ -319,10 +359,10 @@ bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL co | |||
319 | 359 | ||
320 | /* Only act if paused and had media transfer active before */ | 360 | /* Only act if paused and had media transfer active before */ |
321 | if (call->msi_call->self_capabilities == 0 && | 361 | if (call->msi_call->self_capabilities == 0 && |
322 | call->last_capabilities ) { | 362 | call->last_self_capabilities ) { |
323 | 363 | ||
324 | if (msi_change_capabilities(call->msi_call, | 364 | if (msi_change_capabilities(call->msi_call, |
325 | call->last_capabilities) == -1) { | 365 | call->last_self_capabilities) == -1) { |
326 | /* The only reason for this function to fail is invalid state | 366 | /* The only reason for this function to fail is invalid state |
327 | * ( not active ) */ | 367 | * ( not active ) */ |
328 | rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL; | 368 | rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL; |
@@ -342,7 +382,7 @@ bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL co | |||
342 | 382 | ||
343 | /* Only act if not already paused */ | 383 | /* Only act if not already paused */ |
344 | if (call->msi_call->self_capabilities) { | 384 | if (call->msi_call->self_capabilities) { |
345 | call->last_capabilities = call->msi_call->self_capabilities; | 385 | call->last_self_capabilities = call->msi_call->self_capabilities; |
346 | 386 | ||
347 | if (msi_change_capabilities(call->msi_call, 0) == -1 ) { | 387 | if (msi_change_capabilities(call->msi_call, 0) == -1 ) { |
348 | /* The only reason for this function to fail is invalid state | 388 | /* The only reason for this function to fail is invalid state |
@@ -365,7 +405,7 @@ bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL co | |||
365 | call_remove(call); | 405 | call_remove(call); |
366 | } break; | 406 | } break; |
367 | 407 | ||
368 | case TOXAV_CALL_CONTROL_MUTE_AUDIO: { | 408 | case TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO: { |
369 | if (!call->active) { | 409 | if (!call->active) { |
370 | rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL; | 410 | rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL; |
371 | goto END; | 411 | goto END; |
@@ -381,54 +421,42 @@ bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL co | |||
381 | } | 421 | } |
382 | 422 | ||
383 | rtp_stop_receiving(call->rtps[audio_index]); | 423 | rtp_stop_receiving(call->rtps[audio_index]); |
384 | } | 424 | } else { |
385 | } break; | 425 | /* This call was already muted so notify the friend that he can |
386 | 426 | * start sending audio again | |
387 | case TOXAV_CALL_CONTROL_MUTE_VIDEO: { | 427 | */ |
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-> | 428 | if (msi_change_capabilities(call->msi_call, call-> |
395 | msi_call->self_capabilities ^ msi_CapRVideo) == -1) { | 429 | msi_call->self_capabilities | msi_CapRAudio) == -1) { |
396 | /* The only reason for this function to fail is invalid state | 430 | /* The only reason for this function to fail is invalid state |
397 | * ( not active ) */ | 431 | * ( not active ) */ |
398 | rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL; | 432 | rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL; |
399 | goto END; | 433 | goto END; |
400 | } | 434 | } |
401 | 435 | ||
402 | rtp_stop_receiving(call->rtps[video_index]); | 436 | rtp_start_receiving(call->rtps[audio_index]); |
403 | } | 437 | } |
404 | } break; | 438 | } break; |
405 | 439 | ||
406 | case TOXAV_CALL_CONTROL_UNMUTE_AUDIO: { | 440 | case TOXAV_CALL_CONTROL_TOGGLE_MUTE_VIDEO: { |
407 | if (!call->active) { | 441 | if (!call->active) { |
408 | rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL; | 442 | rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL; |
409 | goto END; | 443 | goto END; |
410 | } | 444 | } |
411 | 445 | ||
412 | if (call->msi_call->self_capabilities & ~msi_CapRAudio) { | 446 | if (call->msi_call->self_capabilities & msi_CapRVideo) { |
413 | if (msi_change_capabilities(call->msi_call, call-> | 447 | if (msi_change_capabilities(call->msi_call, call-> |
414 | msi_call->self_capabilities | msi_CapRAudio) == -1) { | 448 | msi_call->self_capabilities ^ msi_CapRVideo) == -1) { |
415 | /* The only reason for this function to fail is invalid state | 449 | /* The only reason for this function to fail is invalid state |
416 | * ( not active ) */ | 450 | * ( not active ) */ |
417 | rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL; | 451 | rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL; |
418 | goto END; | 452 | goto END; |
419 | } | 453 | } |
420 | 454 | ||
421 | rtp_start_receiving(call->rtps[audio_index]); | 455 | rtp_stop_receiving(call->rtps[video_index]); |
422 | } | 456 | } else { |
423 | } break; | 457 | /* This call was already muted so notify the friend that he can |
424 | 458 | * start sending video again | |
425 | case TOXAV_CALL_CONTROL_UNMUTE_VIDEO: { | 459 | */ |
426 | if (!call->active) { | ||
427 | rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL; | ||
428 | goto END; | ||
429 | } | ||
430 | |||
431 | if (call->msi_call->self_capabilities & ~msi_CapRVideo) { | ||
432 | if (msi_change_capabilities(call->msi_call, call-> | 460 | if (msi_change_capabilities(call->msi_call, call-> |
433 | msi_call->self_capabilities | msi_CapRVideo) == -1) { | 461 | msi_call->self_capabilities | msi_CapRVideo) == -1) { |
434 | /* The only reason for this function to fail is invalid state | 462 | /* The only reason for this function to fail is invalid state |
@@ -443,6 +471,8 @@ bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL co | |||
443 | } | 471 | } |
444 | 472 | ||
445 | END: | 473 | END: |
474 | pthread_mutex_unlock(av->mutex); | ||
475 | |||
446 | if (error) | 476 | if (error) |
447 | *error = rc; | 477 | *error = rc; |
448 | 478 | ||
@@ -461,7 +491,10 @@ bool toxav_set_video_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t video_ | |||
461 | 491 | ||
462 | void toxav_callback_request_video_frame(ToxAV* av, toxav_request_video_frame_cb* function, void* user_data) | 492 | void toxav_callback_request_video_frame(ToxAV* av, toxav_request_video_frame_cb* function, void* user_data) |
463 | { | 493 | { |
464 | /* TODO */ | 494 | pthread_mutex_lock(av->mutex); |
495 | av->rvcb.first = function; | ||
496 | av->rvcb.second = user_data; | ||
497 | pthread_mutex_unlock(av->mutex); | ||
465 | } | 498 | } |
466 | 499 | ||
467 | bool toxav_send_video_frame(ToxAV* av, uint32_t friend_number, uint16_t width, uint16_t height, const uint8_t* y, const uint8_t* u, const uint8_t* v, TOXAV_ERR_SEND_FRAME* error) | 500 | bool toxav_send_video_frame(ToxAV* av, uint32_t friend_number, uint16_t width, uint16_t height, const uint8_t* y, const uint8_t* u, const uint8_t* v, TOXAV_ERR_SEND_FRAME* error) |
@@ -474,24 +507,32 @@ bool toxav_send_video_frame(ToxAV* av, uint32_t friend_number, uint16_t width, u | |||
474 | goto END; | 507 | goto END; |
475 | } | 508 | } |
476 | 509 | ||
510 | pthread_mutex_lock(av->mutex); | ||
477 | call = call_get(av, friend_number); | 511 | call = call_get(av, friend_number); |
478 | if (call == NULL) { | 512 | if (call == NULL || !call->active) { |
513 | pthread_mutex_unlock(av->mutex); | ||
479 | rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL; | 514 | rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL; |
480 | goto END; | 515 | goto END; |
481 | } | 516 | } |
482 | 517 | ||
518 | pthread_mutex_lock(call->mutex_video_sending); | ||
519 | pthread_mutex_unlock(av->mutex); | ||
520 | |||
483 | if (call->msi_call->state != msi_CallActive) { | 521 | if (call->msi_call->state != msi_CallActive) { |
484 | /* TODO */ | 522 | /* TODO */ |
523 | pthread_mutex_unlock(call->mutex_video_sending); | ||
485 | rc = TOXAV_ERR_SEND_FRAME_NOT_REQUESTED; | 524 | rc = TOXAV_ERR_SEND_FRAME_NOT_REQUESTED; |
486 | goto END; | 525 | goto END; |
487 | } | 526 | } |
488 | 527 | ||
489 | if ( y == NULL || u == NULL || v == NULL ) { | 528 | if ( y == NULL || u == NULL || v == NULL ) { |
529 | pthread_mutex_unlock(call->mutex_video_sending); | ||
490 | rc = TOXAV_ERR_SEND_FRAME_NULL; | 530 | rc = TOXAV_ERR_SEND_FRAME_NULL; |
491 | goto END; | 531 | goto END; |
492 | } | 532 | } |
493 | 533 | ||
494 | if ( cs_set_sending_video_resolution(call->cs, width, height) != 0 ) { | 534 | if ( cs_set_sending_video_resolution(call->cs, width, height) != 0 ) { |
535 | pthread_mutex_unlock(call->mutex_video_sending); | ||
495 | rc = TOXAV_ERR_SEND_FRAME_INVALID; | 536 | rc = TOXAV_ERR_SEND_FRAME_INVALID; |
496 | goto END; | 537 | goto END; |
497 | } | 538 | } |
@@ -513,6 +554,7 @@ bool toxav_send_video_frame(ToxAV* av, uint32_t friend_number, uint16_t width, u | |||
513 | 554 | ||
514 | vpx_img_free(&img); /* FIXME don't free? */ | 555 | vpx_img_free(&img); /* FIXME don't free? */ |
515 | if ( vrc != VPX_CODEC_OK) { | 556 | if ( vrc != VPX_CODEC_OK) { |
557 | pthread_mutex_unlock(call->mutex_video_sending); | ||
516 | LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(vrc)); | 558 | LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(vrc)); |
517 | rc = TOXAV_ERR_SEND_FRAME_INVALID; | 559 | rc = TOXAV_ERR_SEND_FRAME_INVALID; |
518 | goto END; | 560 | goto END; |
@@ -542,13 +584,18 @@ bool toxav_send_video_frame(ToxAV* av, uint32_t friend_number, uint16_t width, u | |||
542 | for (i = 0; i < parts; i++) { | 584 | for (i = 0; i < parts; i++) { |
543 | iter = cs_iterate_split_video_frame(call->cs, &part_size); | 585 | iter = cs_iterate_split_video_frame(call->cs, &part_size); |
544 | 586 | ||
545 | if (rtp_send_msg(call->rtps[video_index], iter, part_size) < 0) | 587 | if (rtp_send_msg(call->rtps[video_index], iter, part_size) < 0) { |
588 | pthread_mutex_unlock(call->mutex_video_sending); | ||
589 | LOGGER_WARNING("Could not send video frame: %s\n", strerror(errno)); | ||
546 | goto END; | 590 | goto END; |
591 | } | ||
547 | } | 592 | } |
548 | } | 593 | } |
549 | } | 594 | } |
550 | } | 595 | } |
551 | 596 | ||
597 | pthread_mutex_unlock(call->mutex_video_sending); | ||
598 | |||
552 | END: | 599 | END: |
553 | if (error) | 600 | if (error) |
554 | *error = rc; | 601 | *error = rc; |
@@ -558,7 +605,10 @@ END: | |||
558 | 605 | ||
559 | void toxav_callback_request_audio_frame(ToxAV* av, toxav_request_audio_frame_cb* function, void* user_data) | 606 | void toxav_callback_request_audio_frame(ToxAV* av, toxav_request_audio_frame_cb* function, void* user_data) |
560 | { | 607 | { |
561 | /* TODO */ | 608 | pthread_mutex_lock(av->mutex); |
609 | av->racb.first = function; | ||
610 | av->racb.second = user_data; | ||
611 | pthread_mutex_unlock(av->mutex); | ||
562 | } | 612 | } |
563 | 613 | ||
564 | bool toxav_send_audio_frame(ToxAV* av, uint32_t friend_number, const int16_t* pcm, size_t sample_count, uint8_t channels, uint32_t sampling_rate, TOXAV_ERR_SEND_FRAME* error) | 614 | bool toxav_send_audio_frame(ToxAV* av, uint32_t friend_number, const int16_t* pcm, size_t sample_count, uint8_t channels, uint32_t sampling_rate, TOXAV_ERR_SEND_FRAME* error) |
@@ -571,24 +621,32 @@ bool toxav_send_audio_frame(ToxAV* av, uint32_t friend_number, const int16_t* pc | |||
571 | goto END; | 621 | goto END; |
572 | } | 622 | } |
573 | 623 | ||
624 | pthread_mutex_lock(av->mutex); | ||
574 | call = call_get(av, friend_number); | 625 | call = call_get(av, friend_number); |
575 | if (call == NULL) { | 626 | if (call == NULL || !call->active) { |
627 | pthread_mutex_unlock(av->mutex); | ||
576 | rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL; | 628 | rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL; |
577 | goto END; | 629 | goto END; |
578 | } | 630 | } |
579 | 631 | ||
632 | pthread_mutex_lock(call->mutex_audio_sending); | ||
633 | pthread_mutex_unlock(av->mutex); | ||
634 | |||
580 | if (call->msi_call->state != msi_CallActive) { | 635 | if (call->msi_call->state != msi_CallActive) { |
581 | /* TODO */ | 636 | /* TODO */ |
637 | pthread_mutex_unlock(call->mutex_audio_sending); | ||
582 | rc = TOXAV_ERR_SEND_FRAME_NOT_REQUESTED; | 638 | rc = TOXAV_ERR_SEND_FRAME_NOT_REQUESTED; |
583 | goto END; | 639 | goto END; |
584 | } | 640 | } |
585 | 641 | ||
586 | if ( pcm == NULL ) { | 642 | if ( pcm == NULL ) { |
643 | pthread_mutex_unlock(call->mutex_audio_sending); | ||
587 | rc = TOXAV_ERR_SEND_FRAME_NULL; | 644 | rc = TOXAV_ERR_SEND_FRAME_NULL; |
588 | goto END; | 645 | goto END; |
589 | } | 646 | } |
590 | 647 | ||
591 | if ( channels != 1 || channels != 2 ) { | 648 | if ( channels != 1 || channels != 2 ) { |
649 | pthread_mutex_unlock(call->mutex_audio_sending); | ||
592 | rc = TOXAV_ERR_SEND_FRAME_INVALID; | 650 | rc = TOXAV_ERR_SEND_FRAME_INVALID; |
593 | goto END; | 651 | goto END; |
594 | } | 652 | } |
@@ -604,6 +662,7 @@ bool toxav_send_audio_frame(ToxAV* av, uint32_t friend_number, const int16_t* pc | |||
604 | if (vrc < 0) { | 662 | if (vrc < 0) { |
605 | LOGGER_WARNING("Failed to encode frame"); | 663 | LOGGER_WARNING("Failed to encode frame"); |
606 | rc = TOXAV_ERR_SEND_FRAME_INVALID; | 664 | rc = TOXAV_ERR_SEND_FRAME_INVALID; |
665 | pthread_mutex_unlock(call->mutex_audio_sending); | ||
607 | goto END; | 666 | goto END; |
608 | } | 667 | } |
609 | 668 | ||
@@ -611,6 +670,8 @@ bool toxav_send_audio_frame(ToxAV* av, uint32_t friend_number, const int16_t* pc | |||
611 | /* TODO check for error? */ | 670 | /* TODO check for error? */ |
612 | } | 671 | } |
613 | 672 | ||
673 | pthread_mutex_unlock(call->mutex_audio_sending); | ||
674 | |||
614 | END: | 675 | END: |
615 | if (error) | 676 | if (error) |
616 | *error = rc; | 677 | *error = rc; |
@@ -620,14 +681,18 @@ END: | |||
620 | 681 | ||
621 | void toxav_callback_receive_video_frame(ToxAV* av, toxav_receive_video_frame_cb* function, void* user_data) | 682 | void toxav_callback_receive_video_frame(ToxAV* av, toxav_receive_video_frame_cb* function, void* user_data) |
622 | { | 683 | { |
684 | pthread_mutex_lock(av->mutex); | ||
623 | av->vcb.first = function; | 685 | av->vcb.first = function; |
624 | av->vcb.second = user_data; | 686 | av->vcb.second = user_data; |
687 | pthread_mutex_unlock(av->mutex); | ||
625 | } | 688 | } |
626 | 689 | ||
627 | void toxav_callback_receive_audio_frame(ToxAV* av, toxav_receive_audio_frame_cb* function, void* user_data) | 690 | void toxav_callback_receive_audio_frame(ToxAV* av, toxav_receive_audio_frame_cb* function, void* user_data) |
628 | { | 691 | { |
692 | pthread_mutex_lock(av->mutex); | ||
629 | av->acb.first = function; | 693 | av->acb.first = function; |
630 | av->acb.second = user_data; | 694 | av->acb.second = user_data; |
695 | pthread_mutex_unlock(av->mutex); | ||
631 | } | 696 | } |
632 | 697 | ||
633 | 698 | ||
@@ -639,10 +704,12 @@ void toxav_callback_receive_audio_frame(ToxAV* av, toxav_receive_audio_frame_cb* | |||
639 | int callback_invite(void* toxav_inst, MSICall* call) | 704 | int callback_invite(void* toxav_inst, MSICall* call) |
640 | { | 705 | { |
641 | ToxAV* toxav = toxav_inst; | 706 | ToxAV* toxav = toxav_inst; |
707 | pthread_mutex_lock(toxav->mutex); | ||
642 | 708 | ||
643 | ToxAVCall* av_call = call_new(toxav, call->friend_id, NULL); | 709 | ToxAVCall* av_call = call_new(toxav, call->friend_id, NULL); |
644 | if (av_call == NULL) { | 710 | if (av_call == NULL) { |
645 | LOGGER_WARNING("Failed to initialize call..."); | 711 | LOGGER_WARNING("Failed to initialize call..."); |
712 | pthread_mutex_unlock(toxav->mutex); | ||
646 | return -1; | 713 | return -1; |
647 | } | 714 | } |
648 | 715 | ||
@@ -653,36 +720,41 @@ int callback_invite(void* toxav_inst, MSICall* call) | |||
653 | toxav->ccb.first(toxav, call->friend_id, call->peer_capabilities & msi_CapSAudio, | 720 | toxav->ccb.first(toxav, call->friend_id, call->peer_capabilities & msi_CapSAudio, |
654 | call->peer_capabilities & msi_CapSVideo, toxav->ccb.second); | 721 | call->peer_capabilities & msi_CapSVideo, toxav->ccb.second); |
655 | 722 | ||
723 | pthread_mutex_unlock(toxav->mutex); | ||
656 | return 0; | 724 | return 0; |
657 | } | 725 | } |
658 | 726 | ||
659 | int callback_start(void* toxav_inst, MSICall* call) | 727 | int callback_start(void* toxav_inst, MSICall* call) |
660 | { | 728 | { |
661 | ToxAV* toxav = toxav_inst; | 729 | ToxAV* toxav = toxav_inst; |
730 | pthread_mutex_lock(toxav->mutex); | ||
662 | 731 | ||
663 | ToxAVCall* av_call = call_get(toxav, call->friend_id); | 732 | ToxAVCall* av_call = call_get(toxav, call->friend_id); |
664 | 733 | ||
665 | if (av_call == NULL) { | 734 | if (av_call == NULL) { |
666 | /* Should this ever happen? */ | 735 | /* Should this ever happen? */ |
736 | pthread_mutex_unlock(toxav->mutex); | ||
667 | return -1; | 737 | return -1; |
668 | } | 738 | } |
669 | 739 | ||
670 | if (!call_prepare_transmission(av_call)) { | 740 | if (!call_prepare_transmission(av_call)) { |
671 | callback_error(toxav_inst, call); | 741 | callback_error(toxav_inst, call); |
672 | call_remove(av_call); | 742 | call_remove(av_call); |
743 | pthread_mutex_unlock(toxav->mutex); | ||
673 | return -1; | 744 | return -1; |
674 | } | 745 | } |
675 | 746 | ||
676 | if (toxav->scb.first) | 747 | if (toxav->scb.first) |
677 | toxav->scb.first(toxav, call->friend_id, | 748 | toxav->scb.first(toxav, call->friend_id, call->peer_capabilities, toxav->scb.second); |
678 | capabilities_to_state(call->peer_capabilities), toxav->scb.second); | ||
679 | 749 | ||
750 | pthread_mutex_unlock(toxav->mutex); | ||
680 | return 0; | 751 | return 0; |
681 | } | 752 | } |
682 | 753 | ||
683 | int callback_end(void* toxav_inst, MSICall* call) | 754 | int callback_end(void* toxav_inst, MSICall* call) |
684 | { | 755 | { |
685 | ToxAV* toxav = toxav_inst; | 756 | ToxAV* toxav = toxav_inst; |
757 | pthread_mutex_lock(toxav->mutex); | ||
686 | 758 | ||
687 | if (toxav->scb.first) | 759 | if (toxav->scb.first) |
688 | toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_END, toxav->scb.second); | 760 | toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_END, toxav->scb.second); |
@@ -690,43 +762,39 @@ int callback_end(void* toxav_inst, MSICall* call) | |||
690 | call_kill_transmission(call->av_call); | 762 | call_kill_transmission(call->av_call); |
691 | call_remove(call->av_call); | 763 | call_remove(call->av_call); |
692 | 764 | ||
765 | pthread_mutex_unlock(toxav->mutex); | ||
693 | return 0; | 766 | return 0; |
694 | } | 767 | } |
695 | 768 | ||
696 | int callback_error(void* toxav_inst, MSICall* call) | 769 | int callback_error(void* toxav_inst, MSICall* call) |
697 | { | 770 | { |
698 | ToxAV* toxav = toxav_inst; | 771 | ToxAV* toxav = toxav_inst; |
772 | pthread_mutex_lock(toxav->mutex); | ||
699 | 773 | ||
700 | if (toxav->scb.first) | 774 | if (toxav->scb.first) |
701 | toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_ERROR, toxav->scb.second); | 775 | toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_ERROR, toxav->scb.second); |
702 | 776 | ||
777 | call_kill_transmission(call->av_call); | ||
778 | call_remove(call->av_call); | ||
779 | |||
780 | pthread_mutex_unlock(toxav->mutex); | ||
703 | return 0; | 781 | return 0; |
704 | } | 782 | } |
705 | 783 | ||
706 | int callback_capabilites(void* toxav_inst, MSICall* call) | 784 | int callback_capabilites(void* toxav_inst, MSICall* call) |
707 | { | 785 | { |
708 | ToxAV* toxav = toxav_inst; | 786 | ToxAV* toxav = toxav_inst; |
787 | pthread_mutex_lock(toxav->mutex); | ||
788 | |||
789 | /* TODO modify cs? */ | ||
790 | |||
709 | if (toxav->scb.first) | 791 | if (toxav->scb.first) |
710 | toxav->scb.first(toxav, call->friend_id, | 792 | toxav->scb.first(toxav, call->friend_id, call->peer_capabilities, toxav->scb.second); |
711 | capabilities_to_state(call->peer_capabilities), toxav->scb.second); | ||
712 | 793 | ||
794 | pthread_mutex_unlock(toxav->mutex); | ||
713 | return 0; | 795 | return 0; |
714 | } | 796 | } |
715 | 797 | ||
716 | TOXAV_CALL_STATE capabilities_to_state(uint8_t capabilities) | ||
717 | { | ||
718 | if (capabilities == 0) | ||
719 | return TOXAV_CALL_STATE_PAUSED; | ||
720 | else if ((capabilities & msi_CapSAudio) && (capabilities & msi_CapSVideo)) | ||
721 | return TOXAV_CALL_STATE_SENDING_AV; | ||
722 | else if (capabilities & msi_CapSAudio) | ||
723 | return TOXAV_CALL_STATE_SENDING_A; | ||
724 | else if (capabilities & msi_CapSVideo) | ||
725 | return TOXAV_CALL_STATE_SENDING_V; | ||
726 | |||
727 | return TOXAV_CALL_STATE_NOT_SENDING; | ||
728 | } | ||
729 | |||
730 | bool audio_bitrate_invalid(uint32_t bitrate) | 798 | bool audio_bitrate_invalid(uint32_t bitrate) |
731 | { | 799 | { |
732 | /* Opus RFC 6716 section-2.1.1 dictates the following: | 800 | /* Opus RFC 6716 section-2.1.1 dictates the following: |
@@ -743,6 +811,7 @@ bool video_bitrate_invalid(uint32_t bitrate) | |||
743 | 811 | ||
744 | ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error) | 812 | ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error) |
745 | { | 813 | { |
814 | /* Assumes mutex locked */ | ||
746 | TOXAV_ERR_CALL rc = TOXAV_ERR_CALL_OK; | 815 | TOXAV_ERR_CALL rc = TOXAV_ERR_CALL_OK; |
747 | ToxAVCall* call = NULL; | 816 | ToxAVCall* call = NULL; |
748 | 817 | ||
@@ -772,28 +841,10 @@ ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error) | |||
772 | call->av = av; | 841 | call->av = av; |
773 | call->friend_id = friend_number; | 842 | call->friend_id = friend_number; |
774 | 843 | ||
775 | if (create_recursive_mutex(call->mutex_control) != 0) { | ||
776 | free(call); | ||
777 | call = NULL; | ||
778 | rc = TOXAV_ERR_CALL_MALLOC; | ||
779 | goto END; | ||
780 | } | ||
781 | |||
782 | if (create_recursive_mutex(call->mutex_do) != 0) { | ||
783 | pthread_mutex_destroy(call->mutex_control); | ||
784 | free(call); | ||
785 | call = NULL; | ||
786 | rc = TOXAV_ERR_CALL_MALLOC; | ||
787 | goto END; | ||
788 | } | ||
789 | |||
790 | |||
791 | if (av->calls == NULL) { /* Creating */ | 844 | if (av->calls == NULL) { /* Creating */ |
792 | av->calls = calloc (sizeof(ToxAVCall*), friend_number + 1); | 845 | av->calls = calloc (sizeof(ToxAVCall*), friend_number + 1); |
793 | 846 | ||
794 | if (av->calls == NULL) { | 847 | if (av->calls == NULL) { |
795 | pthread_mutex_destroy(call->mutex_control); | ||
796 | pthread_mutex_destroy(call->mutex_do); | ||
797 | free(call); | 848 | free(call); |
798 | call = NULL; | 849 | call = NULL; |
799 | rc = TOXAV_ERR_CALL_MALLOC; | 850 | rc = TOXAV_ERR_CALL_MALLOC; |
@@ -806,8 +857,6 @@ ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error) | |||
806 | void* tmp = realloc(av->calls, sizeof(ToxAVCall*) * friend_number + 1); | 857 | void* tmp = realloc(av->calls, sizeof(ToxAVCall*) * friend_number + 1); |
807 | 858 | ||
808 | if (tmp == NULL) { | 859 | if (tmp == NULL) { |
809 | pthread_mutex_destroy(call->mutex_control); | ||
810 | pthread_mutex_destroy(call->mutex_do); | ||
811 | free(call); | 860 | free(call); |
812 | call = NULL; | 861 | call = NULL; |
813 | rc = TOXAV_ERR_CALL_MALLOC; | 862 | rc = TOXAV_ERR_CALL_MALLOC; |
@@ -843,6 +892,7 @@ END: | |||
843 | 892 | ||
844 | ToxAVCall* call_get(ToxAV* av, uint32_t friend_number) | 893 | ToxAVCall* call_get(ToxAV* av, uint32_t friend_number) |
845 | { | 894 | { |
895 | /* Assumes mutex locked */ | ||
846 | if (av->calls == NULL || av->calls_tail < friend_number) | 896 | if (av->calls == NULL || av->calls_tail < friend_number) |
847 | return NULL; | 897 | return NULL; |
848 | 898 | ||
@@ -851,6 +901,8 @@ ToxAVCall* call_get(ToxAV* av, uint32_t friend_number) | |||
851 | 901 | ||
852 | bool call_prepare_transmission(ToxAVCall* call) | 902 | bool call_prepare_transmission(ToxAVCall* call) |
853 | { | 903 | { |
904 | /* Assumes mutex locked */ | ||
905 | |||
854 | if (call == NULL) | 906 | if (call == NULL) |
855 | return false; | 907 | return false; |
856 | 908 | ||
@@ -860,25 +912,22 @@ bool call_prepare_transmission(ToxAVCall* call) | |||
860 | /* It makes no sense to have CSession without callbacks */ | 912 | /* It makes no sense to have CSession without callbacks */ |
861 | return false; | 913 | return false; |
862 | 914 | ||
863 | pthread_mutex_lock(call->mutex_control); | ||
864 | |||
865 | if (call->active) { | 915 | if (call->active) { |
866 | pthread_mutex_unlock(call->mutex_control); | ||
867 | LOGGER_WARNING("Call already active!\n"); | 916 | LOGGER_WARNING("Call already active!\n"); |
868 | return true; | 917 | return true; |
869 | } | 918 | } |
870 | 919 | ||
871 | if (pthread_mutex_init(call->mutex_encoding_audio, NULL) != 0) | 920 | if (pthread_mutex_init(call->mutex_audio_sending, NULL) != 0) |
872 | goto MUTEX_INIT_ERROR; | 921 | goto MUTEX_INIT_ERROR; |
873 | 922 | ||
874 | if (pthread_mutex_init(call->mutex_encoding_video, NULL) != 0) { | 923 | if (pthread_mutex_init(call->mutex_video_sending, NULL) != 0) { |
875 | pthread_mutex_destroy(call->mutex_encoding_audio); | 924 | pthread_mutex_destroy(call->mutex_audio_sending); |
876 | goto MUTEX_INIT_ERROR; | 925 | goto MUTEX_INIT_ERROR; |
877 | } | 926 | } |
878 | 927 | ||
879 | if (pthread_mutex_init(call->mutex_do, NULL) != 0) { | 928 | if (pthread_mutex_init(call->mutex_decoding, NULL) != 0) { |
880 | pthread_mutex_destroy(call->mutex_encoding_audio); | 929 | pthread_mutex_destroy(call->mutex_audio_sending); |
881 | pthread_mutex_destroy(call->mutex_encoding_video); | 930 | pthread_mutex_destroy(call->mutex_video_sending); |
882 | goto MUTEX_INIT_ERROR; | 931 | goto MUTEX_INIT_ERROR; |
883 | } | 932 | } |
884 | 933 | ||
@@ -945,7 +994,6 @@ bool call_prepare_transmission(ToxAVCall* call) | |||
945 | } | 994 | } |
946 | 995 | ||
947 | call->active = 1; | 996 | call->active = 1; |
948 | pthread_mutex_unlock(call->mutex_control); | ||
949 | return true; | 997 | return true; |
950 | 998 | ||
951 | FAILURE: | 999 | FAILURE: |
@@ -955,16 +1003,12 @@ FAILURE: | |||
955 | call->rtps[video_index] = NULL; | 1003 | call->rtps[video_index] = NULL; |
956 | cs_kill(call->cs); | 1004 | cs_kill(call->cs); |
957 | call->cs = NULL; | 1005 | call->cs = NULL; |
958 | call->active = 0; | 1006 | pthread_mutex_destroy(call->mutex_audio_sending); |
959 | pthread_mutex_destroy(call->mutex_encoding_audio); | 1007 | pthread_mutex_destroy(call->mutex_video_sending); |
960 | pthread_mutex_destroy(call->mutex_encoding_video); | 1008 | pthread_mutex_destroy(call->mutex_decoding); |
961 | pthread_mutex_destroy(call->mutex_do); | ||
962 | |||
963 | pthread_mutex_unlock(call->mutex_control); | ||
964 | return false; | 1009 | return false; |
965 | 1010 | ||
966 | MUTEX_INIT_ERROR: | 1011 | MUTEX_INIT_ERROR: |
967 | pthread_mutex_unlock(call->mutex_control); | ||
968 | LOGGER_ERROR("Mutex initialization failed!\n"); | 1012 | LOGGER_ERROR("Mutex initialization failed!\n"); |
969 | return false; | 1013 | return false; |
970 | } | 1014 | } |
@@ -974,29 +1018,26 @@ void call_kill_transmission(ToxAVCall* call) | |||
974 | if (call == NULL || call->active == 0) | 1018 | if (call == NULL || call->active == 0) |
975 | return; | 1019 | return; |
976 | 1020 | ||
977 | pthread_mutex_lock(call->mutex_control); | ||
978 | |||
979 | call->active = 0; | 1021 | call->active = 0; |
980 | 1022 | ||
981 | pthread_mutex_lock(call->mutex_encoding_audio); | 1023 | pthread_mutex_lock(call->mutex_audio_sending); |
982 | pthread_mutex_unlock(call->mutex_encoding_audio); | 1024 | pthread_mutex_unlock(call->mutex_audio_sending); |
983 | pthread_mutex_lock(call->mutex_encoding_video); | 1025 | pthread_mutex_lock(call->mutex_video_sending); |
984 | pthread_mutex_unlock(call->mutex_encoding_video); | 1026 | pthread_mutex_unlock(call->mutex_video_sending); |
985 | pthread_mutex_lock(call->mutex_do); | 1027 | pthread_mutex_lock(call->mutex_decoding); |
986 | pthread_mutex_unlock(call->mutex_do); | 1028 | pthread_mutex_unlock(call->mutex_decoding); |
987 | 1029 | ||
988 | rtp_kill(call->rtps[audio_index]); | 1030 | rtp_kill(call->rtps[audio_index]); |
989 | call->rtps[audio_index] = NULL; | 1031 | call->rtps[audio_index] = NULL; |
990 | rtp_kill(call->rtps[video_index]); | 1032 | rtp_kill(call->rtps[video_index]); |
991 | call->rtps[video_index] = NULL; | 1033 | call->rtps[video_index] = NULL; |
1034 | |||
992 | cs_kill(call->cs); | 1035 | cs_kill(call->cs); |
993 | call->cs = NULL; | 1036 | call->cs = NULL; |
994 | 1037 | ||
995 | pthread_mutex_destroy(call->mutex_encoding_audio); | 1038 | pthread_mutex_destroy(call->mutex_audio_sending); |
996 | pthread_mutex_destroy(call->mutex_encoding_video); | 1039 | pthread_mutex_destroy(call->mutex_video_sending); |
997 | pthread_mutex_destroy(call->mutex_do); | 1040 | pthread_mutex_destroy(call->mutex_decoding); |
998 | |||
999 | pthread_mutex_unlock(call->mutex_control); | ||
1000 | } | 1041 | } |
1001 | 1042 | ||
1002 | void call_remove(ToxAVCall* call) | 1043 | void call_remove(ToxAVCall* call) |
@@ -1010,9 +1051,6 @@ void call_remove(ToxAVCall* call) | |||
1010 | ToxAVCall* prev = call->prev; | 1051 | ToxAVCall* prev = call->prev; |
1011 | ToxAVCall* next = call->next; | 1052 | ToxAVCall* next = call->next; |
1012 | 1053 | ||
1013 | pthread_mutex_destroy(call->mutex_control); | ||
1014 | pthread_mutex_destroy(call->mutex_do); | ||
1015 | |||
1016 | free(call); | 1054 | free(call); |
1017 | 1055 | ||
1018 | if (prev) | 1056 | if (prev) |
diff --git a/toxav/toxav.h b/toxav/toxav.h index ec232ddd..101047ed 100644 --- a/toxav/toxav.h +++ b/toxav/toxav.h | |||
@@ -187,43 +187,41 @@ bool toxav_answer(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, ui | |||
187 | ******************************************************************************/ | 187 | ******************************************************************************/ |
188 | typedef enum TOXAV_CALL_STATE { | 188 | typedef enum TOXAV_CALL_STATE { |
189 | /** | 189 | /** |
190 | * Not sending anything. Either the friend requested that this client stops | 190 | * Not sending nor receiving anything, meaning, one of the sides requested pause. |
191 | * sending anything, or the client turned off both audio and video by setting | 191 | * The call will be resumed once the side that initiated pause resumes it. |
192 | * the respective bit rates to 0. | ||
193 | * | ||
194 | * If both sides are in this state, the call is effectively on hold, but not | ||
195 | * in the PAUSED state. | ||
196 | */ | 192 | */ |
197 | TOXAV_CALL_STATE_NOT_SENDING, | 193 | TOXAV_CALL_STATE_PAUSED = 0, |
198 | /** | 194 | /** |
199 | * Sending audio only. Either the friend requested that this client stops | 195 | * The flag that marks that friend is sending audio. |
200 | * sending video, or the client turned off video by setting the video bit rate | ||
201 | * to 0. | ||
202 | */ | 196 | */ |
203 | TOXAV_CALL_STATE_SENDING_A, | 197 | TOXAV_CALL_STATE_SENDING_A = 1, |
204 | /** | 198 | /** |
205 | * Sending video only. Either the friend requested that this client stops | 199 | * The flag that marks that friend is sending video. |
206 | * sending audio (muted), or the client turned off audio by setting the audio | ||
207 | * bit rate to 0. | ||
208 | */ | 200 | */ |
209 | TOXAV_CALL_STATE_SENDING_V, | 201 | TOXAV_CALL_STATE_SENDING_V = 2, |
210 | /** | 202 | /** |
211 | * Sending both audio and video. | 203 | * The flag that marks that friend is receiving audio. |
212 | */ | 204 | */ |
213 | TOXAV_CALL_STATE_SENDING_AV, | 205 | TOXAV_CALL_STATE_RECEIVING_A = 4, |
214 | /** | 206 | /** |
215 | * The call is on hold. Both sides stop sending and receiving. | 207 | * The flag that marks that friend is receiving video. |
216 | */ | 208 | */ |
217 | TOXAV_CALL_STATE_PAUSED, | 209 | TOXAV_CALL_STATE_RECEIVING_V = 8, |
210 | |||
211 | /** | ||
212 | * The core will never set TOXAV_CALL_STATE_END or TOXAV_CALL_STATE_ERROR | ||
213 | * together with other states. | ||
214 | */ | ||
215 | |||
218 | /** | 216 | /** |
219 | * The call has finished. This is the final state after which no more state | 217 | * The call has finished. This is the final state after which no more state |
220 | * transitions can occur for the call. | 218 | * transitions can occur for the call. |
221 | */ | 219 | */ |
222 | TOXAV_CALL_STATE_END, | 220 | TOXAV_CALL_STATE_END = 16, |
223 | /** | 221 | /** |
224 | * Sent by the AV core if an error occurred on the remote end. | 222 | * Sent by the AV core if an error occurred on the remote end. |
225 | */ | 223 | */ |
226 | TOXAV_CALL_STATE_ERROR | 224 | TOXAV_CALL_STATE_ERROR = 32 |
227 | } TOXAV_CALL_STATE; | 225 | } TOXAV_CALL_STATE; |
228 | /** | 226 | /** |
229 | * The function type for the `call_state` callback. | 227 | * The function type for the `call_state` callback. |
@@ -231,7 +229,7 @@ typedef enum TOXAV_CALL_STATE { | |||
231 | * @param friend_number The friend number for which the call state changed. | 229 | * @param friend_number The friend number for which the call state changed. |
232 | * @param state The new call state. | 230 | * @param state The new call state. |
233 | */ | 231 | */ |
234 | typedef void toxav_call_state_cb(ToxAV *av, uint32_t friend_number, TOXAV_CALL_STATE state, void *user_data); | 232 | typedef void toxav_call_state_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data); |
235 | /** | 233 | /** |
236 | * Set the callback for the `call_state` event. Pass NULL to unset. | 234 | * Set the callback for the `call_state` event. Pass NULL to unset. |
237 | * | 235 | * |
@@ -261,27 +259,19 @@ typedef enum TOXAV_CALL_CONTROL { | |||
261 | /** | 259 | /** |
262 | * Request that the friend stops sending audio. Regardless of the friend's | 260 | * Request that the friend stops sending audio. Regardless of the friend's |
263 | * compliance, this will cause the `receive_audio_frame` event to stop being | 261 | * compliance, this will cause the `receive_audio_frame` event to stop being |
264 | * triggered on receiving an audio frame from the friend. | 262 | * triggered on receiving an audio frame from the friend. If the audio was |
263 | * already muted, calling this control will notify client to start sending | ||
264 | * audio again. | ||
265 | */ | 265 | */ |
266 | TOXAV_CALL_CONTROL_MUTE_AUDIO, | 266 | TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, |
267 | /** | 267 | /** |
268 | * Request that the friend stops sending video. Regardless of the friend's | 268 | * Request that the friend stops sending video. Regardless of the friend's |
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. If the video was |
271 | */ | 271 | * already muted, calling this control will notify client to start sending |
272 | TOXAV_CALL_CONTROL_MUTE_VIDEO, | 272 | * video again. |
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 | */ | 273 | */ |
284 | TOXAV_CALL_CONTROL_UNMUTE_VIDEO | 274 | TOXAV_CALL_CONTROL_TOGGLE_MUTE_VIDEO, |
285 | } TOXAV_CALL_CONTROL; | 275 | } TOXAV_CALL_CONTROL; |
286 | typedef enum TOXAV_ERR_CALL_CONTROL { | 276 | typedef enum TOXAV_ERR_CALL_CONTROL { |
287 | TOXAV_ERR_CALL_CONTROL_OK, | 277 | TOXAV_ERR_CALL_CONTROL_OK, |