diff options
author | mannol <eniz_vukovic@hotmail.com> | 2015-01-24 23:29:54 +0100 |
---|---|---|
committer | mannol <eniz_vukovic@hotmail.com> | 2015-01-24 23:29:54 +0100 |
commit | 1450c22d01cbb5185ee8eac14657ddf3301d7e48 (patch) | |
tree | 366f795f56689b0fb53dfe52941fb9c813429e8b /toxav/toxav_new.c | |
parent | e57fb8c12ea7de1a5070ea0fc6f14c8e242c409f (diff) |
Current progress
Diffstat (limited to 'toxav/toxav_new.c')
-rw-r--r-- | toxav/toxav_new.c | 710 |
1 files changed, 710 insertions, 0 deletions
diff --git a/toxav/toxav_new.c b/toxav/toxav_new.c new file mode 100644 index 00000000..d6c1872c --- /dev/null +++ b/toxav/toxav_new.c | |||
@@ -0,0 +1,710 @@ | |||
1 | /** toxav.c | ||
2 | * | ||
3 | * Copyright (C) 2013 Tox project All Rights Reserved. | ||
4 | * | ||
5 | * This file is part of Tox. | ||
6 | * | ||
7 | * Tox is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation, either version 3 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * Tox is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifdef HAVE_CONFIG_H | ||
23 | #include "config.h" | ||
24 | #endif /* HAVE_CONFIG_H */ | ||
25 | |||
26 | #include "toxav_new.h" | ||
27 | #include "msi.h" /* Includes codec.h and rtp.h */ | ||
28 | |||
29 | #include "../toxcore/Messenger.h" | ||
30 | #include "../toxcore/logger.h" | ||
31 | #include "../toxcore/util.h" | ||
32 | |||
33 | #include <assert.h> | ||
34 | #include <stdlib.h> | ||
35 | #include <string.h> | ||
36 | |||
37 | |||
38 | enum { | ||
39 | audio_index, | ||
40 | video_index, | ||
41 | }; | ||
42 | |||
43 | typedef struct iToxAVCall | ||
44 | { | ||
45 | pthread_mutex_t mutex_control[1]; | ||
46 | pthread_mutex_t mutex_encoding_audio[1]; | ||
47 | pthread_mutex_t mutex_encoding_video[1]; | ||
48 | pthread_mutex_t mutex_do[1]; | ||
49 | RTPSession *rtps[2]; /** Audio is first and video is second */ | ||
50 | CSSession *cs; | ||
51 | bool active; | ||
52 | int32_t friend_number; | ||
53 | int32_t call_idx; /* FIXME msi compat, remove */ | ||
54 | |||
55 | struct iToxAVCall *prev; | ||
56 | struct iToxAVCall *next; | ||
57 | } IToxAVCall; | ||
58 | |||
59 | struct toxAV | ||
60 | { | ||
61 | Messenger* m; | ||
62 | MSISession* msi; | ||
63 | |||
64 | /* Two-way storage: first is array of calls and second is list of calls with head and tail */ | ||
65 | IToxAVCall** calls; | ||
66 | uint32_t calls_tail; | ||
67 | uint32_t calls_head; | ||
68 | |||
69 | PAIR(toxav_call_cb *, void*) ccb; /* Call callback */ | ||
70 | PAIR(toxav_call_state_cb *, void *) scb; /* Call state callback */ | ||
71 | PAIR(toxav_receive_audio_frame_cb *, void *) acb; /* Audio frame receive callback */ | ||
72 | PAIR(toxav_receive_video_frame_cb *, void *) vcb; /* Video frame receive callback */ | ||
73 | |||
74 | /** Decode time measures */ | ||
75 | int32_t dmssc; /** Measure count */ | ||
76 | int32_t dmsst; /** Last cycle total */ | ||
77 | int32_t dmssa; /** Average decoding time in ms */ | ||
78 | }; | ||
79 | |||
80 | |||
81 | void i_toxav_msi_callback_invite(void* toxav_inst, int32_t call_idx, void *data); | ||
82 | void i_toxav_msi_callback_ringing(void* toxav_inst, int32_t call_idx, void *data); | ||
83 | void i_toxav_msi_callback_start(void* toxav_inst, int32_t call_idx, void *data); | ||
84 | void i_toxav_msi_callback_cancel(void* toxav_inst, int32_t call_idx, void *data); | ||
85 | void i_toxav_msi_callback_reject(void* toxav_inst, int32_t call_idx, void *data); | ||
86 | void i_toxav_msi_callback_end(void* toxav_inst, int32_t call_idx, void *data); | ||
87 | void i_toxav_msi_callback_request_to(void* toxav_inst, int32_t call_idx, void *data); /* TODO remove */ | ||
88 | void i_toxav_msi_callback_peer_to(void* toxav_inst, int32_t call_idx, void *data); | ||
89 | void i_toxav_msi_callback_state_change(void* toxav_inst, int32_t call_idx, void *data); | ||
90 | |||
91 | IToxAVCall* i_toxav_get_call(ToxAV* av, uint32_t friend_number); | ||
92 | IToxAVCall* i_toxav_add_call(ToxAV* av, uint32_t friend_number); | ||
93 | void i_toxav_remove_call(ToxAV* av, uint32_t friend_number); | ||
94 | bool i_toxav_audio_bitrate_invalid(uint32_t bitrate); | ||
95 | bool i_toxav_video_bitrate_invalid(uint32_t bitrate); | ||
96 | IToxAVCall* i_toxav_init_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error); | ||
97 | bool i_toxav_prepare_transmission(ToxAV* av, IToxAVCall* call); | ||
98 | void i_toxav_kill_transmission(ToxAV* av, IToxAVCall* call); | ||
99 | |||
100 | |||
101 | |||
102 | ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error) | ||
103 | { | ||
104 | TOXAV_ERR_NEW rc = TOXAV_ERR_NEW_OK; | ||
105 | ToxAV *av = NULL; | ||
106 | |||
107 | if (tox == NULL) { | ||
108 | rc = TOXAV_ERR_NEW_NULL; | ||
109 | goto FAILURE; | ||
110 | } | ||
111 | |||
112 | if (((Messenger*)tox)->msi_packet) { | ||
113 | rc = TOXAV_ERR_NEW_MULTIPLE; | ||
114 | goto FAILURE; | ||
115 | } | ||
116 | |||
117 | av = calloc ( sizeof(ToxAV), 1); | ||
118 | |||
119 | if (av == NULL) { | ||
120 | LOGGER_WARNING("Allocation failed!"); | ||
121 | rc = TOXAV_ERR_NEW_MALLOC; | ||
122 | goto FAILURE; | ||
123 | } | ||
124 | |||
125 | av->m = (Messenger *)tox; | ||
126 | av->msi = msi_new(av->m, 100); /* TODO remove max calls */ | ||
127 | |||
128 | if (av->msi == NULL) { | ||
129 | rc = TOXAV_ERR_NEW_MALLOC; | ||
130 | goto FAILURE; | ||
131 | } | ||
132 | |||
133 | av->msi->agent_handler = av; | ||
134 | |||
135 | msi_register_callback(av->msi, i_toxav_msi_callback_invite, msi_OnInvite, NULL); | ||
136 | msi_register_callback(av->msi, i_toxav_msi_callback_ringing, msi_OnRinging, NULL); | ||
137 | msi_register_callback(av->msi, i_toxav_msi_callback_start, msi_OnStart, NULL); | ||
138 | msi_register_callback(av->msi, i_toxav_msi_callback_cancel, msi_OnCancel, NULL); | ||
139 | msi_register_callback(av->msi, i_toxav_msi_callback_reject, msi_OnReject, NULL); | ||
140 | msi_register_callback(av->msi, i_toxav_msi_callback_end, msi_OnEnd, NULL); | ||
141 | msi_register_callback(av->msi, i_toxav_msi_callback_request_to, msi_OnRequestTimeout, NULL); | ||
142 | msi_register_callback(av->msi, i_toxav_msi_callback_peer_to, msi_OnPeerTimeout, NULL); | ||
143 | msi_register_callback(av->msi, i_toxav_msi_callback_state_change, msi_OnPeerCSChange, NULL); | ||
144 | msi_register_callback(av->msi, i_toxav_msi_callback_state_change, msi_OnSelfCSChange, NULL); | ||
145 | |||
146 | |||
147 | if (error) | ||
148 | *error = rc; | ||
149 | |||
150 | return av; | ||
151 | |||
152 | FAILURE: | ||
153 | if (error) | ||
154 | *error = rc; | ||
155 | |||
156 | free(av); | ||
157 | |||
158 | return NULL; | ||
159 | } | ||
160 | |||
161 | void toxav_kill(ToxAV* av) | ||
162 | { | ||
163 | if (av == NULL) | ||
164 | return; | ||
165 | |||
166 | msi_kill(av->msi); | ||
167 | /* TODO iterate over calls */ | ||
168 | free(av); | ||
169 | } | ||
170 | |||
171 | Tox* toxav_get_tox(ToxAV* av) | ||
172 | { | ||
173 | return (Tox*) av->m; | ||
174 | } | ||
175 | |||
176 | uint32_t toxav_iteration_interval(const ToxAV* av) | ||
177 | { | ||
178 | |||
179 | } | ||
180 | |||
181 | void toxav_iteration(ToxAV* av) | ||
182 | { | ||
183 | |||
184 | } | ||
185 | |||
186 | bool toxav_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error) | ||
187 | { | ||
188 | IToxAVCall* call = i_toxav_init_call(av, friend_number, audio_bit_rate, video_bit_rate, error); | ||
189 | if (call == NULL) { | ||
190 | return false; | ||
191 | } | ||
192 | |||
193 | /* TODO remove csettings */ | ||
194 | MSICSettings csets; | ||
195 | csets.audio_bitrate = audio_bit_rate; | ||
196 | csets.video_bitrate = video_bit_rate; | ||
197 | |||
198 | csets.call_type = video_bit_rate ? msi_TypeVideo : msi_TypeAudio; | ||
199 | |||
200 | if (msi_invite(av->msi, &call->call_idx, &csets, 1000, friend_number) != 0) { | ||
201 | i_toxav_remove_call(av, friend_number); | ||
202 | if (error) | ||
203 | *error = TOXAV_ERR_CALL_MALLOC; /* FIXME: this should be the only reason to fail */ | ||
204 | return false; | ||
205 | } | ||
206 | |||
207 | return true; | ||
208 | } | ||
209 | |||
210 | void toxav_callback_call(ToxAV* av, toxav_call_cb* function, void* user_data) | ||
211 | { | ||
212 | av->ccb.first = function; | ||
213 | av->ccb.second = user_data; | ||
214 | } | ||
215 | |||
216 | bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_ANSWER* error) | ||
217 | { | ||
218 | TOXAV_ERR_ANSWER rc = TOXAV_ERR_ANSWER_OK; | ||
219 | if (m_friend_exists(av->m, friend_number)) { | ||
220 | rc = TOXAV_ERR_ANSWER_FRIEND_NOT_FOUND; | ||
221 | goto END; | ||
222 | } | ||
223 | |||
224 | if ((audio_bit_rate && i_toxav_audio_bitrate_invalid(audio_bit_rate)) | ||
225 | ||(video_bit_rate && i_toxav_video_bitrate_invalid(video_bit_rate)) | ||
226 | ) { | ||
227 | rc = TOXAV_ERR_CALL_INVALID_BIT_RATE; | ||
228 | goto END; | ||
229 | } | ||
230 | |||
231 | IToxAVCall* call = i_toxav_get_call(av, friend_number); | ||
232 | if (call == NULL || av->msi->calls[call->call_idx]->state != msi_CallRequested) { | ||
233 | rc = TOXAV_ERR_ANSWER_FRIEND_NOT_CALLING; | ||
234 | goto END; | ||
235 | } | ||
236 | |||
237 | /* TODO remove csettings */ | ||
238 | MSICSettings csets; | ||
239 | csets.audio_bitrate = audio_bit_rate; | ||
240 | csets.video_bitrate = video_bit_rate; | ||
241 | |||
242 | csets.call_type = video_bit_rate ? msi_TypeVideo : msi_TypeAudio; | ||
243 | |||
244 | if (msi_answer(av->msi, call->call_idx, &csets) != 0) { | ||
245 | rc = TOXAV_ERR_ANSWER_MALLOC; /* TODO Some error here */ | ||
246 | /* TODO Reject call? */ | ||
247 | } | ||
248 | |||
249 | END: | ||
250 | if (error) | ||
251 | *error = rc; | ||
252 | |||
253 | return rc == TOXAV_ERR_ANSWER_OK; | ||
254 | } | ||
255 | |||
256 | void toxav_callback_call_state(ToxAV* av, toxav_call_state_cb* function, void* user_data) | ||
257 | { | ||
258 | av->scb.first = function; | ||
259 | av->scb.second = user_data; | ||
260 | } | ||
261 | |||
262 | bool toxav_call_control(ToxAV* av, uint32_t friend_number, TOXAV_CALL_CONTROL control, TOXAV_ERR_CALL_CONTROL* error) | ||
263 | { | ||
264 | |||
265 | } | ||
266 | |||
267 | bool toxav_set_audio_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, TOXAV_ERR_BIT_RATE* error) | ||
268 | { | ||
269 | |||
270 | } | ||
271 | |||
272 | bool toxav_set_video_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t video_bit_rate, TOXAV_ERR_BIT_RATE* error) | ||
273 | { | ||
274 | |||
275 | } | ||
276 | |||
277 | void toxav_callback_request_video_frame(ToxAV* av, toxav_request_video_frame_cb* function, void* user_data) | ||
278 | { | ||
279 | |||
280 | } | ||
281 | |||
282 | 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, const uint8_t* a, TOXAV_ERR_SEND_FRAME* error) | ||
283 | { | ||
284 | |||
285 | } | ||
286 | |||
287 | void toxav_callback_request_audio_frame(ToxAV* av, toxav_request_audio_frame_cb* function, void* user_data) | ||
288 | { | ||
289 | |||
290 | } | ||
291 | |||
292 | 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) | ||
293 | { | ||
294 | |||
295 | } | ||
296 | |||
297 | void toxav_callback_receive_video_frame(ToxAV* av, toxav_receive_video_frame_cb* function, void* user_data) | ||
298 | { | ||
299 | |||
300 | } | ||
301 | |||
302 | void toxav_callback_receive_audio_frame(ToxAV* av, toxav_receive_audio_frame_cb* function, void* user_data) | ||
303 | { | ||
304 | |||
305 | } | ||
306 | |||
307 | |||
308 | /******************************************************************************* | ||
309 | * | ||
310 | * :: Internal | ||
311 | * | ||
312 | ******************************************************************************/ | ||
313 | /** TODO: | ||
314 | * - In msi call_idx can be the same as friend id | ||
315 | * - If crutial callback not present send error | ||
316 | * - Remove *data from msi | ||
317 | * - Remove CSettings from msi | ||
318 | */ | ||
319 | void i_toxav_msi_callback_invite(void* toxav_inst, int32_t call_idx, void* data) | ||
320 | { | ||
321 | ToxAV* toxav = toxav_inst; | ||
322 | |||
323 | uint32_t ab = toxav->msi->calls[call_idx]->csettings_peer[0].audio_bitrate; | ||
324 | uint32_t vb = toxav->msi->calls[call_idx]->csettings_peer[0].video_bitrate; | ||
325 | |||
326 | IToxAVCall* call = i_toxav_init_call(toxav, toxav->msi->calls[call_idx]->peers[0], ab, vb, NULL); | ||
327 | if (call == NULL) { | ||
328 | msi_reject(toxav->msi, call_idx, NULL); | ||
329 | return false; | ||
330 | } | ||
331 | |||
332 | call->call_idx = call_idx; | ||
333 | |||
334 | if (toxav->ccb.first) | ||
335 | toxav->ccb.first(toxav, toxav->msi->calls[call_idx]->peers[0], true, true, toxav->ccb.second); | ||
336 | } | ||
337 | |||
338 | void i_toxav_msi_callback_ringing(void* toxav_inst, int32_t call_idx, void* data) | ||
339 | { | ||
340 | ToxAV* toxav = toxav_inst; | ||
341 | if (toxav->scb.first) | ||
342 | toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0], | ||
343 | TOXAV_CALL_STATE_RINGING, toxav->scb.second); | ||
344 | } | ||
345 | |||
346 | void i_toxav_msi_callback_start(void* toxav_inst, int32_t call_idx, void* data) | ||
347 | { | ||
348 | ToxAV* toxav = toxav_inst; | ||
349 | |||
350 | IToxAVCall* call = i_toxav_get_call(toxav, toxav->msi->calls[call_idx]->peers[0]); | ||
351 | |||
352 | if (call == NULL || !i_toxav_prepare_transmission(toxav, call)) { | ||
353 | /* TODO send error */ | ||
354 | i_toxav_remove_call(toxav, toxav->msi->calls[call_idx]->peers[0]); | ||
355 | return; | ||
356 | } | ||
357 | |||
358 | TOXAV_CALL_STATE state; | ||
359 | const MSICSettings* csets = toxav->msi->calls[call_idx]->csettings_peer[0]; | ||
360 | |||
361 | if (csets->audio_bitrate && csets->video_bitrate) | ||
362 | state = TOXAV_CALL_STATE_SENDING_AV; | ||
363 | else if (csets->video_bitrate == 0) | ||
364 | state = TOXAV_CALL_STATE_SENDING_A; | ||
365 | else | ||
366 | state = TOXAV_CALL_STATE_SENDING_V; | ||
367 | |||
368 | if (toxav->scb.first) /* TODO this */ | ||
369 | toxav->scb.first(toxav, call->friend_number, state, toxav->scb.second); | ||
370 | } | ||
371 | |||
372 | void i_toxav_msi_callback_cancel(void* toxav_inst, int32_t call_idx, void* data) | ||
373 | { | ||
374 | ToxAV* toxav = toxav_inst; | ||
375 | if (toxav->scb.first) | ||
376 | toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0], | ||
377 | TOXAV_CALL_STATE_END, toxav->scb.second); | ||
378 | } | ||
379 | |||
380 | void i_toxav_msi_callback_reject(void* toxav_inst, int32_t call_idx, void* data) | ||
381 | { | ||
382 | ToxAV* toxav = toxav_inst; | ||
383 | if (toxav->scb.first) | ||
384 | toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0], | ||
385 | TOXAV_CALL_STATE_END, toxav->scb.second); | ||
386 | } | ||
387 | |||
388 | void i_toxav_msi_callback_end(void* toxav_inst, int32_t call_idx, void* data) | ||
389 | { | ||
390 | ToxAV* toxav = toxav_inst; | ||
391 | if (toxav->scb.first) | ||
392 | toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0], | ||
393 | TOXAV_CALL_STATE_END, toxav->scb.second); | ||
394 | } | ||
395 | |||
396 | void i_toxav_msi_callback_request_to(void* toxav_inst, int32_t call_idx, void* data) | ||
397 | { | ||
398 | /* TODO remove */ | ||
399 | ToxAV* toxav = toxav_inst; | ||
400 | if (toxav->scb.first) | ||
401 | toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0], | ||
402 | TOXAV_CALL_STATE_ERROR, toxav->scb.second); | ||
403 | } | ||
404 | |||
405 | void i_toxav_msi_callback_peer_to(void* toxav_inst, int32_t call_idx, void* data) | ||
406 | { | ||
407 | ToxAV* toxav = toxav_inst; | ||
408 | if (toxav->scb.first) | ||
409 | toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0], | ||
410 | TOXAV_CALL_STATE_ERROR, toxav->scb.second); | ||
411 | } | ||
412 | |||
413 | void i_toxav_msi_callback_state_change(void* toxav_inst, int32_t call_idx, void* data) | ||
414 | { | ||
415 | ToxAV* toxav = toxav_inst; | ||
416 | /* TODO something something msi */ | ||
417 | } | ||
418 | |||
419 | IToxAVCall* i_toxav_get_call(ToxAV* av, uint32_t friend_number) | ||
420 | { | ||
421 | if (av->calls_tail < friend_number) | ||
422 | return NULL; | ||
423 | |||
424 | return av->calls[friend_number]; | ||
425 | } | ||
426 | |||
427 | IToxAVCall* i_toxav_add_call(ToxAV* av, uint32_t friend_number) | ||
428 | { | ||
429 | IToxAVCall* rc = calloc(sizeof(IToxAVCall), 1); | ||
430 | |||
431 | if (rc == NULL) | ||
432 | return NULL; | ||
433 | |||
434 | rc->friend_number = friend_number; | ||
435 | |||
436 | if (create_recursive_mutex(rc->mutex_control) != 0) { | ||
437 | free(rc); | ||
438 | return NULL; | ||
439 | } | ||
440 | |||
441 | if (create_recursive_mutex(rc->mutex_do) != 0) { | ||
442 | pthread_mutex_destroy(rc->mutex_control); | ||
443 | free(rc); | ||
444 | return NULL; | ||
445 | } | ||
446 | |||
447 | |||
448 | if (av->calls == NULL) { /* Creating */ | ||
449 | av->calls = calloc (sizeof(IToxAVCall*), friend_number + 1); | ||
450 | |||
451 | if (av->calls == NULL) { | ||
452 | pthread_mutex_destroy(rc->mutex_control); | ||
453 | pthread_mutex_destroy(rc->mutex_do); | ||
454 | free(rc); | ||
455 | return NULL; | ||
456 | } | ||
457 | |||
458 | av->calls_tail = av->calls_head = friend_number; | ||
459 | |||
460 | } else if (av->calls_tail < friend_number) { /* Appending */ | ||
461 | void* tmp = realloc(av->calls, sizeof(IToxAVCall*) * friend_number + 1); | ||
462 | |||
463 | if (tmp == NULL) { | ||
464 | pthread_mutex_destroy(rc->mutex_control); | ||
465 | pthread_mutex_destroy(rc->mutex_do); | ||
466 | free(rc); | ||
467 | return NULL; | ||
468 | } | ||
469 | |||
470 | av->calls = tmp; | ||
471 | |||
472 | /* Set fields in between to null */ | ||
473 | int32_t i = av->calls_tail; | ||
474 | for (; i < friend_number; i ++) | ||
475 | av->calls[i] = NULL; | ||
476 | |||
477 | rc->prev = av->calls[av->calls_tail]; | ||
478 | av->calls[av->calls_tail]->next = rc; | ||
479 | |||
480 | av->calls_tail = friend_number; | ||
481 | |||
482 | } else if (av->calls_head > friend_number) { /* Inserting at front */ | ||
483 | rc->next = av->calls[av->calls_head]; | ||
484 | av->calls[av->calls_head]->prev = rc; | ||
485 | av->calls_head = friend_number; | ||
486 | } | ||
487 | |||
488 | av->calls[friend_number] = rc; | ||
489 | return rc; | ||
490 | } | ||
491 | |||
492 | void i_toxav_remove_call(ToxAV* av, uint32_t friend_number) | ||
493 | { | ||
494 | IToxAVCall* tc = i_toxav_get_call(av, friend_number); | ||
495 | |||
496 | if (tc == NULL) | ||
497 | return; | ||
498 | |||
499 | IToxAVCall* prev = tc->prev; | ||
500 | IToxAVCall* next = tc->next; | ||
501 | |||
502 | pthread_mutex_destroy(tc->mutex_control); | ||
503 | pthread_mutex_destroy(tc->mutex_do); | ||
504 | |||
505 | free(tc); | ||
506 | |||
507 | if (prev) | ||
508 | prev->next = next; | ||
509 | else if (next) | ||
510 | av->calls_head = next->friend_number; | ||
511 | else goto CLEAR; | ||
512 | |||
513 | if (next) | ||
514 | next->prev = prev; | ||
515 | else if (prev) | ||
516 | av->calls_tail = prev->friend_number; | ||
517 | else goto CLEAR; | ||
518 | |||
519 | av->calls[friend_number] = NULL; | ||
520 | return; | ||
521 | |||
522 | CLEAR: | ||
523 | av->calls_head = av->calls_tail = 0; | ||
524 | free(av->calls); | ||
525 | av->calls = NULL; | ||
526 | } | ||
527 | |||
528 | bool i_toxav_audio_bitrate_invalid(uint32_t bitrate) | ||
529 | { | ||
530 | /* Opus RFC 6716 section-2.1.1 dictates the following: | ||
531 | * Opus supports all bitrates from 6 kbit/s to 510 kbit/s. | ||
532 | */ | ||
533 | return bitrate < 6 || bitrate > 510; | ||
534 | } | ||
535 | |||
536 | bool i_toxav_video_bitrate_invalid(uint32_t bitrate) | ||
537 | { | ||
538 | /* TODO: If anyone knows the answer to this one please fill it up */ | ||
539 | return false; | ||
540 | } | ||
541 | |||
542 | IToxAVCall* i_toxav_init_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error) | ||
543 | { | ||
544 | TOXAV_ERR_CALL rc = TOXAV_ERR_CALL_OK; | ||
545 | IToxAVCall* call = NULL; | ||
546 | |||
547 | if (m_friend_exists(av->m, friend_number)) { | ||
548 | rc = TOXAV_ERR_CALL_FRIEND_NOT_FOUND; | ||
549 | goto END; | ||
550 | } | ||
551 | |||
552 | if (m_get_friend_connectionstatus(av->m, friend_number) != 1) { | ||
553 | rc = TOXAV_ERR_CALL_FRIEND_NOT_CONNECTED; | ||
554 | goto END; | ||
555 | } | ||
556 | |||
557 | if (i_toxav_get_call(av, friend_number) != NULL) { | ||
558 | rc = TOXAV_ERR_CALL_FRIEND_ALREADY_IN_CALL; | ||
559 | goto END; | ||
560 | } | ||
561 | |||
562 | if ((audio_bit_rate && i_toxav_audio_bitrate_invalid(audio_bit_rate)) | ||
563 | ||(video_bit_rate && i_toxav_video_bitrate_invalid(video_bit_rate)) | ||
564 | ) { | ||
565 | rc = TOXAV_ERR_CALL_INVALID_BIT_RATE; | ||
566 | goto END; | ||
567 | } | ||
568 | |||
569 | IToxAVCall* call = i_toxav_add_call(av, friend_number); | ||
570 | if (call == NULL) { | ||
571 | rc = TOXAV_ERR_CALL_MALLOC; | ||
572 | } | ||
573 | |||
574 | END: | ||
575 | if (error) | ||
576 | *error = rc; | ||
577 | |||
578 | return call; | ||
579 | } | ||
580 | |||
581 | bool i_toxav_prepare_transmission(ToxAV* av, IToxAVCall* call) | ||
582 | { | ||
583 | pthread_mutex_lock(call->mutex_control); | ||
584 | |||
585 | if (call->active) { | ||
586 | pthread_mutex_unlock(call->mutex_control); | ||
587 | LOGGER_WARNING("Call already active!\n"); | ||
588 | return true; | ||
589 | } | ||
590 | |||
591 | if (pthread_mutex_init(call->mutex_encoding_audio, NULL) != 0) | ||
592 | goto MUTEX_INIT_ERROR; | ||
593 | |||
594 | if (pthread_mutex_init(call->mutex_encoding_video, NULL) != 0) { | ||
595 | pthread_mutex_destroy(call->mutex_encoding_audio); | ||
596 | goto MUTEX_INIT_ERROR; | ||
597 | } | ||
598 | |||
599 | if (pthread_mutex_init(call->mutex_do, NULL) != 0) { | ||
600 | pthread_mutex_destroy(call->mutex_encoding_audio); | ||
601 | pthread_mutex_destroy(call->mutex_encoding_video); | ||
602 | goto MUTEX_INIT_ERROR; | ||
603 | } | ||
604 | |||
605 | const MSICSettings *c_peer = &av->msi->calls[call->call_idx]->csettings_peer[0]; | ||
606 | const MSICSettings *c_self = &av->msi->calls[call->call_idx]->csettings_local; | ||
607 | |||
608 | call->cs = cs_new(c_self->audio_bitrate, c_peer->audio_bitrate, | ||
609 | c_self->video_bitrate, c_peer->video_bitrate); | ||
610 | |||
611 | if ( !call->cs ) { | ||
612 | LOGGER_ERROR("Error while starting Codec State!\n"); | ||
613 | goto FAILURE; | ||
614 | } | ||
615 | |||
616 | call->cs->agent = av; | ||
617 | call->cs->call_idx = call->call_idx; | ||
618 | |||
619 | call->cs->acb.first = av->acb.first; | ||
620 | call->cs->acb.second = av->acb.second; | ||
621 | |||
622 | call->cs->vcb.first = av->vcb.first; | ||
623 | call->cs->vcb.second = av->vcb.second; | ||
624 | |||
625 | |||
626 | if (c_self->audio_bitrate > 0 || c_peer->audio_bitrate > 0) { /* Prepare audio rtp */ | ||
627 | call->rtps[audio_index] = rtp_new(msi_TypeAudio, av->m, av->msi->calls[call->call_idx]->peers[0]); | ||
628 | |||
629 | if ( !call->rtps[audio_index] ) { | ||
630 | LOGGER_ERROR("Error while starting audio RTP session!\n"); | ||
631 | goto FAILURE; | ||
632 | } | ||
633 | |||
634 | call->rtps[audio_index]->cs = call->cs; | ||
635 | |||
636 | if (c_peer->audio_bitrate > 0) | ||
637 | rtp_register_for_receiving(call->rtps[audio_index]); | ||
638 | } | ||
639 | |||
640 | if (c_self->video_bitrate > 0 || c_peer->video_bitrate > 0) { /* Prepare video rtp */ | ||
641 | call->rtps[video_index] = rtp_new(msi_TypeVideo, av->m, av->msi->calls[call->call_idx]->peers[0]); | ||
642 | |||
643 | if ( !call->rtps[video_index] ) { | ||
644 | LOGGER_ERROR("Error while starting video RTP session!\n"); | ||
645 | goto FAILURE; | ||
646 | } | ||
647 | |||
648 | call->rtps[video_index]->cs = call->cs; | ||
649 | |||
650 | if (c_peer->video_bitrate > 0) | ||
651 | rtp_register_for_receiving(call->rtps[audio_index]); | ||
652 | } | ||
653 | |||
654 | call->active = 1; | ||
655 | pthread_mutex_unlock(call->mutex_control); | ||
656 | return true; | ||
657 | |||
658 | FAILURE: | ||
659 | rtp_kill(call->rtps[audio_index]); | ||
660 | call->rtps[audio_index] = NULL; | ||
661 | rtp_kill(call->rtps[video_index]); | ||
662 | call->rtps[video_index] = NULL; | ||
663 | cs_kill(call->cs); | ||
664 | call->cs = NULL; | ||
665 | call->active = 0; | ||
666 | pthread_mutex_destroy(call->mutex_encoding_audio); | ||
667 | pthread_mutex_destroy(call->mutex_encoding_video); | ||
668 | pthread_mutex_destroy(call->mutex_do); | ||
669 | |||
670 | pthread_mutex_unlock(call->mutex_control); | ||
671 | return false; | ||
672 | |||
673 | MUTEX_INIT_ERROR: | ||
674 | pthread_mutex_unlock(call->mutex_control); | ||
675 | LOGGER_ERROR("Mutex initialization failed!\n"); | ||
676 | return false; | ||
677 | } | ||
678 | |||
679 | void i_toxav_kill_transmission(ToxAV* av, IToxAVCall* call) | ||
680 | { | ||
681 | pthread_mutex_lock(call->mutex_control); | ||
682 | |||
683 | if (!call->active) { | ||
684 | pthread_mutex_unlock(call->mutex_control); | ||
685 | LOGGER_WARNING("Action on inactive call: %d", call->call_idx); | ||
686 | return; | ||
687 | } | ||
688 | |||
689 | call->active = 0; | ||
690 | |||
691 | pthread_mutex_lock(call->mutex_encoding_audio); | ||
692 | pthread_mutex_unlock(call->mutex_encoding_audio); | ||
693 | pthread_mutex_lock(call->mutex_encoding_video); | ||
694 | pthread_mutex_unlock(call->mutex_encoding_video); | ||
695 | pthread_mutex_lock(call->mutex_do); | ||
696 | pthread_mutex_unlock(call->mutex_do); | ||
697 | |||
698 | rtp_kill(call->rtps[audio_index]); | ||
699 | call->rtps[audio_index] = NULL; | ||
700 | rtp_kill(call->rtps[video_index]); | ||
701 | call->rtps[video_index] = NULL; | ||
702 | cs_kill(call->cs); | ||
703 | call->cs = NULL; | ||
704 | |||
705 | pthread_mutex_destroy(call->mutex_encoding_audio); | ||
706 | pthread_mutex_destroy(call->mutex_encoding_video); | ||
707 | pthread_mutex_destroy(call->mutex_do); | ||
708 | |||
709 | pthread_mutex_unlock(call->mutex_control); | ||
710 | } | ||