summaryrefslogtreecommitdiff
path: root/toxav/toxav.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxav/toxav.c')
-rw-r--r--toxav/toxav.c300
1 files changed, 169 insertions, 131 deletions
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
43typedef struct ToxAVCall_s 43typedef 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
65struct toxAV 67struct 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);
92int callback_error(void* toxav_inst, MSICall* call); 96int callback_error(void* toxav_inst, MSICall* call);
93int callback_capabilites(void* toxav_inst, MSICall* call); 97int callback_capabilites(void* toxav_inst, MSICall* call);
94 98
95TOXAV_CALL_STATE capabilities_to_state(uint8_t capabilities);
96ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error); 99ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error);
97ToxAVCall* call_get(ToxAV* av, uint32_t friend_number); 100ToxAVCall* call_get(ToxAV* av, uint32_t friend_number);
98void call_remove(ToxAVCall* call); 101void 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
186uint32_t toxav_iteration_interval(const ToxAV* av) 199uint32_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
217bool toxav_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error) 245bool 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
243void toxav_callback_call(ToxAV* av, toxav_call_cb* function, void* user_data) 276void 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
249bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_ANSWER* error) 284bool 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
282END: 319END:
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
289void toxav_callback_call_state(ToxAV* av, toxav_call_state_cb* function, void* user_data) 328void 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
295bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL control, TOXAV_ERR_CALL_CONTROL* error) 336bool 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
445END: 473END:
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
462void toxav_callback_request_video_frame(ToxAV* av, toxav_request_video_frame_cb* function, void* user_data) 492void 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
467bool 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) 500bool 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
552END: 599END:
553 if (error) 600 if (error)
554 *error = rc; 601 *error = rc;
@@ -558,7 +605,10 @@ END:
558 605
559void toxav_callback_request_audio_frame(ToxAV* av, toxav_request_audio_frame_cb* function, void* user_data) 606void 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
564bool 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) 614bool 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
614END: 675END:
615 if (error) 676 if (error)
616 *error = rc; 677 *error = rc;
@@ -620,14 +681,18 @@ END:
620 681
621void toxav_callback_receive_video_frame(ToxAV* av, toxav_receive_video_frame_cb* function, void* user_data) 682void 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
627void toxav_callback_receive_audio_frame(ToxAV* av, toxav_receive_audio_frame_cb* function, void* user_data) 690void 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*
639int callback_invite(void* toxav_inst, MSICall* call) 704int 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
659int callback_start(void* toxav_inst, MSICall* call) 727int 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
683int callback_end(void* toxav_inst, MSICall* call) 754int 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
696int callback_error(void* toxav_inst, MSICall* call) 769int 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
706int callback_capabilites(void* toxav_inst, MSICall* call) 784int 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
716TOXAV_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
730bool audio_bitrate_invalid(uint32_t bitrate) 798bool 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
744ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error) 812ToxAVCall* 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
844ToxAVCall* call_get(ToxAV* av, uint32_t friend_number) 893ToxAVCall* 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
852bool call_prepare_transmission(ToxAVCall* call) 902bool 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
951FAILURE: 999FAILURE:
@@ -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
966MUTEX_INIT_ERROR: 1011MUTEX_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
1002void call_remove(ToxAVCall* call) 1043void 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)