summaryrefslogtreecommitdiff
path: root/toxav
diff options
context:
space:
mode:
Diffstat (limited to 'toxav')
-rw-r--r--toxav/codec.c20
-rw-r--r--toxav/codec.h8
-rw-r--r--toxav/msi.c581
-rw-r--r--toxav/msi.h71
-rw-r--r--toxav/rtp.c8
-rw-r--r--toxav/rtp.h55
-rw-r--r--toxav/toxav.c6
-rw-r--r--toxav/toxav.h21
8 files changed, 359 insertions, 411 deletions
diff --git a/toxav/codec.c b/toxav/codec.c
index e6fe713e..9fc14071 100644
--- a/toxav/codec.c
+++ b/toxav/codec.c
@@ -1,8 +1,6 @@
1/** codec.c 1/** codec.c
2 * 2 *
3 * Audio and video codec intitialization, encoding/decoding and playback 3 * Copyright (C) 2013-2015 Tox project All Rights Reserved.
4 *
5 * Copyright (C) 2013 Tox project All Rights Reserved.
6 * 4 *
7 * This file is part of Tox. 5 * This file is part of Tox.
8 * 6 *
@@ -124,7 +122,7 @@ static void buffer_free(PayloadBuffer *b)
124} 122}
125 123
126/* JITTER BUFFER WORK */ 124/* JITTER BUFFER WORK */
127typedef struct JitterBuffer { 125typedef struct JitterBuffer_s {
128 RTPMessage **queue; 126 RTPMessage **queue;
129 uint32_t size; 127 uint32_t size;
130 uint32_t capacity; 128 uint32_t capacity;
@@ -711,11 +709,6 @@ int cs_enable_audio_sending(CSSession* cs, uint32_t bitrate, int channels)
711 if (cs->audio_encoder) 709 if (cs->audio_encoder)
712 return 0; 710 return 0;
713 711
714 /**
715 * Encoder is initialized with default values. These values (Sampling rate, channel count)
716 * change on the fly from toxav.
717 */
718
719 int rc = OPUS_OK; 712 int rc = OPUS_OK;
720 cs->audio_encoder = opus_encoder_create(48000, channels, OPUS_APPLICATION_AUDIO, &rc); 713 cs->audio_encoder = opus_encoder_create(48000, channels, OPUS_APPLICATION_AUDIO, &rc);
721 714
@@ -750,12 +743,7 @@ int cs_enable_audio_receiving(CSSession* cs)
750{ 743{
751 if (cs->audio_decoder) 744 if (cs->audio_decoder)
752 return 0; 745 return 0;
753 746
754 /**
755 * Decoder is initialized with default values. These values (Sampling rate, channel count)
756 * change on the fly from toxav.
757 */
758
759 int rc; 747 int rc;
760 cs->audio_decoder = opus_decoder_create(48000, 2, &rc ); 748 cs->audio_decoder = opus_decoder_create(48000, 2, &rc );
761 749
@@ -792,7 +780,7 @@ void queue_message(RTPSession *session, RTPMessage *msg)
792 if (!cs) return; 780 if (!cs) return;
793 781
794 /* Audio */ 782 /* Audio */
795 if (session->payload_type == msi_TypeAudio % 128) { 783 if (session->payload_type == rtp_TypeAudio % 128) {
796 pthread_mutex_lock(cs->queue_mutex); 784 pthread_mutex_lock(cs->queue_mutex);
797 int ret = jbuf_write(cs->j_buf, msg); 785 int ret = jbuf_write(cs->j_buf, msg);
798 pthread_mutex_unlock(cs->queue_mutex); 786 pthread_mutex_unlock(cs->queue_mutex);
diff --git a/toxav/codec.h b/toxav/codec.h
index 02a3b1b4..b5eb19e2 100644
--- a/toxav/codec.h
+++ b/toxav/codec.h
@@ -1,8 +1,6 @@
1/** codec.h 1/** codec.h
2 * 2 *
3 * Audio and video codec intitialization, encoding/decoding and playback 3 * Copyright (C) 2013-2015 Tox project All Rights Reserved.
4 *
5 * Copyright (C) 2013 Tox project All Rights Reserved.
6 * 4 *
7 * This file is part of Tox. 5 * This file is part of Tox.
8 * 6 *
@@ -69,7 +67,7 @@ typedef enum {
69/** 67/**
70 * Codec session - controling codec 68 * Codec session - controling codec
71 */ 69 */
72typedef struct _CSSession { 70typedef struct CSSession_s {
73 71
74 /* VIDEO 72 /* VIDEO
75 * 73 *
@@ -117,7 +115,7 @@ typedef struct _CSSession {
117 int32_t last_pack_channels; 115 int32_t last_pack_channels;
118 int32_t last_packet_sampling_rate; 116 int32_t last_packet_sampling_rate;
119 int32_t last_packet_frame_duration; 117 int32_t last_packet_frame_duration;
120 struct JitterBuffer *j_buf; 118 struct JitterBuffer_s *j_buf;
121 119
122 120
123 /* Voice activity detection */ 121 /* Voice activity detection */
diff --git a/toxav/msi.c b/toxav/msi.c
index e78c57fe..c1342950 100644
--- a/toxav/msi.c
+++ b/toxav/msi.c
@@ -1,6 +1,6 @@
1/** msi.c 1/** msi.c
2 * 2 *
3 * Copyright (C) 2013 Tox project All Rights Reserved. 3 * Copyright (C) 2013-2015 Tox project All Rights Reserved.
4 * 4 *
5 * This file is part of Tox. 5 * This file is part of Tox.
6 * 6 *
@@ -36,11 +36,6 @@
36 36
37#define MSI_MAXMSG_SIZE 256 37#define MSI_MAXMSG_SIZE 256
38 38
39/* Define default timeout for a request.
40 * There is no behavior specified by the msi on what will
41 * client do on timeout, but to call timeout callback.
42 */
43#define m_deftout 10000 /* in milliseconds */
44 39
45/** 40/**
46 * Protocol: 41 * Protocol:
@@ -53,17 +48,11 @@ typedef enum {
53 IDResponse, 48 IDResponse,
54 IDError, 49 IDError,
55 IDCapabilities, 50 IDCapabilities,
51 IDMVFSZ,
52 IDMVFPSZ,
56 53
57} MSIHeaderID; 54} MSIHeaderID;
58 55
59/**
60 * Headers
61 */
62typedef enum {
63 type_request,
64 type_response,
65} MSIMessageType;
66
67typedef enum { 56typedef enum {
68 requ_invite, 57 requ_invite,
69 requ_start, 58 requ_start,
@@ -77,17 +66,20 @@ typedef enum {
77 resp_error, 66 resp_error,
78} MSIResponse; 67} MSIResponse;
79 68
69
80#define GENERIC_HEADER(header, val_type) \ 70#define GENERIC_HEADER(header, val_type) \
81typedef struct { \ 71typedef struct { \
82val_type value; \ 72val_type value; \
83_Bool exists; \ 73bool exists; \
84} MSIHeader##header; 74} MSIHeader##header
85 75
86 76
87GENERIC_HEADER ( Request, MSIRequest ) 77GENERIC_HEADER ( Request, MSIRequest );
88GENERIC_HEADER ( Response, MSIResponse ) 78GENERIC_HEADER ( Response, MSIResponse );
89GENERIC_HEADER ( Error, MSIError ) 79GENERIC_HEADER ( Error, MSIError );
90GENERIC_HEADER ( Capabilities, uint8_t ) 80GENERIC_HEADER ( Capabilities, uint8_t );
81GENERIC_HEADER ( MVFSZ, uint16_t );
82GENERIC_HEADER ( MVFPSZ, uint16_t );
91 83
92 84
93typedef struct { 85typedef struct {
@@ -95,63 +87,36 @@ typedef struct {
95 MSIHeaderResponse response; 87 MSIHeaderResponse response;
96 MSIHeaderError error; 88 MSIHeaderError error;
97 MSIHeaderCapabilities capabilities; 89 MSIHeaderCapabilities capabilities;
90 MSIHeaderMVFSZ mvfsz; /* Max video frame size. NOTE: Value must be in network b-order */
91 MSIHeaderMVFPSZ mvfpsz; /* Max video frame piece size. NOTE: Value must be in network b-order */
98} MSIMessage; 92} MSIMessage;
99 93
100 94
101static void invoke_callback(MSICall* c, MSICallbackID i) 95static int parse_input ( MSIMessage *dest, const uint8_t *data, uint16_t length )
102{
103 if ( c->session->callbacks[i] ) {
104 LOGGER_DEBUG("Invoking callback function: %d", i);
105 c->session->callbacks[i] ( c->session->agent_handler, c );
106 }
107}
108
109/**
110 * Create the message.
111 */
112static MSIMessage *msi_new_message ( MSIMessageType type, const uint8_t type_value )
113{
114 MSIMessage *retu = calloc ( sizeof ( MSIMessage ), 1 );
115
116 if ( retu == NULL ) {
117 LOGGER_WARNING("Allocation failed! Program might misbehave!");
118 return NULL;
119 }
120
121 if ( type == type_request ) {
122 retu->request.exists = 1;
123 retu->request.value = type_value;
124
125 } else {
126 retu->response.exists = 1;
127 retu->response.value = type_value;
128 }
129
130 return retu;
131}
132
133
134/**
135 * Parse raw data received from socket into MSIMessage struct.
136 */
137static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length )
138{ 96{
139 97 /* Parse raw data received from socket into MSIMessage struct */
98
140#define CHECK_SIZE(bytes, constraint, size) \ 99#define CHECK_SIZE(bytes, constraint, size) \
141 if ((constraint -= 3) < 1) { LOGGER_ERROR("Read over length!"); return -1; } \ 100 if ((constraint -= (2 + size)) < 1) { LOGGER_ERROR("Read over length!"); return -1; } \
142 if ( bytes[1] != size ) { LOGGER_ERROR("Invalid data size!"); return -1; } 101 if ( bytes[1] != size ) { LOGGER_ERROR("Invalid data size!"); return -1; }
143 102
144#define CHECK_ENUM_HIGH(bytes, enum_high) \ 103#define CHECK_ENUM_HIGH(bytes, enum_high) /* Assumes size == 1 */ \
145 if ( bytes[2] > enum_high ) { LOGGER_ERROR("Failed enum high limit!"); return -1; } 104 if ( bytes[2] > enum_high ) { LOGGER_ERROR("Failed enum high limit!"); return -1; }
146 105
147#define SET_VALUES(bytes, header) do { \ 106#define SET_UINT8(bytes, header) do { \
148 header.value = bytes[2]; \ 107 header.value = bytes[2]; \
149 header.exists = 1; \ 108 header.exists = true; \
150 bytes += 3; \ 109 bytes += 3; \
151 } while(0) 110 } while(0)
152 111
153 112#define SET_UINT16(bytes, header) do { \
154 if ( msg == NULL ) { 113 memcpy(&header.value, bytes + 2, 2);\
114 header.exists = true; \
115 bytes += 4; \
116 } while(0)
117
118
119 if ( dest == NULL ) {
155 LOGGER_ERROR("Could not parse message: no storage!"); 120 LOGGER_ERROR("Could not parse message: no storage!");
156 return -1; 121 return -1;
157 } 122 }
@@ -169,25 +134,35 @@ static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t lengt
169 case IDRequest: 134 case IDRequest:
170 CHECK_SIZE(it, size_constraint, 1); 135 CHECK_SIZE(it, size_constraint, 1);
171 CHECK_ENUM_HIGH(it, requ_end); 136 CHECK_ENUM_HIGH(it, requ_end);
172 SET_VALUES(it, msg->request); 137 SET_UINT8(it, dest->request);
173 break; 138 break;
174 139
175 case IDResponse: 140 case IDResponse:
176 CHECK_SIZE(it, size_constraint, 1); 141 CHECK_SIZE(it, size_constraint, 1);
177 CHECK_ENUM_HIGH(it, resp_error); 142 CHECK_ENUM_HIGH(it, resp_error);
178 SET_VALUES(it, msg->response); 143 SET_UINT8(it, dest->response);
179 it += 3; 144 it += 3;
180 break; 145 break;
181 146
182 case IDError: 147 case IDError:
183 CHECK_SIZE(it, size_constraint, 1); 148 CHECK_SIZE(it, size_constraint, 1);
184 CHECK_ENUM_HIGH(it, msi_ErrUndisclosed); 149 CHECK_ENUM_HIGH(it, msi_ErrUndisclosed);
185 SET_VALUES(it, msg->error); 150 SET_UINT8(it, dest->error);
186 break; 151 break;
187 152
188 case IDCapabilities: 153 case IDCapabilities:
189 CHECK_SIZE(it, size_constraint, 1); 154 CHECK_SIZE(it, size_constraint, 1);
190 SET_VALUES(it, msg->capabilities); 155 SET_UINT8(it, dest->capabilities);
156 break;
157
158 case IDMVFSZ:
159 CHECK_SIZE(it, size_constraint, 2);
160 SET_UINT16(it, dest->mvfsz);
161 break;
162
163 case IDMVFPSZ:
164 CHECK_SIZE(it, size_constraint, 2);
165 SET_UINT16(it, dest->mvfpsz);
191 break; 166 break;
192 167
193 default: 168 default:
@@ -201,42 +176,15 @@ static int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t lengt
201 176
202#undef CHECK_SIZE 177#undef CHECK_SIZE
203#undef CHECK_ENUM_HIGH 178#undef CHECK_ENUM_HIGH
204#undef SET_VALUES 179#undef SET_UINT8
205} 180#undef SET_UINT16
206
207/**
208 * Parse data from handle_packet.
209 */
210static MSIMessage *parse_in ( const uint8_t *data, uint16_t length )
211{
212 if ( data == NULL ) {
213 LOGGER_WARNING("Tried to parse empty message!");
214 return NULL;
215 }
216
217 MSIMessage *retu = calloc ( sizeof ( MSIMessage ), 1 );
218
219 if ( retu == NULL ) {
220 LOGGER_WARNING("Allocation failed! Program might misbehave!");
221 return NULL;
222 }
223
224 if ( parse_raw_data ( retu, data, length ) == -1 ) {
225
226 free ( retu );
227 return NULL;
228 }
229
230 return retu;
231} 181}
232 182
233 183static uint8_t *parse_header ( MSIHeaderID id, uint8_t *dest, const void *value,
234/** 184 uint8_t value_len, uint16_t *length )
235 * Speaks for itself.
236 */
237static uint8_t *prepare_header ( MSIHeaderID id, uint8_t *dest, const void *value,
238 uint8_t value_len, uint16_t *length )
239{ 185{
186 /* Parse a single header for sending */
187
240 if ( dest == NULL ) { 188 if ( dest == NULL ) {
241 LOGGER_ERROR("No destination space!"); 189 LOGGER_ERROR("No destination space!");
242 return NULL; 190 return NULL;
@@ -260,60 +208,65 @@ static uint8_t *prepare_header ( MSIHeaderID id, uint8_t *dest, const void *valu
260} 208}
261 209
262 210
263/** 211
264 * Parse MSIMessage to send. Returns size in bytes of the parsed message 212static void call_invoke_callback(MSICall* call, MSICallbackID cb)
265 */
266static uint16_t parse_out ( MSIMessage *msg, uint8_t *dest )
267{ 213{
268 if (msg == NULL) { 214 if ( call->session->callbacks[cb] ) {
269 LOGGER_ERROR("No message!"); 215 LOGGER_DEBUG("Invoking callback function: %d", cb);
270 return 0; 216 call->session->callbacks[cb] ( call->session->agent_handler, call );
271 } 217 }
218}
272 219
273 if (dest == NULL ) { 220static int call_send_message ( MSICall *call, const MSIMessage *msg )
274 LOGGER_ERROR("No destination!"); 221{
275 return 0; 222 /* Parse and send message */
276 } 223
224 uint8_t parsed [MSI_MAXMSG_SIZE];
277 225
278 uint8_t *it = dest; 226 uint8_t *it = parsed;
279 uint16_t size = 0; 227 uint16_t size = 0;
280 228
281 if (msg->request.exists) { 229 if (msg->request.exists) {
282 uint8_t cast = msg->request.value; 230 uint8_t cast = msg->request.value;
283 it = prepare_header(IDRequest, it, &cast, 1, &size); 231 it = parse_header(IDRequest, it, &cast,
232 sizeof(cast), &size);
284 } 233 }
285 234
286 if (msg->response.exists) { 235 if (msg->response.exists) {
287 uint8_t cast = msg->response.value; 236 uint8_t cast = msg->response.value;
288 it = prepare_header(IDResponse, it, &cast, 1, &size); 237 it = parse_header(IDResponse, it, &cast,
238 sizeof(cast), &size);
289 } 239 }
290 240
291 if (msg->error.exists) { 241 if (msg->error.exists) {
292 it = prepare_header(IDError, it, &msg->error.value, sizeof(msg->error.value), &size); 242 it = parse_header(IDError, it, &msg->error.value,
243 sizeof(msg->error.value), &size);
293 } 244 }
294 245
295 if (msg->capabilities.exists) { 246 if (msg->capabilities.exists) {
296 it = prepare_header(IDCapabilities, it, &msg->capabilities.value, 247 it = parse_header(IDCapabilities, it, &msg->capabilities.value,
297 sizeof(msg->capabilities.value), &size); 248 sizeof(msg->capabilities.value), &size);
298 } 249 }
299 250
251 if (msg->mvfsz.exists) {
252 it = parse_header(IDMVFSZ, it, &msg->mvfsz.value,
253 sizeof(msg->mvfsz.value), &size);
254 }
255
256 if (msg->mvfpsz.exists) {
257 it = parse_header(IDMVFPSZ, it, &msg->mvfpsz.value,
258 sizeof(msg->mvfpsz.value), &size);
259 }
260
300 *it = 0; 261 *it = 0;
301 size ++; 262 size ++;
302 263
303 return size; 264 if ( it == parsed ) {
304} 265 LOGGER_WARNING("Parsing message failed; empty message");
305
306static int send_message ( MSICall *call, MSIMessage *msg, uint32_t to )
307{
308 uint8_t parsed [MSI_MAXMSG_SIZE];
309 uint16_t length = parse_out ( msg, parsed );
310
311 if ( !length ) {
312 LOGGER_WARNING("Parsing message failed; nothing sent!");
313 return -1; 266 return -1;
314 } 267 }
315 268
316 if ( m_msi_packet(call->session->messenger_handle, to, parsed, length) ) { 269 if ( m_msi_packet(call->session->messenger_handle, call->friend_id, parsed, size) ) {
317 LOGGER_DEBUG("Sent message"); 270 LOGGER_DEBUG("Sent message");
318 return 0; 271 return 0;
319 } 272 }
@@ -321,34 +274,25 @@ static int send_message ( MSICall *call, MSIMessage *msg, uint32_t to )
321 return -1; 274 return -1;
322} 275}
323 276
324static int send_reponse ( MSICall *call, MSIResponse response, uint32_t to ) 277static int call_send_error ( MSICall *call, MSIError error )
325{
326 MSIMessage *msg = msi_new_message ( type_response, response );
327 int ret = send_message ( call, msg, to );
328 free ( msg );
329 return ret;
330}
331
332static int send_error ( MSICall *call, MSIError error, uint32_t to )
333{ 278{
279 /* Send error message */
280
334 if (!call) { 281 if (!call) {
335 LOGGER_WARNING("Cannot handle error on 'null' call"); 282 LOGGER_WARNING("Cannot handle error on 'null' call");
336 return -1; 283 return -1;
337 } 284 }
338 285
339 LOGGER_DEBUG("Sending error: %d on call: %d", error, call->call_idx); 286 LOGGER_DEBUG("Sending error: %d to friend: %d", error, call->friend_id);
340 287
341 MSIMessage *msg_error = msi_new_message ( type_response, resp_error ); 288 MSIMessage msg_error;
289 msg_error.response.exists = true;
290 msg_error.response.value = resp_error;
342 291
343 if (!msg_error) 292 msg_error.error.exists = true;
344 return -1; 293 msg_error.error.value = error;
345
346 msg_error->error.exists = 1;
347 msg_error->error.value = error;
348 294
349 send_message ( call, msg_error, to ); 295 call_send_message ( call, &msg_error );
350 free ( msg_error );
351
352 return 0; 296 return 0;
353} 297}
354 298
@@ -415,7 +359,6 @@ static void kill_call ( MSICall *call )
415 if ( call == NULL ) 359 if ( call == NULL )
416 return; 360 return;
417 361
418
419 MSISession* session = call->session; 362 MSISession* session = call->session;
420 363
421 MSICall* prev = call->prev; 364 MSICall* prev = call->prev;
@@ -446,7 +389,7 @@ CLEAR:
446 389
447 390
448 391
449static void handle_remote_connection_change(Messenger *messenger, int friend_id, uint8_t status, void *session_p) 392static void on_remote_connection_change(Messenger *messenger, int friend_id, uint8_t status, void *session_p)
450{ 393{
451 (void)messenger; 394 (void)messenger;
452 MSISession *session = session_p; 395 MSISession *session = session_p;
@@ -458,7 +401,7 @@ static void handle_remote_connection_change(Messenger *messenger, int friend_id,
458 if (call == NULL) 401 if (call == NULL)
459 return; 402 return;
460 403
461 invoke_callback(call, msi_OnPeerTimeout); 404 call_invoke_callback(call, msi_OnPeerTimeout);
462 kill_call(call); 405 kill_call(call);
463 } 406 }
464 break; 407 break;
@@ -471,7 +414,7 @@ static void handle_remote_connection_change(Messenger *messenger, int friend_id,
471 414
472 415
473/********** Request handlers **********/ 416/********** Request handlers **********/
474static int handle_recv_invite ( MSICall *call, MSIMessage *msg ) 417static int handle_recv_invite ( MSICall *call, const MSIMessage *msg )
475{ 418{
476 if ( call == NULL ) { 419 if ( call == NULL ) {
477 LOGGER_WARNING("Session: %p Handling 'invite' on no call"); 420 LOGGER_WARNING("Session: %p Handling 'invite' on no call");
@@ -482,6 +425,26 @@ static int handle_recv_invite ( MSICall *call, MSIMessage *msg )
482 425
483 LOGGER_DEBUG("Session: %p Handling 'invite' friend: %d", call->session, call->friend_id); 426 LOGGER_DEBUG("Session: %p Handling 'invite' friend: %d", call->session, call->friend_id);
484 427
428 if (!msg->capabilities.exists) {
429 LOGGER_WARNING("Session: %p Invalid capabilities on 'invite'");
430 /* TODO send error */
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;
444 }
445
446 MSIMessage response;
447 response.response.exists = true;
485 448
486 if ( call->state == msi_CallRequesting ) { 449 if ( call->state == msi_CallRequesting ) {
487 /* The rare glare case. 450 /* The rare glare case.
@@ -493,29 +456,54 @@ static int handle_recv_invite ( MSICall *call, MSIMessage *msg )
493 456
494 LOGGER_DEBUG("Glare detected!"); 457 LOGGER_DEBUG("Glare detected!");
495 458
496 MSIMessage *msg_starting = msi_new_message ( type_response, resp_starting ); 459 call->peer_capabilities = msg->capabilities;
497 460
498 call->capabilities &= msg->capabilities; 461 call->peer_mvfsz = ntohs(msg->mvfsz.value);
462 call->peer_mvfpsz = ntohs(msg->mvfpsz.value);
499 463
500 msg_starting->capabilities.value = call->capabilities; 464 /* Send response */
501 msg_starting->capabilities.exists = 1; 465 response.response.value = resp_starting;
466 call_send_message ( call, &response );
467
468 return 0;
469 } else if ( call->state == msi_CallActive ) {
470 /* Changing capabilities.
471 * We send starting but no response is expected.
472 * WARNING: if start is sent call is terminated with an error
473 */
474 LOGGER_DEBUG("Peer is changing capabilities");
475
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 */
482 response.response.value = resp_starting;
483 call_send_message ( call, &response );
502 484
503 send_message ( call, msg_starting, call->friend_id );
504 free ( msg_starting );
505 485
486 call_invoke_callback(call, msi_OnCapabilities);
506 return 0; 487 return 0;
507 } 488 }
508 489
509 call->capabilities = msg->capabilities; 490 call->peer_capabilities = msg->capabilities;
491
492 call->peer_mvfsz = ntohs(msg->mvfsz.value);
493 call->peer_mvfpsz = ntohs(msg->mvfpsz.value);
494
510 call->state = msi_CallRequested; 495 call->state = msi_CallRequested;
511 496
512 send_reponse(call, resp_ringing, call->friend_id); 497 /* Send response */
513 invoke_callback(call, msi_OnInvite); 498 response.response.value = resp_ringing;
514 499 call_send_message ( call, &response );
500
501
502 call_invoke_callback(call, msi_OnInvite);
515 return 0; 503 return 0;
516} 504}
517 505
518static int handle_recv_start ( MSICall *call, MSIMessage *msg ) 506static int handle_recv_start ( MSICall *call, const MSIMessage *msg )
519{ 507{
520 if ( call == NULL ) { 508 if ( call == NULL ) {
521 LOGGER_WARNING("Session: %p Handling 'start' on no call"); 509 LOGGER_WARNING("Session: %p Handling 'start' on no call");
@@ -533,12 +521,12 @@ static int handle_recv_start ( MSICall *call, MSIMessage *msg )
533 LOGGER_DEBUG("Session: %p Handling 'start', friend id: %d", call->session, call->friend_id ); 521 LOGGER_DEBUG("Session: %p Handling 'start', friend id: %d", call->session, call->friend_id );
534 522
535 call->state = msi_CallActive; 523 call->state = msi_CallActive;
536 invoke_callback(call, msi_OnStart); 524 call_invoke_callback(call, msi_OnStart);
537 525
538 return 0; 526 return 0;
539} 527}
540 528
541static int handle_recv_reject ( MSICall *call, MSIMessage *msg ) 529static int handle_recv_reject ( MSICall *call, const MSIMessage *msg )
542{ 530{
543 if ( call == NULL ) { 531 if ( call == NULL ) {
544 LOGGER_WARNING("Session: %p Handling 'start' on no call"); 532 LOGGER_WARNING("Session: %p Handling 'start' on no call");
@@ -555,13 +543,13 @@ static int handle_recv_reject ( MSICall *call, MSIMessage *msg )
555 543
556 LOGGER_DEBUG("Session: %p Handling 'reject', friend id: %u", call->session, call->friend_id); 544 LOGGER_DEBUG("Session: %p Handling 'reject', friend id: %u", call->session, call->friend_id);
557 545
558 invoke_callback(call, msi_OnReject); 546 call_invoke_callback(call, msi_OnReject);
559 kill_call(call); 547 kill_call(call);
560 548
561 return 0; 549 return 0;
562} 550}
563 551
564static int handle_recv_end ( MSICall *call, MSIMessage *msg ) 552static int handle_recv_end ( MSICall *call, const MSIMessage *msg )
565{ 553{
566 (void)msg; 554 (void)msg;
567 555
@@ -572,14 +560,14 @@ static int handle_recv_end ( MSICall *call, MSIMessage *msg )
572 560
573 LOGGER_DEBUG("Session: %p Handling 'end', friend id: %d", call->session, call->friend_id); 561 LOGGER_DEBUG("Session: %p Handling 'end', friend id: %d", call->session, call->friend_id);
574 562
575 invoke_callback(call, msi_OnEnd); 563 call_invoke_callback(call, msi_OnEnd);
576 kill_call ( call ); 564 kill_call ( call );
577 565
578 return 0; 566 return 0;
579} 567}
580 568
581/********** Response handlers **********/ 569/********** Response handlers **********/
582static int handle_recv_ringing ( MSICall *call, MSIMessage *msg ) 570static int handle_recv_ringing ( MSICall *call, const MSIMessage *msg )
583{ 571{
584 if ( call == NULL ) { 572 if ( call == NULL ) {
585 LOGGER_WARNING("Session: %p Handling 'start' on no call"); 573 LOGGER_WARNING("Session: %p Handling 'start' on no call");
@@ -596,36 +584,65 @@ static int handle_recv_ringing ( MSICall *call, MSIMessage *msg )
596 584
597 LOGGER_DEBUG("Session: %p Handling 'ringing' friend id: %d", call->session, call->friend_id ); 585 LOGGER_DEBUG("Session: %p Handling 'ringing' friend id: %d", call->session, call->friend_id );
598 586
599 invoke_callback(call, msi_OnRinging); 587 call_invoke_callback(call, msi_OnRinging);
600 return 0; 588 return 0;
601} 589}
602static int handle_recv_starting ( MSICall *call, MSIMessage *msg ) 590
591static int handle_recv_starting ( MSICall *call, const MSIMessage *msg )
603{ 592{
604 if ( call == NULL ) { 593 if ( call == NULL ) {
605 LOGGER_WARNING("Session: %p Handling 'starting' on non-existing call"); 594 LOGGER_WARNING("Session: %p Handling 'starting' on non-existing call");
606 return 0; 595 return 0;
607 } 596 }
608 597
609 if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) { 598 if ( call->state == msi_CallActive ) {
599 LOGGER_DEBUG("Capabilities change confirmed");
600 return 0;
601 } else if ( call->state != msi_CallRequested || call->state != msi_CallRequesting ) {
610 LOGGER_WARNING("Session: %p Invalid call state on 'starting'"); 602 LOGGER_WARNING("Session: %p Invalid call state on 'starting'");
611 /* TODO send error */ 603 /* TODO send error */
612 return -1; 604 return -1;
613 } 605 }
614 606
615 MSIMessage *msg_start = msi_new_message ( type_request, requ_start );
616 send_message ( call, msg_start, call->friend_id );
617 free ( msg_start );
618
619 if (call->state == msi_CallRequesting) { 607 if (call->state == msi_CallRequesting) {
608 if (!msg->capabilities.exists) {
609 LOGGER_WARNING("Session: %p Invalid capabilities on 'starting'");
610 /* TODO send error */
611 return -1;
612 }
613
614 if (!msg->mvfsz.exists) {
615 LOGGER_WARNING("Session: %p Invalid mvfsz on 'invite'");
616 /* TODO send error */
617 return -1;
618 }
619
620 if (!msg->mvfpsz.exists) {
621 LOGGER_WARNING("Session: %p Invalid mvfpsz on 'invite'");
622 /* TODO send error */
623 return -1;
624 }
625
626 call->peer_capabilities = msg->capabilities.value;
627
628 call->peer_mvfsz = ntohs(msg->mvfsz.value);
629 call->peer_mvfpsz = ntohs(msg->mvfpsz.value);
630
620 call->state = msi_CallActive; 631 call->state = msi_CallActive;
621 invoke_callback(call, msi_OnStart); 632 call_invoke_callback(call, msi_OnStart);
622 } 633 }
623
624 /* Otherwise it's a glare case so don't start until 'start' is recved */ 634 /* Otherwise it's a glare case so don't start until 'start' is recved */
625 635
636 /* Send start in either case (glare or normal) */
637 MSIMessage msg_start;
638 msg_start.request.exists = true;
639 msg_start.request.value = requ_start;
640 call_send_message ( call, &msg_start );
641
626 return 0; 642 return 0;
627} 643}
628static int handle_recv_error ( MSICall *call, MSIMessage *msg ) 644
645static int handle_recv_error ( MSICall *call, const MSIMessage *msg )
629{ 646{
630 if ( call == NULL ) { 647 if ( call == NULL ) {
631 LOGGER_WARNING("Handling 'error' on non-existing call!"); 648 LOGGER_WARNING("Handling 'error' on non-existing call!");
@@ -634,46 +651,15 @@ static int handle_recv_error ( MSICall *call, MSIMessage *msg )
634 651
635 LOGGER_DEBUG("Session: %p Handling 'error' friend id: %d", call->session, call->friend_id ); 652 LOGGER_DEBUG("Session: %p Handling 'error' friend id: %d", call->session, call->friend_id );
636 653
637 invoke_callback(call, msi_OnError); 654 call_invoke_callback(call, msi_OnError);
638 655
639 /* TODO Handle error accordingly */ 656 /* TODO Handle error accordingly */
640 657
641 return -1; 658 return -1;
642} 659}
643 660
644/** 661static void handle_msi_packet ( Messenger *messenger, int friend_id, const uint8_t *data,
645 * BASIC call flow: 662 uint16_t length, void *object )
646 *
647 * ALICE BOB
648 * | invite --> |
649 * | |
650 * | <-- ringing |
651 * | |
652 * | <-- starting |
653 * | |
654 * | start --> |
655 * | |
656 * | <-- MEDIA TRANS --> |
657 * | |
658 * | end --> |
659 * | |
660 * | <-- ending |
661 *
662 * Alice calls Bob by sending invite packet.
663 * Bob recvs the packet and sends an ringing packet;
664 * which notifies Alice that her invite is acknowledged.
665 * Ringing screen shown on both sides.
666 * Bob accepts the invite for a call by sending starting packet.
667 * Alice recvs the starting packet and sends the started packet to
668 * inform Bob that she recved the starting packet.
669 * Now the media transmission is established ( i.e. RTP transmission ).
670 * Alice hangs up and sends end packet.
671 * Bob recves the end packet and sends ending packet
672 * as the acknowledgement that the call is ending.
673 *
674 *
675 */
676static void msi_handle_packet ( Messenger *messenger, int friend_id, const uint8_t *data, uint16_t length, void *object )
677{ 663{
678 LOGGER_DEBUG("Got msi message"); 664 LOGGER_DEBUG("Got msi message");
679 665
@@ -681,11 +667,9 @@ static void msi_handle_packet ( Messenger *messenger, int friend_id, const uint8
681 (void)messenger; 667 (void)messenger;
682 668
683 MSISession *session = object; 669 MSISession *session = object;
684 MSIMessage *msg; 670 MSIMessage msg;
685 671
686 msg = parse_in ( data, length ); 672 if ( parse_input ( &msg, data, length ) == -1 ) {
687
688 if ( !msg ) {
689 LOGGER_WARNING("Error parsing message"); 673 LOGGER_WARNING("Error parsing message");
690 return; 674 return;
691 } else { 675 } else {
@@ -697,7 +681,7 @@ static void msi_handle_packet ( Messenger *messenger, int friend_id, const uint8
697 MSICall *call = get_call(session, friend_id); 681 MSICall *call = get_call(session, friend_id);
698 682
699 if (call == NULL) { 683 if (call == NULL) {
700 if (msg->request != requ_invite) { 684 if (msg.request != requ_invite) {
701 /* TODO send error */ 685 /* TODO send error */
702 return; 686 return;
703 } 687 }
@@ -712,36 +696,36 @@ static void msi_handle_packet ( Messenger *messenger, int friend_id, const uint8
712 696
713 /* Now handle message */ 697 /* Now handle message */
714 int rc = 0; 698 int rc = 0;
715 if ( msg->request.exists ) { /* Handle request */ 699 if ( msg.request.exists ) { /* Handle request */
716 switch (msg->request.value) { 700 switch (msg.request.value) {
717 case requ_invite: 701 case requ_invite:
718 rc = handle_recv_invite ( call, msg ); 702 rc = handle_recv_invite ( call, &msg );
719 break; 703 break;
720 704
721 case requ_start: 705 case requ_start:
722 rc = handle_recv_start ( call, msg ); 706 rc = handle_recv_start ( call, &msg );
723 break; 707 break;
724 708
725 case requ_reject: 709 case requ_reject:
726 rc = handle_recv_reject ( call, msg ); 710 rc = handle_recv_reject ( call, &msg );
727 break; 711 break;
728 712
729 case requ_end: 713 case requ_end:
730 rc = handle_recv_end ( call, msg ); 714 rc = handle_recv_end ( call, &msg );
731 break; 715 break;
732 } 716 }
733 } else if ( msg->response.exists ) { /* Handle response */ 717 } else if ( msg.response.exists ) { /* Handle response */
734 switch (msg->response.value) { 718 switch (msg.response.value) {
735 case resp_ringing: 719 case resp_ringing:
736 rc = handle_recv_ringing ( call, msg ); 720 rc = handle_recv_ringing ( call, &msg );
737 break; 721 break;
738 722
739 case resp_starting: 723 case resp_starting:
740 rc = handle_recv_starting ( call, msg ); 724 rc = handle_recv_starting ( call, &msg );
741 break; 725 break;
742 726
743 case resp_error: 727 case resp_error:
744 rc = handle_recv_error ( call, msg ); 728 rc = handle_recv_error ( call, &msg );
745 break; 729 break;
746 } 730 }
747 } else { 731 } else {
@@ -753,7 +737,6 @@ static void msi_handle_packet ( Messenger *messenger, int friend_id, const uint8
753 if (rc == -1) 737 if (rc == -1)
754 kill_call(call); 738 kill_call(call);
755 739
756 free ( msg );
757 pthread_mutex_unlock(session->mutex); 740 pthread_mutex_unlock(session->mutex);
758} 741}
759 742
@@ -787,10 +770,10 @@ MSISession *msi_new ( Messenger *messenger )
787 770
788 retu->messenger_handle = messenger; 771 retu->messenger_handle = messenger;
789 772
790 m_callback_msi_packet(messenger, msi_handle_packet, retu ); 773 m_callback_msi_packet(messenger, handle_msi_packet, retu );
791 774
792 /* This is called when remote terminates session */ 775 /* This is called when remote terminates session */
793 m_callback_connectionstatus_internal_av(messenger, handle_remote_connection_change, retu); 776 m_callback_connectionstatus_internal_av(messenger, on_remote_connection_change, retu);
794 777
795 LOGGER_DEBUG("New msi session: %p ", retu); 778 LOGGER_DEBUG("New msi session: %p ", retu);
796 return retu; 779 return retu;
@@ -807,15 +790,15 @@ int msi_kill ( MSISession *session )
807 pthread_mutex_lock(session->mutex); 790 pthread_mutex_lock(session->mutex);
808 791
809 if (session->calls) { 792 if (session->calls) {
810 MSIMessage *msg_end = msi_new_message ( type_request, requ_end ); 793 MSIMessage msg_end;
794 msg_end.request.exists = true;
795 msg_end.request.value = requ_end;
811 796
812 MSICall* it = get_call(session, session->calls_head); 797 MSICall* it = get_call(session, session->calls_head);
813 for (; it; it = it->next) { 798 for (; it; it = it->next) {
814 send_message(it, msg_end, it->friend_id); 799 call_send_message(it, &msg_end);
815 kill_call(it); 800 kill_call(it); /* This will eventually free session->calls */
816 } 801 }
817
818 free(msg_end);
819 } 802 }
820 803
821 pthread_mutex_unlock(session->mutex); 804 pthread_mutex_unlock(session->mutex);
@@ -840,15 +823,22 @@ int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_
840 if ( *call == NULL ) 823 if ( *call == NULL )
841 return -1; 824 return -1;
842 825
843 *call->capabilities = capabilities; 826 *call->self_capabilities = capabilities;
827
828 MSIMessage msg_invite;
829 msg_invite.request.exists = true;
830 msg_invite.request.value = requ_invite;
844 831
845 MSIMessage *msg_invite = msi_new_message ( type_request, requ_invite ); 832 msg_invite.capabilities.exists = true;
833 msg_invite.capabilities.value = capabilities;
846 834
847 msg_invite->capabilities.value = capabilities; 835 msg_invite.mvfsz.exists = true;
848 msg_invite->capabilities.exists = 1; 836 msg_invite.mvfsz.value = htons(D_MVFSZ);
849 837
850 send_message ( *call, msg_invite, friend_id ); 838 msg_invite.mvfpsz.exists = true;
851 free( msg_invite ); 839 msg_invite.mvfpsz.value = htons(D_MVFPSZ);
840
841 call_send_message ( *call, &msg_invite );
852 842
853 *call->state = msi_CallRequesting; 843 *call->state = msi_CallRequesting;
854 844
@@ -860,9 +850,10 @@ int msi_hangup ( MSICall* call )
860{ 850{
861 LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index); 851 LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index);
862 852
863 MSIMessage *msg_end = msi_new_message ( type_request, requ_end ); 853 MSIMessage msg_end;
864 send_message ( call, msg_end, call->friend_id ); 854 msg_end.request.exists = true;
865 free ( msg_end ); 855 msg_end.request.value = requ_end;
856 call_send_message ( call, &msg_end );
866 857
867 kill_call(call); 858 kill_call(call);
868 return 0; 859 return 0;
@@ -870,22 +861,29 @@ int msi_hangup ( MSICall* call )
870 861
871int msi_answer ( MSICall* call, uint8_t capabilities ) 862int msi_answer ( MSICall* call, uint8_t capabilities )
872{ 863{
873 LOGGER_DEBUG("Session: %p Answering call: %u", session, call_index); 864 LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_id);
874 865
875 if ( call->state != msi_CallRequested ) { 866 if ( call->state != msi_CallRequested ) {
876 LOGGER_ERROR("Call is in invalid state!"); 867 LOGGER_ERROR("Call is in invalid state!");
877 return -1; 868 return -1;
878 } 869 }
879 870
880 call->capabilities = capabilities; 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;
881 879
882 MSIMessage *msg_starting = msi_new_message ( type_response, resp_starting ); 880 msg_starting.mvfsz.exists = true;
881 msg_starting.mvfsz.value = htons(D_MVFSZ);
883 882
884 msg_starting->capabilities.value = capabilities; 883 msg_starting.mvfpsz.exists = true;
885 msg_starting->capabilities.exists = 1; 884 msg_starting.mvfpsz.value = htons(D_MVFPSZ);
886 885
887 send_message ( call, msg_starting, call->friend_id ); 886 call_send_message ( call, &msg_starting );
888 free ( msg_starting );
889 887
890 return 0; 888 return 0;
891} 889}
@@ -896,57 +894,30 @@ int msi_reject ( MSICall* call )
896 894
897 if ( call->state != msi_CallRequested ) { 895 if ( call->state != msi_CallRequested ) {
898 LOGGER_ERROR("Call is in invalid state!"); 896 LOGGER_ERROR("Call is in invalid state!");
899 return msi_ErrorInvalidState; 897 return -1;
900 } 898 }
901 899
902 MSIMessage *msg_reject = msi_new_message ( type_request, requ_reject ); 900 MSIMessage msg_reject;
903 send_message ( call, msg_reject, call->friend_id ); 901 msg_reject.request.exists = true;
904 free ( msg_reject ); 902 msg_reject.request.value = requ_reject;
903
904 call_send_message ( call, &msg_reject );
905 905
906 return 0; 906 return 0;
907} 907}
908 908
909int msi_change_csettings( MSICall* call, uint8_t capabilities ) 909int msi_change_csettings( MSICall* call, uint8_t capabilities )
910{ 910{
911 pthread_mutex_lock(session->mutex); 911 call->self_capabilities = capabilities;
912 912
913 LOGGER_DEBUG("Changing media on call: %d", call_index); 913 MSIMessage msg_invite;
914 914 msg_invite.request.exists = true;
915 MSICall *call = session->calls[call_index]; 915 msg_invite.request.value = requ_invite;
916 916
917 if ( call->state != msi_CallActive ) { 917 msg_invite.capabilities.exists = true;
918 LOGGER_ERROR("Call is not active!"); 918 msg_invite.capabilities.value = capabilities;
919 pthread_mutex_unlock(session->mutex); 919
920 return msi_ErrorInvalidState; 920 call_send_message ( *call, &msg_invite );
921 } 921
922
923 MSICSettings *local = &call->csettings_local;
924
925 if (
926 local->call_type == csettings->call_type &&
927 local->video_bitrate == csettings->video_bitrate &&
928 local->max_video_width == csettings->max_video_width &&
929 local->max_video_height == csettings->max_video_height &&
930 local->audio_bitrate == csettings->audio_bitrate &&
931 local->audio_frame_duration == csettings->audio_frame_duration &&
932 local->audio_sample_rate == csettings->audio_sample_rate &&
933 local->audio_channels == csettings->audio_channels ) {
934 LOGGER_ERROR("Call is already set accordingly!");
935 pthread_mutex_unlock(session->mutex);
936 return -1;
937 }
938
939 *local = *csettings;
940
941 MSIMessage *msg_invite = msi_new_message ( type_request, requ_invite );
942
943 msi_msg_set_csettings ( msg_invite, local );
944 send_message ( session, call, msg_invite, call->peers[0] );
945 free ( msg_invite );
946
947 LOGGER_DEBUG("Request for media change sent");
948
949 pthread_mutex_unlock(session->mutex);
950
951 return 0; 922 return 0;
952} \ No newline at end of file 923} \ No newline at end of file
diff --git a/toxav/msi.h b/toxav/msi.h
index 8fa309c3..a1eb499b 100644
--- a/toxav/msi.h
+++ b/toxav/msi.h
@@ -1,6 +1,6 @@
1/** msi.h 1/** msi.h
2 * 2 *
3 * Copyright (C) 2013 Tox project All Rights Reserved. 3 * Copyright (C) 2013-2015 Tox project All Rights Reserved.
4 * 4 *
5 * This file is part of Tox. 5 * This file is part of Tox.
6 * 6 *
@@ -28,17 +28,9 @@
28#include "codec.h" 28#include "codec.h"
29#include "../toxcore/Messenger.h" 29#include "../toxcore/Messenger.h"
30 30
31typedef uint8_t MSICallIDType[12]; 31/** Preconfigured values for video splitting */
32typedef uint8_t MSIReasonStrType[255]; 32#define D_MVFSZ 40000 /* 256KiB */
33typedef void ( *MSICallbackType ) ( void *agent, int32_t call_idx); 33#define D_MVFPSZ 500 /* 1.25 KiB*/
34
35/**
36 * Call type identifier. Also used as rtp callback prefix.
37 */
38typedef enum {
39 msi_TypeAudio = 192,
40 msi_TypeVideo
41} MSICallType;
42 34
43/** 35/**
44 * Error codes. 36 * Error codes.
@@ -62,31 +54,12 @@ typedef enum {
62 * Call state identifiers. 54 * Call state identifiers.
63 */ 55 */
64typedef enum { 56typedef enum {
57 msi_CallInactive, /* Default */
58 msi_CallActive,
65 msi_CallRequesting, /* when sending call invite */ 59 msi_CallRequesting, /* when sending call invite */
66 msi_CallRequested, /* when getting call invite */ 60 msi_CallRequested, /* when getting call invite */
67 msi_CallActive,
68 msi_CallHold,
69 msi_CallOver
70
71} MSICallState; 61} MSICallState;
72 62
73
74/**
75 * Encoding settings.
76 */
77typedef struct {
78 MSICallType call_type;
79
80 uint32_t video_bitrate; /* In kbits/s */
81 uint16_t max_video_width; /* In px */
82 uint16_t max_video_height; /* In px */
83
84 uint32_t audio_bitrate; /* In bits/s */
85 uint16_t audio_frame_duration; /* In ms */
86 uint32_t audio_sample_rate; /* In Hz */
87 uint32_t audio_channels;
88} MSICSettings;
89
90/** 63/**
91 * Callbacks ids that handle the states 64 * Callbacks ids that handle the states
92 */ 65 */
@@ -97,32 +70,25 @@ typedef enum {
97 msi_OnReject, /* The side that was invited rejected the call */ 70 msi_OnReject, /* The side that was invited rejected the call */
98 msi_OnEnd, /* Call that was active ended */ 71 msi_OnEnd, /* Call that was active ended */
99 msi_OnError, /* Call that was active ended */ 72 msi_OnError, /* Call that was active ended */
100 msi_OnRequestTimeout, /* When the requested action didn't get response in specified time */
101 msi_OnPeerTimeout, /* Peer timed out; stop the call */ 73 msi_OnPeerTimeout, /* Peer timed out; stop the call */
102 msi_OnPeerCSChange, /* Peer requested Csettings change */ 74 msi_OnCapabilities, /* Peer requested capabilities change */
103 msi_OnSelfCSChange /* Csettings change confirmation */
104} MSICallbackID; 75} MSICallbackID;
105 76
106/** 77/**
107 * Errors
108 */
109typedef enum {
110 msi_ErrorNoCall = -20, /* Trying to perform call action while not in a call */
111 msi_ErrorInvalidState = -21, /* Trying to perform call action while in invalid state*/
112 msi_ErrorAlreadyInCallWithPeer = -22, /* Trying to call peer when already in a call with peer */
113 msi_ErrorReachedCallLimit = -23, /* Cannot handle more calls */
114} MSIError;
115
116/**
117 * The call struct. Please do not modify outside msi.c 78 * The call struct. Please do not modify outside msi.c
118 */ 79 */
119typedef struct MSICall_s { 80typedef struct MSICall_s {
120 struct MSISession_s *session; /* Session pointer */ 81 struct MSISession_s *session; /* Session pointer */
121 82
122 MSICallState state; 83 MSICallState state;
123 uint8_t capabilities; /* Active capabilities */
124 84
125 uint32_t friend_id; /* Index of this call in MSISession */ 85 uint8_t peer_capabilities; /* Peer capabilities */
86 uint8_t self_capabilities; /* Self capabilities */
87
88 uint16_t peer_mvfsz; /* Max video frame size */
89 uint16_t peer_mvfpsz; /* Max video frame part size */
90
91 uint32_t friend_id; /* Index of this call in MSISession */
126 92
127 struct MSICall_s* next; 93 struct MSICall_s* next;
128 struct MSICall_s* prev; 94 struct MSICall_s* prev;
@@ -130,6 +96,11 @@ typedef struct MSICall_s {
130 96
131 97
132/** 98/**
99 * Msi callback type. 'agent' is a pointer to ToxAv
100 */
101typedef void ( *MSICallbackType ) ( void *agent, MSICall* call);
102
103/**
133 * Control session struct. Please do not modify outside msi.c 104 * Control session struct. Please do not modify outside msi.c
134 */ 105 */
135typedef struct MSISession_s { 106typedef struct MSISession_s {
@@ -142,7 +113,7 @@ typedef struct MSISession_s {
142 Messenger *messenger_handle; 113 Messenger *messenger_handle;
143 114
144 pthread_mutex_t mutex[1]; 115 pthread_mutex_t mutex[1];
145 MSICallbackType callbacks[10]; 116 MSICallbackType callbacks[8];
146} MSISession; 117} MSISession;
147 118
148/** 119/**
diff --git a/toxav/rtp.c b/toxav/rtp.c
index a50dd7ce..396e0202 100644
--- a/toxav/rtp.c
+++ b/toxav/rtp.c
@@ -1,6 +1,6 @@
1/** rtp.c 1/** rtp.c
2 * 2 *
3 * Copyright (C) 2013 Tox project All Rights Reserved. 3 * Copyright (C) 2013-2015 Tox project All Rights Reserved.
4 * 4 *
5 * This file is part of Tox. 5 * This file is part of Tox.
6 * 6 *
@@ -333,8 +333,6 @@ RTPMessage *msg_parse ( const uint8_t *data, int length )
333 return NULL; 333 return NULL;
334 } 334 }
335 335
336 retu->next = NULL;
337
338 return retu; 336 return retu;
339} 337}
340 338
@@ -415,8 +413,6 @@ RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t
415 413
416 retu->length = total_length; 414 retu->length = total_length;
417 415
418 retu->next = NULL;
419
420 return retu; 416 return retu;
421} 417}
422 418
@@ -497,7 +493,7 @@ int rtp_send_msg ( RTPSession *session, const uint8_t *data, uint16_t length )
497 if ( -1 == send_custom_lossy_packet(session->m, session->dest, msg->data, msg->length) ) { 493 if ( -1 == send_custom_lossy_packet(session->m, session->dest, msg->data, msg->length) ) {
498 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno)); 494 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno));
499 rtp_free_msg ( session, msg ); 495 rtp_free_msg ( session, msg );
500 return rtp_ErrorSending; 496 return -1;
501 } 497 }
502 498
503 499
diff --git a/toxav/rtp.h b/toxav/rtp.h
index b1888f6c..e3b38a8e 100644
--- a/toxav/rtp.h
+++ b/toxav/rtp.h
@@ -1,6 +1,6 @@
1/** rtp.h 1/** rtp.h
2 * 2 *
3 * Copyright (C) 2013 Tox project All Rights Reserved. 3 * Copyright (C) 2013-2015 Tox project All Rights Reserved.
4 * 4 *
5 * This file is part of Tox. 5 * This file is part of Tox.
6 * 6 *
@@ -31,13 +31,18 @@
31#define MAX_SEQU_NUM 65535 31#define MAX_SEQU_NUM 65535
32#define MAX_RTP_SIZE 65535 32#define MAX_RTP_SIZE 65535
33 33
34/**
35 * Payload type identifier. Also used as rtp callback prefix.
36 */
34typedef enum { 37typedef enum {
35 rtp_ErrorSending = -40 38 rtp_TypeAudio = 192,
36} RTPError; 39 rtp_TypeVideo
40} RTPPayloadType;
41
37/** 42/**
38 * Standard rtp header 43 * Standard rtp header
39 */ 44 */
40typedef struct _RTPHeader { 45typedef struct {
41 uint8_t flags; /* Version(2),Padding(1), Ext(1), Cc(4) */ 46 uint8_t flags; /* Version(2),Padding(1), Ext(1), Cc(4) */
42 uint8_t marker_payloadt; /* Marker(1), PlayLoad Type(7) */ 47 uint8_t marker_payloadt; /* Marker(1), PlayLoad Type(7) */
43 uint16_t sequnum; /* Sequence Number */ 48 uint16_t sequnum; /* Sequence Number */
@@ -51,7 +56,7 @@ typedef struct _RTPHeader {
51/** 56/**
52 * Standard rtp extension header. 57 * Standard rtp extension header.
53 */ 58 */
54typedef struct _RTPExtHeader { 59typedef struct {
55 uint16_t type; /* Extension profile */ 60 uint16_t type; /* Extension profile */
56 uint16_t length; /* Number of extensions */ 61 uint16_t length; /* Number of extensions */
57 uint32_t *table; /* Extension's table */ 62 uint32_t *table; /* Extension's table */
@@ -61,45 +66,43 @@ typedef struct _RTPExtHeader {
61/** 66/**
62 * Standard rtp message. 67 * Standard rtp message.
63 */ 68 */
64typedef struct _RTPMessage { 69typedef struct {
65 RTPHeader *header; 70 RTPHeader *header;
66 RTPExtHeader *ext_header; 71 RTPExtHeader *ext_header;
67 72
68 uint8_t data[MAX_RTP_SIZE]; 73 uint8_t data[MAX_RTP_SIZE];
69 uint32_t length; 74 uint32_t length;
70
71 struct _RTPMessage *next;
72} RTPMessage; 75} RTPMessage;
73 76
74/** 77/**
75 * RTP control session. 78 * RTP control session.
76 */ 79 */
77typedef struct _RTPSession { 80typedef struct {
78 uint8_t version; 81 uint8_t version;
79 uint8_t padding; 82 uint8_t padding;
80 uint8_t extension; 83 uint8_t extension;
81 uint8_t cc; 84 uint8_t cc;
82 uint8_t marker; 85 uint8_t marker;
83 uint8_t payload_type; 86 uint8_t payload_type;
84 uint16_t sequnum; /* Set when sending */ 87 uint16_t sequnum; /* Set when sending */
85 uint16_t rsequnum; /* Check when recving msg */ 88 uint16_t rsequnum; /* Check when recving msg */
86 uint32_t timestamp; 89 uint32_t timestamp;
87 uint32_t ssrc; 90 uint32_t ssrc;
88 uint32_t *csrc; 91 uint32_t *csrc;
89 92
90 /* If some additional data must be sent via message 93 /* If some additional data must be sent via message
91 * apply it here. Only by allocating this member you will be 94 * apply it here. Only by allocating this member you will be
92 * automatically placing it within a message. 95 * automatically placing it within a message.
93 */ 96 */
94 RTPExtHeader *ext_header; 97 RTPExtHeader *ext_header;
95 98
96 /* Msg prefix for core to know when recving */ 99 /* Msg prefix for core to know when recving */
97 uint8_t prefix; 100 uint8_t prefix;
98 101
99 int dest; 102 int dest;
100 103
101 struct _CSSession *cs; 104 struct CSSession_s *cs;
102 Messenger* m; 105 Messenger *m;
103 106
104} RTPSession; 107} RTPSession;
105 108
@@ -119,7 +122,7 @@ void rtp_kill ( RTPSession* session );
119int rtp_register_for_receiving (RTPSession *session); 122int rtp_register_for_receiving (RTPSession *session);
120 123
121/** 124/**
122 * Sends msg to _RTPSession::dest 125 * Sends msg to RTPSession::dest
123 */ 126 */
124int rtp_send_msg ( RTPSession* session, const uint8_t* data, uint16_t length ); 127int rtp_send_msg ( RTPSession* session, const uint8_t* data, uint16_t length );
125 128
diff --git a/toxav/toxav.c b/toxav/toxav.c
index 72f99576..864d16cf 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -1,6 +1,6 @@
1/** toxav.c 1/** toxav.c
2 * 2 *
3 * Copyright (C) 2013 Tox project All Rights Reserved. 3 * Copyright (C) 2013-2015 Tox project All Rights Reserved.
4 * 4 *
5 * This file is part of Tox. 5 * This file is part of Tox.
6 * 6 *
@@ -843,7 +843,7 @@ bool i_toxav_prepare_transmission(ToxAV* av, IToxAVCall* call)
843 843
844 844
845 if (c_self->audio_bitrate > 0 || c_peer->audio_bitrate > 0) { /* Prepare audio rtp */ 845 if (c_self->audio_bitrate > 0 || c_peer->audio_bitrate > 0) { /* Prepare audio rtp */
846 call->rtps[audio_index] = rtp_new(msi_TypeAudio, av->m, av->msi->calls[call->call_idx]->peers[0]); 846 call->rtps[audio_index] = rtp_new(rtp_TypeAudio, av->m, av->msi->calls[call->call_idx]->peers[0]);
847 847
848 if ( !call->rtps[audio_index] ) { 848 if ( !call->rtps[audio_index] ) {
849 LOGGER_ERROR("Error while starting audio RTP session!\n"); 849 LOGGER_ERROR("Error while starting audio RTP session!\n");
@@ -857,7 +857,7 @@ bool i_toxav_prepare_transmission(ToxAV* av, IToxAVCall* call)
857 } 857 }
858 858
859 if (c_self->video_bitrate > 0 || c_peer->video_bitrate > 0) { /* Prepare video rtp */ 859 if (c_self->video_bitrate > 0 || c_peer->video_bitrate > 0) { /* Prepare video rtp */
860 call->rtps[video_index] = rtp_new(msi_TypeVideo, av->m, av->msi->calls[call->call_idx]->peers[0]); 860 call->rtps[video_index] = rtp_new(rtp_TypeVideo, av->m, av->msi->calls[call->call_idx]->peers[0]);
861 861
862 if ( !call->rtps[video_index] ) { 862 if ( !call->rtps[video_index] ) {
863 LOGGER_ERROR("Error while starting video RTP session!\n"); 863 LOGGER_ERROR("Error while starting video RTP session!\n");
diff --git a/toxav/toxav.h b/toxav/toxav.h
index 04ad3cd0..c1c6019c 100644
--- a/toxav/toxav.h
+++ b/toxav/toxav.h
@@ -1,3 +1,24 @@
1/** toxav.h
2 *
3 * Copyright (C) 2013-2015 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
1#ifndef TOXAV_H 22#ifndef TOXAV_H
2#define TOXAV_H 23#define TOXAV_H
3 24