diff options
Diffstat (limited to 'toxav/toxav.c')
-rw-r--r-- | toxav/toxav.c | 432 |
1 files changed, 234 insertions, 198 deletions
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 { | |||
42 | 42 | ||
43 | typedef struct ToxAVCall_s | 43 | typedef struct ToxAVCall_s |
44 | { | 44 | { |
45 | ToxAV* av; | ||
45 | pthread_mutex_t mutex_control[1]; | 46 | pthread_mutex_t mutex_control[1]; |
46 | pthread_mutex_t mutex_encoding_audio[1]; | 47 | pthread_mutex_t mutex_encoding_audio[1]; |
47 | pthread_mutex_t mutex_encoding_video[1]; | 48 | pthread_mutex_t mutex_encoding_video[1]; |
@@ -55,6 +56,8 @@ typedef struct ToxAVCall_s | |||
55 | uint32_t s_audio_b; /* Sending audio bitrate */ | 56 | uint32_t s_audio_b; /* Sending audio bitrate */ |
56 | uint32_t s_video_b; /* Sending video bitrate */ | 57 | uint32_t s_video_b; /* Sending video bitrate */ |
57 | 58 | ||
59 | uint8_t last_capabilities; | ||
60 | |||
58 | struct ToxAVCall_s *prev; | 61 | struct ToxAVCall_s *prev; |
59 | struct ToxAVCall_s *next; | 62 | struct ToxAVCall_s *next; |
60 | } ToxAVCall; | 63 | } ToxAVCall; |
@@ -83,22 +86,20 @@ struct toxAV | |||
83 | }; | 86 | }; |
84 | 87 | ||
85 | 88 | ||
86 | void i_callback_invite(void* toxav_inst, MSICall* call); | 89 | int callback_invite(void* toxav_inst, MSICall* call); |
87 | void i_callback_ringing(void* toxav_inst, MSICall* call); | 90 | int callback_start(void* toxav_inst, MSICall* call); |
88 | void i_callback_start(void* toxav_inst, MSICall* call); | 91 | int callback_end(void* toxav_inst, MSICall* call); |
89 | void i_callback_end(void* toxav_inst, MSICall* call); | 92 | int callback_error(void* toxav_inst, MSICall* call); |
90 | void i_callback_error(void* toxav_inst, MSICall* call); | 93 | int callback_capabilites(void* toxav_inst, MSICall* call); |
91 | void i_callback_capabilites(void* toxav_inst, MSICall* call); | ||
92 | 94 | ||
93 | TOXAV_CALL_STATE capabilities_to_state(uint8_t capabilities); | 95 | TOXAV_CALL_STATE capabilities_to_state(uint8_t capabilities); |
94 | ToxAVCall* i_toxav_get_call(ToxAV* av, uint32_t friend_number); | 96 | ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error); |
95 | ToxAVCall* i_toxav_add_call(ToxAV* av, uint32_t friend_number); | 97 | ToxAVCall* call_get(ToxAV* av, uint32_t friend_number); |
96 | void i_toxav_remove_call(ToxAV* av, uint32_t friend_number); | 98 | void call_remove(ToxAVCall* call); |
97 | ToxAVCall* i_toxav_init_call(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error); | 99 | bool audio_bitrate_invalid(uint32_t bitrate); |
98 | bool i_toxav_audio_bitrate_invalid(uint32_t bitrate); | 100 | bool video_bitrate_invalid(uint32_t bitrate); |
99 | bool i_toxav_video_bitrate_invalid(uint32_t bitrate); | 101 | bool call_prepare_transmission(ToxAVCall* call); |
100 | bool i_toxav_prepare_transmission(ToxAV* av, ToxAVCall* call); | 102 | void call_kill_transmission(ToxAVCall* call); |
101 | void i_toxav_kill_transmission(ToxAV* av, uint32_t friend_number); | ||
102 | 103 | ||
103 | 104 | ||
104 | 105 | ||
@@ -136,14 +137,12 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error) | |||
136 | av->interval = 200; | 137 | av->interval = 200; |
137 | av->msi->av = av; | 138 | av->msi->av = av; |
138 | 139 | ||
139 | msi_register_callback(av->msi, i_callback_invite, msi_OnInvite); | 140 | msi_register_callback(av->msi, callback_invite, msi_OnInvite); |
140 | msi_register_callback(av->msi, i_callback_ringing, msi_OnRinging); | 141 | msi_register_callback(av->msi, callback_start, msi_OnStart); |
141 | msi_register_callback(av->msi, i_callback_start, msi_OnStart); | 142 | msi_register_callback(av->msi, callback_end, msi_OnEnd); |
142 | msi_register_callback(av->msi, i_callback_end, msi_OnReject); | 143 | msi_register_callback(av->msi, callback_error, msi_OnError); |
143 | msi_register_callback(av->msi, i_callback_end, msi_OnEnd); | 144 | msi_register_callback(av->msi, callback_error, msi_OnPeerTimeout); |
144 | msi_register_callback(av->msi, i_callback_error, msi_OnError); | 145 | msi_register_callback(av->msi, callback_capabilites, msi_OnCapabilities); |
145 | msi_register_callback(av->msi, i_callback_error, msi_OnPeerTimeout); | ||
146 | msi_register_callback(av->msi, i_callback_capabilites, msi_OnCapabilities); | ||
147 | 146 | ||
148 | 147 | ||
149 | if (error) | 148 | if (error) |
@@ -166,7 +165,16 @@ void toxav_kill(ToxAV* av) | |||
166 | return; | 165 | return; |
167 | 166 | ||
168 | msi_kill(av->msi); | 167 | msi_kill(av->msi); |
169 | /* TODO iterate over calls */ | 168 | |
169 | /* Msi kill will hang up all calls so just clean these calls */ | ||
170 | if (av->calls) { | ||
171 | ToxAVCall* it = call_get(av, av->calls_head); | ||
172 | for (; it; it = it->next) { | ||
173 | call_kill_transmission(it); | ||
174 | call_remove(it); /* This will eventually free av->calls */ | ||
175 | } | ||
176 | } | ||
177 | |||
170 | free(av); | 178 | free(av); |
171 | } | 179 | } |
172 | 180 | ||
@@ -208,20 +216,20 @@ void toxav_iteration(ToxAV* av) | |||
208 | 216 | ||
209 | bool toxav_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error) | 217 | bool toxav_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error) |
210 | { | 218 | { |
211 | ToxAVCall* call = i_toxav_init_call(av, friend_number, error); | 219 | ToxAVCall* call = call_new(av, friend_number, error); |
212 | if (call == NULL) | 220 | if (call == NULL) |
213 | return false; | 221 | return false; |
214 | 222 | ||
215 | call->s_audio_b = audio_bit_rate; | 223 | call->s_audio_b = audio_bit_rate; |
216 | call->s_video_b = video_bit_rate; | 224 | call->s_video_b = video_bit_rate; |
217 | 225 | ||
218 | uint8_t capabilities = 0; | 226 | call->last_capabilities = msi_CapRAudio | msi_CapRVideo; |
219 | 227 | ||
220 | capabilities |= audio_bit_rate > 0 ? msi_CapSAudio : 0; | 228 | call->last_capabilities |= audio_bit_rate > 0 ? msi_CapSAudio : 0; |
221 | capabilities |= video_bit_rate > 0 ? msi_CapSVideo : 0; | 229 | call->last_capabilities |= video_bit_rate > 0 ? msi_CapSVideo : 0; |
222 | 230 | ||
223 | if (msi_invite(av->msi, &call->msi_call, friend_number, capabilities) != 0) { | 231 | if (msi_invite(av->msi, &call->msi_call, friend_number, call->last_capabilities) != 0) { |
224 | i_toxav_remove_call(av, friend_number); | 232 | call_remove(call); |
225 | if (error) | 233 | if (error) |
226 | *error = TOXAV_ERR_CALL_MALLOC; | 234 | *error = TOXAV_ERR_CALL_MALLOC; |
227 | return false; | 235 | return false; |
@@ -244,14 +252,14 @@ bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, ui | |||
244 | goto END; | 252 | goto END; |
245 | } | 253 | } |
246 | 254 | ||
247 | if ((audio_bit_rate && i_toxav_audio_bitrate_invalid(audio_bit_rate)) | 255 | if ((audio_bit_rate && audio_bitrate_invalid(audio_bit_rate)) |
248 | ||(video_bit_rate && i_toxav_video_bitrate_invalid(video_bit_rate)) | 256 | ||(video_bit_rate && video_bitrate_invalid(video_bit_rate)) |
249 | ) { | 257 | ) { |
250 | rc = TOXAV_ERR_CALL_INVALID_BIT_RATE; | 258 | rc = TOXAV_ERR_CALL_INVALID_BIT_RATE; |
251 | goto END; | 259 | goto END; |
252 | } | 260 | } |
253 | 261 | ||
254 | ToxAVCall* call = i_toxav_get_call(av, friend_number); | 262 | ToxAVCall* call = call_get(av, friend_number); |
255 | if (call == NULL) { | 263 | if (call == NULL) { |
256 | rc = TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING; | 264 | rc = TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING; |
257 | goto END; | 265 | goto END; |
@@ -260,12 +268,12 @@ bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, ui | |||
260 | call->s_audio_b = audio_bit_rate; | 268 | call->s_audio_b = audio_bit_rate; |
261 | call->s_video_b = video_bit_rate; | 269 | call->s_video_b = video_bit_rate; |
262 | 270 | ||
263 | uint8_t capabilities = 0; | 271 | call->last_capabilities = msi_CapRAudio | msi_CapRVideo; |
264 | 272 | ||
265 | capabilities |= audio_bit_rate > 0 ? msi_CapSAudio : 0; | 273 | call->last_capabilities |= audio_bit_rate > 0 ? msi_CapSAudio : 0; |
266 | capabilities |= video_bit_rate > 0 ? msi_CapSVideo : 0; | 274 | call->last_capabilities |= video_bit_rate > 0 ? msi_CapSVideo : 0; |
267 | 275 | ||
268 | if (msi_answer(call->msi_call, capabilities) != 0) | 276 | if (msi_answer(call->msi_call, call->last_capabilities) != 0) |
269 | rc = TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING; /* the only reason for msi_answer to fail */ | 277 | rc = TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING; /* the only reason for msi_answer to fail */ |
270 | 278 | ||
271 | 279 | ||
@@ -292,7 +300,7 @@ bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL co | |||
292 | } | 300 | } |
293 | 301 | ||
294 | 302 | ||
295 | ToxAVCall* call = i_toxav_get_call(av, friend_number); | 303 | ToxAVCall* call = call_get(av, friend_number); |
296 | if (call == NULL) { | 304 | if (call == NULL) { |
297 | rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL; | 305 | rc = TOXAV_ERR_CALL_CONTROL_FRIEND_NOT_IN_CALL; |
298 | goto END; | 306 | goto END; |
@@ -302,29 +310,53 @@ bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL co | |||
302 | switch (control) | 310 | switch (control) |
303 | { | 311 | { |
304 | case TOXAV_CALL_CONTROL_RESUME: { | 312 | case TOXAV_CALL_CONTROL_RESUME: { |
305 | 313 | if (call->msi_call->self_capabilities == 0 && | |
314 | call->last_capabilities ) { | ||
315 | /* Only act if paused and had media transfer active before */ | ||
316 | |||
317 | if (msi_change_capabilities(call->msi_call, call->last_capabilities) == -1) | ||
318 | return false; | ||
319 | |||
320 | rtp_start_receiving(call->rtps[audio_index]); | ||
321 | rtp_start_receiving(call->rtps[video_index]); | ||
322 | } | ||
306 | } break; | 323 | } break; |
307 | 324 | ||
308 | case TOXAV_CALL_CONTROL_PAUSE: { | 325 | case TOXAV_CALL_CONTROL_PAUSE: { |
309 | 326 | if (call->msi_call->self_capabilities) { | |
327 | /* Only act if not already paused */ | ||
328 | |||
329 | call->last_capabilities = call->msi_call->self_capabilities; | ||
330 | |||
331 | if (msi_change_capabilities(call->msi_call, 0) == -1 ) | ||
332 | return false; | ||
333 | |||
334 | rtp_stop_receiving(call->rtps[audio_index]); | ||
335 | rtp_stop_receiving(call->rtps[video_index]); | ||
336 | } | ||
310 | } break; | 337 | } break; |
311 | 338 | ||
312 | case TOXAV_CALL_CONTROL_CANCEL: { | 339 | case TOXAV_CALL_CONTROL_CANCEL: { |
313 | if (call->msi_call->state == msi_CallActive | 340 | /* Hang up */ |
314 | || call->msi_call->state == msi_CallRequesting) { | 341 | msi_hangup(call->msi_call); |
315 | /* Hang up */ | ||
316 | msi_hangup(call->msi_call); | ||
317 | } else if (call->msi_call->state == msi_CallRequested) { | ||
318 | /* Reject the call */ | ||
319 | msi_reject(call->msi_call); | ||
320 | } | ||
321 | 342 | ||
322 | // No mather the case, terminate the call | 343 | /* No mather the case, terminate the call */ |
323 | i_toxav_remove_call(av, friend_number); | 344 | call_remove(call); |
324 | } break; | 345 | } break; |
325 | 346 | ||
326 | case TOXAV_CALL_CONTROL_MUTE_AUDIO: { | 347 | case TOXAV_CALL_CONTROL_MUTE_AUDIO: { |
327 | 348 | if (call->msi_call->self_capabilities & msi_CapRAudio || | |
349 | call->msi_call->self_capabilities & msi_CapSAudio) { | ||
350 | |||
351 | uint8_t capabilities = call->msi_call->self_capabilities; | ||
352 | capabilities ^= msi_CapRAudio; | ||
353 | capabilities ^= msi_CapRAudio; | ||
354 | |||
355 | if (msi_change_capabilities(call->msi_call, call->msi_call->self_capabilities) == -1) | ||
356 | return false; | ||
357 | |||
358 | rtp_stop_receiving(call->rtps[audio_index]); | ||
359 | } | ||
328 | } break; | 360 | } break; |
329 | 361 | ||
330 | case TOXAV_CALL_CONTROL_MUTE_VIDEO: { | 362 | 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 | |||
364 | goto END; | 396 | goto END; |
365 | } | 397 | } |
366 | 398 | ||
367 | call = i_toxav_get_call(av, friend_number); | 399 | call = call_get(av, friend_number); |
368 | if (call == NULL) { | 400 | if (call == NULL) { |
369 | rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL; | 401 | rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL; |
370 | goto END; | 402 | goto END; |
@@ -461,7 +493,7 @@ bool toxav_send_audio_frame(ToxAV* av, uint32_t friend_number, const int16_t* pc | |||
461 | goto END; | 493 | goto END; |
462 | } | 494 | } |
463 | 495 | ||
464 | call = i_toxav_get_call(av, friend_number); | 496 | call = call_get(av, friend_number); |
465 | if (call == NULL) { | 497 | if (call == NULL) { |
466 | rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL; | 498 | rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_IN_CALL; |
467 | goto END; | 499 | goto END; |
@@ -526,19 +558,16 @@ void toxav_callback_receive_audio_frame(ToxAV* av, toxav_receive_audio_frame_cb* | |||
526 | * :: Internal | 558 | * :: Internal |
527 | * | 559 | * |
528 | ******************************************************************************/ | 560 | ******************************************************************************/ |
529 | /** TODO: | 561 | /** TODO: |
530 | * - If crutial callback not present send error. | ||
531 | * - Error handling by return values from callbacks and setting 'error'. | ||
532 | */ | 562 | */ |
533 | void i_callback_invite(void* toxav_inst, MSICall* call) | 563 | int callback_invite(void* toxav_inst, MSICall* call) |
534 | { | 564 | { |
535 | ToxAV* toxav = toxav_inst; | 565 | ToxAV* toxav = toxav_inst; |
536 | 566 | ||
537 | ToxAVCall* av_call = i_toxav_init_call(toxav, call->friend_id, NULL); | 567 | ToxAVCall* av_call = call_new(toxav, call->friend_id, NULL); |
538 | if (av_call == NULL) { | 568 | if (av_call == NULL) { |
539 | LOGGER_WARNING("Failed to start call, rejecting..."); | 569 | LOGGER_WARNING("Failed to initialize call..."); |
540 | msi_reject(call); | 570 | return -1; |
541 | return; | ||
542 | } | 571 | } |
543 | 572 | ||
544 | call->av_call = av_call; | 573 | call->av_call = av_call; |
@@ -547,55 +576,59 @@ void i_callback_invite(void* toxav_inst, MSICall* call) | |||
547 | if (toxav->ccb.first) | 576 | if (toxav->ccb.first) |
548 | toxav->ccb.first(toxav, call->friend_id, call->peer_capabilities & msi_CapSAudio, | 577 | toxav->ccb.first(toxav, call->friend_id, call->peer_capabilities & msi_CapSAudio, |
549 | call->peer_capabilities & msi_CapSVideo, toxav->ccb.second); | 578 | call->peer_capabilities & msi_CapSVideo, toxav->ccb.second); |
579 | |||
580 | return 0; | ||
550 | } | 581 | } |
551 | 582 | ||
552 | void i_callback_ringing(void* toxav_inst, MSICall* call) | 583 | int callback_start(void* toxav_inst, MSICall* call) |
553 | { | ||
554 | ToxAV* toxav = toxav_inst; | ||
555 | if (toxav->scb.first) | ||
556 | toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_RINGING, toxav->scb.second); | ||
557 | } | ||
558 | |||
559 | void i_callback_start(void* toxav_inst, MSICall* call) | ||
560 | { | 584 | { |
561 | ToxAV* toxav = toxav_inst; | 585 | ToxAV* toxav = toxav_inst; |
562 | 586 | ||
563 | ToxAVCall* av_call = i_toxav_get_call(toxav, call->friend_id); | 587 | ToxAVCall* av_call = call_get(toxav, call->friend_id); |
564 | 588 | ||
565 | if (av_call == NULL || !i_toxav_prepare_transmission(toxav, av_call)) { | 589 | if (av_call == NULL || !call_prepare_transmission(av_call)) { |
566 | /* TODO send error */ | 590 | call_remove(av_call); |
567 | i_toxav_remove_call(toxav, call->friend_id); | 591 | return -1; |
568 | return; | ||
569 | } | 592 | } |
570 | 593 | ||
571 | TOXAV_CALL_STATE state = capabilities_to_state(av_call->msi_call->peer_capabilities); | 594 | TOXAV_CALL_STATE state = capabilities_to_state(av_call->msi_call->peer_capabilities); |
572 | 595 | ||
573 | if (toxav->scb.first) | 596 | if (toxav->scb.first) |
574 | toxav->scb.first(toxav, call->friend_id, state, toxav->scb.second); | 597 | toxav->scb.first(toxav, call->friend_id, state, toxav->scb.second); |
598 | |||
599 | return 0; | ||
575 | } | 600 | } |
576 | 601 | ||
577 | void i_callback_end(void* toxav_inst, MSICall* call) | 602 | int callback_end(void* toxav_inst, MSICall* call) |
578 | { | 603 | { |
579 | ToxAV* toxav = toxav_inst; | 604 | ToxAV* toxav = toxav_inst; |
580 | 605 | ||
581 | i_toxav_kill_transmission(toxav, call->friend_id); | 606 | call_kill_transmission(call->av_call); |
582 | i_toxav_remove_call(toxav, call->friend_id); | 607 | call_remove(call->av_call); |
583 | 608 | ||
584 | if (toxav->scb.first) | 609 | if (toxav->scb.first) |
585 | toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_END, toxav->scb.second); | 610 | toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_END, toxav->scb.second); |
611 | |||
612 | return 0; | ||
586 | } | 613 | } |
587 | 614 | ||
588 | void i_callback_error(void* toxav_inst, MSICall* call) | 615 | int callback_error(void* toxav_inst, MSICall* call) |
589 | { | 616 | { |
590 | ToxAV* toxav = toxav_inst; | 617 | ToxAV* toxav = toxav_inst; |
591 | if (toxav->scb.first) | 618 | if (toxav->scb.first) |
592 | toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_ERROR, toxav->scb.second); | 619 | toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_ERROR, toxav->scb.second); |
620 | |||
621 | return 0; | ||
593 | } | 622 | } |
594 | 623 | ||
595 | void i_callback_capabilites(void* toxav_inst, MSICall* call) | 624 | int callback_capabilites(void* toxav_inst, MSICall* call) |
596 | { | 625 | { |
597 | ToxAV* toxav = toxav_inst; | 626 | ToxAV* toxav = toxav_inst; |
598 | /* TODO handle this */ | 627 | if (toxav->scb.first) |
628 | toxav->scb.first(toxav, call->friend_id, | ||
629 | capabilities_to_state(call->peer_capabilities), toxav->scb.second); | ||
630 | |||
631 | return 0; | ||
599 | } | 632 | } |
600 | 633 | ||
601 | TOXAV_CALL_STATE capabilities_to_state(uint8_t capabilities) | 634 | TOXAV_CALL_STATE capabilities_to_state(uint8_t capabilities) |
@@ -610,32 +643,64 @@ TOXAV_CALL_STATE capabilities_to_state(uint8_t capabilities) | |||
610 | return TOXAV_CALL_STATE_PAUSED; | 643 | return TOXAV_CALL_STATE_PAUSED; |
611 | } | 644 | } |
612 | 645 | ||
613 | ToxAVCall* i_toxav_get_call(ToxAV* av, uint32_t friend_number) | 646 | bool audio_bitrate_invalid(uint32_t bitrate) |
614 | { | 647 | { |
615 | if (av->calls == NULL || av->calls_tail < friend_number) | 648 | /* Opus RFC 6716 section-2.1.1 dictates the following: |
616 | return NULL; | 649 | * Opus supports all bitrates from 6 kbit/s to 510 kbit/s. |
617 | 650 | */ | |
618 | return av->calls[friend_number]; | 651 | return bitrate < 6 || bitrate > 510; |
619 | } | 652 | } |
620 | 653 | ||
621 | ToxAVCall* i_toxav_add_call(ToxAV* av, uint32_t friend_number) | 654 | bool video_bitrate_invalid(uint32_t bitrate) |
622 | { | 655 | { |
623 | ToxAVCall* rc = calloc(sizeof(ToxAVCall), 1); | 656 | /* TODO: If anyone knows the answer to this one please fill it up */ |
657 | return false; | ||
658 | } | ||
659 | |||
660 | ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error) | ||
661 | { | ||
662 | TOXAV_ERR_CALL rc = TOXAV_ERR_CALL_OK; | ||
663 | ToxAVCall* call = NULL; | ||
624 | 664 | ||
625 | if (rc == NULL) | 665 | if (m_friend_exists(av->m, friend_number) == 0) { |
626 | return NULL; | 666 | rc = TOXAV_ERR_CALL_FRIEND_NOT_FOUND; |
667 | goto END; | ||
668 | } | ||
627 | 669 | ||
628 | rc->friend_id = friend_number; | 670 | if (m_get_friend_connectionstatus(av->m, friend_number) != 1) { |
671 | rc = TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED; | ||
672 | goto END; | ||
673 | } | ||
629 | 674 | ||
630 | if (create_recursive_mutex(rc->mutex_control) != 0) { | 675 | if (call_get(av, friend_number) != NULL) { |
631 | free(rc); | 676 | rc = TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL; |
632 | return NULL; | 677 | goto END; |
633 | } | 678 | } |
634 | 679 | ||
635 | if (create_recursive_mutex(rc->mutex_do) != 0) { | 680 | |
636 | pthread_mutex_destroy(rc->mutex_control); | 681 | call = calloc(sizeof(ToxAVCall), 1); |
637 | free(rc); | 682 | |
638 | return NULL; | 683 | if (call == NULL) { |
684 | rc = TOXAV_ERR_CALL_MALLOC; | ||
685 | goto END; | ||
686 | } | ||
687 | |||
688 | call->av = av; | ||
689 | call->friend_id = friend_number; | ||
690 | |||
691 | if (create_recursive_mutex(call->mutex_control) != 0) { | ||
692 | free(call); | ||
693 | call = NULL; | ||
694 | rc = TOXAV_ERR_CALL_MALLOC; | ||
695 | goto END; | ||
696 | } | ||
697 | |||
698 | if (create_recursive_mutex(call->mutex_do) != 0) { | ||
699 | pthread_mutex_destroy(call->mutex_control); | ||
700 | free(call); | ||
701 | call = NULL; | ||
702 | rc = TOXAV_ERR_CALL_MALLOC; | ||
703 | goto END; | ||
639 | } | 704 | } |
640 | 705 | ||
641 | 706 | ||
@@ -643,10 +708,12 @@ ToxAVCall* i_toxav_add_call(ToxAV* av, uint32_t friend_number) | |||
643 | av->calls = calloc (sizeof(ToxAVCall*), friend_number + 1); | 708 | av->calls = calloc (sizeof(ToxAVCall*), friend_number + 1); |
644 | 709 | ||
645 | if (av->calls == NULL) { | 710 | if (av->calls == NULL) { |
646 | pthread_mutex_destroy(rc->mutex_control); | 711 | pthread_mutex_destroy(call->mutex_control); |
647 | pthread_mutex_destroy(rc->mutex_do); | 712 | pthread_mutex_destroy(call->mutex_do); |
648 | free(rc); | 713 | free(call); |
649 | return NULL; | 714 | call = NULL; |
715 | rc = TOXAV_ERR_CALL_MALLOC; | ||
716 | goto END; | ||
650 | } | 717 | } |
651 | 718 | ||
652 | av->calls_tail = av->calls_head = friend_number; | 719 | av->calls_tail = av->calls_head = friend_number; |
@@ -655,10 +722,12 @@ ToxAVCall* i_toxav_add_call(ToxAV* av, uint32_t friend_number) | |||
655 | void* tmp = realloc(av->calls, sizeof(ToxAVCall*) * friend_number + 1); | 722 | void* tmp = realloc(av->calls, sizeof(ToxAVCall*) * friend_number + 1); |
656 | 723 | ||
657 | if (tmp == NULL) { | 724 | if (tmp == NULL) { |
658 | pthread_mutex_destroy(rc->mutex_control); | 725 | pthread_mutex_destroy(call->mutex_control); |
659 | pthread_mutex_destroy(rc->mutex_do); | 726 | pthread_mutex_destroy(call->mutex_do); |
660 | free(rc); | 727 | free(call); |
661 | return NULL; | 728 | call = NULL; |
729 | rc = TOXAV_ERR_CALL_MALLOC; | ||
730 | goto END; | ||
662 | } | 731 | } |
663 | 732 | ||
664 | av->calls = tmp; | 733 | av->calls = tmp; |
@@ -668,105 +737,41 @@ ToxAVCall* i_toxav_add_call(ToxAV* av, uint32_t friend_number) | |||
668 | for (; i < friend_number; i ++) | 737 | for (; i < friend_number; i ++) |
669 | av->calls[i] = NULL; | 738 | av->calls[i] = NULL; |
670 | 739 | ||
671 | rc->prev = av->calls[av->calls_tail]; | 740 | call->prev = av->calls[av->calls_tail]; |
672 | av->calls[av->calls_tail]->next = rc; | 741 | av->calls[av->calls_tail]->next = call; |
673 | 742 | ||
674 | av->calls_tail = friend_number; | 743 | av->calls_tail = friend_number; |
675 | 744 | ||
676 | } else if (av->calls_head > friend_number) { /* Inserting at front */ | 745 | } else if (av->calls_head > friend_number) { /* Inserting at front */ |
677 | rc->next = av->calls[av->calls_head]; | 746 | call->next = av->calls[av->calls_head]; |
678 | av->calls[av->calls_head]->prev = rc; | 747 | av->calls[av->calls_head]->prev = call; |
679 | av->calls_head = friend_number; | 748 | av->calls_head = friend_number; |
680 | } | 749 | } |
681 | 750 | ||
682 | av->calls[friend_number] = rc; | 751 | av->calls[friend_number] = call; |
683 | return rc; | ||
684 | } | ||
685 | |||
686 | void i_toxav_remove_call(ToxAV* av, uint32_t friend_number) | ||
687 | { | ||
688 | ToxAVCall* tc = i_toxav_get_call(av, friend_number); | ||
689 | |||
690 | if (tc == NULL) | ||
691 | return; | ||
692 | |||
693 | ToxAVCall* prev = tc->prev; | ||
694 | ToxAVCall* next = tc->next; | ||
695 | |||
696 | pthread_mutex_destroy(tc->mutex_control); | ||
697 | pthread_mutex_destroy(tc->mutex_do); | ||
698 | |||
699 | free(tc); | ||
700 | |||
701 | if (prev) | ||
702 | prev->next = next; | ||
703 | else if (next) | ||
704 | av->calls_head = next->friend_id; | ||
705 | else goto CLEAR; | ||
706 | 752 | ||
707 | if (next) | 753 | END: |
708 | next->prev = prev; | ||
709 | else if (prev) | ||
710 | av->calls_tail = prev->friend_id; | ||
711 | else goto CLEAR; | ||
712 | |||
713 | av->calls[friend_number] = NULL; | ||
714 | return; | ||
715 | |||
716 | CLEAR: | ||
717 | av->calls_head = av->calls_tail = 0; | ||
718 | free(av->calls); | ||
719 | av->calls = NULL; | ||
720 | } | ||
721 | |||
722 | ToxAVCall* i_toxav_init_call(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error) | ||
723 | { | ||
724 | TOXAV_ERR_CALL rc = TOXAV_ERR_CALL_OK; | ||
725 | ToxAVCall* call = NULL; | ||
726 | |||
727 | if (m_friend_exists(av->m, friend_number) == 0) { | ||
728 | rc = TOXAV_ERR_CALL_FRIEND_NOT_FOUND; | ||
729 | goto END; | ||
730 | } | ||
731 | |||
732 | if (m_get_friend_connectionstatus(av->m, friend_number) != 1) { | ||
733 | rc = TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED; | ||
734 | goto END; | ||
735 | } | ||
736 | |||
737 | if (i_toxav_get_call(av, friend_number) != NULL) { | ||
738 | rc = TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL; | ||
739 | goto END; | ||
740 | } | ||
741 | |||
742 | call = i_toxav_add_call(av, friend_number); | ||
743 | if (call == NULL) { | ||
744 | rc = TOXAV_ERR_CALL_MALLOC; | ||
745 | } | ||
746 | |||
747 | END: | ||
748 | if (error) | 754 | if (error) |
749 | *error = rc; | 755 | *error = rc; |
750 | 756 | ||
751 | return call; | 757 | return call; |
752 | } | 758 | } |
753 | 759 | ||
754 | bool i_toxav_audio_bitrate_invalid(uint32_t bitrate) | 760 | ToxAVCall* call_get(ToxAV* av, uint32_t friend_number) |
755 | { | 761 | { |
756 | /* Opus RFC 6716 section-2.1.1 dictates the following: | 762 | if (av->calls == NULL || av->calls_tail < friend_number) |
757 | * Opus supports all bitrates from 6 kbit/s to 510 kbit/s. | 763 | return NULL; |
758 | */ | 764 | |
759 | return bitrate < 6 || bitrate > 510; | 765 | return av->calls[friend_number]; |
760 | } | ||
761 | |||
762 | bool i_toxav_video_bitrate_invalid(uint32_t bitrate) | ||
763 | { | ||
764 | /* TODO: If anyone knows the answer to this one please fill it up */ | ||
765 | return false; | ||
766 | } | 766 | } |
767 | 767 | ||
768 | bool i_toxav_prepare_transmission(ToxAV* av, ToxAVCall* call) | 768 | bool call_prepare_transmission(ToxAVCall* call) |
769 | { | 769 | { |
770 | if (call == NULL) | ||
771 | return false; | ||
772 | |||
773 | ToxAV* av = call->av; | ||
774 | |||
770 | if (!av->acb.first && !av->vcb.first) | 775 | if (!av->acb.first && !av->vcb.first) |
771 | /* It makes no sense to have CSession without callbacks */ | 776 | /* It makes no sense to have CSession without callbacks */ |
772 | return false; | 777 | return false; |
@@ -830,7 +835,7 @@ bool i_toxav_prepare_transmission(ToxAV* av, ToxAVCall* call) | |||
830 | goto FAILURE; | 835 | goto FAILURE; |
831 | } | 836 | } |
832 | 837 | ||
833 | rtp_register_for_receiving(call->rtps[audio_index]); | 838 | rtp_start_receiving(call->rtps[audio_index]); |
834 | } | 839 | } |
835 | } | 840 | } |
836 | 841 | ||
@@ -854,8 +859,8 @@ bool i_toxav_prepare_transmission(ToxAV* av, ToxAVCall* call) | |||
854 | LOGGER_WARNING("Failed to enable video receiving!"); | 859 | LOGGER_WARNING("Failed to enable video receiving!"); |
855 | goto FAILURE; | 860 | goto FAILURE; |
856 | } | 861 | } |
857 | 862 | ||
858 | rtp_register_for_receiving(call->rtps[audio_index]); | 863 | rtp_start_receiving(call->rtps[audio_index]); |
859 | } | 864 | } |
860 | } | 865 | } |
861 | 866 | ||
@@ -863,7 +868,7 @@ bool i_toxav_prepare_transmission(ToxAV* av, ToxAVCall* call) | |||
863 | pthread_mutex_unlock(call->mutex_control); | 868 | pthread_mutex_unlock(call->mutex_control); |
864 | return true; | 869 | return true; |
865 | 870 | ||
866 | FAILURE: | 871 | FAILURE: |
867 | rtp_kill(call->rtps[audio_index]); | 872 | rtp_kill(call->rtps[audio_index]); |
868 | call->rtps[audio_index] = NULL; | 873 | call->rtps[audio_index] = NULL; |
869 | rtp_kill(call->rtps[video_index]); | 874 | rtp_kill(call->rtps[video_index]); |
@@ -878,25 +883,19 @@ FAILURE: | |||
878 | pthread_mutex_unlock(call->mutex_control); | 883 | pthread_mutex_unlock(call->mutex_control); |
879 | return false; | 884 | return false; |
880 | 885 | ||
881 | MUTEX_INIT_ERROR: | 886 | MUTEX_INIT_ERROR: |
882 | pthread_mutex_unlock(call->mutex_control); | 887 | pthread_mutex_unlock(call->mutex_control); |
883 | LOGGER_ERROR("Mutex initialization failed!\n"); | 888 | LOGGER_ERROR("Mutex initialization failed!\n"); |
884 | return false; | 889 | return false; |
885 | } | 890 | } |
886 | 891 | ||
887 | void i_toxav_kill_transmission(ToxAV* av, uint32_t friend_number) | 892 | void call_kill_transmission(ToxAVCall* call) |
888 | { | 893 | { |
889 | ToxAVCall* call = i_toxav_get_call(av, friend_number); | 894 | if (call == NULL || call->active == 0) |
890 | if (!call) | ||
891 | return; | 895 | return; |
892 | 896 | ||
893 | pthread_mutex_lock(call->mutex_control); | 897 | pthread_mutex_lock(call->mutex_control); |
894 | 898 | ||
895 | if (!call->active) { | ||
896 | pthread_mutex_unlock(call->mutex_control); | ||
897 | return; | ||
898 | } | ||
899 | |||
900 | call->active = 0; | 899 | call->active = 0; |
901 | 900 | ||
902 | pthread_mutex_lock(call->mutex_encoding_audio); | 901 | pthread_mutex_lock(call->mutex_encoding_audio); |
@@ -918,4 +917,41 @@ void i_toxav_kill_transmission(ToxAV* av, uint32_t friend_number) | |||
918 | pthread_mutex_destroy(call->mutex_do); | 917 | pthread_mutex_destroy(call->mutex_do); |
919 | 918 | ||
920 | pthread_mutex_unlock(call->mutex_control); | 919 | pthread_mutex_unlock(call->mutex_control); |
920 | } | ||
921 | |||
922 | void call_remove(ToxAVCall* call) | ||
923 | { | ||
924 | if (call == NULL) | ||
925 | return; | ||
926 | |||
927 | uint32_t friend_id = call->friend_id; | ||
928 | ToxAV* av = call->av; | ||
929 | |||
930 | ToxAVCall* prev = call->prev; | ||
931 | ToxAVCall* next = call->next; | ||
932 | |||
933 | pthread_mutex_destroy(call->mutex_control); | ||
934 | pthread_mutex_destroy(call->mutex_do); | ||
935 | |||
936 | free(call); | ||
937 | |||
938 | if (prev) | ||
939 | prev->next = next; | ||
940 | else if (next) | ||
941 | av->calls_head = next->friend_id; | ||
942 | else goto CLEAR; | ||
943 | |||
944 | if (next) | ||
945 | next->prev = prev; | ||
946 | else if (prev) | ||
947 | av->calls_tail = prev->friend_id; | ||
948 | else goto CLEAR; | ||
949 | |||
950 | av->calls[friend_id] = NULL; | ||
951 | return; | ||
952 | |||
953 | CLEAR: | ||
954 | av->calls_head = av->calls_tail = 0; | ||
955 | free(av->calls); | ||
956 | av->calls = NULL; | ||
921 | } \ No newline at end of file | 957 | } \ No newline at end of file |