diff options
-rw-r--r-- | toxav/msi.c | 703 | ||||
-rw-r--r-- | toxav/msi.h | 18 | ||||
-rw-r--r-- | toxav/toxav.c | 187 |
3 files changed, 437 insertions, 471 deletions
diff --git a/toxav/msi.c b/toxav/msi.c index c1342950..cc855613 100644 --- a/toxav/msi.c +++ b/toxav/msi.c | |||
@@ -33,9 +33,11 @@ | |||
33 | #include <string.h> | 33 | #include <string.h> |
34 | #include <stdlib.h> | 34 | #include <stdlib.h> |
35 | #include <stdbool.h> | 35 | #include <stdbool.h> |
36 | #include <assert.h> | ||
36 | 37 | ||
37 | #define MSI_MAXMSG_SIZE 256 | 38 | #define MSI_MAXMSG_SIZE 256 |
38 | 39 | ||
40 | /* TODO send error on any calloc or etc */ | ||
39 | 41 | ||
40 | /** | 42 | /** |
41 | * Protocol: | 43 | * Protocol: |
@@ -63,14 +65,13 @@ typedef enum { | |||
63 | typedef enum { | 65 | typedef enum { |
64 | resp_ringing, | 66 | resp_ringing, |
65 | resp_starting, | 67 | resp_starting, |
66 | resp_error, | ||
67 | } MSIResponse; | 68 | } MSIResponse; |
68 | 69 | ||
69 | 70 | ||
70 | #define GENERIC_HEADER(header, val_type) \ | 71 | #define GENERIC_HEADER(header, val_type) \ |
71 | typedef struct { \ | 72 | typedef struct { \ |
72 | val_type value; \ | 73 | val_type value; \ |
73 | bool exists; \ | 74 | bool exists; \ |
74 | } MSIHeader##header | 75 | } MSIHeader##header |
75 | 76 | ||
76 | 77 | ||
@@ -92,7 +93,207 @@ typedef struct { | |||
92 | } MSIMessage; | 93 | } MSIMessage; |
93 | 94 | ||
94 | 95 | ||
95 | static int parse_input ( MSIMessage *dest, const uint8_t *data, uint16_t length ) | 96 | int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length ); |
97 | uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length ); | ||
98 | int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg ); | ||
99 | int send_error ( Messenger* m, uint32_t friend_id, MSIError error ); | ||
100 | static void invoke_callback(MSICall* call, MSICallbackID cb); | ||
101 | static MSICall *get_call ( MSISession *session, uint32_t friend_id ); | ||
102 | MSICall *new_call ( MSISession *session, uint32_t friend_id ); | ||
103 | void kill_call ( MSICall *call ); | ||
104 | void on_peer_status(Messenger *m, int friend_id, uint8_t status, void *data); | ||
105 | int handle_recv_invite ( MSICall *call, const MSIMessage *msg ); | ||
106 | int handle_recv_start ( MSICall *call, const MSIMessage *msg ); | ||
107 | int handle_recv_reject ( MSICall *call, const MSIMessage *msg ); | ||
108 | int handle_recv_end ( MSICall *call, const MSIMessage *msg ); | ||
109 | int handle_recv_ringing ( MSICall *call, const MSIMessage *msg ); | ||
110 | int handle_recv_starting ( MSICall *call, const MSIMessage *msg ); | ||
111 | int handle_recv_error ( MSICall *call, const MSIMessage *msg ); | ||
112 | void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint16_t length, void *object ); | ||
113 | |||
114 | |||
115 | /** | ||
116 | * Public functions | ||
117 | */ | ||
118 | void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id) | ||
119 | { | ||
120 | session->callbacks[id] = callback; | ||
121 | } | ||
122 | MSISession *msi_new ( Messenger *messenger ) | ||
123 | { | ||
124 | if (messenger == NULL) { | ||
125 | LOGGER_ERROR("Could not init session on empty messenger!"); | ||
126 | return NULL; | ||
127 | } | ||
128 | |||
129 | MSISession *retu = calloc ( sizeof ( MSISession ), 1 ); | ||
130 | |||
131 | if (retu == NULL) { | ||
132 | LOGGER_ERROR("Allocation failed! Program might misbehave!"); | ||
133 | return NULL; | ||
134 | } | ||
135 | |||
136 | if (create_recursive_mutex(retu->mutex) != 0) { | ||
137 | LOGGER_ERROR("Failed to init mutex! Program might misbehave"); | ||
138 | free(retu); | ||
139 | return NULL; | ||
140 | } | ||
141 | |||
142 | retu->messenger = messenger; | ||
143 | |||
144 | m_callback_msi_packet(messenger, handle_msi_packet, retu ); | ||
145 | |||
146 | /* This is called when remote terminates session */ | ||
147 | m_callback_connectionstatus_internal_av(messenger, on_peer_status, retu); | ||
148 | |||
149 | LOGGER_DEBUG("New msi session: %p ", retu); | ||
150 | return retu; | ||
151 | } | ||
152 | int msi_kill ( MSISession *session ) | ||
153 | { | ||
154 | if (session == NULL) { | ||
155 | LOGGER_ERROR("Tried to terminate non-existing session"); | ||
156 | return -1; | ||
157 | } | ||
158 | |||
159 | m_callback_msi_packet((struct Messenger *) session->messenger, NULL, NULL); | ||
160 | pthread_mutex_lock(session->mutex); | ||
161 | |||
162 | if (session->calls) { | ||
163 | MSIMessage msg_end; | ||
164 | msg_end.request.exists = true; | ||
165 | msg_end.request.value = requ_end; | ||
166 | |||
167 | MSICall* it = get_call(session, session->calls_head); | ||
168 | for (; it; it = it->next) { | ||
169 | send_message(session->messenger, it->friend_id, &msg_end); | ||
170 | kill_call(it); /* This will eventually free session->calls */ | ||
171 | } | ||
172 | } | ||
173 | |||
174 | pthread_mutex_unlock(session->mutex); | ||
175 | pthread_mutex_destroy(session->mutex); | ||
176 | |||
177 | LOGGER_DEBUG("Terminated session: %p", session); | ||
178 | free ( session ); | ||
179 | return 0; | ||
180 | } | ||
181 | int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_t capabilities ) | ||
182 | { | ||
183 | LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id); | ||
184 | |||
185 | if (get_call(session, friend_id) != NULL) { | ||
186 | LOGGER_ERROR("Already in a call"); | ||
187 | return -1; | ||
188 | } | ||
189 | |||
190 | (*call) = new_call ( session, friend_id ); | ||
191 | |||
192 | if ( *call == NULL ) | ||
193 | return -1; | ||
194 | |||
195 | (*call)->self_capabilities = capabilities; | ||
196 | |||
197 | MSIMessage msg_invite; | ||
198 | msg_invite.request.exists = true; | ||
199 | msg_invite.request.value = requ_invite; | ||
200 | |||
201 | msg_invite.capabilities.exists = true; | ||
202 | msg_invite.capabilities.value = capabilities; | ||
203 | |||
204 | msg_invite.mvfsz.exists = true; | ||
205 | msg_invite.mvfsz.value = htons(D_MVFSZ); | ||
206 | |||
207 | msg_invite.mvfpsz.exists = true; | ||
208 | msg_invite.mvfpsz.value = htons(D_MVFPSZ); | ||
209 | |||
210 | send_message ( (*call)->session->messenger, (*call)->friend_id, &msg_invite ); | ||
211 | |||
212 | (*call)->state = msi_CallRequesting; | ||
213 | |||
214 | LOGGER_DEBUG("Invite sent"); | ||
215 | return 0; | ||
216 | } | ||
217 | int msi_hangup ( MSICall* call ) | ||
218 | { | ||
219 | LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index); | ||
220 | |||
221 | MSIMessage msg_end; | ||
222 | msg_end.request.exists = true; | ||
223 | msg_end.request.value = requ_end; | ||
224 | send_message ( call->session->messenger, call->friend_id, &msg_end ); | ||
225 | |||
226 | kill_call(call); | ||
227 | return 0; | ||
228 | } | ||
229 | int msi_answer ( MSICall* call, uint8_t capabilities ) | ||
230 | { | ||
231 | LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_id); | ||
232 | |||
233 | if ( call->state != msi_CallRequested ) { | ||
234 | LOGGER_ERROR("Call is in invalid state!"); | ||
235 | return -1; | ||
236 | } | ||
237 | |||
238 | call->self_capabilities = capabilities; | ||
239 | |||
240 | MSIMessage msg_starting; | ||
241 | msg_starting.response.exists = true; | ||
242 | msg_starting.response.value = resp_starting; | ||
243 | |||
244 | msg_starting.capabilities.exists = true; | ||
245 | msg_starting.capabilities.value = capabilities; | ||
246 | |||
247 | msg_starting.mvfsz.exists = true; | ||
248 | msg_starting.mvfsz.value = htons(D_MVFSZ); | ||
249 | |||
250 | msg_starting.mvfpsz.exists = true; | ||
251 | msg_starting.mvfpsz.value = htons(D_MVFPSZ); | ||
252 | |||
253 | send_message ( call->session->messenger, call->friend_id, &msg_starting ); | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | int msi_reject ( MSICall* call ) | ||
258 | { | ||
259 | LOGGER_DEBUG("Session: %p Rejecting call: %u; reason: %s", session, call_index, reason ? reason : "Unknown"); | ||
260 | |||
261 | if ( call->state != msi_CallRequested ) { | ||
262 | LOGGER_ERROR("Call is in invalid state!"); | ||
263 | return -1; | ||
264 | } | ||
265 | |||
266 | MSIMessage msg_reject; | ||
267 | msg_reject.request.exists = true; | ||
268 | msg_reject.request.value = requ_reject; | ||
269 | |||
270 | send_message ( call->session->messenger, call->friend_id, &msg_reject ); | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | int msi_change_csettings( MSICall* call, uint8_t capabilities ) | ||
275 | { | ||
276 | call->self_capabilities = capabilities; | ||
277 | |||
278 | MSIMessage msg_invite; | ||
279 | msg_invite.request.exists = true; | ||
280 | msg_invite.request.value = requ_invite; | ||
281 | |||
282 | msg_invite.capabilities.exists = true; | ||
283 | msg_invite.capabilities.value = capabilities; | ||
284 | |||
285 | send_message ( call->session->messenger, call->friend_id, &msg_invite ); | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | |||
291 | |||
292 | /** | ||
293 | * Private functions | ||
294 | */ | ||
295 | |||
296 | int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length ) | ||
96 | { | 297 | { |
97 | /* Parse raw data received from socket into MSIMessage struct */ | 298 | /* Parse raw data received from socket into MSIMessage struct */ |
98 | 299 | ||
@@ -116,10 +317,7 @@ static int parse_input ( MSIMessage *dest, const uint8_t *data, uint16_t length | |||
116 | } while(0) | 317 | } while(0) |
117 | 318 | ||
118 | 319 | ||
119 | if ( dest == NULL ) { | 320 | assert(dest); |
120 | LOGGER_ERROR("Could not parse message: no storage!"); | ||
121 | return -1; | ||
122 | } | ||
123 | 321 | ||
124 | if ( length == 0 || data[length - 1] ) { /* End byte must have value 0 */ | 322 | if ( length == 0 || data[length - 1] ) { /* End byte must have value 0 */ |
125 | LOGGER_ERROR("Invalid end byte"); | 323 | LOGGER_ERROR("Invalid end byte"); |
@@ -139,7 +337,7 @@ static int parse_input ( MSIMessage *dest, const uint8_t *data, uint16_t length | |||
139 | 337 | ||
140 | case IDResponse: | 338 | case IDResponse: |
141 | CHECK_SIZE(it, size_constraint, 1); | 339 | CHECK_SIZE(it, size_constraint, 1); |
142 | CHECK_ENUM_HIGH(it, resp_error); | 340 | CHECK_ENUM_HIGH(it, resp_starting); |
143 | SET_UINT8(it, dest->response); | 341 | SET_UINT8(it, dest->response); |
144 | it += 3; | 342 | it += 3; |
145 | break; | 343 | break; |
@@ -179,22 +377,13 @@ static int parse_input ( MSIMessage *dest, const uint8_t *data, uint16_t length | |||
179 | #undef SET_UINT8 | 377 | #undef SET_UINT8 |
180 | #undef SET_UINT16 | 378 | #undef SET_UINT16 |
181 | } | 379 | } |
182 | 380 | uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length ) | |
183 | static uint8_t *parse_header ( MSIHeaderID id, uint8_t *dest, const void *value, | ||
184 | uint8_t value_len, uint16_t *length ) | ||
185 | { | 381 | { |
186 | /* Parse a single header for sending */ | 382 | /* Parse a single header for sending */ |
383 | assert(dest); | ||
384 | assert(value); | ||
385 | assert(value_len); | ||
187 | 386 | ||
188 | if ( dest == NULL ) { | ||
189 | LOGGER_ERROR("No destination space!"); | ||
190 | return NULL; | ||
191 | } | ||
192 | |||
193 | if (value == NULL || value_len == 0) { | ||
194 | LOGGER_ERROR("Empty header value"); | ||
195 | return NULL; | ||
196 | } | ||
197 | |||
198 | *dest = id; | 387 | *dest = id; |
199 | dest ++; | 388 | dest ++; |
200 | *dest = value_len; | 389 | *dest = value_len; |
@@ -206,20 +395,10 @@ static uint8_t *parse_header ( MSIHeaderID id, uint8_t *dest, const void *value, | |||
206 | 395 | ||
207 | return dest + value_len; /* Set to next position ready to be written */ | 396 | return dest + value_len; /* Set to next position ready to be written */ |
208 | } | 397 | } |
209 | 398 | int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg ) | |
210 | |||
211 | |||
212 | static void call_invoke_callback(MSICall* call, MSICallbackID cb) | ||
213 | { | ||
214 | if ( call->session->callbacks[cb] ) { | ||
215 | LOGGER_DEBUG("Invoking callback function: %d", cb); | ||
216 | call->session->callbacks[cb] ( call->session->agent_handler, call ); | ||
217 | } | ||
218 | } | ||
219 | |||
220 | static int call_send_message ( MSICall *call, const MSIMessage *msg ) | ||
221 | { | 399 | { |
222 | /* Parse and send message */ | 400 | /* Parse and send message */ |
401 | assert(m); | ||
223 | 402 | ||
224 | uint8_t parsed [MSI_MAXMSG_SIZE]; | 403 | uint8_t parsed [MSI_MAXMSG_SIZE]; |
225 | 404 | ||
@@ -228,33 +407,33 @@ static int call_send_message ( MSICall *call, const MSIMessage *msg ) | |||
228 | 407 | ||
229 | if (msg->request.exists) { | 408 | if (msg->request.exists) { |
230 | uint8_t cast = msg->request.value; | 409 | uint8_t cast = msg->request.value; |
231 | it = parse_header(IDRequest, it, &cast, | 410 | it = msg_parse_header_out(IDRequest, it, &cast, |
232 | sizeof(cast), &size); | 411 | sizeof(cast), &size); |
233 | } | 412 | } |
234 | 413 | ||
235 | if (msg->response.exists) { | 414 | if (msg->response.exists) { |
236 | uint8_t cast = msg->response.value; | 415 | uint8_t cast = msg->response.value; |
237 | it = parse_header(IDResponse, it, &cast, | 416 | it = msg_parse_header_out(IDResponse, it, &cast, |
238 | sizeof(cast), &size); | 417 | sizeof(cast), &size); |
239 | } | 418 | } |
240 | 419 | ||
241 | if (msg->error.exists) { | 420 | if (msg->error.exists) { |
242 | it = parse_header(IDError, it, &msg->error.value, | 421 | it = msg_parse_header_out(IDError, it, &msg->error.value, |
243 | sizeof(msg->error.value), &size); | 422 | sizeof(msg->error.value), &size); |
244 | } | 423 | } |
245 | 424 | ||
246 | if (msg->capabilities.exists) { | 425 | if (msg->capabilities.exists) { |
247 | it = parse_header(IDCapabilities, it, &msg->capabilities.value, | 426 | it = msg_parse_header_out(IDCapabilities, it, &msg->capabilities.value, |
248 | sizeof(msg->capabilities.value), &size); | 427 | sizeof(msg->capabilities.value), &size); |
249 | } | 428 | } |
250 | 429 | ||
251 | if (msg->mvfsz.exists) { | 430 | if (msg->mvfsz.exists) { |
252 | it = parse_header(IDMVFSZ, it, &msg->mvfsz.value, | 431 | it = msg_parse_header_out(IDMVFSZ, it, &msg->mvfsz.value, |
253 | sizeof(msg->mvfsz.value), &size); | 432 | sizeof(msg->mvfsz.value), &size); |
254 | } | 433 | } |
255 | 434 | ||
256 | if (msg->mvfpsz.exists) { | 435 | if (msg->mvfpsz.exists) { |
257 | it = parse_header(IDMVFPSZ, it, &msg->mvfpsz.value, | 436 | it = msg_parse_header_out(IDMVFPSZ, it, &msg->mvfpsz.value, |
258 | sizeof(msg->mvfpsz.value), &size); | 437 | sizeof(msg->mvfpsz.value), &size); |
259 | } | 438 | } |
260 | 439 | ||
@@ -266,47 +445,50 @@ static int call_send_message ( MSICall *call, const MSIMessage *msg ) | |||
266 | return -1; | 445 | return -1; |
267 | } | 446 | } |
268 | 447 | ||
269 | if ( m_msi_packet(call->session->messenger_handle, call->friend_id, parsed, size) ) { | 448 | if ( m_msi_packet(m, friend_id, parsed, size) ) { |
270 | LOGGER_DEBUG("Sent message"); | 449 | LOGGER_DEBUG("Sent message"); |
271 | return 0; | 450 | return 0; |
272 | } | 451 | } |
273 | 452 | ||
274 | return -1; | 453 | return -1; |
275 | } | 454 | } |
276 | 455 | int send_error ( Messenger* m, uint32_t friend_id, MSIError error ) | |
277 | static int call_send_error ( MSICall *call, MSIError error ) | ||
278 | { | 456 | { |
279 | /* Send error message */ | 457 | /* Send error message */ |
458 | assert(m); | ||
280 | 459 | ||
281 | if (!call) { | 460 | LOGGER_DEBUG("Sending error: %d to friend: %d", error, friend_id); |
282 | LOGGER_WARNING("Cannot handle error on 'null' call"); | ||
283 | return -1; | ||
284 | } | ||
285 | |||
286 | LOGGER_DEBUG("Sending error: %d to friend: %d", error, call->friend_id); | ||
287 | 461 | ||
288 | MSIMessage msg_error; | 462 | MSIMessage msg_error; |
289 | msg_error.response.exists = true; | ||
290 | msg_error.response.value = resp_error; | ||
291 | 463 | ||
292 | msg_error.error.exists = true; | 464 | msg_error.error.exists = true; |
293 | msg_error.error.value = error; | 465 | msg_error.error.value = error; |
294 | 466 | ||
295 | call_send_message ( call, &msg_error ); | 467 | send_message ( m, friend_id, &msg_error ); |
296 | return 0; | 468 | return 0; |
297 | } | 469 | } |
298 | 470 | static void invoke_callback(MSICall* call, MSICallbackID cb) | |
299 | 471 | { | |
472 | assert(call); | ||
473 | |||
474 | if ( call->session->callbacks[cb] ) { | ||
475 | LOGGER_DEBUG("Invoking callback function: %d", cb); | ||
476 | call->session->callbacks[cb] ( call->session->av, call ); | ||
477 | } | ||
478 | } | ||
300 | static MSICall *get_call ( MSISession *session, uint32_t friend_id ) | 479 | static MSICall *get_call ( MSISession *session, uint32_t friend_id ) |
301 | { | 480 | { |
481 | assert(session); | ||
482 | |||
302 | if (session->calls == NULL || session->calls_tail < friend_id) | 483 | if (session->calls == NULL || session->calls_tail < friend_id) |
303 | return NULL; | 484 | return NULL; |
304 | 485 | ||
305 | return session->calls[friend_id]; | 486 | return session->calls[friend_id]; |
306 | } | 487 | } |
307 | 488 | MSICall *new_call ( MSISession *session, uint32_t friend_id ) | |
308 | static MSICall *new_call ( MSISession *session, uint32_t friend_id ) | ||
309 | { | 489 | { |
490 | assert(session); | ||
491 | |||
310 | MSICall *rc = calloc(sizeof(MSICall), 1); | 492 | MSICall *rc = calloc(sizeof(MSICall), 1); |
311 | 493 | ||
312 | if (rc == NULL) | 494 | if (rc == NULL) |
@@ -353,8 +535,7 @@ static MSICall *new_call ( MSISession *session, uint32_t friend_id ) | |||
353 | session->calls[friend_id] = rc; | 535 | session->calls[friend_id] = rc; |
354 | return rc; | 536 | return rc; |
355 | } | 537 | } |
356 | 538 | void kill_call ( MSICall *call ) | |
357 | static void kill_call ( MSICall *call ) | ||
358 | { | 539 | { |
359 | if ( call == NULL ) | 540 | if ( call == NULL ) |
360 | return; | 541 | return; |
@@ -386,22 +567,21 @@ CLEAR: | |||
386 | session->calls = NULL; | 567 | session->calls = NULL; |
387 | free(call); | 568 | free(call); |
388 | } | 569 | } |
389 | 570 | void on_peer_status(Messenger *m, int friend_id, uint8_t status, void *data) | |
390 | |||
391 | |||
392 | static void on_remote_connection_change(Messenger *messenger, int friend_id, uint8_t status, void *session_p) | ||
393 | { | 571 | { |
394 | (void)messenger; | 572 | (void)m; |
395 | MSISession *session = session_p; | 573 | MSISession *session = data; |
396 | 574 | ||
397 | switch ( status ) { | 575 | switch ( status ) { |
398 | case 0: { /* Went offline */ | 576 | case 0: { /* Friend is now offline */ |
577 | LOGGER_DEBUG("Friend %d is now offline", friend_id); | ||
578 | |||
399 | MSICall* call = get_call(session, friend_id); | 579 | MSICall* call = get_call(session, friend_id); |
400 | 580 | ||
401 | if (call == NULL) | 581 | if (call == NULL) |
402 | return; | 582 | return; |
403 | 583 | ||
404 | call_invoke_callback(call, msi_OnPeerTimeout); | 584 | invoke_callback(call, msi_OnPeerTimeout); |
405 | kill_call(call); | 585 | kill_call(call); |
406 | } | 586 | } |
407 | break; | 587 | break; |
@@ -410,16 +590,9 @@ static void on_remote_connection_change(Messenger *messenger, int friend_id, uin | |||
410 | break; | 590 | break; |
411 | } | 591 | } |
412 | } | 592 | } |
413 | 593 | int handle_recv_invite ( MSICall *call, const MSIMessage *msg ) | |
414 | |||
415 | |||
416 | /********** Request handlers **********/ | ||
417 | static int handle_recv_invite ( MSICall *call, const MSIMessage *msg ) | ||
418 | { | 594 | { |
419 | if ( call == NULL ) { | 595 | assert(call); |
420 | LOGGER_WARNING("Session: %p Handling 'invite' on no call"); | ||
421 | return -1; | ||
422 | } | ||
423 | 596 | ||
424 | MSISession* session = call->session; | 597 | MSISession* session = call->session; |
425 | 598 | ||
@@ -427,19 +600,7 @@ static int handle_recv_invite ( MSICall *call, const MSIMessage *msg ) | |||
427 | 600 | ||
428 | if (!msg->capabilities.exists) { | 601 | if (!msg->capabilities.exists) { |
429 | LOGGER_WARNING("Session: %p Invalid capabilities on 'invite'"); | 602 | LOGGER_WARNING("Session: %p Invalid capabilities on 'invite'"); |
430 | /* TODO send error */ | 603 | call->error = msi_InvalidMessage; |
431 | return -1; | ||
432 | } | ||
433 | |||
434 | if (!msg->mvfsz.exists) { | ||
435 | LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'"); | ||
436 | /* TODO send error */ | ||
437 | return -1; | ||
438 | } | ||
439 | |||
440 | if (!msg->mvfpsz.exists) { | ||
441 | LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'"); | ||
442 | /* TODO send error */ | ||
443 | return -1; | 604 | return -1; |
444 | } | 605 | } |
445 | 606 | ||
@@ -456,14 +617,32 @@ static int handle_recv_invite ( MSICall *call, const MSIMessage *msg ) | |||
456 | 617 | ||
457 | LOGGER_DEBUG("Glare detected!"); | 618 | LOGGER_DEBUG("Glare detected!"); |
458 | 619 | ||
459 | call->peer_capabilities = msg->capabilities; | 620 | if (!msg->mvfsz.exists) { |
621 | LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'"); | ||
622 | call->error = msi_InvalidMessage; | ||
623 | return -1; | ||
624 | } | ||
625 | |||
626 | if (!msg->mvfpsz.exists) { | ||
627 | LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'"); | ||
628 | call->error = msi_InvalidMessage; | ||
629 | return -1; | ||
630 | } | ||
631 | |||
632 | call->peer_capabilities = msg->capabilities.value; | ||
460 | 633 | ||
461 | call->peer_mvfsz = ntohs(msg->mvfsz.value); | 634 | call->peer_mvfsz = ntohs(msg->mvfsz.value); |
462 | call->peer_mvfpsz = ntohs(msg->mvfpsz.value); | 635 | call->peer_mvfpsz = ntohs(msg->mvfpsz.value); |
463 | 636 | ||
637 | if (call->peer_mvfsz > call->peer_mvfpsz) { | ||
638 | LOGGER_WARNING("Session: %p mvfsz param greater than mvfpsz on 'invite'"); | ||
639 | call->error = msi_InvalidParam; | ||
640 | return -1; | ||
641 | } | ||
642 | |||
464 | /* Send response */ | 643 | /* Send response */ |
465 | response.response.value = resp_starting; | 644 | response.response.value = resp_starting; |
466 | call_send_message ( call, &response ); | 645 | send_message ( call->session->messenger, call->friend_id, &response ); |
467 | 646 | ||
468 | return 0; | 647 | return 0; |
469 | } else if ( call->state == msi_CallActive ) { | 648 | } else if ( call->state == msi_CallActive ) { |
@@ -473,21 +652,33 @@ static int handle_recv_invite ( MSICall *call, const MSIMessage *msg ) | |||
473 | */ | 652 | */ |
474 | LOGGER_DEBUG("Peer is changing capabilities"); | 653 | LOGGER_DEBUG("Peer is changing capabilities"); |
475 | 654 | ||
476 | call->peer_capabilities = msg->capabilities; | ||
477 | |||
478 | call->peer_mvfsz = ntohs(msg->mvfsz.value); | ||
479 | call->peer_mvfpsz = ntohs(msg->mvfpsz.value); | ||
480 | |||
481 | /* Send response */ | 655 | /* Send response */ |
482 | response.response.value = resp_starting; | 656 | response.response.value = resp_starting; |
483 | call_send_message ( call, &response ); | 657 | send_message ( call->session->messenger, call->friend_id, &response ); |
484 | 658 | ||
659 | if ( call->peer_capabilities != msg->capabilities.value) { | ||
660 | /* Only invoke callback if capabilities changed */ | ||
661 | call->peer_capabilities = msg->capabilities.value; | ||
662 | invoke_callback(call, msi_OnCapabilities); | ||
663 | } | ||
485 | 664 | ||
486 | call_invoke_callback(call, msi_OnCapabilities); | ||
487 | return 0; | 665 | return 0; |
488 | } | 666 | } |
489 | 667 | ||
490 | call->peer_capabilities = msg->capabilities; | 668 | |
669 | if (!msg->mvfsz.exists) { | ||
670 | LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'"); | ||
671 | call->error = msi_InvalidMessage; | ||
672 | return -1; | ||
673 | } | ||
674 | |||
675 | if (!msg->mvfpsz.exists) { | ||
676 | LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'"); | ||
677 | call->error = msi_InvalidMessage; | ||
678 | return -1; | ||
679 | } | ||
680 | |||
681 | call->peer_capabilities = msg->capabilities.value; | ||
491 | 682 | ||
492 | call->peer_mvfsz = ntohs(msg->mvfsz.value); | 683 | call->peer_mvfsz = ntohs(msg->mvfsz.value); |
493 | call->peer_mvfpsz = ntohs(msg->mvfpsz.value); | 684 | call->peer_mvfpsz = ntohs(msg->mvfpsz.value); |
@@ -496,23 +687,19 @@ static int handle_recv_invite ( MSICall *call, const MSIMessage *msg ) | |||
496 | 687 | ||
497 | /* Send response */ | 688 | /* Send response */ |
498 | response.response.value = resp_ringing; | 689 | response.response.value = resp_ringing; |
499 | call_send_message ( call, &response ); | 690 | send_message ( call->session->messenger, call->friend_id, &response ); |
500 | 691 | ||
501 | 692 | ||
502 | call_invoke_callback(call, msi_OnInvite); | 693 | invoke_callback(call, msi_OnInvite); |
503 | return 0; | 694 | return 0; |
504 | } | 695 | } |
505 | 696 | int handle_recv_start ( MSICall *call, const MSIMessage *msg ) | |
506 | static int handle_recv_start ( MSICall *call, const MSIMessage *msg ) | ||
507 | { | 697 | { |
508 | if ( call == NULL ) { | 698 | assert(call); |
509 | LOGGER_WARNING("Session: %p Handling 'start' on no call"); | ||
510 | return -1; | ||
511 | } | ||
512 | 699 | ||
513 | if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) { | 700 | if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) { |
514 | LOGGER_WARNING("Session: %p Invalid call state on 'start'"); | 701 | LOGGER_WARNING("Session: %p Invalid call state on 'start'"); |
515 | /* TODO send error */ | 702 | call->error = msi_InvalidState; |
516 | return -1; | 703 | return -1; |
517 | } | 704 | } |
518 | 705 | ||
@@ -521,105 +708,88 @@ static int handle_recv_start ( MSICall *call, const MSIMessage *msg ) | |||
521 | LOGGER_DEBUG("Session: %p Handling 'start', friend id: %d", call->session, call->friend_id ); | 708 | LOGGER_DEBUG("Session: %p Handling 'start', friend id: %d", call->session, call->friend_id ); |
522 | 709 | ||
523 | call->state = msi_CallActive; | 710 | call->state = msi_CallActive; |
524 | call_invoke_callback(call, msi_OnStart); | 711 | invoke_callback(call, msi_OnStart); |
525 | 712 | ||
526 | return 0; | 713 | return 0; |
527 | } | 714 | } |
528 | 715 | int handle_recv_reject ( MSICall *call, const MSIMessage *msg ) | |
529 | static int handle_recv_reject ( MSICall *call, const MSIMessage *msg ) | ||
530 | { | 716 | { |
531 | if ( call == NULL ) { | 717 | assert(call); |
532 | LOGGER_WARNING("Session: %p Handling 'start' on no call"); | ||
533 | return -1; | ||
534 | } | ||
535 | 718 | ||
536 | (void)msg; | 719 | (void)msg; |
537 | 720 | ||
538 | if ( call->state != msi_CallRequesting ) { | 721 | if ( call->state != msi_CallRequesting ) { |
539 | LOGGER_WARNING("Session: %p Invalid call state on 'reject'"); | 722 | LOGGER_WARNING("Session: %p Invalid call state on 'reject'"); |
540 | /* TODO send error */ | 723 | call->error = msi_InvalidState; |
541 | return -1; | 724 | return -1; |
542 | } | 725 | } |
543 | 726 | ||
544 | LOGGER_DEBUG("Session: %p Handling 'reject', friend id: %u", call->session, call->friend_id); | 727 | LOGGER_DEBUG("Session: %p Handling 'reject', friend id: %u", call->session, call->friend_id); |
545 | 728 | ||
546 | call_invoke_callback(call, msi_OnReject); | 729 | invoke_callback(call, msi_OnReject); |
547 | kill_call(call); | 730 | kill_call(call); |
548 | 731 | ||
549 | return 0; | 732 | return 0; |
550 | } | 733 | } |
551 | 734 | int handle_recv_end ( MSICall *call, const MSIMessage *msg ) | |
552 | static int handle_recv_end ( MSICall *call, const MSIMessage *msg ) | ||
553 | { | 735 | { |
554 | (void)msg; | 736 | assert(call); |
555 | 737 | ||
556 | if ( call == NULL ) { | 738 | (void)msg; |
557 | LOGGER_WARNING("Session: %p Handling 'start' on no call"); | ||
558 | return -1; | ||
559 | } | ||
560 | 739 | ||
561 | LOGGER_DEBUG("Session: %p Handling 'end', friend id: %d", call->session, call->friend_id); | 740 | LOGGER_DEBUG("Session: %p Handling 'end', friend id: %d", call->session, call->friend_id); |
562 | 741 | ||
563 | call_invoke_callback(call, msi_OnEnd); | 742 | invoke_callback(call, msi_OnEnd); |
564 | kill_call ( call ); | 743 | kill_call ( call ); |
565 | 744 | ||
566 | return 0; | 745 | return 0; |
567 | } | 746 | } |
568 | 747 | int handle_recv_ringing ( MSICall *call, const MSIMessage *msg ) | |
569 | /********** Response handlers **********/ | ||
570 | static int handle_recv_ringing ( MSICall *call, const MSIMessage *msg ) | ||
571 | { | 748 | { |
572 | if ( call == NULL ) { | 749 | assert(call); |
573 | LOGGER_WARNING("Session: %p Handling 'start' on no call"); | ||
574 | return -1; | ||
575 | } | ||
576 | 750 | ||
577 | (void)msg; | 751 | (void)msg; |
578 | 752 | ||
579 | if ( call->state != msi_CallRequesting ) { | 753 | if ( call->state != msi_CallRequesting ) { |
580 | LOGGER_WARNING("Session: %p Invalid call state on 'ringing'"); | 754 | LOGGER_WARNING("Session: %p Invalid call state on 'ringing'"); |
581 | /* TODO send error */ | 755 | call->error = msi_InvalidState; |
582 | return -1; | 756 | return -1; |
583 | } | 757 | } |
584 | 758 | ||
585 | LOGGER_DEBUG("Session: %p Handling 'ringing' friend id: %d", call->session, call->friend_id ); | 759 | LOGGER_DEBUG("Session: %p Handling 'ringing' friend id: %d", call->session, call->friend_id ); |
586 | 760 | ||
587 | call_invoke_callback(call, msi_OnRinging); | 761 | invoke_callback(call, msi_OnRinging); |
588 | return 0; | 762 | return 0; |
589 | } | 763 | } |
590 | 764 | int handle_recv_starting ( MSICall *call, const MSIMessage *msg ) | |
591 | static int handle_recv_starting ( MSICall *call, const MSIMessage *msg ) | ||
592 | { | 765 | { |
593 | if ( call == NULL ) { | 766 | assert(call); |
594 | LOGGER_WARNING("Session: %p Handling 'starting' on non-existing call"); | ||
595 | return 0; | ||
596 | } | ||
597 | 767 | ||
598 | if ( call->state == msi_CallActive ) { | 768 | if ( call->state == msi_CallActive ) { |
599 | LOGGER_DEBUG("Capabilities change confirmed"); | 769 | LOGGER_DEBUG("Capabilities change confirmed"); |
600 | return 0; | 770 | return 0; |
601 | } else if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) { | 771 | } else if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) { |
602 | LOGGER_WARNING("Session: %p Invalid call state on 'starting'"); | 772 | LOGGER_WARNING("Session: %p Invalid call state on 'starting'"); |
603 | /* TODO send error */ | 773 | call->error = msi_InvalidState; |
604 | return -1; | 774 | return -1; |
605 | } | 775 | } |
606 | 776 | ||
607 | if (call->state == msi_CallRequesting) { | 777 | if (call->state == msi_CallRequesting) { |
608 | if (!msg->capabilities.exists) { | 778 | if (!msg->capabilities.exists) { |
609 | LOGGER_WARNING("Session: %p Invalid capabilities on 'starting'"); | 779 | LOGGER_WARNING("Session: %p Invalid capabilities on 'starting'"); |
610 | /* TODO send error */ | 780 | call->error = msi_InvalidParam; |
611 | return -1; | 781 | return -1; |
612 | } | 782 | } |
613 | 783 | ||
614 | if (!msg->mvfsz.exists) { | 784 | if (!msg->mvfsz.exists) { |
615 | LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'"); | 785 | LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'"); |
616 | /* TODO send error */ | 786 | call->error = msi_InvalidParam; |
617 | return -1; | 787 | return -1; |
618 | } | 788 | } |
619 | 789 | ||
620 | if (!msg->mvfpsz.exists) { | 790 | if (!msg->mvfpsz.exists) { |
621 | LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'"); | 791 | LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'"); |
622 | /* TODO send error */ | 792 | call->error = msi_InvalidParam; |
623 | return -1; | 793 | return -1; |
624 | } | 794 | } |
625 | 795 | ||
@@ -628,8 +798,15 @@ static int handle_recv_starting ( MSICall *call, const MSIMessage *msg ) | |||
628 | call->peer_mvfsz = ntohs(msg->mvfsz.value); | 798 | call->peer_mvfsz = ntohs(msg->mvfsz.value); |
629 | call->peer_mvfpsz = ntohs(msg->mvfpsz.value); | 799 | call->peer_mvfpsz = ntohs(msg->mvfpsz.value); |
630 | 800 | ||
801 | |||
802 | if (call->peer_mvfsz > call->peer_mvfpsz) { | ||
803 | LOGGER_WARNING("Session: %p mvfsz param greater than mvfpsz on 'invite'"); | ||
804 | call->error = msi_InvalidParam; | ||
805 | return -1; | ||
806 | } | ||
807 | |||
631 | call->state = msi_CallActive; | 808 | call->state = msi_CallActive; |
632 | call_invoke_callback(call, msi_OnStart); | 809 | invoke_callback(call, msi_OnStart); |
633 | } | 810 | } |
634 | /* Otherwise it's a glare case so don't start until 'start' is recved */ | 811 | /* Otherwise it's a glare case so don't start until 'start' is recved */ |
635 | 812 | ||
@@ -637,65 +814,55 @@ static int handle_recv_starting ( MSICall *call, const MSIMessage *msg ) | |||
637 | MSIMessage msg_start; | 814 | MSIMessage msg_start; |
638 | msg_start.request.exists = true; | 815 | msg_start.request.exists = true; |
639 | msg_start.request.value = requ_start; | 816 | msg_start.request.value = requ_start; |
640 | call_send_message ( call, &msg_start ); | 817 | send_message ( call->session->messenger, call->friend_id, &msg_start ); |
641 | 818 | ||
642 | return 0; | 819 | return 0; |
643 | } | 820 | } |
644 | 821 | int handle_recv_error ( MSICall *call, const MSIMessage *msg ) | |
645 | static int handle_recv_error ( MSICall *call, const MSIMessage *msg ) | ||
646 | { | 822 | { |
647 | if ( call == NULL ) { | 823 | assert(call); |
648 | LOGGER_WARNING("Handling 'error' on non-existing call!"); | ||
649 | return -1; | ||
650 | } | ||
651 | 824 | ||
652 | LOGGER_DEBUG("Session: %p Handling 'error' friend id: %d", call->session, call->friend_id ); | 825 | LOGGER_DEBUG("Session: %p Handling 'error' friend id: %d", call->session, call->friend_id ); |
826 | |||
827 | call->error = msg->error.value; | ||
828 | invoke_callback(call, msi_OnError); | ||
653 | 829 | ||
654 | call_invoke_callback(call, msi_OnError); | 830 | return 0; |
655 | |||
656 | /* TODO Handle error accordingly */ | ||
657 | |||
658 | return -1; | ||
659 | } | 831 | } |
660 | 832 | void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint16_t length, void *object ) | |
661 | static void handle_msi_packet ( Messenger *messenger, int friend_id, const uint8_t *data, | ||
662 | uint16_t length, void *object ) | ||
663 | { | 833 | { |
664 | LOGGER_DEBUG("Got msi message"); | 834 | LOGGER_DEBUG("Got msi message"); |
665 | 835 | ||
666 | /* Unused */ | ||
667 | (void)messenger; | ||
668 | |||
669 | MSISession *session = object; | 836 | MSISession *session = object; |
670 | MSIMessage msg; | 837 | MSIMessage msg; |
838 | |||
839 | int rc = 0; | ||
671 | 840 | ||
672 | if ( parse_input ( &msg, data, length ) == -1 ) { | 841 | if ( msg_parse_in ( &msg, data, length ) == -1 ) { |
673 | LOGGER_WARNING("Error parsing message"); | 842 | LOGGER_WARNING("Error parsing message"); |
843 | send_error(m, friend_id, msi_InvalidMessage); | ||
674 | return; | 844 | return; |
675 | } else { | 845 | } else { |
676 | LOGGER_DEBUG("Successfully parsed message"); | 846 | LOGGER_DEBUG("Successfully parsed message"); |
677 | } | 847 | } |
678 | 848 | ||
679 | pthread_mutex_lock(session->mutex); | ||
680 | |||
681 | MSICall *call = get_call(session, friend_id); | 849 | MSICall *call = get_call(session, friend_id); |
682 | 850 | ||
683 | if (call == NULL) { | 851 | if (call == NULL) { |
684 | if (msg.request != requ_invite) { | 852 | if (msg.request.value != requ_invite) { |
685 | /* TODO send error */ | 853 | send_error(m, friend_id, msi_StrayMessage); |
686 | return; | 854 | return; |
687 | } | 855 | } |
688 | 856 | ||
689 | call = new_call(session, friend_id); | 857 | call = new_call(session, friend_id); |
690 | if (call == NULL) { | 858 | if (call == NULL) { |
691 | /* TODO send error */ | 859 | send_error(m, friend_id, msi_SystemError); |
692 | return; | 860 | return; |
693 | } | 861 | } |
694 | } | 862 | } |
695 | 863 | ||
696 | 864 | ||
697 | /* Now handle message */ | 865 | /* Now handle message */ |
698 | int rc = 0; | ||
699 | if ( msg.request.exists ) { /* Handle request */ | 866 | if ( msg.request.exists ) { /* Handle request */ |
700 | switch (msg.request.value) { | 867 | switch (msg.request.value) { |
701 | case requ_invite: | 868 | case requ_invite: |
@@ -723,201 +890,21 @@ static void handle_msi_packet ( Messenger *messenger, int friend_id, const uint8 | |||
723 | case resp_starting: | 890 | case resp_starting: |
724 | rc = handle_recv_starting ( call, &msg ); | 891 | rc = handle_recv_starting ( call, &msg ); |
725 | break; | 892 | break; |
726 | |||
727 | case resp_error: | ||
728 | rc = handle_recv_error ( call, &msg ); | ||
729 | break; | ||
730 | } | 893 | } |
894 | } else if (msg.error.exists) { | ||
895 | handle_recv_error ( call, &msg ); | ||
896 | rc = -1; | ||
731 | } else { | 897 | } else { |
732 | LOGGER_WARNING("Invalid message: no resp nor requ headers"); | 898 | LOGGER_WARNING("Invalid message; none of the request, response or error!"); |
733 | /* TODO send error */ | 899 | call->error = msi_InvalidMessage; |
734 | rc = -1; | 900 | rc = -1; |
735 | } | 901 | } |
736 | 902 | ||
737 | if (rc == -1) | ||
738 | kill_call(call); | ||
739 | 903 | ||
740 | pthread_mutex_unlock(session->mutex); | 904 | if (rc == -1) { |
741 | } | 905 | if (call->error != msi_ErrorNone) |
742 | 906 | send_error(m, friend_id, call->error); | |
743 | |||
744 | |||
745 | /********** User functions **********/ | ||
746 | void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id) | ||
747 | { | ||
748 | session->callbacks[id] = callback; | ||
749 | } | ||
750 | |||
751 | MSISession *msi_new ( Messenger *messenger ) | ||
752 | { | ||
753 | if (messenger == NULL) { | ||
754 | LOGGER_ERROR("Could not init session on empty messenger!"); | ||
755 | return NULL; | ||
756 | } | ||
757 | |||
758 | MSISession *retu = calloc ( sizeof ( MSISession ), 1 ); | ||
759 | |||
760 | if (retu == NULL) { | ||
761 | LOGGER_ERROR("Allocation failed! Program might misbehave!"); | ||
762 | return NULL; | ||
763 | } | ||
764 | |||
765 | if (create_recursive_mutex(retu->mutex) != 0) { | ||
766 | LOGGER_ERROR("Failed to init mutex! Program might misbehave"); | ||
767 | free(retu); | ||
768 | return NULL; | ||
769 | } | ||
770 | |||
771 | retu->messenger_handle = messenger; | ||
772 | |||
773 | m_callback_msi_packet(messenger, handle_msi_packet, retu ); | ||
774 | |||
775 | /* This is called when remote terminates session */ | ||
776 | m_callback_connectionstatus_internal_av(messenger, on_remote_connection_change, retu); | ||
777 | |||
778 | LOGGER_DEBUG("New msi session: %p ", retu); | ||
779 | return retu; | ||
780 | } | ||
781 | |||
782 | int msi_kill ( MSISession *session ) | ||
783 | { | ||
784 | if (session == NULL) { | ||
785 | LOGGER_ERROR("Tried to terminate non-existing session"); | ||
786 | return -1; | ||
787 | } | ||
788 | |||
789 | m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL); | ||
790 | pthread_mutex_lock(session->mutex); | ||
791 | |||
792 | if (session->calls) { | ||
793 | MSIMessage msg_end; | ||
794 | msg_end.request.exists = true; | ||
795 | msg_end.request.value = requ_end; | ||
796 | 907 | ||
797 | MSICall* it = get_call(session, session->calls_head); | 908 | kill_call(call); |
798 | for (; it; it = it->next) { | ||
799 | call_send_message(it, &msg_end); | ||
800 | kill_call(it); /* This will eventually free session->calls */ | ||
801 | } | ||
802 | } | ||
803 | |||
804 | pthread_mutex_unlock(session->mutex); | ||
805 | pthread_mutex_destroy(session->mutex); | ||
806 | |||
807 | LOGGER_DEBUG("Terminated session: %p", session); | ||
808 | free ( session ); | ||
809 | return 0; | ||
810 | } | ||
811 | |||
812 | int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_t capabilities ) | ||
813 | { | ||
814 | LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id); | ||
815 | |||
816 | if (get_call(session, friend_id) != NULL) { | ||
817 | LOGGER_ERROR("Already in a call"); | ||
818 | return -1; | ||
819 | } | ||
820 | |||
821 | *call = new_call ( session, friend_id ); | ||
822 | |||
823 | if ( *call == NULL ) | ||
824 | return -1; | ||
825 | |||
826 | *call->self_capabilities = capabilities; | ||
827 | |||
828 | MSIMessage msg_invite; | ||
829 | msg_invite.request.exists = true; | ||
830 | msg_invite.request.value = requ_invite; | ||
831 | |||
832 | msg_invite.capabilities.exists = true; | ||
833 | msg_invite.capabilities.value = capabilities; | ||
834 | |||
835 | msg_invite.mvfsz.exists = true; | ||
836 | msg_invite.mvfsz.value = htons(D_MVFSZ); | ||
837 | |||
838 | msg_invite.mvfpsz.exists = true; | ||
839 | msg_invite.mvfpsz.value = htons(D_MVFPSZ); | ||
840 | |||
841 | call_send_message ( *call, &msg_invite ); | ||
842 | |||
843 | *call->state = msi_CallRequesting; | ||
844 | |||
845 | LOGGER_DEBUG("Invite sent"); | ||
846 | return 0; | ||
847 | } | ||
848 | |||
849 | int msi_hangup ( MSICall* call ) | ||
850 | { | ||
851 | LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index); | ||
852 | |||
853 | MSIMessage msg_end; | ||
854 | msg_end.request.exists = true; | ||
855 | msg_end.request.value = requ_end; | ||
856 | call_send_message ( call, &msg_end ); | ||
857 | |||
858 | kill_call(call); | ||
859 | return 0; | ||
860 | } | ||
861 | |||
862 | int msi_answer ( MSICall* call, uint8_t capabilities ) | ||
863 | { | ||
864 | LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_id); | ||
865 | |||
866 | if ( call->state != msi_CallRequested ) { | ||
867 | LOGGER_ERROR("Call is in invalid state!"); | ||
868 | return -1; | ||
869 | } | ||
870 | |||
871 | call->self_capabilities = capabilities; | ||
872 | |||
873 | MSIMessage msg_starting; | ||
874 | msg_starting.response.exists = true; | ||
875 | msg_starting.response.value = resp_starting; | ||
876 | |||
877 | msg_starting.capabilities.exists = true; | ||
878 | msg_starting.capabilities.value = capabilities; | ||
879 | |||
880 | msg_starting.mvfsz.exists = true; | ||
881 | msg_starting.mvfsz.value = htons(D_MVFSZ); | ||
882 | |||
883 | msg_starting.mvfpsz.exists = true; | ||
884 | msg_starting.mvfpsz.value = htons(D_MVFPSZ); | ||
885 | |||
886 | call_send_message ( call, &msg_starting ); | ||
887 | |||
888 | return 0; | ||
889 | } | ||
890 | |||
891 | int msi_reject ( MSICall* call ) | ||
892 | { | ||
893 | LOGGER_DEBUG("Session: %p Rejecting call: %u; reason: %s", session, call_index, reason ? reason : "Unknown"); | ||
894 | |||
895 | if ( call->state != msi_CallRequested ) { | ||
896 | LOGGER_ERROR("Call is in invalid state!"); | ||
897 | return -1; | ||
898 | } | 909 | } |
899 | |||
900 | MSIMessage msg_reject; | ||
901 | msg_reject.request.exists = true; | ||
902 | msg_reject.request.value = requ_reject; | ||
903 | |||
904 | call_send_message ( call, &msg_reject ); | ||
905 | |||
906 | return 0; | ||
907 | } | 910 | } |
908 | |||
909 | int msi_change_csettings( MSICall* call, uint8_t capabilities ) | ||
910 | { | ||
911 | call->self_capabilities = capabilities; | ||
912 | |||
913 | MSIMessage msg_invite; | ||
914 | msg_invite.request.exists = true; | ||
915 | msg_invite.request.value = requ_invite; | ||
916 | |||
917 | msg_invite.capabilities.exists = true; | ||
918 | msg_invite.capabilities.value = capabilities; | ||
919 | |||
920 | call_send_message ( *call, &msg_invite ); | ||
921 | |||
922 | return 0; | ||
923 | } \ No newline at end of file | ||
diff --git a/toxav/msi.h b/toxav/msi.h index a1eb499b..4f27b9f8 100644 --- a/toxav/msi.h +++ b/toxav/msi.h | |||
@@ -36,6 +36,12 @@ | |||
36 | * Error codes. | 36 | * Error codes. |
37 | */ | 37 | */ |
38 | typedef enum { | 38 | typedef enum { |
39 | msi_ErrorNone, | ||
40 | msi_InvalidMessage, | ||
41 | msi_InvalidParam, | ||
42 | msi_InvalidState, | ||
43 | msi_StrayMessage, | ||
44 | msi_SystemError, | ||
39 | msi_ErrUndisclosed, | 45 | msi_ErrUndisclosed, |
40 | } MSIError; | 46 | } MSIError; |
41 | 47 | ||
@@ -69,7 +75,7 @@ typedef enum { | |||
69 | msi_OnStart, /* Call (RTP transmission) started */ | 75 | msi_OnStart, /* Call (RTP transmission) started */ |
70 | msi_OnReject, /* The side that was invited rejected the call */ | 76 | msi_OnReject, /* The side that was invited rejected the call */ |
71 | msi_OnEnd, /* Call that was active ended */ | 77 | msi_OnEnd, /* Call that was active ended */ |
72 | msi_OnError, /* Call that was active ended */ | 78 | msi_OnError, /* On protocol error */ |
73 | msi_OnPeerTimeout, /* Peer timed out; stop the call */ | 79 | msi_OnPeerTimeout, /* Peer timed out; stop the call */ |
74 | msi_OnCapabilities, /* Peer requested capabilities change */ | 80 | msi_OnCapabilities, /* Peer requested capabilities change */ |
75 | } MSICallbackID; | 81 | } MSICallbackID; |
@@ -90,6 +96,10 @@ typedef struct MSICall_s { | |||
90 | 96 | ||
91 | uint32_t friend_id; /* Index of this call in MSISession */ | 97 | uint32_t friend_id; /* Index of this call in MSISession */ |
92 | 98 | ||
99 | MSIError error; /* Last error */ | ||
100 | |||
101 | void* av_call; /* Pointer to av call handler */ | ||
102 | |||
93 | struct MSICall_s* next; | 103 | struct MSICall_s* next; |
94 | struct MSICall_s* prev; | 104 | struct MSICall_s* prev; |
95 | } MSICall; | 105 | } MSICall; |
@@ -109,8 +119,8 @@ typedef struct MSISession_s { | |||
109 | uint32_t calls_tail; | 119 | uint32_t calls_tail; |
110 | uint32_t calls_head; | 120 | uint32_t calls_head; |
111 | 121 | ||
112 | void *agent_handler; | 122 | void *av; |
113 | Messenger *messenger_handle; | 123 | Messenger *messenger; |
114 | 124 | ||
115 | pthread_mutex_t mutex[1]; | 125 | pthread_mutex_t mutex[1]; |
116 | MSICallbackType callbacks[8]; | 126 | MSICallbackType callbacks[8]; |
@@ -119,7 +129,7 @@ typedef struct MSISession_s { | |||
119 | /** | 129 | /** |
120 | * Start the control session. | 130 | * Start the control session. |
121 | */ | 131 | */ |
122 | MSISession *msi_new ( Messenger *messenger, int32_t max_calls ); | 132 | MSISession *msi_new ( Messenger *messenger ); |
123 | 133 | ||
124 | /** | 134 | /** |
125 | * Terminate control session. NOTE: all calls will be freed | 135 | * Terminate control session. NOTE: all calls will be freed |
diff --git a/toxav/toxav.c b/toxav/toxav.c index 864d16cf..12a65737 100644 --- a/toxav/toxav.c +++ b/toxav/toxav.c | |||
@@ -49,8 +49,8 @@ typedef struct iToxAVCall | |||
49 | RTPSession *rtps[2]; /** Audio is first and video is second */ | 49 | RTPSession *rtps[2]; /** Audio is first and video is second */ |
50 | CSSession *cs; | 50 | CSSession *cs; |
51 | bool active; | 51 | bool active; |
52 | int32_t friend_number; | 52 | int32_t friend_id; |
53 | int32_t call_idx; /* FIXME msi compat, remove */ | 53 | MSICall* msi_call; |
54 | 54 | ||
55 | struct iToxAVCall *prev; | 55 | struct iToxAVCall *prev; |
56 | struct iToxAVCall *next; | 56 | struct iToxAVCall *next; |
@@ -80,21 +80,20 @@ struct toxAV | |||
80 | }; | 80 | }; |
81 | 81 | ||
82 | 82 | ||
83 | void i_toxav_msi_callback_invite(void* toxav_inst, int32_t call_idx, void *data); | 83 | void i_callback_invite(void* toxav_inst, MSICall* call); |
84 | void i_toxav_msi_callback_ringing(void* toxav_inst, int32_t call_idx, void *data); | 84 | void i_callback_ringing(void* toxav_inst, MSICall* call); |
85 | void i_toxav_msi_callback_start(void* toxav_inst, int32_t call_idx, void *data); | 85 | void i_callback_start(void* toxav_inst, MSICall* call); |
86 | void i_toxav_msi_callback_reject(void* toxav_inst, int32_t call_idx, void *data); | 86 | void i_callback_end(void* toxav_inst, MSICall* call); |
87 | void i_toxav_msi_callback_end(void* toxav_inst, int32_t call_idx, void *data); | 87 | void i_callback_error(void* toxav_inst, MSICall* call); |
88 | void i_toxav_msi_callback_request_to(void* toxav_inst, int32_t call_idx, void *data); /* TODO remove */ | 88 | void i_callback_capabilites(void* toxav_inst, MSICall* call); |
89 | void i_toxav_msi_callback_peer_to(void* toxav_inst, int32_t call_idx, void *data); | ||
90 | void i_toxav_msi_callback_state_change(void* toxav_inst, int32_t call_idx, void *data); | ||
91 | 89 | ||
90 | TOXAV_CALL_STATE capabilities_to_state(uint8_t capabilities); | ||
92 | IToxAVCall* i_toxav_get_call(ToxAV* av, uint32_t friend_number); | 91 | IToxAVCall* i_toxav_get_call(ToxAV* av, uint32_t friend_number); |
93 | IToxAVCall* i_toxav_add_call(ToxAV* av, uint32_t friend_number); | 92 | IToxAVCall* i_toxav_add_call(ToxAV* av, uint32_t friend_number); |
94 | void i_toxav_remove_call(ToxAV* av, uint32_t friend_number); | 93 | void i_toxav_remove_call(ToxAV* av, uint32_t friend_number); |
94 | IToxAVCall* i_toxav_init_call(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error); | ||
95 | bool i_toxav_audio_bitrate_invalid(uint32_t bitrate); | 95 | bool i_toxav_audio_bitrate_invalid(uint32_t bitrate); |
96 | bool i_toxav_video_bitrate_invalid(uint32_t bitrate); | 96 | bool i_toxav_video_bitrate_invalid(uint32_t bitrate); |
97 | 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); | ||
98 | bool i_toxav_prepare_transmission(ToxAV* av, IToxAVCall* call); | 97 | bool i_toxav_prepare_transmission(ToxAV* av, IToxAVCall* call); |
99 | void i_toxav_kill_transmission(ToxAV* av, uint32_t friend_number); | 98 | void i_toxav_kill_transmission(ToxAV* av, uint32_t friend_number); |
100 | 99 | ||
@@ -124,7 +123,7 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error) | |||
124 | } | 123 | } |
125 | 124 | ||
126 | av->m = (Messenger *)tox; | 125 | av->m = (Messenger *)tox; |
127 | av->msi = msi_new(av->m, 100); /* TODO remove max calls */ | 126 | av->msi = msi_new(av->m); |
128 | 127 | ||
129 | if (av->msi == NULL) { | 128 | if (av->msi == NULL) { |
130 | rc = TOXAV_ERR_NEW_MALLOC; | 129 | rc = TOXAV_ERR_NEW_MALLOC; |
@@ -132,17 +131,16 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error) | |||
132 | } | 131 | } |
133 | 132 | ||
134 | av->interval = 200; | 133 | av->interval = 200; |
135 | av->msi->agent_handler = av; | 134 | av->msi->av = av; |
136 | 135 | ||
137 | msi_register_callback(av->msi, i_toxav_msi_callback_invite, msi_OnInvite, NULL); | 136 | msi_register_callback(av->msi, i_callback_invite, msi_OnInvite); |
138 | msi_register_callback(av->msi, i_toxav_msi_callback_ringing, msi_OnRinging, NULL); | 137 | msi_register_callback(av->msi, i_callback_ringing, msi_OnRinging); |
139 | msi_register_callback(av->msi, i_toxav_msi_callback_start, msi_OnStart, NULL); | 138 | msi_register_callback(av->msi, i_callback_start, msi_OnStart); |
140 | msi_register_callback(av->msi, i_toxav_msi_callback_reject, msi_OnReject, NULL); | 139 | msi_register_callback(av->msi, i_callback_end, msi_OnReject); |
141 | msi_register_callback(av->msi, i_toxav_msi_callback_end, msi_OnEnd, NULL); | 140 | msi_register_callback(av->msi, i_callback_end, msi_OnEnd); |
142 | msi_register_callback(av->msi, i_toxav_msi_callback_request_to, msi_OnRequestTimeout, NULL); | 141 | msi_register_callback(av->msi, i_callback_error, msi_OnError); |
143 | msi_register_callback(av->msi, i_toxav_msi_callback_peer_to, msi_OnPeerTimeout, NULL); | 142 | msi_register_callback(av->msi, i_callback_error, msi_OnPeerTimeout); |
144 | msi_register_callback(av->msi, i_toxav_msi_callback_state_change, msi_OnPeerCSChange, NULL); | 143 | msi_register_callback(av->msi, i_callback_capabilites, msi_OnCapabilities); |
145 | msi_register_callback(av->msi, i_toxav_msi_callback_state_change, msi_OnSelfCSChange, NULL); | ||
146 | 144 | ||
147 | 145 | ||
148 | if (error) | 146 | if (error) |
@@ -209,7 +207,7 @@ void toxav_iteration(ToxAV* av) | |||
209 | 207 | ||
210 | bool toxav_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error) | 208 | bool toxav_call(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_CALL* error) |
211 | { | 209 | { |
212 | IToxAVCall* call = i_toxav_init_call(av, friend_number, audio_bit_rate, video_bit_rate, error); | 210 | IToxAVCall* call = i_toxav_init_call(av, friend_number, error); |
213 | if (call == NULL) { | 211 | if (call == NULL) { |
214 | return false; | 212 | return false; |
215 | } | 213 | } |
@@ -528,109 +526,87 @@ void toxav_callback_receive_audio_frame(ToxAV* av, toxav_receive_audio_frame_cb* | |||
528 | * | 526 | * |
529 | ******************************************************************************/ | 527 | ******************************************************************************/ |
530 | /** TODO: | 528 | /** TODO: |
531 | * - In msi call_idx can be the same as friend id | 529 | * - If crutial callback not present send error. |
532 | * - If crutial callback not present send error | 530 | * - Error handling by return values from callbacks and setting 'error'. |
533 | * - Remove *data from msi | ||
534 | * - Remove CSettings from msi | ||
535 | */ | 531 | */ |
536 | void i_toxav_msi_callback_invite(void* toxav_inst, int32_t call_idx, void* data) | 532 | void i_callback_invite(void* toxav_inst, MSICall* call) |
537 | { | 533 | { |
538 | ToxAV* toxav = toxav_inst; | 534 | ToxAV* toxav = toxav_inst; |
539 | 535 | ||
540 | uint32_t ab = toxav->msi->calls[call_idx]->csettings_peer[0].audio_bitrate; | 536 | IToxAVCall* av_call = i_toxav_init_call(toxav, call->friend_id, NULL); |
541 | uint32_t vb = toxav->msi->calls[call_idx]->csettings_peer[0].video_bitrate; | 537 | if (av_call == NULL) { |
542 | 538 | LOGGER_WARNING("Failed to start call, rejecting..."); | |
543 | IToxAVCall* call = i_toxav_init_call(toxav, toxav->msi->calls[call_idx]->peers[0], ab, vb, NULL); | 539 | msi_reject(toxav->msi, call); |
544 | if (call == NULL) { | 540 | return; |
545 | LOGGER_WARNING("No call, rejecting..."); | ||
546 | msi_reject(toxav->msi, call_idx, NULL); | ||
547 | } | 541 | } |
548 | 542 | ||
549 | call->call_idx = call_idx; | 543 | call->av_call = av_call; |
544 | av_call->msi_call = call; | ||
550 | 545 | ||
551 | if (toxav->ccb.first) | 546 | if (toxav->ccb.first) |
552 | toxav->ccb.first(toxav, toxav->msi->calls[call_idx]->peers[0], true, true, toxav->ccb.second); | 547 | toxav->ccb.first(toxav, call->friend_id, call->peer_capabilities & msi_CapSAudio, |
548 | call->peer_capabilities & msi_CapSVideo, toxav->ccb.second); | ||
553 | } | 549 | } |
554 | 550 | ||
555 | void i_toxav_msi_callback_ringing(void* toxav_inst, int32_t call_idx, void* data) | 551 | void i_callback_ringing(void* toxav_inst, MSICall* call) |
556 | { | 552 | { |
557 | ToxAV* toxav = toxav_inst; | 553 | ToxAV* toxav = toxav_inst; |
558 | if (toxav->scb.first) | 554 | if (toxav->scb.first) |
559 | toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0], | 555 | toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_RINGING, toxav->scb.second); |
560 | TOXAV_CALL_STATE_RINGING, toxav->scb.second); | ||
561 | } | 556 | } |
562 | 557 | ||
563 | void i_toxav_msi_callback_start(void* toxav_inst, int32_t call_idx, void* data) | 558 | void i_callback_start(void* toxav_inst, MSICall* call) |
564 | { | 559 | { |
565 | ToxAV* toxav = toxav_inst; | 560 | ToxAV* toxav = toxav_inst; |
566 | 561 | ||
567 | IToxAVCall* call = i_toxav_get_call(toxav, toxav->msi->calls[call_idx]->peers[0]); | 562 | IToxAVCall* call = i_toxav_get_call(toxav, call->friend_id); |
568 | 563 | ||
569 | if (call == NULL || !i_toxav_prepare_transmission(toxav, call)) { | 564 | if (call == NULL || !i_toxav_prepare_transmission(toxav, call)) { |
570 | /* TODO send error */ | 565 | /* TODO send error */ |
571 | i_toxav_remove_call(toxav, toxav->msi->calls[call_idx]->peers[0]); | 566 | i_toxav_remove_call(toxav, call->friend_id); |
572 | return; | 567 | return; |
573 | } | 568 | } |
574 | 569 | ||
575 | TOXAV_CALL_STATE state; | 570 | TOXAV_CALL_STATE state = capabilities_to_state(call->msi_call->peer_capabilities); |
576 | const MSICSettings* csets = &toxav->msi->calls[call_idx]->csettings_peer[0]; | ||
577 | |||
578 | if (csets->audio_bitrate && csets->video_bitrate) | ||
579 | state = TOXAV_CALL_STATE_SENDING_AV; | ||
580 | else if (csets->video_bitrate == 0) | ||
581 | state = TOXAV_CALL_STATE_SENDING_A; | ||
582 | else | ||
583 | state = TOXAV_CALL_STATE_SENDING_V; | ||
584 | |||
585 | if (toxav->scb.first) /* TODO this */ | ||
586 | toxav->scb.first(toxav, call->friend_number, state, toxav->scb.second); | ||
587 | } | ||
588 | |||
589 | void i_toxav_msi_callback_reject(void* toxav_inst, int32_t call_idx, void* data) | ||
590 | { | ||
591 | ToxAV* toxav = toxav_inst; | ||
592 | |||
593 | i_toxav_kill_transmission(toxav, toxav->msi->calls[call_idx]->peers[0]); | ||
594 | i_toxav_remove_call(toxav, toxav->msi->calls[call_idx]->peers[0]); | ||
595 | 571 | ||
596 | if (toxav->scb.first) | 572 | if (toxav->scb.first) |
597 | toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0], | 573 | toxav->scb.first(toxav, call->friend_id, state, toxav->scb.second); |
598 | TOXAV_CALL_STATE_END, toxav->scb.second); | ||
599 | } | 574 | } |
600 | 575 | ||
601 | void i_toxav_msi_callback_end(void* toxav_inst, int32_t call_idx, void* data) | 576 | void i_callback_end(void* toxav_inst, MSICall* call) |
602 | { | 577 | { |
603 | ToxAV* toxav = toxav_inst; | 578 | ToxAV* toxav = toxav_inst; |
604 | 579 | ||
605 | i_toxav_kill_transmission(toxav, toxav->msi->calls[call_idx]->peers[0]); | 580 | i_toxav_kill_transmission(toxav, call->friend_id); |
606 | i_toxav_remove_call(toxav, toxav->msi->calls[call_idx]->peers[0]); | 581 | i_toxav_remove_call(toxav, call->friend_id); |
607 | 582 | ||
608 | if (toxav->scb.first) | 583 | if (toxav->scb.first) |
609 | toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0], | 584 | toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_END, toxav->scb.second); |
610 | TOXAV_CALL_STATE_END, toxav->scb.second); | ||
611 | } | 585 | } |
612 | 586 | ||
613 | void i_toxav_msi_callback_request_to(void* toxav_inst, int32_t call_idx, void* data) | 587 | void i_callback_error(void* toxav_inst, MSICall* call) |
614 | { | 588 | { |
615 | /* TODO remove */ | ||
616 | ToxAV* toxav = toxav_inst; | 589 | ToxAV* toxav = toxav_inst; |
617 | if (toxav->scb.first) | 590 | if (toxav->scb.first) |
618 | toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0], | 591 | toxav->scb.first(toxav, call->friend_id, TOXAV_CALL_STATE_ERROR, toxav->scb.second); |
619 | TOXAV_CALL_STATE_ERROR, toxav->scb.second); | ||
620 | } | 592 | } |
621 | 593 | ||
622 | void i_toxav_msi_callback_peer_to(void* toxav_inst, int32_t call_idx, void* data) | 594 | void i_callback_capabilites(void* toxav_inst, MSICall* call) |
623 | { | 595 | { |
624 | ToxAV* toxav = toxav_inst; | 596 | ToxAV* toxav = toxav_inst; |
625 | if (toxav->scb.first) | 597 | /* TODO something something msi */ |
626 | toxav->scb.first(toxav, toxav->msi->calls[call_idx]->peers[0], | ||
627 | TOXAV_CALL_STATE_ERROR, toxav->scb.second); | ||
628 | } | 598 | } |
629 | 599 | ||
630 | void i_toxav_msi_callback_state_change(void* toxav_inst, int32_t call_idx, void* data) | 600 | TOXAV_CALL_STATE capabilities_to_state(uint8_t capabilities) |
631 | { | 601 | { |
632 | ToxAV* toxav = toxav_inst; | 602 | if ((capabilities & msi_CapSAudio) && (capabilities & msi_CapSVideo)) |
633 | /* TODO something something msi */ | 603 | return TOXAV_CALL_STATE_SENDING_AV; |
604 | else if (capabilities & msi_CapSAudio) | ||
605 | return TOXAV_CALL_STATE_SENDING_A; | ||
606 | else if (capabilities & msi_CapSVideo) | ||
607 | return TOXAV_CALL_STATE_SENDING_V; | ||
608 | else | ||
609 | return TOXAV_CALL_STATE_PAUSED; | ||
634 | } | 610 | } |
635 | 611 | ||
636 | IToxAVCall* i_toxav_get_call(ToxAV* av, uint32_t friend_number) | 612 | IToxAVCall* i_toxav_get_call(ToxAV* av, uint32_t friend_number) |
@@ -648,7 +624,7 @@ IToxAVCall* i_toxav_add_call(ToxAV* av, uint32_t friend_number) | |||
648 | if (rc == NULL) | 624 | if (rc == NULL) |
649 | return NULL; | 625 | return NULL; |
650 | 626 | ||
651 | rc->friend_number = friend_number; | 627 | rc->friend_id = friend_number; |
652 | 628 | ||
653 | if (create_recursive_mutex(rc->mutex_control) != 0) { | 629 | if (create_recursive_mutex(rc->mutex_control) != 0) { |
654 | free(rc); | 630 | free(rc); |
@@ -724,13 +700,13 @@ void i_toxav_remove_call(ToxAV* av, uint32_t friend_number) | |||
724 | if (prev) | 700 | if (prev) |
725 | prev->next = next; | 701 | prev->next = next; |
726 | else if (next) | 702 | else if (next) |
727 | av->calls_head = next->friend_number; | 703 | av->calls_head = next->friend_id; |
728 | else goto CLEAR; | 704 | else goto CLEAR; |
729 | 705 | ||
730 | if (next) | 706 | if (next) |
731 | next->prev = prev; | 707 | next->prev = prev; |
732 | else if (prev) | 708 | else if (prev) |
733 | av->calls_tail = prev->friend_number; | 709 | av->calls_tail = prev->friend_id; |
734 | else goto CLEAR; | 710 | else goto CLEAR; |
735 | 711 | ||
736 | av->calls[friend_number] = NULL; | 712 | av->calls[friend_number] = NULL; |
@@ -742,21 +718,7 @@ CLEAR: | |||
742 | av->calls = NULL; | 718 | av->calls = NULL; |
743 | } | 719 | } |
744 | 720 | ||
745 | bool i_toxav_audio_bitrate_invalid(uint32_t bitrate) | 721 | IToxAVCall* i_toxav_init_call(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error) |
746 | { | ||
747 | /* Opus RFC 6716 section-2.1.1 dictates the following: | ||
748 | * Opus supports all bitrates from 6 kbit/s to 510 kbit/s. | ||
749 | */ | ||
750 | return bitrate < 6 || bitrate > 510; | ||
751 | } | ||
752 | |||
753 | bool i_toxav_video_bitrate_invalid(uint32_t bitrate) | ||
754 | { | ||
755 | /* TODO: If anyone knows the answer to this one please fill it up */ | ||
756 | return false; | ||
757 | } | ||
758 | |||
759 | 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) | ||
760 | { | 722 | { |
761 | TOXAV_ERR_CALL rc = TOXAV_ERR_CALL_OK; | 723 | TOXAV_ERR_CALL rc = TOXAV_ERR_CALL_OK; |
762 | IToxAVCall* call = NULL; | 724 | IToxAVCall* call = NULL; |
@@ -776,25 +738,32 @@ IToxAVCall* i_toxav_init_call(ToxAV* av, uint32_t friend_number, uint32_t audio_ | |||
776 | goto END; | 738 | goto END; |
777 | } | 739 | } |
778 | 740 | ||
779 | if ((audio_bit_rate && i_toxav_audio_bitrate_invalid(audio_bit_rate)) | ||
780 | ||(video_bit_rate && i_toxav_video_bitrate_invalid(video_bit_rate)) | ||
781 | ) { | ||
782 | rc = TOXAV_ERR_CALL_INVALID_BIT_RATE; | ||
783 | goto END; | ||
784 | } | ||
785 | |||
786 | call = i_toxav_add_call(av, friend_number); | 741 | call = i_toxav_add_call(av, friend_number); |
787 | if (call == NULL) { | 742 | if (call == NULL) { |
788 | rc = TOXAV_ERR_CALL_MALLOC; | 743 | rc = TOXAV_ERR_CALL_MALLOC; |
789 | } | 744 | } |
790 | 745 | ||
791 | END: | 746 | END: |
792 | if (error) | 747 | if (error) |
793 | *error = rc; | 748 | *error = rc; |
794 | 749 | ||
795 | return call; | 750 | return call; |
796 | } | 751 | } |
797 | 752 | ||
753 | bool i_toxav_audio_bitrate_invalid(uint32_t bitrate) | ||
754 | { | ||
755 | /* Opus RFC 6716 section-2.1.1 dictates the following: | ||
756 | * Opus supports all bitrates from 6 kbit/s to 510 kbit/s. | ||
757 | */ | ||
758 | return bitrate < 6 || bitrate > 510; | ||
759 | } | ||
760 | |||
761 | bool i_toxav_video_bitrate_invalid(uint32_t bitrate) | ||
762 | { | ||
763 | /* TODO: If anyone knows the answer to this one please fill it up */ | ||
764 | return false; | ||
765 | } | ||
766 | |||
798 | bool i_toxav_prepare_transmission(ToxAV* av, IToxAVCall* call) | 767 | bool i_toxav_prepare_transmission(ToxAV* av, IToxAVCall* call) |
799 | { | 768 | { |
800 | pthread_mutex_lock(call->mutex_control); | 769 | pthread_mutex_lock(call->mutex_control); |
@@ -838,7 +807,7 @@ bool i_toxav_prepare_transmission(ToxAV* av, IToxAVCall* call) | |||
838 | memcpy(&call->cs->acb, &av->acb, sizeof(av->acb)); | 807 | memcpy(&call->cs->acb, &av->acb, sizeof(av->acb)); |
839 | memcpy(&call->cs->vcb, &av->vcb, sizeof(av->vcb)); | 808 | memcpy(&call->cs->vcb, &av->vcb, sizeof(av->vcb)); |
840 | 809 | ||
841 | call->cs->friend_number = call->friend_number; | 810 | call->cs->friend_number = call->friend_id; |
842 | call->cs->call_idx = call->call_idx; | 811 | call->cs->call_idx = call->call_idx; |
843 | 812 | ||
844 | 813 | ||
@@ -929,4 +898,4 @@ void i_toxav_kill_transmission(ToxAV* av, uint32_t friend_number) | |||
929 | pthread_mutex_destroy(call->mutex_do); | 898 | pthread_mutex_destroy(call->mutex_do); |
930 | 899 | ||
931 | pthread_mutex_unlock(call->mutex_control); | 900 | pthread_mutex_unlock(call->mutex_control); |
932 | } | 901 | } \ No newline at end of file |