diff options
-rw-r--r-- | toxav/Makefile.inc | 4 | ||||
-rw-r--r-- | toxav/codec.c | 10 | ||||
-rw-r--r-- | toxav/codec.h | 2 | ||||
-rw-r--r-- | toxav/event.c | 380 | ||||
-rw-r--r-- | toxav/event.h | 47 | ||||
-rw-r--r-- | toxav/msi.c | 322 | ||||
-rw-r--r-- | toxav/msi.h | 2 | ||||
-rw-r--r-- | toxav/toxav.c | 105 |
8 files changed, 364 insertions, 508 deletions
diff --git a/toxav/Makefile.inc b/toxav/Makefile.inc index fdd20a26..de8ef8ff 100644 --- a/toxav/Makefile.inc +++ b/toxav/Makefile.inc | |||
@@ -4,9 +4,7 @@ lib_LTLIBRARIES += libtoxav.la | |||
4 | libtoxav_la_include_HEADERS = ../toxav/toxav.h | 4 | libtoxav_la_include_HEADERS = ../toxav/toxav.h |
5 | libtoxav_la_includedir = $(includedir)/tox | 5 | libtoxav_la_includedir = $(includedir)/tox |
6 | 6 | ||
7 | libtoxav_la_SOURCES = ../toxav/event.h \ | 7 | libtoxav_la_SOURCES = ../toxav/rtp.h \ |
8 | ../toxav/event.c \ | ||
9 | ../toxav/rtp.h \ | ||
10 | ../toxav/rtp.c \ | 8 | ../toxav/rtp.c \ |
11 | ../toxav/msi.h \ | 9 | ../toxav/msi.h \ |
12 | ../toxav/msi.c \ | 10 | ../toxav/msi.c \ |
diff --git a/toxav/codec.c b/toxav/codec.c index 9ca9a50c..3e6de803 100644 --- a/toxav/codec.c +++ b/toxav/codec.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /** media.c | 1 | /** codec.c |
2 | * | 2 | * |
3 | * Audio and video codec intitialization, encoding/decoding and playback | 3 | * Audio and video codec intitialization, encoding/decoding and playback |
4 | * | 4 | * |
@@ -212,7 +212,7 @@ int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t | |||
212 | vpx_codec_enc_cfg_t cfg; | 212 | vpx_codec_enc_cfg_t cfg; |
213 | int rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0); | 213 | int rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0); |
214 | 214 | ||
215 | if (rc) { | 215 | if (rc != VPX_CODEC_OK) { |
216 | LOGGER_ERROR("Failed to get config: %s", vpx_codec_err_to_string(rc)); | 216 | LOGGER_ERROR("Failed to get config: %s", vpx_codec_err_to_string(rc)); |
217 | return -1; | 217 | return -1; |
218 | } | 218 | } |
@@ -234,6 +234,12 @@ int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t | |||
234 | } | 234 | } |
235 | 235 | ||
236 | rc = vpx_codec_control(&cs->v_encoder, VP8E_SET_CPUUSED, 7); | 236 | rc = vpx_codec_control(&cs->v_encoder, VP8E_SET_CPUUSED, 7); |
237 | |||
238 | if ( rc != VPX_CODEC_OK) { | ||
239 | LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); | ||
240 | return -1; | ||
241 | } | ||
242 | |||
237 | return 0; | 243 | return 0; |
238 | } | 244 | } |
239 | 245 | ||
diff --git a/toxav/codec.h b/toxav/codec.h index d48e252c..7ddf2943 100644 --- a/toxav/codec.h +++ b/toxav/codec.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /** media.h | 1 | /** codec.h |
2 | * | 2 | * |
3 | * Audio and video codec intitialization, encoding/decoding and playback | 3 | * Audio and video codec intitialization, encoding/decoding and playback |
4 | * | 4 | * |
diff --git a/toxav/event.c b/toxav/event.c deleted file mode 100644 index 3916b744..00000000 --- a/toxav/event.c +++ /dev/null | |||
@@ -1,380 +0,0 @@ | |||
1 | /** event.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 | |||
23 | #ifdef HAVE_CONFIG_H | ||
24 | #include "config.h" | ||
25 | #endif /* HAVE_CONFIG_H */ | ||
26 | |||
27 | #include <stdlib.h> | ||
28 | #include "../toxcore/network.h" /* current_time_monotonic() */ | ||
29 | #include "event.h" | ||
30 | |||
31 | #define _GNU_SOURCE | ||
32 | |||
33 | #include <assert.h> | ||
34 | #include <unistd.h> | ||
35 | #include <stddef.h> | ||
36 | #include <inttypes.h> | ||
37 | #include <pthread.h> | ||
38 | #include <stdio.h> | ||
39 | |||
40 | #define RUN_IN_THREAD(func, args) { pthread_t _tid; \ | ||
41 | pthread_create(&_tid, NULL, func, args); assert( pthread_detach(_tid) == 0 ); } | ||
42 | |||
43 | #define LOCK(event_handler) pthread_mutex_lock (&event_handler->mutex) | ||
44 | #define UNLOCK(event_handler) pthread_mutex_unlock(&event_handler->mutex) | ||
45 | |||
46 | #define FREQUENCY 10000 | ||
47 | |||
48 | #define inline__ inline __attribute__((always_inline)) | ||
49 | |||
50 | |||
51 | typedef struct _EventContainer { | ||
52 | void *(*func)(void *); | ||
53 | void *func_args; | ||
54 | unsigned timeout; | ||
55 | long long id; | ||
56 | |||
57 | } EventContainer; | ||
58 | |||
59 | typedef struct _EventHandler { | ||
60 | EventContainer *timed_events; | ||
61 | size_t timed_events_count; | ||
62 | |||
63 | int running; | ||
64 | |||
65 | pthread_mutex_t mutex; | ||
66 | |||
67 | } EventHandler; | ||
68 | |||
69 | int throw_event( void *(func)(void *), void *arg ); | ||
70 | int reset_timer_event ( int id, uint32_t timeout ); | ||
71 | int throw_timer_event ( void *(func)(void *), void *arg, unsigned timeout); | ||
72 | int cancel_timer_event ( int id ); | ||
73 | int execute_timer_event ( int id ); | ||
74 | |||
75 | struct _Event event = { | ||
76 | throw_event, | ||
77 | /* reset_timer_event */ NULL, | ||
78 | throw_timer_event, | ||
79 | cancel_timer_event, | ||
80 | /*execute_timer_event*/ NULL | ||
81 | }; | ||
82 | |||
83 | /* | ||
84 | * Random functions used by this file | ||
85 | */ | ||
86 | void clear_events (EventContainer **event_container, size_t *counter) | ||
87 | { | ||
88 | free(*event_container ); | ||
89 | |||
90 | *event_container = NULL; | ||
91 | *counter = 0; | ||
92 | } | ||
93 | |||
94 | int pop_id ( EventContainer **event_container, size_t *counter, int id ) | ||
95 | { | ||
96 | if ( !*event_container || !*counter || !id ) | ||
97 | return -1; | ||
98 | |||
99 | EventContainer *_it = *event_container; | ||
100 | int i; | ||
101 | |||
102 | for ( i = *counter; i; -- i ) { | ||
103 | if ( _it->id == id ) { /* Hit! */ | ||
104 | break; | ||
105 | } | ||
106 | |||
107 | ++_it; | ||
108 | } | ||
109 | |||
110 | if ( i ) { | ||
111 | for ( ; i; -- i ) { | ||
112 | *_it = *(_it + 1); | ||
113 | ++_it; | ||
114 | } | ||
115 | |||
116 | -- (*counter ); | ||
117 | |||
118 | if ( !(*counter)) { /* Free and set to NULL */ | ||
119 | free(*event_container); | ||
120 | *event_container = NULL; | ||
121 | } else { | ||
122 | void *_result = realloc(*event_container, sizeof(EventContainer) * (*counter )); /* resize */ | ||
123 | |||
124 | |||
125 | if ( _result != NULL ) { | ||
126 | *event_container = _result; | ||
127 | return 0; | ||
128 | } else { | ||
129 | /* Not sure what would happen next so abort execution. | ||
130 | */ | ||
131 | fprintf(stderr, "CRITICAL! Failed to reallocate memory in %s():%d, aborting...", __func__, __LINE__); | ||
132 | abort(); | ||
133 | return -1; | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | |||
138 | /* not found here */ | ||
139 | |||
140 | return -1; | ||
141 | } | ||
142 | |||
143 | void push_event ( EventContainer **container, size_t *counter, void *(func)(void *), void *arg ) | ||
144 | { | ||
145 | EventContainer *_new = realloc((*container ), sizeof(EventContainer) * ((*counter ) + 1)); | ||
146 | |||
147 | if ( _new == NULL ) { | ||
148 | /* Not sure what would happen next so abort execution. | ||
149 | * TODO: This could notice the calling function | ||
150 | * about realloc failing. | ||
151 | */ | ||
152 | fprintf(stderr, "CRITICAL! Failed to reallocate memory in %s():%d, aborting...", __func__, __LINE__); | ||
153 | abort(); | ||
154 | } | ||
155 | |||
156 | _new[*counter].func = func; | ||
157 | _new[*counter].func_args = arg; | ||
158 | _new[*counter].timeout = 0; | ||
159 | _new[*counter].id = 0; | ||
160 | |||
161 | (*container) = _new; | ||
162 | |||
163 | (*counter )++; | ||
164 | } | ||
165 | |||
166 | void reorder_events ( size_t counter, EventContainer *container, unsigned timeout ) | ||
167 | { | ||
168 | if ( counter > 1 ) { | ||
169 | |||
170 | int i = counter - 1; | ||
171 | |||
172 | /* start from behind excluding last added member */ | ||
173 | EventContainer *_it = &container[i - 1]; | ||
174 | |||
175 | EventContainer _last_added = container[i]; | ||
176 | |||
177 | for ( ; i; --i ) { | ||
178 | if ( _it->timeout > timeout ) { | ||
179 | *(_it + 1) = *_it; | ||
180 | *_it = _last_added; | ||
181 | -- _it; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | } | ||
186 | } | ||
187 | |||
188 | /* ============================================= */ | ||
189 | |||
190 | /* main poll for event execution */ | ||
191 | void *event_poll( void *arg ) | ||
192 | { | ||
193 | EventHandler *_event_handler = arg; | ||
194 | |||
195 | while ( _event_handler->running ) { | ||
196 | |||
197 | LOCK( _event_handler ); | ||
198 | |||
199 | if ( _event_handler->timed_events ) { | ||
200 | |||
201 | uint32_t _time = ((uint32_t)current_time_monotonic()); | ||
202 | |||
203 | if ( _event_handler->timed_events[0].timeout < _time ) { | ||
204 | |||
205 | RUN_IN_THREAD ( _event_handler->timed_events[0].func, | ||
206 | _event_handler->timed_events[0].func_args ); | ||
207 | |||
208 | pop_id(&_event_handler->timed_events, | ||
209 | &_event_handler->timed_events_count, | ||
210 | _event_handler->timed_events[0].id); | ||
211 | |||
212 | } | ||
213 | |||
214 | } | ||
215 | |||
216 | UNLOCK( _event_handler ); | ||
217 | |||
218 | usleep(FREQUENCY); | ||
219 | } | ||
220 | |||
221 | LOCK( _event_handler ); | ||
222 | |||
223 | clear_events(&_event_handler->timed_events, &_event_handler->timed_events_count); | ||
224 | |||
225 | UNLOCK( _event_handler ); | ||
226 | |||
227 | _event_handler->running = -1; | ||
228 | pthread_exit(NULL); | ||
229 | } | ||
230 | |||
231 | int throw_event( void *(func)(void *), void *arg ) | ||
232 | { | ||
233 | pthread_t _tid; | ||
234 | int _rc = | ||
235 | pthread_create(&_tid, NULL, func, arg ); | ||
236 | |||
237 | return (0 != _rc ) ? _rc : pthread_detach(_tid); | ||
238 | } | ||
239 | |||
240 | EventHandler event_handler; | ||
241 | |||
242 | /* Place and order array of timers */ | ||
243 | int throw_timer_event ( void *(func)(void *), void *arg, unsigned timeout) | ||
244 | { | ||
245 | static int _unique_id = 1; | ||
246 | |||
247 | push_event(&event_handler.timed_events, &(event_handler.timed_events_count), func, arg ); | ||
248 | |||
249 | size_t _counter = event_handler.timed_events_count; | ||
250 | |||
251 | event_handler.timed_events[_counter - 1].timeout = timeout + ((uint32_t)current_time_monotonic()); | ||
252 | event_handler.timed_events[_counter - 1].id = _unique_id; | ||
253 | ++_unique_id; | ||
254 | |||
255 | |||
256 | /* reorder */ | ||
257 | |||
258 | reorder_events(_counter, event_handler.timed_events, timeout ); | ||
259 | |||
260 | return _unique_id - 1; | ||
261 | } | ||
262 | |||
263 | int execute_timer_event ( int id ) | ||
264 | { | ||
265 | int _status; | ||
266 | |||
267 | LOCK((&event_handler)); | ||
268 | EventContainer *_it = event_handler.timed_events; | ||
269 | |||
270 | int _i = event_handler.timed_events_count; | ||
271 | |||
272 | /* Find it and execute */ | ||
273 | for ( ; _i; _i-- ) { | ||
274 | if ( _it->id == id ) { | ||
275 | RUN_IN_THREAD ( _it->func, _it->func_args ); | ||
276 | break; | ||
277 | } | ||
278 | |||
279 | ++_it; | ||
280 | } | ||
281 | |||
282 | /* Now remove it from the queue */ | ||
283 | |||
284 | if ( _i ) { | ||
285 | for ( ; _i; -- _i ) { | ||
286 | *_it = *(_it + 1); | ||
287 | ++_it; | ||
288 | } | ||
289 | |||
290 | -- event_handler.timed_events_count; | ||
291 | |||
292 | if ( !event_handler.timed_events_count ) { /* Free and set to null */ | ||
293 | free(event_handler.timed_events); | ||
294 | event_handler.timed_events = NULL; | ||
295 | } else { | ||
296 | void *_result = realloc(event_handler.timed_events, | ||
297 | sizeof(EventContainer) * event_handler.timed_events_count); /* resize */ | ||
298 | |||
299 | if ( _result != NULL ) { | ||
300 | event_handler.timed_events = _result; | ||
301 | } else { | ||
302 | /* Not sure what would happen next so abort execution. | ||
303 | */ | ||
304 | fprintf(stderr, "CRITICAL! Failed to reallocate memory in %s():%d, aborting...", __func__, __LINE__); | ||
305 | abort(); | ||
306 | return -1; | ||
307 | } | ||
308 | } | ||
309 | |||
310 | _status = 0; | ||
311 | |||
312 | } else _status = -1; | ||
313 | |||
314 | UNLOCK((&event_handler)); | ||
315 | |||
316 | return _status; | ||
317 | } | ||
318 | |||
319 | int reset_timer_event ( int id, uint32_t timeout ) | ||
320 | { | ||
321 | int _status; | ||
322 | |||
323 | LOCK((&event_handler)); | ||
324 | |||
325 | EventContainer *_it = event_handler.timed_events; | ||
326 | |||
327 | int _i = event_handler.timed_events_count; | ||
328 | |||
329 | /* Find it and change */ | ||
330 | for ( ; _i; _i-- ) { | ||
331 | if ( _it->id == id ) { | ||
332 | _it->timeout = timeout + ((uint32_t)current_time_monotonic()); | ||
333 | break; | ||
334 | } | ||
335 | |||
336 | ++_it; | ||
337 | } | ||
338 | |||
339 | _status = _i ? -1 : 0; | ||
340 | |||
341 | UNLOCK((&event_handler)); | ||
342 | |||
343 | return _status; | ||
344 | } | ||
345 | |||
346 | /* Remove timer from array */ | ||
347 | inline__ int cancel_timer_event ( int id ) | ||
348 | { | ||
349 | return pop_id (&event_handler.timed_events, &event_handler.timed_events_count, id ); | ||
350 | } | ||
351 | |||
352 | |||
353 | /* Initialization and termination of event polls | ||
354 | * This will be run at the beginning and the end of the program execution. | ||
355 | * I think that's the best way to do it. | ||
356 | */ | ||
357 | |||
358 | void __attribute__((constructor)) init_event_poll () | ||
359 | { | ||
360 | event_handler.timed_events = NULL; | ||
361 | event_handler.timed_events_count = 0; | ||
362 | |||
363 | event_handler.running = 1; | ||
364 | |||
365 | pthread_mutex_init(&event_handler.mutex, NULL); | ||
366 | |||
367 | RUN_IN_THREAD(event_poll, &event_handler); | ||
368 | } | ||
369 | |||
370 | /* NOTE: Do we need this? */ | ||
371 | void __attribute__((destructor)) terminate_event_poll() | ||
372 | { | ||
373 | /* Exit thread */ | ||
374 | event_handler.running = 0; | ||
375 | |||
376 | /* Give it enought time to exit */ | ||
377 | usleep(FREQUENCY * 2); | ||
378 | |||
379 | pthread_mutex_destroy( &event_handler.mutex ); | ||
380 | } \ No newline at end of file | ||
diff --git a/toxav/event.h b/toxav/event.h deleted file mode 100644 index e8bc5e37..00000000 --- a/toxav/event.h +++ /dev/null | |||
@@ -1,47 +0,0 @@ | |||
1 | /** event.h | ||
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 | |||
23 | #ifndef __TOXEVENT | ||
24 | #define __TOXEVENT | ||
25 | |||
26 | |||
27 | /** | ||
28 | * - Events are, in fact, ran in their own threads upon execution. | ||
29 | * - Event handler is initialized at the start, before the main() function | ||
30 | * and terminated after it's execution. | ||
31 | * - Timers are checked for timeout every ~10000 ns. | ||
32 | * - Timers can be canceled or ran immediately via | ||
33 | * timer_release() or timer_now() functions. | ||
34 | * - Timeout is measured in milliseconds. | ||
35 | * | ||
36 | * NOTE: timer_reset () and timer_now() are not tested nor usable atm | ||
37 | * | ||
38 | */ | ||
39 | extern struct _Event { | ||
40 | int (*rise) (void *( func ) ( void *), void *arg); | ||
41 | int (*timer_reset ) ( int id, unsigned timeout ); | ||
42 | int (*timer_alloc) (void *( func ) ( void *), void *arg, unsigned timeout); | ||
43 | int (*timer_release) (int id); | ||
44 | int (*timer_now) ( int id ); | ||
45 | } event; | ||
46 | |||
47 | #endif /* _MSI__EVENT_H_ */ | ||
diff --git a/toxav/msi.c b/toxav/msi.c index 1d3a406b..a74f8a58 100644 --- a/toxav/msi.c +++ b/toxav/msi.c | |||
@@ -115,7 +115,6 @@ static struct _Callbacks { | |||
115 | 115 | ||
116 | inline__ void invoke_callback(int32_t call_index, MSICallbackID id) | 116 | inline__ void invoke_callback(int32_t call_index, MSICallbackID id) |
117 | { | 117 | { |
118 | /*if ( callbacks[id].function ) event.rise ( callbacks[id].function, callbacks[id].data );*/ | ||
119 | if ( callbacks[id].function ) { | 118 | if ( callbacks[id].function ) { |
120 | LOGGER_DEBUG("Invoking callback function: %d", id); | 119 | LOGGER_DEBUG("Invoking callback function: %d", id); |
121 | callbacks[id].function ( call_index, callbacks[id].data ); | 120 | callbacks[id].function ( call_index, callbacks[id].data ); |
@@ -220,7 +219,7 @@ if ( *iterator != value_byte || size_con <= type_size_const) { return -1; } size | |||
220 | iterator ++; if(size_con <= 3) {return -1;} size_con -= 3; \ | 219 | iterator ++; if(size_con <= 3) {return -1;} size_con -= 3; \ |
221 | uint16_t _value_size; memcpy(&_value_size, iterator, sizeof(_value_size)); _value_size = ntohs(_value_size);\ | 220 | uint16_t _value_size; memcpy(&_value_size, iterator, sizeof(_value_size)); _value_size = ntohs(_value_size);\ |
222 | if(size_con < _value_size) { return -1; } size_con -= _value_size; \ | 221 | if(size_con < _value_size) { return -1; } size_con -= _value_size; \ |
223 | if ( !(header.header_value = calloc(sizeof(uint8_t), _value_size)) ); \ | 222 | if ( !(header.header_value = calloc(sizeof(uint8_t), _value_size)) ) \ |
224 | LOGGER_ERROR("Allocation failed! Program might misbehave!"); \ | 223 | LOGGER_ERROR("Allocation failed! Program might misbehave!"); \ |
225 | header.size = _value_size; \ | 224 | header.size = _value_size; \ |
226 | memcpy(header.header_value, iterator + 2, _value_size);\ | 225 | memcpy(header.header_value, iterator + 2, _value_size);\ |
@@ -538,6 +537,233 @@ GENERIC_SETTER_DEFINITION ( info ) | |||
538 | GENERIC_SETTER_DEFINITION ( callid ) | 537 | GENERIC_SETTER_DEFINITION ( callid ) |
539 | 538 | ||
540 | 539 | ||
540 | |||
541 | |||
542 | typedef struct _Timer { | ||
543 | void *(*func)(void *); | ||
544 | void *func_args; | ||
545 | uint64_t timeout; | ||
546 | size_t idx; | ||
547 | |||
548 | } Timer; | ||
549 | |||
550 | typedef struct _TimerHandler { | ||
551 | Timer **timers; | ||
552 | pthread_mutex_t mutex; | ||
553 | |||
554 | size_t max_capacity; | ||
555 | size_t size; | ||
556 | uint64_t resolution; | ||
557 | |||
558 | _Bool running; | ||
559 | |||
560 | } TimerHandler; | ||
561 | |||
562 | |||
563 | /** | ||
564 | * @brief Allocate timer in array | ||
565 | * | ||
566 | * @param timers_container Handler | ||
567 | * @param func Function to be executed | ||
568 | * @param arg Its args | ||
569 | * @param timeout Timeout in ms | ||
570 | * @return int | ||
571 | */ | ||
572 | int timer_alloc ( TimerHandler *timers_container, void *(func)(void *), void *arg, unsigned timeout) | ||
573 | { | ||
574 | pthread_mutex_lock(&timers_container->mutex); | ||
575 | |||
576 | int i = 0; | ||
577 | |||
578 | for (; i < timers_container->max_capacity && timers_container->timers[i]; i ++); | ||
579 | |||
580 | if (i == timers_container->max_capacity) { | ||
581 | LOGGER_WARNING("Maximum capacity reached!"); | ||
582 | pthread_mutex_unlock(&timers_container->mutex); | ||
583 | return -1; | ||
584 | } | ||
585 | |||
586 | Timer *timer = timers_container->timers[i] = calloc(sizeof(Timer), 1); | ||
587 | |||
588 | if (timer == NULL) { | ||
589 | LOGGER_ERROR("Failed to allocate timer!"); | ||
590 | pthread_mutex_unlock(&timers_container->mutex); | ||
591 | return -1; | ||
592 | } | ||
593 | |||
594 | timers_container->size ++; | ||
595 | |||
596 | timer->func = func; | ||
597 | timer->func_args = arg; | ||
598 | timer->timeout = timeout + current_time_monotonic(); /* In ms */ | ||
599 | timer->idx = i; | ||
600 | |||
601 | /* reorder */ | ||
602 | if (i) { | ||
603 | int j = i - 1; | ||
604 | |||
605 | for (; j >= 0 && timeout < timers_container->timers[j]->timeout; j--) { | ||
606 | Timer *tmp = timers_container->timers[j]; | ||
607 | timers_container->timers[j] = timer; | ||
608 | timers_container->timers[j + 1] = tmp; | ||
609 | } | ||
610 | } | ||
611 | |||
612 | pthread_mutex_unlock(&timers_container->mutex); | ||
613 | |||
614 | LOGGER_DEBUG("Allocated timer index: %d timeout: %d, current size: %d", i, timeout, timers_container->size); | ||
615 | return i; | ||
616 | } | ||
617 | |||
618 | /** | ||
619 | * @brief Remove timer from array | ||
620 | * | ||
621 | * @param timers_container handler | ||
622 | * @param idx index | ||
623 | * @return int | ||
624 | */ | ||
625 | int timer_release ( TimerHandler *timers_container, int idx ) | ||
626 | { | ||
627 | int rc = pthread_mutex_trylock(&timers_container->mutex); | ||
628 | |||
629 | Timer **timed_events = timers_container->timers; | ||
630 | |||
631 | if (!timed_events[idx]) { | ||
632 | LOGGER_WARNING("No event under index: %d", idx); | ||
633 | |||
634 | if ( rc != EBUSY ) pthread_mutex_unlock(&timers_container->mutex); | ||
635 | |||
636 | return -1; | ||
637 | } | ||
638 | |||
639 | free(timed_events[idx]); | ||
640 | |||
641 | timed_events[idx] = NULL; | ||
642 | |||
643 | int i = idx + 1; | ||
644 | |||
645 | for (; i < timers_container->max_capacity && timed_events[i]; i ++) { | ||
646 | timed_events[i - 1] = timed_events[i]; | ||
647 | timed_events[i] = NULL; | ||
648 | } | ||
649 | |||
650 | timers_container->size--; | ||
651 | |||
652 | LOGGER_DEBUG("Popped index: %d, current size: %d ", idx, timers_container->size); | ||
653 | |||
654 | if ( rc != EBUSY ) pthread_mutex_unlock(&timers_container->mutex); | ||
655 | |||
656 | return 0; | ||
657 | } | ||
658 | |||
659 | /** | ||
660 | * @brief Main poll for timer execution | ||
661 | * | ||
662 | * @param arg ... | ||
663 | * @return void* | ||
664 | */ | ||
665 | void *timer_poll( void *arg ) | ||
666 | { | ||
667 | TimerHandler *handler = arg; | ||
668 | |||
669 | while ( handler->running ) { | ||
670 | |||
671 | pthread_mutex_lock(&handler->mutex); | ||
672 | |||
673 | if ( handler->running ) { | ||
674 | |||
675 | uint64_t time = current_time_monotonic(); | ||
676 | |||
677 | while ( handler->timers[0] && handler->timers[0]->timeout < time ) { | ||
678 | |||
679 | pthread_t _tid; | ||
680 | |||
681 | if ( 0 != pthread_create(&_tid, NULL, handler->timers[0]->func, handler->timers[0]->func_args) || | ||
682 | 0 != pthread_detach(_tid) ) | ||
683 | LOGGER_ERROR("Failed to execute timer at: %d!", handler->timers[0]->timeout); | ||
684 | |||
685 | else LOGGER_DEBUG("Exectued timer assigned at: %d", handler->timers[0]->timeout); | ||
686 | |||
687 | timer_release(handler, 0); | ||
688 | } | ||
689 | |||
690 | } | ||
691 | |||
692 | pthread_mutex_unlock(&handler->mutex); | ||
693 | |||
694 | usleep(handler->resolution); | ||
695 | } | ||
696 | |||
697 | pthread_exit(NULL); | ||
698 | } | ||
699 | |||
700 | /** | ||
701 | * @brief Start timer poll and return handler | ||
702 | * | ||
703 | * @param max_capacity capacity | ||
704 | * @param resolution ... | ||
705 | * @return TimerHandler* | ||
706 | */ | ||
707 | TimerHandler *timer_init_session (int max_capacity, int resolution) | ||
708 | { | ||
709 | TimerHandler *handler = calloc(1, sizeof(TimerHandler)); | ||
710 | |||
711 | if (handler == NULL) { | ||
712 | LOGGER_ERROR("Failed to allocate memory, program might misbehave!"); | ||
713 | return NULL; | ||
714 | } | ||
715 | |||
716 | handler->timers = calloc(max_capacity, sizeof(Timer *)); | ||
717 | |||
718 | if (handler->timers == NULL) { | ||
719 | LOGGER_ERROR("Failed to allocate %d timed events!", max_capacity); | ||
720 | free(handler); | ||
721 | return NULL; | ||
722 | } | ||
723 | |||
724 | handler->max_capacity = max_capacity; | ||
725 | handler->running = 1; | ||
726 | handler->resolution = resolution; | ||
727 | |||
728 | pthread_mutex_init(&handler->mutex, NULL); | ||
729 | |||
730 | |||
731 | pthread_t _tid; | ||
732 | |||
733 | if ( 0 != pthread_create(&_tid, NULL, timer_poll, handler) || 0 != pthread_detach(_tid) ) { | ||
734 | LOGGER_ERROR("Failed to start timer poll thread!"); | ||
735 | free(handler->timers); | ||
736 | free(handler); | ||
737 | return NULL; | ||
738 | } | ||
739 | |||
740 | return handler; | ||
741 | } | ||
742 | |||
743 | /** | ||
744 | * @brief Terminate timer session | ||
745 | * | ||
746 | * @param handler The timer handler | ||
747 | * @return void | ||
748 | */ | ||
749 | void timer_terminate_session(TimerHandler *handler) | ||
750 | { | ||
751 | pthread_mutex_lock(&handler->mutex); | ||
752 | |||
753 | handler->running = 0; | ||
754 | |||
755 | pthread_mutex_unlock(&handler->mutex); | ||
756 | |||
757 | int i = 0; | ||
758 | |||
759 | for (; i < handler->max_capacity; i ++) | ||
760 | free(handler->timers[i]); | ||
761 | |||
762 | free(handler->timers); | ||
763 | |||
764 | pthread_mutex_destroy( &handler->mutex ); | ||
765 | } | ||
766 | |||
541 | /** | 767 | /** |
542 | * @brief Generate _random_ alphanumerical string. | 768 | * @brief Generate _random_ alphanumerical string. |
543 | * | 769 | * |
@@ -731,7 +957,11 @@ MSICall *find_call ( MSISession *session, uint8_t *call_id ) | |||
731 | 957 | ||
732 | for (; i < session->max_calls; i ++ ) | 958 | for (; i < session->max_calls; i ++ ) |
733 | if ( session->calls[i] && memcmp(session->calls[i]->id, call_id, CALL_ID_LEN) == 0 ) { | 959 | if ( session->calls[i] && memcmp(session->calls[i]->id, call_id, CALL_ID_LEN) == 0 ) { |
734 | LOGGER_DEBUG("Found call id: %s", session->calls[i]->id); | 960 | LOGGER_SCOPE( |
961 | char tmp[CALL_ID_LEN + 1] = {'\0'}; | ||
962 | memcpy(tmp, session->calls[i]->id, CALL_ID_LEN); | ||
963 | LOGGER_DEBUG("Found call id: %s", tmp); | ||
964 | ); | ||
735 | return session->calls[i]; | 965 | return session->calls[i]; |
736 | } | 966 | } |
737 | 967 | ||
@@ -883,8 +1113,8 @@ int terminate_call ( MSISession *session, MSICall *call ) | |||
883 | * NOTE: This has to be done before possibly | 1113 | * NOTE: This has to be done before possibly |
884 | * locking the mutex the second time | 1114 | * locking the mutex the second time |
885 | */ | 1115 | */ |
886 | event.timer_release ( call->request_timer_id ); | 1116 | timer_release ( session->timer_handler, call->request_timer_id ); |
887 | event.timer_release ( call->ringing_timer_id ); | 1117 | timer_release ( session->timer_handler, call->ringing_timer_id ); |
888 | 1118 | ||
889 | /* Get a handle */ | 1119 | /* Get a handle */ |
890 | pthread_mutex_lock ( &call->mutex ); | 1120 | pthread_mutex_lock ( &call->mutex ); |
@@ -1055,10 +1285,6 @@ int handle_recv_reject ( MSISession *session, MSICall *call, MSIMessage *msg ) | |||
1055 | pthread_mutex_unlock(&session->mutex); | 1285 | pthread_mutex_unlock(&session->mutex); |
1056 | 1286 | ||
1057 | invoke_callback(call->call_idx, MSI_OnReject); | 1287 | invoke_callback(call->call_idx, MSI_OnReject); |
1058 | /* | ||
1059 | event.timer_release ( session->call->request_timer_id ); | ||
1060 | session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); | ||
1061 | */ | ||
1062 | 1288 | ||
1063 | terminate_call(session, call); | 1289 | terminate_call(session, call); |
1064 | return 1; | 1290 | return 1; |
@@ -1123,7 +1349,7 @@ int handle_recv_ringing ( MSISession *session, MSICall *call, MSIMessage *msg ) | |||
1123 | 1349 | ||
1124 | LOGGER_DEBUG("Session: %p Handling 'ringing' on call: %s", session, call->id ); | 1350 | LOGGER_DEBUG("Session: %p Handling 'ringing' on call: %s", session, call->id ); |
1125 | 1351 | ||
1126 | call->ringing_timer_id = event.timer_alloc ( handle_timeout, call, call->ringing_tout_ms ); | 1352 | call->ringing_timer_id = timer_alloc ( session->timer_handler, handle_timeout, call, call->ringing_tout_ms ); |
1127 | 1353 | ||
1128 | pthread_mutex_unlock(&session->mutex); | 1354 | pthread_mutex_unlock(&session->mutex); |
1129 | 1355 | ||
@@ -1150,7 +1376,7 @@ int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage *msg ) | |||
1150 | flush_peer_type ( call, msg, 0 ); | 1376 | flush_peer_type ( call, msg, 0 ); |
1151 | 1377 | ||
1152 | 1378 | ||
1153 | event.timer_release ( call->ringing_timer_id ); | 1379 | timer_release ( session->timer_handler, call->ringing_timer_id ); |
1154 | pthread_mutex_unlock(&session->mutex); | 1380 | pthread_mutex_unlock(&session->mutex); |
1155 | 1381 | ||
1156 | invoke_callback(call->call_idx, MSI_OnStarting); | 1382 | invoke_callback(call->call_idx, MSI_OnStarting); |
@@ -1168,7 +1394,7 @@ int handle_recv_ending ( MSISession *session, MSICall *call, MSIMessage *msg ) | |||
1168 | LOGGER_DEBUG("Session: %p Handling 'ending' on call: %s", session, call->id ); | 1394 | LOGGER_DEBUG("Session: %p Handling 'ending' on call: %s", session, call->id ); |
1169 | 1395 | ||
1170 | /* Stop timer */ | 1396 | /* Stop timer */ |
1171 | event.timer_release ( call->request_timer_id ); | 1397 | timer_release ( session->timer_handler, call->request_timer_id ); |
1172 | 1398 | ||
1173 | pthread_mutex_unlock(&session->mutex); | 1399 | pthread_mutex_unlock(&session->mutex); |
1174 | 1400 | ||
@@ -1246,89 +1472,88 @@ void msi_handle_packet ( Messenger *messenger, int source, const uint8_t *data, | |||
1246 | /* Unused */ | 1472 | /* Unused */ |
1247 | (void)messenger; | 1473 | (void)messenger; |
1248 | 1474 | ||
1249 | MSISession *_session = object; | 1475 | MSISession *session = object; |
1250 | MSIMessage *_msg; | 1476 | MSIMessage *msg; |
1251 | 1477 | ||
1252 | if ( !length ) { | 1478 | if ( !length ) { |
1253 | LOGGER_WARNING("Lenght param negative"); | 1479 | LOGGER_WARNING("Lenght param negative"); |
1254 | return; | 1480 | return; |
1255 | } | 1481 | } |
1256 | 1482 | ||
1257 | _msg = parse_message ( data, length ); | 1483 | msg = parse_message ( data, length ); |
1258 | 1484 | ||
1259 | if ( !_msg ) { | 1485 | if ( !msg ) { |
1260 | LOGGER_WARNING("Error parsing message"); | 1486 | LOGGER_WARNING("Error parsing message"); |
1261 | return; | 1487 | return; |
1262 | } else { | 1488 | } else { |
1263 | LOGGER_DEBUG("Successfully parsed message"); | 1489 | LOGGER_DEBUG("Successfully parsed message"); |
1264 | } | 1490 | } |
1265 | 1491 | ||
1266 | _msg->friend_id = source; | 1492 | msg->friend_id = source; |
1267 | 1493 | ||
1268 | 1494 | ||
1269 | /* Find what call */ | 1495 | /* Find what call */ |
1270 | MSICall *_call = _msg->callid.header_value ? find_call(_session, _msg->callid.header_value ) : NULL; | 1496 | MSICall *call = msg->callid.header_value ? find_call(session, msg->callid.header_value ) : NULL; |
1271 | 1497 | ||
1272 | /* Now handle message */ | 1498 | /* Now handle message */ |
1273 | 1499 | ||
1274 | if ( _msg->request.header_value ) { /* Handle request */ | 1500 | if ( msg->request.header_value ) { /* Handle request */ |
1275 | 1501 | ||
1276 | if ( _msg->response.size > 32 ) { | 1502 | if ( msg->response.size > 32 ) { |
1277 | LOGGER_WARNING("Header size too big"); | 1503 | LOGGER_WARNING("Header size too big"); |
1278 | goto free_end; | 1504 | goto free_end; |
1279 | } | 1505 | } |
1280 | 1506 | ||
1281 | uint8_t _request_value[32]; | 1507 | uint8_t _request_value[32]; |
1282 | 1508 | ||
1283 | memcpy(_request_value, _msg->request.header_value, _msg->request.size); | 1509 | memcpy(_request_value, msg->request.header_value, msg->request.size); |
1284 | _request_value[_msg->request.size] = '\0'; | 1510 | _request_value[msg->request.size] = '\0'; |
1285 | 1511 | ||
1286 | if ( same ( _request_value, stringify_request ( invite ) ) ) { | 1512 | if ( same ( _request_value, stringify_request ( invite ) ) ) { |
1287 | handle_recv_invite ( _session, _call, _msg ); | 1513 | handle_recv_invite ( session, call, msg ); |
1288 | 1514 | ||
1289 | } else if ( same ( _request_value, stringify_request ( start ) ) ) { | 1515 | } else if ( same ( _request_value, stringify_request ( start ) ) ) { |
1290 | handle_recv_start ( _session, _call, _msg ); | 1516 | handle_recv_start ( session, call, msg ); |
1291 | 1517 | ||
1292 | } else if ( same ( _request_value, stringify_request ( cancel ) ) ) { | 1518 | } else if ( same ( _request_value, stringify_request ( cancel ) ) ) { |
1293 | handle_recv_cancel ( _session, _call, _msg ); | 1519 | handle_recv_cancel ( session, call, msg ); |
1294 | 1520 | ||
1295 | } else if ( same ( _request_value, stringify_request ( reject ) ) ) { | 1521 | } else if ( same ( _request_value, stringify_request ( reject ) ) ) { |
1296 | handle_recv_reject ( _session, _call, _msg ); | 1522 | handle_recv_reject ( session, call, msg ); |
1297 | 1523 | ||
1298 | } else if ( same ( _request_value, stringify_request ( end ) ) ) { | 1524 | } else if ( same ( _request_value, stringify_request ( end ) ) ) { |
1299 | handle_recv_end ( _session, _call, _msg ); | 1525 | handle_recv_end ( session, call, msg ); |
1300 | } else { | 1526 | } else { |
1301 | LOGGER_WARNING("Uknown request"); | 1527 | LOGGER_WARNING("Uknown request"); |
1302 | goto free_end; | 1528 | goto free_end; |
1303 | } | 1529 | } |
1304 | 1530 | ||
1305 | } else if ( _msg->response.header_value ) { /* Handle response */ | 1531 | } else if ( msg->response.header_value ) { /* Handle response */ |
1306 | 1532 | ||
1307 | if ( _msg->response.size > 32 ) { | 1533 | if ( msg->response.size > 32 ) { |
1308 | LOGGER_WARNING("Header size too big"); | 1534 | LOGGER_WARNING("Header size too big"); |
1309 | goto free_end; | 1535 | goto free_end; |
1310 | } | 1536 | } |
1311 | 1537 | ||
1312 | /* Got response so cancel timer */ | 1538 | /* Got response so cancel timer */ |
1313 | if ( _call ) | 1539 | if ( call ) timer_release ( session->timer_handler, call->request_timer_id ); |
1314 | event.timer_release ( _call->request_timer_id ); | ||
1315 | 1540 | ||
1316 | uint8_t _response_value[32]; | 1541 | uint8_t _response_value[32]; |
1317 | 1542 | ||
1318 | memcpy(_response_value, _msg->response.header_value, _msg->response.size); | 1543 | memcpy(_response_value, msg->response.header_value, msg->response.size); |
1319 | _response_value[_msg->response.size] = '\0'; | 1544 | _response_value[msg->response.size] = '\0'; |
1320 | 1545 | ||
1321 | if ( same ( _response_value, stringify_response ( ringing ) ) ) { | 1546 | if ( same ( _response_value, stringify_response ( ringing ) ) ) { |
1322 | handle_recv_ringing ( _session, _call, _msg ); | 1547 | handle_recv_ringing ( session, call, msg ); |
1323 | 1548 | ||
1324 | } else if ( same ( _response_value, stringify_response ( starting ) ) ) { | 1549 | } else if ( same ( _response_value, stringify_response ( starting ) ) ) { |
1325 | handle_recv_starting ( _session, _call, _msg ); | 1550 | handle_recv_starting ( session, call, msg ); |
1326 | 1551 | ||
1327 | } else if ( same ( _response_value, stringify_response ( ending ) ) ) { | 1552 | } else if ( same ( _response_value, stringify_response ( ending ) ) ) { |
1328 | handle_recv_ending ( _session, _call, _msg ); | 1553 | handle_recv_ending ( session, call, msg ); |
1329 | 1554 | ||
1330 | } else if ( same ( _response_value, stringify_response ( error ) ) ) { | 1555 | } else if ( same ( _response_value, stringify_response ( error ) ) ) { |
1331 | handle_recv_error ( _session, _call, _msg ); | 1556 | handle_recv_error ( session, call, msg ); |
1332 | 1557 | ||
1333 | } else { | 1558 | } else { |
1334 | LOGGER_WARNING("Uknown response"); | 1559 | LOGGER_WARNING("Uknown response"); |
@@ -1340,7 +1565,7 @@ void msi_handle_packet ( Messenger *messenger, int source, const uint8_t *data, | |||
1340 | } | 1565 | } |
1341 | 1566 | ||
1342 | free_end: | 1567 | free_end: |
1343 | free_message ( _msg ); | 1568 | free_message ( msg ); |
1344 | } | 1569 | } |
1345 | 1570 | ||
1346 | 1571 | ||
@@ -1373,7 +1598,12 @@ MSISession *msi_init_session ( Messenger *messenger, int32_t max_calls ) | |||
1373 | return NULL; | 1598 | return NULL; |
1374 | } | 1599 | } |
1375 | 1600 | ||
1376 | if ( !max_calls) return NULL; | 1601 | TimerHandler *handler = timer_init_session(max_calls * 10, 10000); |
1602 | |||
1603 | if ( !max_calls || !handler ) { | ||
1604 | LOGGER_WARNING("Invalid max call treshold or timer handler initialization failed!"); | ||
1605 | return NULL; | ||
1606 | } | ||
1377 | 1607 | ||
1378 | MSISession *_retu = calloc ( sizeof ( MSISession ), 1 ); | 1608 | MSISession *_retu = calloc ( sizeof ( MSISession ), 1 ); |
1379 | 1609 | ||
@@ -1384,6 +1614,7 @@ MSISession *msi_init_session ( Messenger *messenger, int32_t max_calls ) | |||
1384 | 1614 | ||
1385 | _retu->messenger_handle = messenger; | 1615 | _retu->messenger_handle = messenger; |
1386 | _retu->agent_handler = NULL; | 1616 | _retu->agent_handler = NULL; |
1617 | _retu->timer_handler = handler; | ||
1387 | 1618 | ||
1388 | if (!(_retu->calls = calloc( sizeof (MSICall *), max_calls ))) { | 1619 | if (!(_retu->calls = calloc( sizeof (MSICall *), max_calls ))) { |
1389 | LOGGER_ERROR("Allocation failed! Program might misbehave!"); | 1620 | LOGGER_ERROR("Allocation failed! Program might misbehave!"); |
@@ -1440,6 +1671,7 @@ int msi_terminate_session ( MSISession *session ) | |||
1440 | msi_cancel ( session, idx, session->calls[idx]->peers [_it], "MSI session terminated!" ); | 1671 | msi_cancel ( session, idx, session->calls[idx]->peers [_it], "MSI session terminated!" ); |
1441 | } | 1672 | } |
1442 | 1673 | ||
1674 | timer_terminate_session(session->timer_handler); | ||
1443 | 1675 | ||
1444 | pthread_mutex_destroy(&session->mutex); | 1676 | pthread_mutex_destroy(&session->mutex); |
1445 | 1677 | ||
@@ -1495,7 +1727,7 @@ int msi_invite ( MSISession *session, int32_t *call_index, MSICallType call_type | |||
1495 | 1727 | ||
1496 | _call->state = call_inviting; | 1728 | _call->state = call_inviting; |
1497 | 1729 | ||
1498 | _call->request_timer_id = event.timer_alloc ( handle_timeout, _call, m_deftout ); | 1730 | _call->request_timer_id = timer_alloc ( session->timer_handler, handle_timeout, _call, m_deftout ); |
1499 | 1731 | ||
1500 | LOGGER_DEBUG("Invite sent"); | 1732 | LOGGER_DEBUG("Invite sent"); |
1501 | 1733 | ||
@@ -1543,8 +1775,8 @@ int msi_hangup ( MSISession *session, int32_t call_index ) | |||
1543 | 1775 | ||
1544 | free_message ( _msg_end ); | 1776 | free_message ( _msg_end ); |
1545 | 1777 | ||
1546 | session->calls[call_index]->request_timer_id = event.timer_alloc ( handle_timeout, session->calls[call_index], | 1778 | session->calls[call_index]->request_timer_id = |
1547 | m_deftout ); | 1779 | timer_alloc ( session->timer_handler, handle_timeout, session->calls[call_index], m_deftout ); |
1548 | 1780 | ||
1549 | pthread_mutex_unlock(&session->mutex); | 1781 | pthread_mutex_unlock(&session->mutex); |
1550 | return 0; | 1782 | return 0; |
@@ -1620,7 +1852,7 @@ int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const c | |||
1620 | free_message ( _msg_cancel ); | 1852 | free_message ( _msg_cancel ); |
1621 | 1853 | ||
1622 | /*session->calls[call_index]->state = call_hanged_up; | 1854 | /*session->calls[call_index]->state = call_hanged_up; |
1623 | session->calls[call_index]->request_timer_id = event.timer_alloc ( handle_timeout, session->calls[call_index], m_deftout );*/ | 1855 | session->calls[call_index]->request_timer_id = timer_alloc ( handle_timeout, session->calls[call_index], m_deftout );*/ |
1624 | terminate_call ( session, session->calls[call_index] ); | 1856 | terminate_call ( session, session->calls[call_index] ); |
1625 | pthread_mutex_unlock(&session->mutex); | 1857 | pthread_mutex_unlock(&session->mutex); |
1626 | 1858 | ||
@@ -1656,8 +1888,8 @@ int msi_reject ( MSISession *session, int32_t call_index, const uint8_t *reason | |||
1656 | 1888 | ||
1657 | session->calls[call_index]->state = call_hanged_up; | 1889 | session->calls[call_index]->state = call_hanged_up; |
1658 | 1890 | ||
1659 | session->calls[call_index]->request_timer_id = event.timer_alloc ( handle_timeout, session->calls[call_index], | 1891 | session->calls[call_index]->request_timer_id = |
1660 | m_deftout ); | 1892 | timer_alloc ( session->timer_handler, handle_timeout, session->calls[call_index], m_deftout ); |
1661 | 1893 | ||
1662 | pthread_mutex_unlock(&session->mutex); | 1894 | pthread_mutex_unlock(&session->mutex); |
1663 | return 0; | 1895 | return 0; |
diff --git a/toxav/msi.h b/toxav/msi.h index 02432daf..0020df4c 100644 --- a/toxav/msi.h +++ b/toxav/msi.h | |||
@@ -105,6 +105,8 @@ typedef struct _MSISession { | |||
105 | uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */ | 105 | uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */ |
106 | 106 | ||
107 | pthread_mutex_t mutex; | 107 | pthread_mutex_t mutex; |
108 | |||
109 | void *timer_handler; | ||
108 | } MSISession; | 110 | } MSISession; |
109 | 111 | ||
110 | 112 | ||
diff --git a/toxav/toxav.c b/toxav/toxav.c index 3085827c..e98c9c4b 100644 --- a/toxav/toxav.c +++ b/toxav/toxav.c | |||
@@ -66,6 +66,8 @@ typedef struct _CallSpecific { | |||
66 | uint32_t frame_limit; /* largest address written to in frame_buf for current input frame*/ | 66 | uint32_t frame_limit; /* largest address written to in frame_buf for current input frame*/ |
67 | uint8_t frame_id, frame_outid; /* id of input and output video frame */ | 67 | uint8_t frame_id, frame_outid; /* id of input and output video frame */ |
68 | void *frame_buf; /* buffer for split video payloads */ | 68 | void *frame_buf; /* buffer for split video payloads */ |
69 | |||
70 | _Bool call_active; | ||
69 | } CallSpecific; | 71 | } CallSpecific; |
70 | 72 | ||
71 | 73 | ||
@@ -296,8 +298,9 @@ int toxav_stop_call ( ToxAv *av, int32_t call_index ) | |||
296 | */ | 298 | */ |
297 | int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video ) | 299 | int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video ) |
298 | { | 300 | { |
299 | if ( !av->msi_session || cii(call_index, av->msi_session) || !av->msi_session->calls[call_index] ) { | 301 | if ( !av->msi_session || cii(call_index, av->msi_session) || |
300 | LOGGER_ERROR("Error while starting audio RTP session: invalid call!\n"); | 302 | !av->msi_session->calls[call_index] || av->calls[call_index].call_active) { |
303 | LOGGER_ERROR("Error while starting RTP session: invalid call!\n"); | ||
301 | return ErrorInternal; | 304 | return ErrorInternal; |
302 | } | 305 | } |
303 | 306 | ||
@@ -320,6 +323,8 @@ int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettin | |||
320 | 323 | ||
321 | if ( !call->crtps[video_index] ) { | 324 | if ( !call->crtps[video_index] ) { |
322 | LOGGER_ERROR("Error while starting video RTP session!\n"); | 325 | LOGGER_ERROR("Error while starting video RTP session!\n"); |
326 | |||
327 | rtp_terminate_session(call->crtps[audio_index], av->messenger); | ||
323 | return ErrorStartingVideoRtp; | 328 | return ErrorStartingVideoRtp; |
324 | } | 329 | } |
325 | 330 | ||
@@ -330,23 +335,40 @@ int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettin | |||
330 | call->frame_buf = calloc(MAX_VIDEOFRAME_SIZE, 1); | 335 | call->frame_buf = calloc(MAX_VIDEOFRAME_SIZE, 1); |
331 | 336 | ||
332 | if (!call->frame_buf) { | 337 | if (!call->frame_buf) { |
338 | rtp_terminate_session(call->crtps[audio_index], av->messenger); | ||
339 | rtp_terminate_session(call->crtps[video_index], av->messenger); | ||
340 | LOGGER_WARNING("Frame buffer allocation failed!"); | ||
333 | return ErrorInternal; | 341 | return ErrorInternal; |
334 | } | 342 | } |
335 | 343 | ||
336 | } | 344 | } |
337 | 345 | ||
338 | if ( !(call->j_buf = create_queue(codec_settings->jbuf_capacity)) ) return ErrorInternal; | 346 | if ( !(call->j_buf = create_queue(codec_settings->jbuf_capacity)) ) { |
347 | rtp_terminate_session(call->crtps[audio_index], av->messenger); | ||
348 | rtp_terminate_session(call->crtps[video_index], av->messenger); | ||
349 | free(call->frame_buf); | ||
350 | LOGGER_WARNING("Jitter buffer creaton failed!"); | ||
351 | return ErrorInternal; | ||
352 | } | ||
339 | 353 | ||
340 | call->cs = codec_init_session(codec_settings->audio_bitrate, | 354 | if ( (call->cs = codec_init_session(codec_settings->audio_bitrate, |
341 | codec_settings->audio_frame_duration, | 355 | codec_settings->audio_frame_duration, |
342 | codec_settings->audio_sample_rate, | 356 | codec_settings->audio_sample_rate, |
343 | codec_settings->audio_channels, | 357 | codec_settings->audio_channels, |
344 | codec_settings->audio_VAD_tolerance, | 358 | codec_settings->audio_VAD_tolerance, |
345 | codec_settings->video_width, | 359 | codec_settings->video_width, |
346 | codec_settings->video_height, | 360 | codec_settings->video_height, |
347 | codec_settings->video_bitrate); | 361 | codec_settings->video_bitrate) )) { |
362 | call->call_active = 1; | ||
363 | return ErrorNone; | ||
364 | } | ||
348 | 365 | ||
349 | return call->cs ? ErrorNone : ErrorInternal; | 366 | rtp_terminate_session(call->crtps[audio_index], av->messenger); |
367 | rtp_terminate_session(call->crtps[video_index], av->messenger); | ||
368 | free(call->frame_buf); | ||
369 | terminate_queue(call->j_buf); | ||
370 | |||
371 | return ErrorInternal; | ||
350 | } | 372 | } |
351 | 373 | ||
352 | /** | 374 | /** |
@@ -359,22 +381,24 @@ int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettin | |||
359 | */ | 381 | */ |
360 | int toxav_kill_transmission ( ToxAv *av, int32_t call_index ) | 382 | int toxav_kill_transmission ( ToxAv *av, int32_t call_index ) |
361 | { | 383 | { |
362 | if (cii(call_index, av->msi_session)) return ErrorNoCall; | 384 | if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) { |
385 | LOGGER_WARNING("Action on inactive call: %d", call_index); | ||
386 | return ErrorNoCall; | ||
387 | } | ||
363 | 388 | ||
364 | CallSpecific *call = &av->calls[call_index]; | 389 | CallSpecific *call = &av->calls[call_index]; |
365 | 390 | ||
391 | call->call_active = 0; | ||
392 | |||
366 | if ( call->crtps[audio_index] && -1 == rtp_terminate_session(call->crtps[audio_index], av->messenger) ) { | 393 | if ( call->crtps[audio_index] && -1 == rtp_terminate_session(call->crtps[audio_index], av->messenger) ) { |
367 | LOGGER_ERROR("Error while terminating audio RTP session!\n"); | 394 | LOGGER_ERROR("Error while terminating audio RTP session!\n"); |
368 | return ErrorTerminatingAudioRtp; | 395 | /*return ErrorTerminatingAudioRtp;*/ |
369 | } | 396 | } else call->crtps[audio_index] = NULL; |
370 | 397 | ||
371 | if ( call->crtps[video_index] && -1 == rtp_terminate_session(call->crtps[video_index], av->messenger) ) { | 398 | if ( call->crtps[video_index] && -1 == rtp_terminate_session(call->crtps[video_index], av->messenger) ) { |
372 | LOGGER_ERROR("Error while terminating video RTP session!\n"); | 399 | LOGGER_ERROR("Error while terminating video RTP session!\n"); |
373 | return ErrorTerminatingVideoRtp; | 400 | /*return ErrorTerminatingVideoRtp;*/ |
374 | } | 401 | } else call->crtps[video_index] = NULL; |
375 | |||
376 | call->crtps[audio_index] = NULL; | ||
377 | call->crtps[video_index] = NULL; | ||
378 | 402 | ||
379 | if ( call->j_buf ) { | 403 | if ( call->j_buf ) { |
380 | terminate_queue(call->j_buf); | 404 | terminate_queue(call->j_buf); |
@@ -388,6 +412,7 @@ int toxav_kill_transmission ( ToxAv *av, int32_t call_index ) | |||
388 | LOGGER_DEBUG("Terminated codec session"); | 412 | LOGGER_DEBUG("Terminated codec session"); |
389 | } else LOGGER_DEBUG("No codec session"); | 413 | } else LOGGER_DEBUG("No codec session"); |
390 | 414 | ||
415 | |||
391 | return ErrorNone; | 416 | return ErrorNone; |
392 | } | 417 | } |
393 | 418 | ||
@@ -406,8 +431,6 @@ int toxav_kill_transmission ( ToxAv *av, int32_t call_index ) | |||
406 | inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, const uint8_t *payload, | 431 | inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, const uint8_t *payload, |
407 | unsigned int length ) | 432 | unsigned int length ) |
408 | { | 433 | { |
409 | if (cii(call_index, av->msi_session)) return ErrorNoCall; | ||
410 | |||
411 | #define send(data, len) rtp_send_msg(av->calls[call_index].crtps[type - TypeAudio], av->msi_session->messenger_handle, data, len) | 434 | #define send(data, len) rtp_send_msg(av->calls[call_index].crtps[type - TypeAudio], av->msi_session->messenger_handle, data, len) |
412 | 435 | ||
413 | if (av->calls[call_index].crtps[type - TypeAudio]) { | 436 | if (av->calls[call_index].crtps[type - TypeAudio]) { |
@@ -465,8 +488,6 @@ inline__ int toxav_recv_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallTy | |||
465 | { | 488 | { |
466 | if ( !dest ) return ErrorInternal; | 489 | if ( !dest ) return ErrorInternal; |
467 | 490 | ||
468 | if (cii(call_index, av->msi_session)) return ErrorNoCall; | ||
469 | |||
470 | CallSpecific *call = &av->calls[call_index]; | 491 | CallSpecific *call = &av->calls[call_index]; |
471 | 492 | ||
472 | if ( !call->crtps[type - TypeAudio] ) return ErrorNoRtpSession; | 493 | if ( !call->crtps[type - TypeAudio] ) return ErrorNoRtpSession; |
@@ -518,7 +539,11 @@ inline__ int toxav_recv_video ( ToxAv *av, int32_t call_index, vpx_image_t **out | |||
518 | { | 539 | { |
519 | if ( !output ) return ErrorInternal; | 540 | if ( !output ) return ErrorInternal; |
520 | 541 | ||
521 | if (cii(call_index, av->msi_session)) return ErrorNoCall; | 542 | if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) { |
543 | LOGGER_WARNING("Action on inactive call: %d", call_index); | ||
544 | return ErrorNoCall; | ||
545 | } | ||
546 | |||
522 | 547 | ||
523 | uint8_t packet [RTP_PAYLOAD_SIZE]; | 548 | uint8_t packet [RTP_PAYLOAD_SIZE]; |
524 | CallSpecific *call = &av->calls[call_index]; | 549 | CallSpecific *call = &av->calls[call_index]; |
@@ -586,7 +611,11 @@ inline__ int toxav_recv_video ( ToxAv *av, int32_t call_index, vpx_image_t **out | |||
586 | */ | 611 | */ |
587 | inline__ int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size) | 612 | inline__ int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size) |
588 | { | 613 | { |
589 | if (cii(call_index, av->msi_session)) return ErrorNoCall; | 614 | if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) { |
615 | LOGGER_WARNING("Action on inactive call: %d", call_index); | ||
616 | return ErrorNoCall; | ||
617 | } | ||
618 | |||
590 | 619 | ||
591 | return toxav_send_rtp_payload(av, call_index, TypeVideo, frame, frame_size); | 620 | return toxav_send_rtp_payload(av, call_index, TypeVideo, frame, frame_size); |
592 | } | 621 | } |
@@ -604,7 +633,11 @@ inline__ int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *fr | |||
604 | */ | 633 | */ |
605 | inline__ int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input) | 634 | inline__ int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input) |
606 | { | 635 | { |
607 | if (cii(call_index, av->msi_session)) return ErrorNoCall; | 636 | if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) { |
637 | LOGGER_WARNING("Action on inactive call: %d", call_index); | ||
638 | return ErrorNoCall; | ||
639 | } | ||
640 | |||
608 | 641 | ||
609 | CallSpecific *call = &av->calls[call_index]; | 642 | CallSpecific *call = &av->calls[call_index]; |
610 | 643 | ||
@@ -649,7 +682,11 @@ inline__ int toxav_recv_audio ( ToxAv *av, int32_t call_index, int frame_size, i | |||
649 | { | 682 | { |
650 | if ( !dest ) return ErrorInternal; | 683 | if ( !dest ) return ErrorInternal; |
651 | 684 | ||
652 | if (cii(call_index, av->msi_session)) return ErrorNoCall; | 685 | if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) { |
686 | LOGGER_WARNING("Action on inactive call: %d", call_index); | ||
687 | return ErrorNoCall; | ||
688 | } | ||
689 | |||
653 | 690 | ||
654 | CallSpecific *call = &av->calls[call_index]; | 691 | CallSpecific *call = &av->calls[call_index]; |
655 | 692 | ||
@@ -690,7 +727,11 @@ inline__ int toxav_recv_audio ( ToxAv *av, int32_t call_index, int frame_size, i | |||
690 | */ | 727 | */ |
691 | inline__ int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size) | 728 | inline__ int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size) |
692 | { | 729 | { |
693 | if (cii(call_index, av->msi_session)) return ErrorNoCall; | 730 | if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) { |
731 | LOGGER_WARNING("Action on inactive call: %d", call_index); | ||
732 | return ErrorNoCall; | ||
733 | } | ||
734 | |||
694 | 735 | ||
695 | return toxav_send_rtp_payload(av, call_index, TypeAudio, frame, frame_size); | 736 | return toxav_send_rtp_payload(av, call_index, TypeAudio, frame, frame_size); |
696 | } | 737 | } |
@@ -710,7 +751,11 @@ inline__ int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *fr | |||
710 | inline__ int toxav_prepare_audio_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, | 751 | inline__ int toxav_prepare_audio_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, |
711 | const int16_t *frame, int frame_size) | 752 | const int16_t *frame, int frame_size) |
712 | { | 753 | { |
713 | if (cii(call_index, av->msi_session)) return ErrorNoCall; | 754 | if (cii(call_index, av->msi_session) || !av->calls[call_index].call_active) { |
755 | LOGGER_WARNING("Action on inactive call: %d", call_index); | ||
756 | return ErrorNoCall; | ||
757 | } | ||
758 | |||
714 | 759 | ||
715 | int32_t rc = opus_encode(av->calls[call_index].cs->audio_encoder, frame, frame_size, dest, dest_max); | 760 | int32_t rc = opus_encode(av->calls[call_index].cs->audio_encoder, frame, frame_size, dest, dest_max); |
716 | 761 | ||