summaryrefslogtreecommitdiff
path: root/toxav
diff options
context:
space:
mode:
authorirungentoo <irungentoo@gmail.com>2014-05-25 12:27:48 -0400
committerirungentoo <irungentoo@gmail.com>2014-05-25 12:27:48 -0400
commit82e38883a239f265089982bc255de0f9db618ce7 (patch)
tree1d38b2ff978e86246695cc7e473af309eacdba2a /toxav
parent9d53bc5d1dabd3142f58cafd9fffa18f783f96df (diff)
parent08ca08dcd952d55a0df75e5efa25a5d8afa70e3f (diff)
Merge branch 'mannol1-Multicalls' into multi-av
Diffstat (limited to 'toxav')
-rw-r--r--toxav/Makefile.inc43
-rw-r--r--toxav/media.c144
-rw-r--r--toxav/media.h24
-rw-r--r--[-rwxr-xr-x]toxav/msi.c937
-rw-r--r--[-rwxr-xr-x]toxav/msi.h67
-rwxr-xr-xtoxav/phone.c1460
-rw-r--r--[-rwxr-xr-x]toxav/rtp.c161
-rw-r--r--[-rwxr-xr-x]toxav/rtp.h18
-rw-r--r--[-rwxr-xr-x]toxav/toxav.c445
-rw-r--r--[-rwxr-xr-x]toxav/toxav.h114
10 files changed, 1210 insertions, 2203 deletions
diff --git a/toxav/Makefile.inc b/toxav/Makefile.inc
index 60b50ff0..65098f1f 100644
--- a/toxav/Makefile.inc
+++ b/toxav/Makefile.inc
@@ -34,45 +34,4 @@ libtoxav_la_LIBADD = libtoxcore.la \
34 $(PTHREAD_LIBS) \ 34 $(PTHREAD_LIBS) \
35 $(AV_LIBS) 35 $(AV_LIBS)
36 36
37 37endif \ No newline at end of file
38endif
39
40
41
42
43
44
45if BUILD_PHONE
46
47
48noinst_PROGRAMS += phone
49
50phone_SOURCES = ../toxav/phone.c
51
52phone_CFLAGS = -I../toxcore \
53 -I../toxav \
54 $(AVFORMAT_CFLAGS) \
55 $(AVCODEC_CFLAGS) \
56 $(AVUTIL_CFLAGS) \
57 $(AVDEVICE_CFLAGS) \
58 $(SWSCALE_CFLAGS) \
59 $(SDL_CFLAGS) \
60 $(OPENAL_CFLAGS)
61
62phone_LDADD = libtoxav.la \
63 libtoxcore.la \
64 $(AVFORMAT_LIBS) \
65 $(AVCODEC_LIBS) \
66 $(AVUTIL_LIBS) \
67 $(AVDEVICE_LIBS) \
68 $(SWSCALE_LIBS) \
69 $(SDL_LIBS) \
70 $(OPENAL_LIBS) \
71 $(OPUS_LIBS) \
72 $(VPX_LIBS)\
73 $(PTHREAD_LIBS)\
74 $(NACL_OBJECTS) \
75 $(NACL_LIBS)
76
77
78endif
diff --git a/toxav/media.c b/toxav/media.c
index a9a4adb8..16156d9d 100644
--- a/toxav/media.c
+++ b/toxav/media.c
@@ -26,6 +26,8 @@
26#include "config.h" 26#include "config.h"
27#endif /* HAVE_CONFIG_H */ 27#endif /* HAVE_CONFIG_H */
28 28
29#include "../toxcore/logger.h"
30
29#include <stdio.h> 31#include <stdio.h>
30#include <stdlib.h> 32#include <stdlib.h>
31#include <math.h> 33#include <math.h>
@@ -34,40 +36,31 @@
34#include "rtp.h" 36#include "rtp.h"
35#include "media.h" 37#include "media.h"
36 38
37struct jitter_buffer { 39int empty_queue(JitterBuffer *q)
38 RTPMessage **queue;
39 uint16_t capacity;
40 uint16_t size;
41 uint16_t front;
42 uint16_t rear;
43 uint8_t queue_ready;
44 uint16_t current_id;
45 uint32_t current_ts;
46 uint8_t id_set;
47};
48
49int empty_queue(struct jitter_buffer *q)
50{ 40{
51 while (q->size > 0) { 41 while (q->size > 0) {
52 rtp_free_msg(NULL, q->queue[q->front]); 42 rtp_free_msg(NULL, q->queue[q->front]);
53 q->front++; 43 q->front++;
54 44
55 if (q->front == q->capacity) 45 if (q->front == q->capacity)
56 q->front = 0; 46 q->front = 0;
57 47
58 q->size--; 48 q->size--;
59 } 49 }
60 50
61 q->id_set = 0; 51 q->id_set = 0;
62 q->queue_ready = 0; 52 q->queue_ready = 0;
63 return 0; 53 return 0;
64} 54}
65 55
66struct jitter_buffer *create_queue(int capacity) 56JitterBuffer *create_queue(int capacity)
67{ 57{
68 struct jitter_buffer *q; 58 JitterBuffer *q;
69 q = calloc(sizeof(struct jitter_buffer), 1); 59
70 q->queue = calloc(sizeof(RTPMessage *), capacity); 60 if ( !(q = calloc(sizeof(JitterBuffer), 1)) ) return NULL;
61
62 if (!(q->queue = calloc(sizeof(RTPMessage *), capacity))) return NULL;
63
71 q->size = 0; 64 q->size = 0;
72 q->capacity = capacity; 65 q->capacity = capacity;
73 q->front = 0; 66 q->front = 0;
@@ -79,17 +72,17 @@ struct jitter_buffer *create_queue(int capacity)
79 return q; 72 return q;
80} 73}
81 74
82/* returns 1 if 'a' has a higher sequence number than 'b' */ 75void terminate_queue(JitterBuffer *q)
83uint8_t sequence_number_older(uint16_t sn_a, uint16_t sn_b, uint32_t ts_a, uint32_t ts_b)
84{ 76{
85 /* TODO: There is already this kind of function in toxrtp.c. 77 empty_queue(q);
86 * Maybe merge? 78 free(q->queue);
87 */ 79 free(q);
88 return (sn_a > sn_b || ts_a > ts_b);
89} 80}
90 81
82#define sequnum_older(sn_a, sn_b, ts_a, ts_b) (sn_a > sn_b || ts_a > ts_b)
83
91/* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */ 84/* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */
92RTPMessage *dequeue(struct jitter_buffer *q, int *success) 85RTPMessage *dequeue(JitterBuffer *q, int *success)
93{ 86{
94 if (q->size == 0 || q->queue_ready == 0) { /* Empty queue */ 87 if (q->size == 0 || q->queue_ready == 0) { /* Empty queue */
95 q->queue_ready = 0; 88 q->queue_ready = 0;
@@ -112,14 +105,13 @@ RTPMessage *dequeue(struct jitter_buffer *q, int *success)
112 q->current_id = next_id; 105 q->current_id = next_id;
113 q->current_ts = next_ts; 106 q->current_ts = next_ts;
114 } else { 107 } else {
115 if (sequence_number_older(next_id, q->current_id, next_ts, q->current_ts)) { 108 if (sequnum_older(next_id, q->current_id, next_ts, q->current_ts)) {
116 /*printf("nextid: %d current: %d\n", next_id, q->current_id);*/ 109 LOGGER_DEBUG("nextid: %d current: %d\n", next_id, q->current_id);
117 q->current_id = (q->current_id + 1) % MAX_SEQU_NUM; 110 q->current_id = (q->current_id + 1) % MAX_SEQU_NUM;
118 *success = 2; /* tell the decoder the packet is lost */ 111 *success = 2; /* tell the decoder the packet is lost */
119 return NULL; 112 return NULL;
120 } else { 113 } else {
121 /* packet too old */ 114 LOGGER_DEBUG("Packet too old");
122 /*printf("packet too old\n");*/
123 *success = 0; 115 *success = 0;
124 return NULL; 116 return NULL;
125 } 117 }
@@ -139,12 +131,11 @@ RTPMessage *dequeue(struct jitter_buffer *q, int *success)
139} 131}
140 132
141 133
142int queue(struct jitter_buffer *q, RTPMessage *pk) 134void queue(JitterBuffer *q, RTPMessage *pk)
143{ 135{
144 if (q->size == q->capacity) { /* Full, empty queue */ 136 if (q->size == q->capacity) { /* Full, empty queue */
137 LOGGER_DEBUG("Queue full s(%d) c(%d), emptying...", q->size, q->capacity);
145 empty_queue(q); 138 empty_queue(q);
146 /*rtp_free_msg(NULL, pk);*/
147 return 0;
148 } 139 }
149 140
150 if (q->size > 8) 141 if (q->size > 8)
@@ -169,13 +160,13 @@ int queue(struct jitter_buffer *q, RTPMessage *pk)
169 if (b < 0) 160 if (b < 0)
170 b += q->capacity; 161 b += q->capacity;
171 162
172 if (sequence_number_older(q->queue[b]->header->sequnum, q->queue[a]->header->sequnum, 163 if (sequnum_older(q->queue[b]->header->sequnum, q->queue[a]->header->sequnum,
173 q->queue[b]->header->timestamp, q->queue[a]->header->timestamp)) { 164 q->queue[b]->header->timestamp, q->queue[a]->header->timestamp)) {
174 RTPMessage *temp; 165 RTPMessage *temp;
175 temp = q->queue[a]; 166 temp = q->queue[a];
176 q->queue[a] = q->queue[b]; 167 q->queue[a] = q->queue[b];
177 q->queue[b] = temp; 168 q->queue[b] = temp;
178 /*printf("had to swap\n");*/ 169 LOGGER_DEBUG("Had to swap");
179 } else { 170 } else {
180 break; 171 break;
181 } 172 }
@@ -185,19 +176,15 @@ int queue(struct jitter_buffer *q, RTPMessage *pk)
185 if (a < 0) 176 if (a < 0)
186 a += q->capacity; 177 a += q->capacity;
187 } 178 }
188
189 if (pk)
190 return 1;
191
192 return 0;
193} 179}
194 180
195 181
196int init_video_decoder(CodecState *cs) 182int init_video_decoder(CodecState *cs)
197{ 183{
198 if (vpx_codec_dec_init_ver(&cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0, 184 int rc = vpx_codec_dec_init_ver(&cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0, VPX_DECODER_ABI_VERSION);
199 VPX_DECODER_ABI_VERSION) != VPX_CODEC_OK) { 185
200 /*fprintf(stderr, "Init video_decoder failed!\n");*/ 186 if ( rc != VPX_CODEC_OK) {
187 LOGGER_ERROR("Init video_decoder failed: %s", vpx_codec_err_to_string(rc));
201 return -1; 188 return -1;
202 } 189 }
203 190
@@ -210,7 +197,7 @@ int init_audio_decoder(CodecState *cs, uint32_t audio_channels)
210 cs->audio_decoder = opus_decoder_create(cs->audio_sample_rate, audio_channels, &rc ); 197 cs->audio_decoder = opus_decoder_create(cs->audio_sample_rate, audio_channels, &rc );
211 198
212 if ( rc != OPUS_OK ) { 199 if ( rc != OPUS_OK ) {
213 /*fprintf(stderr, "Error while starting audio decoder!\n");*/ 200 LOGGER_ERROR("Error while starting audio decoder: %s", opus_strerror(rc));
214 return -1; 201 return -1;
215 } 202 }
216 203
@@ -221,10 +208,10 @@ int init_audio_decoder(CodecState *cs, uint32_t audio_channels)
221int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t video_bitrate) 208int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t video_bitrate)
222{ 209{
223 vpx_codec_enc_cfg_t cfg; 210 vpx_codec_enc_cfg_t cfg;
224 int res = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0); 211 int rc = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0);
225 212
226 if (res) { 213 if (rc) {
227 /*fprintf(stderr, "Failed to get config: %s\n", vpx_codec_err_to_string(res));*/ 214 LOGGER_ERROR("Failed to get config: %s", vpx_codec_err_to_string(rc));
228 return -1; 215 return -1;
229 } 216 }
230 217
@@ -232,9 +219,10 @@ int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t
232 cfg.g_w = width; 219 cfg.g_w = width;
233 cfg.g_h = height; 220 cfg.g_h = height;
234 221
235 if (vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, 222 rc = vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION);
236 VPX_ENCODER_ABI_VERSION) != VPX_CODEC_OK) { 223
237 /*fprintf(stderr, "Failed to initialize encoder\n");*/ 224 if ( rc != VPX_CODEC_OK) {
225 LOGGER_ERROR("Failed to initialize encoder: %s", vpx_codec_err_to_string(rc));
238 return -1; 226 return -1;
239 } 227 }
240 228
@@ -243,13 +231,30 @@ int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t
243 231
244int init_audio_encoder(CodecState *cs, uint32_t audio_channels) 232int init_audio_encoder(CodecState *cs, uint32_t audio_channels)
245{ 233{
246 int err = OPUS_OK; 234 int rc = OPUS_OK;
247 cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, audio_channels, OPUS_APPLICATION_AUDIO, &err); 235 cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, audio_channels, OPUS_APPLICATION_AUDIO, &rc);
248 err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate)); 236
249 err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10)); 237 if ( rc != OPUS_OK ) {
238 LOGGER_ERROR("Error while starting audio encoder: %s", opus_strerror(rc));
239 return -1;
240 }
241
242 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate));
250 243
244 if ( rc != OPUS_OK ) {
245 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc));
246 return -1;
247 }
248
249 rc = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10));
250
251 if ( rc != OPUS_OK ) {
252 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc));
253 return -1;
254 }
251 255
252 return err == OPUS_OK ? 0 : -1; 256
257 return 0;
253} 258}
254 259
255 260
@@ -262,7 +267,8 @@ CodecState *codec_init_session ( uint32_t audio_bitrate,
262 uint32_t video_bitrate ) 267 uint32_t video_bitrate )
263{ 268{
264 CodecState *retu = calloc(sizeof(CodecState), 1); 269 CodecState *retu = calloc(sizeof(CodecState), 1);
265 assert(retu); 270
271 if (!retu) return NULL;
266 272
267 retu->audio_bitrate = audio_bitrate; 273 retu->audio_bitrate = audio_bitrate;
268 retu->audio_sample_rate = audio_sample_rate; 274 retu->audio_sample_rate = audio_sample_rate;
@@ -271,8 +277,7 @@ CodecState *codec_init_session ( uint32_t audio_bitrate,
271 if (!video_width || !video_height) { /* Disable video */ 277 if (!video_width || !video_height) { /* Disable video */
272 /*video_width = 320; 278 /*video_width = 320;
273 video_height = 240; */ 279 video_height = 240; */
274 } 280 } else {
275 else {
276 retu->capabilities |= ( 0 == init_video_encoder(retu, video_width, video_height, video_bitrate) ) ? v_encoding : 0; 281 retu->capabilities |= ( 0 == init_video_encoder(retu, video_width, video_height, video_bitrate) ) ? v_encoding : 0;
277 retu->capabilities |= ( 0 == init_video_decoder(retu) ) ? v_decoding : 0; 282 retu->capabilities |= ( 0 == init_video_decoder(retu) ) ? v_decoding : 0;
278 } 283 }
@@ -280,24 +285,29 @@ CodecState *codec_init_session ( uint32_t audio_bitrate,
280 retu->capabilities |= ( 0 == init_audio_encoder(retu, audio_channels) ) ? a_encoding : 0; 285 retu->capabilities |= ( 0 == init_audio_encoder(retu, audio_channels) ) ? a_encoding : 0;
281 retu->capabilities |= ( 0 == init_audio_decoder(retu, audio_channels) ) ? a_decoding : 0; 286 retu->capabilities |= ( 0 == init_audio_decoder(retu, audio_channels) ) ? a_decoding : 0;
282 287
288 if ( retu->capabilities == 0 ) { /* everything failed */
289 free (retu);
290 return NULL;
291 }
292
283 return retu; 293 return retu;
284} 294}
285 295
286void codec_terminate_session ( CodecState *cs ) 296void codec_terminate_session ( CodecState *cs )
287{ 297{
288 if ( cs->audio_encoder ) 298 if ( cs->audio_encoder )
289 opus_encoder_destroy(cs->audio_encoder); 299 opus_encoder_destroy(cs->audio_encoder);
290 300
291 if ( cs->audio_decoder ) 301 if ( cs->audio_decoder )
292 opus_decoder_destroy(cs->audio_decoder); 302 opus_decoder_destroy(cs->audio_decoder);
293
294 303
295 /* TODO: Terminate video 304
296 * Do what??? 305 /* TODO: Terminate video
306 * Do what?
297 */ 307 */
298 if ( cs->capabilities & v_decoding ) 308 if ( cs->capabilities & v_decoding )
299 vpx_codec_destroy(&cs->v_decoder); 309 vpx_codec_destroy(&cs->v_decoder);
300 310
301 if ( cs->capabilities & v_encoding ) 311 if ( cs->capabilities & v_encoding )
302 vpx_codec_destroy(&cs->v_encoder); 312 vpx_codec_destroy(&cs->v_encoder);
303} 313}
diff --git a/toxav/media.h b/toxav/media.h
index 57817516..66798351 100644
--- a/toxav/media.h
+++ b/toxav/media.h
@@ -38,8 +38,7 @@
38/* Audio encoding/decoding */ 38/* Audio encoding/decoding */
39#include <opus.h> 39#include <opus.h>
40 40
41typedef enum _Capabilities 41typedef enum _Capabilities {
42{
43 none, 42 none,
44 a_encoding = 1 << 0, 43 a_encoding = 1 << 0,
45 a_decoding = 1 << 1, 44 a_decoding = 1 << 1,
@@ -65,13 +64,26 @@ typedef struct _CodecState {
65 OpusDecoder *audio_decoder; 64 OpusDecoder *audio_decoder;
66 65
67 uint64_t capabilities; /* supports*/ 66 uint64_t capabilities; /* supports*/
68 67
69} CodecState; 68} CodecState;
70 69
71struct jitter_buffer *create_queue(int capacity);
72 70
73int queue(struct jitter_buffer *q, RTPMessage *pk); 71typedef struct _JitterBuffer {
74RTPMessage *dequeue(struct jitter_buffer *q, int *success); 72 RTPMessage **queue;
73 uint16_t capacity;
74 uint16_t size;
75 uint16_t front;
76 uint16_t rear;
77 uint8_t queue_ready;
78 uint16_t current_id;
79 uint32_t current_ts;
80 uint8_t id_set;
81} JitterBuffer;
82
83JitterBuffer *create_queue(int capacity);
84void terminate_queue(JitterBuffer *q);
85void queue(JitterBuffer *q, RTPMessage *pk);
86RTPMessage *dequeue(JitterBuffer *q, int *success);
75 87
76 88
77CodecState *codec_init_session ( uint32_t audio_bitrate, 89CodecState *codec_init_session ( uint32_t audio_bitrate,
diff --git a/toxav/msi.c b/toxav/msi.c
index 6cb423cf..5b13da61 100755..100644
--- a/toxav/msi.c
+++ b/toxav/msi.c
@@ -26,7 +26,7 @@
26#include "config.h" 26#include "config.h"
27#endif /* HAVE_CONFIG_H */ 27#endif /* HAVE_CONFIG_H */
28 28
29#define _BSD_SOURCE 29#include "../toxcore/logger.h"
30 30
31#include "msi.h" 31#include "msi.h"
32#include "event.h" 32#include "event.h"
@@ -117,13 +117,16 @@ typedef struct _MSIMessage {
117 117
118static struct _Callbacks { 118static struct _Callbacks {
119 MSICallback function; 119 MSICallback function;
120 void* data; 120 void *data;
121} callbacks[11] = {0}; 121} callbacks[11] = {0};
122 122
123inline__ void invoke_callback(MSICallbackID id) 123inline__ void invoke_callback(int32_t call_index, MSICallbackID id)
124{ 124{
125 /*if ( callbacks[id].function ) event.rise ( callbacks[id].function, callbacks[id].data );*/ 125 /*if ( callbacks[id].function ) event.rise ( callbacks[id].function, callbacks[id].data );*/
126 if ( callbacks[id].function ) callbacks[id].function ( callbacks[id].data ); 126 if ( callbacks[id].function ) {
127 LOGGER_DEBUG("Invoking callback function: %d", id);
128 callbacks[id].function ( call_index, callbacks[id].data );
129 }
127} 130}
128 131
129/*static MSICallback callbacks[10] = {0};*/ 132/*static MSICallback callbacks[10] = {0};*/
@@ -204,18 +207,6 @@ static inline__ const uint8_t *stringify_response ( MSIResponse response )
204} 207}
205 208
206 209
207#define ON_HEADER(iterator, header, descriptor, size_const) \
208( memcmp(iterator, descriptor, size_const) == 0){ /* Okay */ \
209 iterator += size_const; /* Set iterator at beginning of value part */ \
210 if ( *iterator != value_byte ) { assert(0); return -1; }\
211 iterator ++;\
212 uint16_t _value_size = (uint16_t) *(iterator ) << 8 | \
213 (uint16_t) *(iterator + 1); \
214 header.header_value = calloc(sizeof(uint8_t), _value_size); \
215 header.size = _value_size; \
216 memcpy(header.header_value, iterator + 2, _value_size);\
217 iterator = iterator + 2 + _value_size; /* set iterator at new header or end_byte */ \
218}
219 210
220/** 211/**
221 * @brief Parse raw 'data' received from socket into MSIMessage struct. 212 * @brief Parse raw 'data' received from socket into MSIMessage struct.
@@ -230,7 +221,22 @@ static inline__ const uint8_t *stringify_response ( MSIResponse response )
230 */ 221 */
231int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length ) 222int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length )
232{ 223{
233 assert ( msg ); 224
225#define ON_HEADER(iterator, header, descriptor, size_const) \
226( memcmp(iterator, descriptor, size_const) == 0){ /* Okay */ \
227iterator += size_const; /* Set iterator at begining of value part */ \
228if ( *iterator != value_byte ) { assert(0); return -1; }\
229 iterator ++;\
230 uint16_t _value_size = (uint16_t) *(iterator ) << 8 | \
231 (uint16_t) *(iterator + 1); \
232 header.header_value = calloc(sizeof(uint8_t), _value_size); \
233 header.size = _value_size; \
234 memcpy(header.header_value, iterator + 2, _value_size);\
235 iterator = iterator + 2 + _value_size; /* set iterator at new header or end_byte */ }
236
237 if ( msg == NULL ) {
238 LOGGER_ERROR("Could not parse message: no storage!");
239 }
234 240
235 if ( data[length - 1] ) /* End byte must have value 0 */ 241 if ( data[length - 1] ) /* End byte must have value 0 */
236 return -1; 242 return -1;
@@ -290,9 +296,13 @@ int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length )
290 break; 296 break;
291 297
292 default: 298 default:
299 LOGGER_ERROR("Unkown field value");
293 return -1; 300 return -1;
294 } 301 }
295 } else return -1; 302 } else {
303 LOGGER_ERROR("Invalid field byte or field size too large");
304 return -1;
305 }
296 306
297 /* If it's anything else return failure as the message is invalid */ 307 /* If it's anything else return failure as the message is invalid */
298 308
@@ -304,8 +314,9 @@ int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length )
304 314
305#define ALLOCATE_HEADER( var, mheader_value, t_size) \ 315#define ALLOCATE_HEADER( var, mheader_value, t_size) \
306var.header_value = calloc(sizeof *mheader_value, t_size); \ 316var.header_value = calloc(sizeof *mheader_value, t_size); \
307memcpy(var.header_value, mheader_value, t_size); \ 317if (var.header_value == NULL) { LOGGER_WARNING("Header allocation failed!"); } \
308var.size = t_size; 318else { memcpy(var.header_value, mheader_value, t_size); \
319var.size = t_size; }
309 320
310 321
311/** 322/**
@@ -316,7 +327,9 @@ var.size = t_size;
316 */ 327 */
317void free_message ( MSIMessage *msg ) 328void free_message ( MSIMessage *msg )
318{ 329{
319 assert ( msg ); 330 if ( msg == NULL ) {
331 LOGGER_ERROR("Tried to free empty message");
332 }
320 333
321 free ( msg->calltype.header_value ); 334 free ( msg->calltype.header_value );
322 free ( msg->request.header_value ); 335 free ( msg->request.header_value );
@@ -343,7 +356,11 @@ void free_message ( MSIMessage *msg )
343MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id ) 356MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id )
344{ 357{
345 MSIMessage *_retu = calloc ( sizeof ( MSIMessage ), 1 ); 358 MSIMessage *_retu = calloc ( sizeof ( MSIMessage ), 1 );
346 assert ( _retu ); 359
360 if ( _retu == NULL ) {
361 LOGGER_WARNING("Allocation failed!");
362 return NULL;
363 }
347 364
348 if ( type == TYPE_REQUEST ) { 365 if ( type == TYPE_REQUEST ) {
349 ALLOCATE_HEADER ( _retu->request, type_id, strlen ( (const char *)type_id ) ) 366 ALLOCATE_HEADER ( _retu->request, type_id, strlen ( (const char *)type_id ) )
@@ -371,10 +388,17 @@ MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id )
371 */ 388 */
372MSIMessage *parse_message ( const uint8_t *data, uint16_t length ) 389MSIMessage *parse_message ( const uint8_t *data, uint16_t length )
373{ 390{
374 assert ( data ); 391 if ( data == NULL ) {
392 LOGGER_WARNING("Tried to parse empty message!");
393 return NULL;
394 }
375 395
376 MSIMessage *_retu = calloc ( sizeof ( MSIMessage ), 1 ); 396 MSIMessage *_retu = calloc ( sizeof ( MSIMessage ), 1 );
377 assert ( _retu ); 397
398 if ( _retu == NULL ) {
399 LOGGER_WARNING("Allocation failed!");
400 return NULL;
401 }
378 402
379 memset ( _retu, 0, sizeof ( MSIMessage ) ); 403 memset ( _retu, 0, sizeof ( MSIMessage ) );
380 404
@@ -397,6 +421,42 @@ MSIMessage *parse_message ( const uint8_t *data, uint16_t length )
397 421
398 422
399/** 423/**
424 * @brief Makes clear message presentation
425 *
426 * @param msg Message
427 * @param dest Dest string
428 * @return int
429 */
430int stringify_message(MSIMessage *msg, char *dest)
431{
432#define HDR_TO_STR(__dest, __hdr) if (__hdr.header_value) {\
433 char nltstr[MSI_MAXMSG_SIZE]; memset(nltstr, '\0', MSI_MAXMSG_SIZE); int i = 0; \
434 for ( ; i < __hdr.size; i ++) nltstr[i] = (char)__hdr.header_value[i]; \
435 }
436
437 if ( !msg || !dest )
438 return -1;
439
440 HDR_TO_STR(dest, msg->version);
441 HDR_TO_STR(dest, msg->request);
442 HDR_TO_STR(dest, msg->response);
443 HDR_TO_STR(dest, msg->reason);
444 HDR_TO_STR(dest, msg->callid);
445 HDR_TO_STR(dest, msg->calltype);
446 HDR_TO_STR(dest, msg->cryptokey);
447 HDR_TO_STR(dest, msg->nonce);
448
449// if (msg->version.header_value) {
450// U8_TO_NLTCHAR(msg->version.header_value, msg->version.size, nltstr, MSI_MAXMSG_SIZE);
451// sprintf(dest, "Version: %s\n", nltstr);
452// }
453
454 return 0;
455}
456
457
458
459/**
400 * @brief Speaks for it self. 460 * @brief Speaks for it self.
401 * 461 *
402 * @param dest Container. 462 * @param dest Container.
@@ -413,9 +473,21 @@ uint8_t *append_header_to_string (
413 uint16_t value_len, 473 uint16_t value_len,
414 uint16_t *length ) 474 uint16_t *length )
415{ 475{
416 assert ( dest ); 476 if ( dest == NULL ) {
417 assert ( header_value ); 477 LOGGER_ERROR("No destination space!");
418 assert ( header_field ); 478 assert(dest);
479 }
480
481 if (header_value == NULL) {
482 LOGGER_ERROR("Empty header value");
483 return NULL;
484 }
485
486 if ( header_field == NULL ) {
487 LOGGER_ERROR("Empty header field");
488 return NULL;
489 }
490
419 491
420 const uint8_t *_hvit = header_value; 492 const uint8_t *_hvit = header_value;
421 uint16_t _total = 6 + value_len; /* 6 is known plus header value len + field len*/ 493 uint16_t _total = 6 + value_len; /* 6 is known plus header value len + field len*/
@@ -466,10 +538,6 @@ uint8_t *append_header_to_string (
466} 538}
467 539
468 540
469#define CLEAN_ASSIGN(added, var, field, header)\
470if ( header.header_value ) { var = append_header_to_string(var, (const uint8_t*)field, header.header_value, header.size, &added); }
471
472
473/** 541/**
474 * @brief Convert MSIMessage struct to _sendable_ string. 542 * @brief Convert MSIMessage struct to _sendable_ string.
475 * 543 *
@@ -477,10 +545,20 @@ if ( header.header_value ) { var = append_header_to_string(var, (const uint8_t*)
477 * @param dest Destination. 545 * @param dest Destination.
478 * @return uint16_t It's final size. 546 * @return uint16_t It's final size.
479 */ 547 */
480uint16_t message_to_string ( MSIMessage *msg, uint8_t *dest ) 548uint16_t message_to_send ( MSIMessage *msg, uint8_t *dest )
481{ 549{
482 assert ( msg ); 550#define CLEAN_ASSIGN(added, var, field, header)\
483 assert ( dest ); 551 if ( header.header_value ) { var = append_header_to_string(var, (const uint8_t*)field, header.header_value, header.size, &added); }
552
553 if (msg == NULL) {
554 LOGGER_ERROR("Empty message!");
555 return 0;
556 }
557
558 if (dest == NULL ) {
559 LOGGER_ERROR("Empty destination!");
560 return 0;
561 }
484 562
485 uint8_t *_iterated = dest; 563 uint8_t *_iterated = dest;
486 uint16_t _size = 0; 564 uint16_t _size = 0;
@@ -525,7 +603,10 @@ GENERIC_SETTER_DEFINITION ( nonce )
525 */ 603 */
526void t_randomstr ( uint8_t *str, size_t size ) 604void t_randomstr ( uint8_t *str, size_t size )
527{ 605{
528 assert ( str ); 606 if (str == NULL) {
607 LOGGER_DEBUG("Empty destination!");
608 return;
609 }
529 610
530 static const uint8_t _bytes[] = 611 static const uint8_t _bytes[] =
531 "0123456789" 612 "0123456789"
@@ -607,32 +688,51 @@ static inline__ const uint8_t *stringify_error_code ( MSICallError error_code )
607 * @retval -1 Error occurred. 688 * @retval -1 Error occurred.
608 * @retval 0 Success. 689 * @retval 0 Success.
609 */ 690 */
610int send_message ( MSISession *session, MSIMessage *msg, uint32_t to ) 691int send_message ( MSISession *session, MSICall *call, MSIMessage *msg, uint32_t to )
611{ 692{
612 msi_msg_set_callid ( msg, session->call->id, CALL_ID_LEN ); 693 msi_msg_set_callid ( msg, call->id, CALL_ID_LEN );
613 694
614 uint8_t _msg_string_final [MSI_MAXMSG_SIZE]; 695 uint8_t _msg_string_final [MSI_MAXMSG_SIZE];
615 uint16_t _length = message_to_string ( msg, _msg_string_final ); 696 uint16_t _length = message_to_send ( msg, _msg_string_final );
616 697
617 return m_msi_packet(session->messenger_handle, to, _msg_string_final, _length) ? 0 : -1; 698 if (!_length) {
699 LOGGER_WARNING("Parsing message failed; nothing sent!");
700 return -1;
701 }
702
703 /*
704 LOGGER_SCOPE(
705 char cast[MSI_MAXMSG_SIZE];
706 stringify_message(msg, cast);
707 LOGGER_DEBUG("[Call: %s] [to: %u] Sending message: len: %d\n%s", call->id, to, _length, cast);
708 );*/
709
710
711 if ( m_msi_packet(session->messenger_handle, to, _msg_string_final, _length) ) {
712 LOGGER_DEBUG("Sent message");
713 return 0;
714 }
715
716 return -1;
618} 717}
619 718
620 719
621/** 720/**
622 * @brief Determine 'bigger' call id 721 * @brief Determine 'bigger' call id
623 * 722 *
624 * @param first duh 723 * @param first duh
625 * @param second duh 724 * @param second duh
626 * @return int 725 * @return int
627 * @retval 0 it's first 726 * @retval 0 it's first
628 * @retval 1 it's second 727 * @retval 1 it's second
629 */ 728 */
630int call_id_bigger( const uint8_t* first, const uint8_t* second) 729int call_id_bigger( const uint8_t *first, const uint8_t *second)
631{ 730{
632 int i = 0; 731 int i = 0;
732
633 for (; i < CALL_ID_LEN; i ++) { 733 for (; i < CALL_ID_LEN; i ++) {
634 734
635 if ( first[i] != second[i] ) 735 if ( first[i] != second[i] )
636 return first[i] > second [i] ? 0 : 1; 736 return first[i] > second [i] ? 0 : 1;
637 } 737 }
638} 738}
@@ -646,19 +746,19 @@ int call_id_bigger( const uint8_t* first, const uint8_t* second)
646 * @param peer_id The peer. 746 * @param peer_id The peer.
647 * @return void 747 * @return void
648 */ 748 */
649void flush_peer_type ( MSISession *session, MSIMessage *msg, int peer_id ) 749void flush_peer_type ( MSICall *call, MSIMessage *msg, int peer_id )
650{ 750{
651 if ( msg->calltype.header_value ) { 751 if ( msg->calltype.header_value ) {
652 uint8_t hdrval [MSI_MAXMSG_SIZE]; /* Make sure no overflow */ 752 uint8_t hdrval [MSI_MAXMSG_SIZE]; /* Make sure no overflow */
653 753
654 memcpy(hdrval, msg->calltype.header_value, msg->calltype.size); 754 memcpy(hdrval, msg->calltype.header_value, msg->calltype.size);
655 hdrval[msg->calltype.size] = '\0'; 755 hdrval[msg->calltype.size] = '\0';
656 756
657 if ( strcmp ( ( const char * ) hdrval, CT_AUDIO_HEADER_VALUE ) == 0 ) { 757 if ( strcmp ( ( const char * ) hdrval, CT_AUDIO_HEADER_VALUE ) == 0 ) {
658 session->call->type_peer[peer_id] = type_audio; 758 call->type_peer[peer_id] = type_audio;
659 759
660 } else if ( strcmp ( ( const char * ) hdrval, CT_VIDEO_HEADER_VALUE ) == 0 ) { 760 } else if ( strcmp ( ( const char * ) hdrval, CT_VIDEO_HEADER_VALUE ) == 0 ) {
661 session->call->type_peer[peer_id] = type_video; 761 call->type_peer[peer_id] = type_video;
662 } else {} /* Error */ 762 } else {} /* Error */
663 } else {} /* Error */ 763 } else {} /* Error */
664} 764}
@@ -669,13 +769,19 @@ void handle_remote_connection_change(Messenger *messenger, int friend_num, uint8
669 769
670 switch ( status ) { 770 switch ( status ) {
671 case 0: { /* Went offline */ 771 case 0: { /* Went offline */
672 if ( session->call ) { 772 uint32_t j = 0;
773
774 for ( ; j < session->max_calls; j ++ ) {
775
776 if ( !session->calls[j] ) continue;
777
673 int i = 0; 778 int i = 0;
674 779
675 for ( ; i < session->call->peer_count; i ++ ) 780 for ( ; i < session->calls[j]->peer_count; i ++ )
676 if ( session->call->peers[i] == friend_num ) { 781 if ( session->calls[j]->peers[i] == friend_num ) {
677 invoke_callback(MSI_OnPeerTimeout); 782 invoke_callback(j, MSI_OnPeerTimeout);
678 return; 783 LOGGER_DEBUG("Remote: %d timed out!", friend_num);
784 return; /* TODO: On group calls change behaviour */
679 } 785 }
680 } 786 }
681 } 787 }
@@ -686,6 +792,21 @@ void handle_remote_connection_change(Messenger *messenger, int friend_num, uint8
686 } 792 }
687} 793}
688 794
795MSICall *find_call ( MSISession *session, uint8_t *call_id )
796{
797 if ( call_id == NULL ) return NULL;
798
799 uint32_t i = 0;
800
801 for (; i < session->max_calls; i ++ )
802 if ( session->calls[i] && memcmp(session->calls[i]->id, call_id, CALL_ID_LEN) == 0 ) {
803 LOGGER_DEBUG("Found call id: %s", session->calls[i]->id);
804 return session->calls[i];
805 }
806
807 return NULL;
808}
809
689/** 810/**
690 * @brief Sends error response to peer. 811 * @brief Sends error response to peer.
691 * 812 *
@@ -695,20 +816,22 @@ void handle_remote_connection_change(Messenger *messenger, int friend_num, uint8
695 * @return int 816 * @return int
696 * @retval 0 It's always success. 817 * @retval 0 It's always success.
697 */ 818 */
698int handle_error ( MSISession *session, MSICallError errid, uint32_t to ) 819int handle_error ( MSISession *session, MSICall *call, MSICallError errid, uint32_t to )
699{ 820{
821 LOGGER_DEBUG("Sending error: %d on call: %s", errid, call->id);
822
700 MSIMessage *_msg_error = msi_new_message ( TYPE_RESPONSE, stringify_response ( error ) ); 823 MSIMessage *_msg_error = msi_new_message ( TYPE_RESPONSE, stringify_response ( error ) );
701 824
702 const uint8_t *_error_code_str = stringify_error_code ( errid ); 825 const uint8_t *_error_code_str = stringify_error_code ( errid );
703 826
704 msi_msg_set_reason ( _msg_error, _error_code_str, strlen ( ( const char * ) _error_code_str ) ); 827 msi_msg_set_reason ( _msg_error, _error_code_str, strlen ( ( const char * ) _error_code_str ) );
705 send_message ( session, _msg_error, to ); 828 send_message ( session, call, _msg_error, to );
706 free_message ( _msg_error ); 829 free_message ( _msg_error );
707 830
708 session->last_error_id = errid; 831 session->last_error_id = errid;
709 session->last_error_str = stringify_error ( errid ); 832 session->last_error_str = stringify_error ( errid );
710 833
711 invoke_callback(MSI_OnError); 834 invoke_callback(call->call_idx, MSI_OnError);
712 835
713 return 0; 836 return 0;
714} 837}
@@ -723,16 +846,17 @@ int handle_error ( MSISession *session, MSICallError errid, uint32_t to )
723 * @retval -1 No error. 846 * @retval -1 No error.
724 * @retval 0 Error occurred and response sent. 847 * @retval 0 Error occurred and response sent.
725 */ 848 */
726int has_call_error ( MSISession *session, MSIMessage *msg ) 849int has_call_error ( MSISession *session, MSICall *call, MSIMessage *msg )
727{ 850{
728 if ( !msg->callid.header_value ) { 851 if ( !msg->callid.header_value ) {
729 return handle_error ( session, error_no_callid, msg->friend_id ); 852 return handle_error ( session, call, error_no_callid, msg->friend_id );
730 853
731 } else if ( !session->call ) { 854 } else if ( !call ) {
732 return handle_error ( session, error_no_call, msg->friend_id ); 855 LOGGER_WARNING("Handling message while no call!");
856 return 0;
733 857
734 } else if ( memcmp ( session->call->id, msg->callid.header_value, CALL_ID_LEN ) != 0 ) { 858 } else if ( memcmp ( call->id, msg->callid.header_value, CALL_ID_LEN ) != 0 ) {
735 return handle_error ( session, error_id_mismatch, msg->friend_id ); 859 return handle_error ( session, call, error_id_mismatch, msg->friend_id );
736 860
737 } 861 }
738 862
@@ -741,33 +865,6 @@ int has_call_error ( MSISession *session, MSIMessage *msg )
741 865
742 866
743/** 867/**
744 * @brief Function called at request timeout.
745 *
746 * @param arg Control session
747 * @return void*
748 */
749void *handle_timeout ( void *arg )
750{
751 /* TODO: Cancel might not arrive there; set up
752 * timers on these cancels and terminate call on
753 * their timeout
754 */
755 MSISession *_session = arg;
756
757 invoke_callback(MSI_OnRequestTimeout);
758
759 if ( _session && _session->call ) {
760
761 /* TODO: Cancel all? */
762 /* uint16_t _it = 0;
763 for ( ; _it < _session->call->peer_count; _it++ ) */
764 msi_cancel ( _session, _session->call->peers [0], "Request timedout" );
765 }
766
767 pthread_exit(NULL);
768}
769
770/**
771 * @brief Add peer to peer list. 868 * @brief Add peer to peer list.
772 * 869 *
773 * @param call What call. 870 * @param call What call.
@@ -785,6 +882,8 @@ void add_peer( MSICall *call, int peer_id )
785 } 882 }
786 883
787 call->peers[call->peer_count - 1] = peer_id; 884 call->peers[call->peer_count - 1] = peer_id;
885
886 LOGGER_DEBUG("Added peer: %d", peer_id);
788} 887}
789 888
790 889
@@ -798,14 +897,43 @@ void add_peer( MSICall *call, int peer_id )
798 */ 897 */
799MSICall *init_call ( MSISession *session, int peers, int ringing_timeout ) 898MSICall *init_call ( MSISession *session, int peers, int ringing_timeout )
800{ 899{
801 assert ( session );
802 assert ( peers );
803 900
804 MSICall *_call = calloc ( sizeof ( MSICall ), 1 ); 901 if (peers == 0) {
902 LOGGER_ERROR("No peers!");
903 return NULL;
904 }
905
906 int32_t _call_idx = 0;
907
908 for (; _call_idx < session->max_calls; _call_idx ++) {
909 if ( !session->calls[_call_idx] ) {
910 session->calls[_call_idx] = calloc ( sizeof ( MSICall ), 1 );
911 break;
912 }
913 }
914
915 if ( _call_idx == session->max_calls ) {
916 LOGGER_WARNING("Reached maximum amount of calls!");
917 return NULL;
918 }
919
920
921 MSICall *_call = session->calls[_call_idx];
922 _call->call_idx = _call_idx;
923
924 if ( _call == NULL ) {
925 LOGGER_WARNING("Allocation failed!");
926 return NULL;
927 }
928
805 _call->type_peer = calloc ( sizeof ( MSICallType ), peers ); 929 _call->type_peer = calloc ( sizeof ( MSICallType ), peers );
806 930
807 assert ( _call ); 931 if ( _call->type_peer == NULL ) {
808 assert ( _call->type_peer ); 932 LOGGER_WARNING("Allocation failed!");
933 return NULL;
934 }
935
936 _call->session = session;
809 937
810 /*_call->_participant_count = _peers;*/ 938 /*_call->_participant_count = _peers;*/
811 939
@@ -821,6 +949,7 @@ MSICall *init_call ( MSISession *session, int peers, int ringing_timeout )
821 949
822 pthread_mutex_init ( &_call->mutex, NULL ); 950 pthread_mutex_init ( &_call->mutex, NULL );
823 951
952 LOGGER_DEBUG("Started new call with index: %u", _call_idx);
824 return _call; 953 return _call;
825} 954}
826 955
@@ -833,263 +962,307 @@ MSICall *init_call ( MSISession *session, int peers, int ringing_timeout )
833 * @retval -1 Error occurred. 962 * @retval -1 Error occurred.
834 * @retval 0 Success. 963 * @retval 0 Success.
835 */ 964 */
836int terminate_call ( MSISession *session ) 965int terminate_call ( MSISession *session, MSICall *call )
837{ 966{
838 assert ( session ); 967 if ( !call ) {
839 968 LOGGER_WARNING("Tried to terminate non-existing call!");
840 if ( !session->call )
841 return -1; 969 return -1;
970 }
842 971
972 int rc = pthread_mutex_trylock(&session->mutex); /* Lock if not locked */
843 973
974 LOGGER_DEBUG("Terminated call id: %d", call->call_idx);
844 /* Check event loop and cancel timed events if there are any 975 /* Check event loop and cancel timed events if there are any
845 * NOTE: This has to be done before possibly 976 * NOTE: This has to be done before possibly
846 * locking the mutex the second time 977 * locking the mutex the second time
847 */ 978 */
848 event.timer_release ( session->call->request_timer_id ); 979 event.timer_release ( call->request_timer_id );
849 event.timer_release ( session->call->ringing_timer_id ); 980 event.timer_release ( call->ringing_timer_id );
850 981
851 /* Get a handle */ 982 /* Get a handle */
852 pthread_mutex_lock ( &session->call->mutex ); 983 pthread_mutex_lock ( &call->mutex );
853 984
854 MSICall *_call = session->call; 985 session->calls[call->call_idx] = NULL;
855 session->call = NULL;
856 986
857 free ( _call->type_peer ); 987 free ( call->type_peer );
858 free ( _call->key_local ); 988 free ( call->key_local );
859 free ( _call->key_peer ); 989 free ( call->key_peer );
860 free ( _call->peers); 990 free ( call->peers);
861 991
862 /* Release handle */ 992 /* Release handle */
863 pthread_mutex_unlock ( &_call->mutex ); 993 pthread_mutex_unlock ( &call->mutex );
864 994
865 pthread_mutex_destroy ( &_call->mutex ); 995 pthread_mutex_destroy ( &call->mutex );
866 996
867 free ( _call ); 997 free ( call );
998
999 if ( rc != EBUSY ) /* Unlock if locked by this call */
1000 pthread_mutex_unlock(&session->mutex);
868 1001
869 return 0; 1002 return 0;
870} 1003}
871 1004
872 1005
1006/**
1007 * @brief Function called at request timeout. If not called in thread it might cause trouble
1008 *
1009 * @param arg Control session
1010 * @return void*
1011 */
1012void *handle_timeout ( void *arg )
1013{
1014 /* TODO: Cancel might not arrive there; set up
1015 * timers on these cancels and terminate call on
1016 * their timeout
1017 */
1018 MSICall *_call = arg;
1019
1020 LOGGER_DEBUG("[Call: %s] Request timed out!", _call->id);
1021
1022 invoke_callback(_call->call_idx, MSI_OnRequestTimeout);
1023
1024 if ( _call && _call->session ) {
1025
1026 /* TODO: Cancel all? */
1027 /* uint16_t _it = 0;
1028 * for ( ; _it < _session->call->peer_count; _it++ ) */
1029 msi_cancel ( _call->session, _call->call_idx, _call->peers [0], "Request timed out" );
1030 terminate_call(_call->session, _call);
1031 }
1032
1033 pthread_exit(NULL);
1034}
1035
1036
873/********** Request handlers **********/ 1037/********** Request handlers **********/
874int handle_recv_invite ( MSISession *session, MSIMessage *msg ) 1038int handle_recv_invite ( MSISession *session, MSICall *call, MSIMessage *msg )
875{ 1039{
876 assert ( session ); 1040 LOGGER_DEBUG("Session: %p Handling 'invite' on call: %s", session, call ? (char *)call->id : "making new");
877 1041
878 1042 if ( call ) {
879 if ( session->call ) { 1043 if ( call->peers[0] == msg->friend_id ) {
880 if ( session->call->peers[0] == msg->friend_id ) { 1044 /* The glare case. A calls B when at the same time
881 /* The glare case. A calls B when at the same time
882 * B calls A. Who has advantage is set bey calculating 1045 * B calls A. Who has advantage is set bey calculating
883 * 'bigger' Call id and then that call id is being used in 1046 * 'bigger' Call id and then that call id is being used in
884 * future. User with 'bigger' Call id has the advantage 1047 * future. User with 'bigger' Call id has the advantage
885 * as in he will wait the response from the other. 1048 * as in he will wait the response from the other.
886 */ 1049 */
887 1050
888 if ( call_id_bigger (session->call->id, msg->callid.header_value) == 1 ) { /* Peer has advantage */ 1051 if ( call_id_bigger (call->id, msg->callid.header_value) == 1 ) { /* Peer has advantage */
889 terminate_call(session); 1052 terminate_call(session, call);
890 } 1053 } else {
891 else {
892 return 0; /* Wait for ringing from peer */ 1054 return 0; /* Wait for ringing from peer */
893 } 1055 }
894 1056
895 } 1057 } else {
896 else { 1058 handle_error ( session, call, error_busy, msg->friend_id ); /* TODO: Ugh*/
897 handle_error ( session, error_busy, msg->friend_id );
898 return 0; 1059 return 0;
899 } 1060 }
900 } 1061 }
901 1062
902 if ( !msg->callid.header_value ) { 1063 if ( !msg->callid.header_value ) {
903 handle_error ( session, error_no_callid, msg->friend_id ); 1064 handle_error ( session, call, error_no_callid, msg->friend_id );
904 return 0; 1065 return 0;
905 } 1066 }
906 1067
907 session->call = init_call ( session, 1, 0 ); 1068 MSICall *new_call = init_call ( session, 1, 0 );
908 memcpy ( session->call->id, msg->callid.header_value, CALL_ID_LEN );
909 session->call->state = call_starting;
910 1069
911 add_peer( session->call, msg->friend_id); 1070 if ( !new_call ) {
1071 handle_error ( session, call, error_busy, msg->friend_id );
1072 return 0;
1073 }
912 1074
913 flush_peer_type ( session, msg, 0 ); 1075 memcpy ( new_call->id, msg->callid.header_value, CALL_ID_LEN );
1076 new_call->state = call_starting;
1077
1078 add_peer( new_call, msg->friend_id);
1079
1080 flush_peer_type ( new_call, msg, 0 );
914 1081
915 MSIMessage *_msg_ringing = msi_new_message ( TYPE_RESPONSE, stringify_response ( ringing ) ); 1082 MSIMessage *_msg_ringing = msi_new_message ( TYPE_RESPONSE, stringify_response ( ringing ) );
916 send_message ( session, _msg_ringing, msg->friend_id ); 1083 send_message ( session, new_call, _msg_ringing, msg->friend_id );
917 free_message ( _msg_ringing ); 1084 free_message ( _msg_ringing );
918 1085
919 invoke_callback(MSI_OnInvite); 1086 invoke_callback(new_call->call_idx, MSI_OnInvite);
920 1087
921 return 1; 1088 return 1;
922} 1089}
923int handle_recv_start ( MSISession *session, MSIMessage *msg ) 1090int handle_recv_start ( MSISession *session, MSICall *call, MSIMessage *msg )
924{ 1091{
925 assert ( session ); 1092 LOGGER_DEBUG("Session: %p Handling 'start' on call: %s, friend id: %d", session, call->id, msg->friend_id );
926 1093
927 if ( has_call_error ( session, msg ) == 0 ) 1094 if ( has_call_error ( session, call, msg ) == 0 )
928 return 0; 1095 return -1;
929 1096
930 if ( !msg->cryptokey.header_value ) 1097 if ( !msg->cryptokey.header_value )
931 return handle_error ( session, error_no_crypto_key, msg->friend_id ); 1098 return handle_error ( session, call, error_no_crypto_key, msg->friend_id );
932 1099
933 session->call->state = call_active; 1100 call->state = call_active;
934 1101
935 session->call->key_peer = calloc ( sizeof ( uint8_t ), crypto_box_KEYBYTES ); 1102 call->key_peer = calloc ( sizeof ( uint8_t ), crypto_box_KEYBYTES );
936 memcpy ( session->call->key_peer, msg->cryptokey.header_value, crypto_box_KEYBYTES ); 1103 memcpy ( call->key_peer, msg->cryptokey.header_value, crypto_box_KEYBYTES );
937 1104
938 session->call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); 1105 call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES );
939 memcpy ( session->call->nonce_peer, msg->nonce.header_value, crypto_box_NONCEBYTES ); 1106 memcpy ( call->nonce_peer, msg->nonce.header_value, crypto_box_NONCEBYTES );
940 1107
941 flush_peer_type ( session, msg, 0 ); 1108 flush_peer_type ( call, msg, 0 );
942 1109
943 invoke_callback(MSI_OnStart); 1110 invoke_callback(call->call_idx, MSI_OnStart);
944 1111
945 return 1; 1112 return 1;
946} 1113}
947int handle_recv_reject ( MSISession *session, MSIMessage *msg ) 1114int handle_recv_reject ( MSISession *session, MSICall *call, MSIMessage *msg )
948{ 1115{
949 assert ( session ); 1116 LOGGER_DEBUG("Session: %p Handling 'reject' on call: %s", session, call->id);
950 1117
951 if ( has_call_error ( session, msg ) == 0 ) 1118 if ( has_call_error ( session, call, msg ) == 0 )
952 return 0; 1119 return 0;
953 1120
954 1121
955 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); 1122 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) );
956 send_message ( session, _msg_ending, msg->friend_id ); 1123 send_message ( session, call, _msg_ending, msg->friend_id );
957 free_message ( _msg_ending ); 1124 free_message ( _msg_ending );
958 1125
959 1126
960 invoke_callback(MSI_OnReject); 1127 invoke_callback(call->call_idx, MSI_OnReject);
961 /* 1128 /*
962 event.timer_release ( session->call->request_timer_id ); 1129 event.timer_release ( session->call->request_timer_id );
963 session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); 1130 session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout );
964 */ 1131 */
965 1132
966 terminate_call(session); 1133 terminate_call(session, call);
967 1134
968 return 1; 1135 return 1;
969} 1136}
970int handle_recv_cancel ( MSISession *session, MSIMessage *msg ) 1137int handle_recv_cancel ( MSISession *session, MSICall *call, MSIMessage *msg )
971{ 1138{
972 assert ( session ); 1139 LOGGER_DEBUG("Session: %p Handling 'cancel' on call: %s", session, call->id );
973 1140
974 if ( has_call_error ( session, msg ) == 0 ) 1141 if ( has_call_error ( session, call, msg ) == 0 )
975 return 0; 1142 return 0;
976 1143
977 /* Act as end message */ 1144 /* Act as end message */
978 1145 /*
979 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); 1146 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) );
980 send_message ( session, _msg_ending, msg->friend_id ); 1147 send_message ( session, call, _msg_ending, msg->friend_id );
981 free_message ( _msg_ending ); 1148 free_message ( _msg_ending );*/
982 1149
983 invoke_callback(MSI_OnCancel); 1150 invoke_callback(call->call_idx, MSI_OnCancel);
984 1151
985 terminate_call ( session ); 1152 terminate_call ( session, call );
986 1153
987 return 1; 1154 return 1;
988} 1155}
989int handle_recv_end ( MSISession *session, MSIMessage *msg ) 1156int handle_recv_end ( MSISession *session, MSICall *call, MSIMessage *msg )
990{ 1157{
991 assert ( session ); 1158 LOGGER_DEBUG("Session: %p Handling 'end' on call: %s", session, call->id );
992 1159
993 if ( has_call_error ( session, msg ) == 0 ) 1160 if ( has_call_error ( session, call, msg ) == 0 )
994 return 0; 1161 return 0;
995 1162
996 1163
997 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) ); 1164 MSIMessage *_msg_ending = msi_new_message ( TYPE_RESPONSE, stringify_response ( ending ) );
998 send_message ( session, _msg_ending, msg->friend_id ); 1165 send_message ( session, call, _msg_ending, msg->friend_id );
999 free_message ( _msg_ending ); 1166 free_message ( _msg_ending );
1000 1167
1001 invoke_callback(MSI_OnEnd); 1168 invoke_callback(call->call_idx, MSI_OnEnd);
1002 1169
1003 terminate_call ( session ); 1170 terminate_call ( session, call );
1004 return 1; 1171 return 1;
1005} 1172}
1006 1173
1007/********** Response handlers **********/ 1174/********** Response handlers **********/
1008int handle_recv_ringing ( MSISession *session, MSIMessage *msg ) 1175int handle_recv_ringing ( MSISession *session, MSICall *call, MSIMessage *msg )
1009{ 1176{
1010 assert ( session ); 1177 if ( has_call_error ( session, call, msg ) == 0 )
1011
1012 if ( has_call_error ( session, msg ) == 0 )
1013 return 0; 1178 return 0;
1014 1179
1015 session->call->ringing_timer_id = event.timer_alloc ( handle_timeout, session, session->call->ringing_tout_ms ); 1180 LOGGER_DEBUG("Session: %p Handling 'ringing' on call: %s", session, call->id );
1016 1181
1017 invoke_callback(MSI_OnRinging); 1182 call->ringing_timer_id = event.timer_alloc ( handle_timeout, call, call->ringing_tout_ms );
1183
1184 invoke_callback(call->call_idx, MSI_OnRinging);
1018 1185
1019 return 1; 1186 return 1;
1020} 1187}
1021int handle_recv_starting ( MSISession *session, MSIMessage *msg ) 1188int handle_recv_starting ( MSISession *session, MSICall *call, MSIMessage *msg )
1022{ 1189{
1023 assert ( session ); 1190 if ( has_call_error ( session, call, msg ) == 0 )
1024
1025 if ( has_call_error ( session, msg ) == 0 )
1026 return 0; 1191 return 0;
1027 1192
1193 LOGGER_DEBUG("Session: %p Handling 'starting' on call: %s", session, call->id );
1194
1195
1028 if ( !msg->cryptokey.header_value ) { 1196 if ( !msg->cryptokey.header_value ) {
1029 return handle_error ( session, error_no_crypto_key, msg->friend_id ); 1197 return handle_error ( session, call, error_no_crypto_key, msg->friend_id );
1030 } 1198 }
1031 1199
1032 /* Generate local key/nonce to send */ 1200 /* Generate local key/nonce to send */
1033 session->call->key_local = calloc ( sizeof ( uint8_t ), crypto_box_KEYBYTES ); 1201 call->key_local = calloc ( sizeof ( uint8_t ), crypto_box_KEYBYTES );
1034 new_symmetric_key ( session->call->key_local ); 1202 new_symmetric_key ( call->key_local );
1035 1203
1036 session->call->nonce_local = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); 1204 call->nonce_local = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES );
1037 new_nonce ( session->call->nonce_local ); 1205 new_nonce ( call->nonce_local );
1038 1206
1039 /* Save peer key/nonce */ 1207 /* Save peer key/nonce */
1040 session->call->key_peer = calloc ( sizeof ( uint8_t ), crypto_box_KEYBYTES ); 1208 call->key_peer = calloc ( sizeof ( uint8_t ), crypto_box_KEYBYTES );
1041 memcpy ( session->call->key_peer, msg->cryptokey.header_value, crypto_box_KEYBYTES ); 1209 memcpy ( call->key_peer, msg->cryptokey.header_value, crypto_box_KEYBYTES );
1042 1210
1043 session->call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); 1211 call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES );
1044 memcpy ( session->call->nonce_peer, msg->nonce.header_value, crypto_box_NONCEBYTES ); 1212 memcpy ( call->nonce_peer, msg->nonce.header_value, crypto_box_NONCEBYTES );
1045 1213
1046 session->call->state = call_active; 1214 call->state = call_active;
1047 1215
1048 MSIMessage *_msg_start = msi_new_message ( TYPE_REQUEST, stringify_request ( start ) ); 1216 MSIMessage *_msg_start = msi_new_message ( TYPE_REQUEST, stringify_request ( start ) );
1049 msi_msg_set_cryptokey ( _msg_start, session->call->key_local, crypto_box_KEYBYTES ); 1217 msi_msg_set_cryptokey ( _msg_start, call->key_local, crypto_box_KEYBYTES );
1050 msi_msg_set_nonce ( _msg_start, session->call->nonce_local, crypto_box_NONCEBYTES ); 1218 msi_msg_set_nonce ( _msg_start, call->nonce_local, crypto_box_NONCEBYTES );
1051 send_message ( session, _msg_start, msg->friend_id ); 1219 send_message ( session, call, _msg_start, msg->friend_id );
1052 free_message ( _msg_start ); 1220 free_message ( _msg_start );
1053 1221
1054 flush_peer_type ( session, msg, 0 ); 1222 flush_peer_type ( call, msg, 0 );
1055 1223
1056 invoke_callback(MSI_OnStarting); 1224 invoke_callback(call->call_idx, MSI_OnStarting);
1057 1225
1058 event.timer_release ( session->call->ringing_timer_id ); 1226 event.timer_release ( call->ringing_timer_id );
1059 1227
1060 return 1; 1228 return 1;
1061} 1229}
1062int handle_recv_ending ( MSISession *session, MSIMessage *msg ) 1230int handle_recv_ending ( MSISession *session, MSICall *call, MSIMessage *msg )
1063{ 1231{
1064 assert ( session ); 1232 if ( has_call_error ( session, call, msg ) == 0 )
1065
1066 if ( has_call_error ( session, msg ) == 0 )
1067 return 0; 1233 return 0;
1068 1234
1069 /* Stop timer */ 1235 LOGGER_DEBUG("Session: %p Handling 'ending' on call: %s", session, call->id );
1070 event.timer_release ( session->call->request_timer_id ); 1236
1071 1237 /* Stop timer */
1072 invoke_callback(MSI_OnEnding); 1238 event.timer_release ( call->request_timer_id );
1073 1239
1240 invoke_callback(call->call_idx, MSI_OnEnding);
1241
1074 /* Terminate call */ 1242 /* Terminate call */
1075 terminate_call ( session ); 1243 terminate_call ( session, call );
1076 1244
1077 return 1; 1245 return 1;
1078} 1246}
1079int handle_recv_error ( MSISession *session, MSIMessage *msg ) 1247int handle_recv_error ( MSISession *session, MSICall *call, MSIMessage *msg )
1080{ 1248{
1081 assert ( session ); 1249 if ( !call ) {
1082 assert ( session->call ); 1250 LOGGER_WARNING("Handling 'error' on non-existing call!");
1251 return -1;
1252 }
1253
1254 LOGGER_DEBUG("Session: %p Handling 'error' on call: %s", session, call->id );
1083 1255
1084 /* Handle error accordingly */ 1256 /* Handle error accordingly */
1085 if ( msg->reason.header_value ) { 1257 if ( msg->reason.header_value ) {
1086 session->last_error_id = atoi ( ( const char * ) msg->reason.header_value ); 1258 session->last_error_id = atoi ( ( const char * ) msg->reason.header_value );
1087 session->last_error_str = stringify_error ( session->last_error_id ); 1259 session->last_error_str = stringify_error ( session->last_error_id );
1260 LOGGER_DEBUG("Error reason: %s", session->last_error_str);
1088 } 1261 }
1089 1262
1090 invoke_callback(MSI_OnEnding); 1263 invoke_callback(call->call_idx, MSI_OnEnding);
1091 1264
1092 terminate_call ( session ); 1265 terminate_call ( session, call );
1093 return 1; 1266 return 1;
1094} 1267}
1095 1268
@@ -1128,108 +1301,112 @@ int handle_recv_error ( MSISession *session, MSIMessage *msg )
1128 */ 1301 */
1129void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16_t length, void *object ) 1302void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16_t length, void *object )
1130{ 1303{
1304 LOGGER_DEBUG("Got msi message");
1131 /* Unused */ 1305 /* Unused */
1132 (void)messenger; 1306 (void)messenger;
1133 1307
1134 MSISession *_session = object; 1308 MSISession *_session = object;
1135 MSIMessage *_msg; 1309 MSIMessage *_msg;
1136 1310
1137 if ( !length ) return; 1311 if ( !length ) {
1312 LOGGER_WARNING("Lenght param negative");
1313 return;
1314 }
1138 1315
1139 _msg = parse_message ( data, length ); 1316 _msg = parse_message ( data, length );
1140 1317
1141 if ( !_msg ) return; 1318 if ( !_msg ) {
1319 LOGGER_WARNING("Error parsing message");
1320 return;
1321 } else {
1322 LOGGER_DEBUG("Successfully parsed message");
1323 }
1142 1324
1143 _msg->friend_id = source; 1325 _msg->friend_id = source;
1144 1326
1327 pthread_mutex_lock(&_session->mutex);
1328
1329 /* Find what call */
1330 MSICall *_call = _msg->callid.header_value ? find_call(_session, _msg->callid.header_value ) : NULL;
1331
1332
1145 1333
1146 /* Now handle message */ 1334 /* Now handle message */
1147 1335
1148 if ( _msg->request.header_value ) { /* Handle request */ 1336 if ( _msg->request.header_value ) { /* Handle request */
1149 1337
1150 if ( _msg->response.size > 32 ) goto free_end; 1338 if ( _msg->response.size > 32 ) {
1151 1339 LOGGER_WARNING("Header size too big");
1340 goto free_end;
1341 }
1342
1152 uint8_t _request_value[32]; 1343 uint8_t _request_value[32];
1153 1344
1154 memcpy(_request_value, _msg->request.header_value, _msg->request.size); 1345 memcpy(_request_value, _msg->request.header_value, _msg->request.size);
1155 _request_value[_msg->request.size] = '\0'; 1346 _request_value[_msg->request.size] = '\0';
1156 1347
1157 if ( same ( _request_value, stringify_request ( invite ) ) ) { 1348 if ( same ( _request_value, stringify_request ( invite ) ) ) {
1158 handle_recv_invite ( _session, _msg ); 1349 handle_recv_invite ( _session, _call, _msg );
1159 1350
1160 } else if ( same ( _request_value, stringify_request ( start ) ) ) { 1351 } else if ( same ( _request_value, stringify_request ( start ) ) ) {
1161 handle_recv_start ( _session, _msg ); 1352 handle_recv_start ( _session, _call, _msg );
1162 1353
1163 } else if ( same ( _request_value, stringify_request ( cancel ) ) ) { 1354 } else if ( same ( _request_value, stringify_request ( cancel ) ) ) {
1164 handle_recv_cancel ( _session, _msg ); 1355 handle_recv_cancel ( _session, _call, _msg );
1165 1356
1166 } else if ( same ( _request_value, stringify_request ( reject ) ) ) { 1357 } else if ( same ( _request_value, stringify_request ( reject ) ) ) {
1167 handle_recv_reject ( _session, _msg ); 1358 handle_recv_reject ( _session, _call, _msg );
1168 1359
1169 } else if ( same ( _request_value, stringify_request ( end ) ) ) { 1360 } else if ( same ( _request_value, stringify_request ( end ) ) ) {
1170 handle_recv_end ( _session, _msg ); 1361 handle_recv_end ( _session, _call, _msg );
1362 } else {
1363 LOGGER_WARNING("Uknown request");
1364 goto free_end;
1171 } 1365 }
1172 1366
1173 else goto free_end;
1174
1175 } else if ( _msg->response.header_value ) { /* Handle response */ 1367 } else if ( _msg->response.header_value ) { /* Handle response */
1176 1368
1177 if ( _msg->response.size > 32 ) goto free_end; 1369 if ( _msg->response.size > 32 ) {
1178 1370 LOGGER_WARNING("Header size too big");
1371 goto free_end;
1372 }
1373
1179 uint8_t _response_value[32]; 1374 uint8_t _response_value[32];
1180 1375
1181 memcpy(_response_value, _msg->response.header_value, _msg->response.size); 1376 memcpy(_response_value, _msg->response.header_value, _msg->response.size);
1182 _response_value[_msg->response.size] = '\0'; 1377 _response_value[_msg->response.size] = '\0';
1183 1378
1184 if ( same ( _response_value, stringify_response ( ringing ) ) ) { 1379 if ( same ( _response_value, stringify_response ( ringing ) ) ) {
1185 handle_recv_ringing ( _session, _msg ); 1380 handle_recv_ringing ( _session, _call, _msg );
1186 1381
1187 } else if ( same ( _response_value, stringify_response ( starting ) ) ) { 1382 } else if ( same ( _response_value, stringify_response ( starting ) ) ) {
1188 handle_recv_starting ( _session, _msg ); 1383 handle_recv_starting ( _session, _call, _msg );
1189 1384
1190 } else if ( same ( _response_value, stringify_response ( ending ) ) ) { 1385 } else if ( same ( _response_value, stringify_response ( ending ) ) ) {
1191 handle_recv_ending ( _session, _msg ); 1386 handle_recv_ending ( _session, _call, _msg );
1192 1387
1193 } else if ( same ( _response_value, stringify_response ( error ) ) ) { 1388 } else if ( same ( _response_value, stringify_response ( error ) ) ) {
1194 handle_recv_error ( _session, _msg ); 1389 handle_recv_error ( _session, _call, _msg );
1195 1390
1196 } else goto free_end; 1391 } else {
1392 LOGGER_WARNING("Uknown response");
1393 goto free_end;
1394 }
1197 1395
1198 /* Got response so cancel timer */ 1396 /* Got response so cancel timer */
1199 if ( _session->call ) 1397 if ( _call )
1200 event.timer_release ( _session->call->request_timer_id ); 1398 event.timer_release ( _call->request_timer_id );
1201 1399
1400 } else {
1401 LOGGER_WARNING("Invalid message: no resp nor requ headers");
1202 } 1402 }
1203 1403
1204 free_end:free_message ( _msg ); 1404free_end:
1405 free_message ( _msg );
1406 pthread_mutex_unlock(&_session->mutex);
1205} 1407}
1206 1408
1207 1409
1208/********************************************************************************************************************
1209 * *******************************************************************************************************************
1210 ********************************************************************************************************************
1211 ********************************************************************************************************************
1212 ********************************************************************************************************************
1213 *
1214 *
1215 *
1216 * PUBLIC API FUNCTIONS IMPLEMENTATIONS
1217 *
1218 *
1219 *
1220 ********************************************************************************************************************
1221 ********************************************************************************************************************
1222 ********************************************************************************************************************
1223 ********************************************************************************************************************
1224 ********************************************************************************************************************/
1225
1226
1227
1228
1229
1230
1231
1232
1233/** 1410/**
1234 * @brief Callback setter. 1411 * @brief Callback setter.
1235 * 1412 *
@@ -1237,7 +1414,7 @@ void msi_handle_packet ( Messenger *messenger, int source, uint8_t *data, uint16
1237 * @param id The id. 1414 * @param id The id.
1238 * @return void 1415 * @return void
1239 */ 1416 */
1240void msi_register_callback ( MSICallback callback, MSICallbackID id, void* userdata ) 1417void msi_register_callback ( MSICallback callback, MSICallbackID id, void *userdata )
1241{ 1418{
1242 callbacks[id].function = callback; 1419 callbacks[id].function = callback;
1243 callbacks[id].data = userdata; 1420 callbacks[id].data = userdata;
@@ -1248,21 +1425,31 @@ void msi_register_callback ( MSICallback callback, MSICallbackID id, void* userd
1248 * @brief Start the control session. 1425 * @brief Start the control session.
1249 * 1426 *
1250 * @param messenger Tox* object. 1427 * @param messenger Tox* object.
1251 * @param user_agent User agent, i.e. 'Venom'; 'QT-gui' 1428 * @param max_calls Amount of calls possible
1252 * @return MSISession* The created session. 1429 * @return MSISession* The created session.
1253 * @retval NULL Error occurred. 1430 * @retval NULL Error occurred.
1254 */ 1431 */
1255MSISession *msi_init_session ( Messenger* messenger ) 1432MSISession *msi_init_session ( Messenger *messenger, int32_t max_calls )
1256{ 1433{
1257 assert ( messenger ); 1434 if (messenger == NULL) {
1435 LOGGER_ERROR("Could not init session on empty messenger!");
1436 return NULL;
1437 }
1438
1439 if ( !max_calls) return NULL;
1258 1440
1259 MSISession *_retu = calloc ( sizeof ( MSISession ), 1 ); 1441 MSISession *_retu = calloc ( sizeof ( MSISession ), 1 );
1260 assert ( _retu ); 1442
1443 if (_retu == NULL) {
1444 LOGGER_ERROR("Allocation failed!");
1445 return NULL;
1446 }
1261 1447
1262 _retu->messenger_handle = messenger; 1448 _retu->messenger_handle = messenger;
1263 _retu->agent_handler = NULL; 1449 _retu->agent_handler = NULL;
1264 1450
1265 _retu->call = NULL; 1451 _retu->calls = calloc( sizeof (MSICall *), max_calls );
1452 _retu->max_calls = max_calls;
1266 1453
1267 _retu->frequ = 10000; /* default value? */ 1454 _retu->frequ = 10000; /* default value? */
1268 _retu->call_timeout = 30000; /* default value? */ 1455 _retu->call_timeout = 30000; /* default value? */
@@ -1273,6 +1460,9 @@ MSISession *msi_init_session ( Messenger* messenger )
1273 /* This is called when remote terminates session */ 1460 /* This is called when remote terminates session */
1274 m_callback_connectionstatus_internal_av(messenger, handle_remote_connection_change, _retu); 1461 m_callback_connectionstatus_internal_av(messenger, handle_remote_connection_change, _retu);
1275 1462
1463 pthread_mutex_init(&_retu->mutex, NULL);
1464
1465 LOGGER_DEBUG("New msi session: %p max calls: %u", _retu, max_calls);
1276 return _retu; 1466 return _retu;
1277} 1467}
1278 1468
@@ -1285,20 +1475,33 @@ MSISession *msi_init_session ( Messenger* messenger )
1285 */ 1475 */
1286int msi_terminate_session ( MSISession *session ) 1476int msi_terminate_session ( MSISession *session )
1287{ 1477{
1288 assert ( session ); 1478 if (session == NULL) {
1289 1479 LOGGER_ERROR("Tried to terminate non-existing session");
1290 int _status = 0; 1480 return -1;
1291
1292 /* If have call, cancel it */
1293 if ( session->call ) {
1294 /* Cancel all? */
1295 uint16_t _it = 0;
1296 for ( ; _it < session->call->peer_count; _it++ )
1297 msi_cancel ( session, session->call->peers [_it], "MSI session terminated!" );
1298 } 1481 }
1299 1482
1483 pthread_mutex_lock(&session->mutex);
1300 m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL); 1484 m_callback_msi_packet((struct Messenger *) session->messenger_handle, NULL, NULL);
1485 pthread_mutex_unlock(&session->mutex);
1301 1486
1487 int _status = 0;
1488
1489 /* If have calls, cancel them */
1490 uint32_t idx = 0;
1491
1492 for (; idx < session->max_calls; idx ++) if ( session->calls[idx] ) {
1493 /* Cancel all? */
1494 uint16_t _it = 0;
1495 /*for ( ; _it < session->calls[idx]->peer_count; _it++ )
1496 * FIXME: will not work on multiple peers, must cancel call for all peers
1497 */
1498 msi_cancel ( session, idx, session->calls[idx]->peers [_it], "MSI session terminated!" );
1499 }
1500
1501
1502 pthread_mutex_destroy(&session->mutex);
1503
1504 LOGGER_DEBUG("Terminated session: %p", session);
1302 free ( session ); 1505 free ( session );
1303 return _status; 1506 return _status;
1304} 1507}
@@ -1313,34 +1516,46 @@ int msi_terminate_session ( MSISession *session )
1313 * @param friend_id The friend. 1516 * @param friend_id The friend.
1314 * @return int 1517 * @return int
1315 */ 1518 */
1316int msi_invite ( MSISession *session, MSICallType call_type, uint32_t rngsec, uint32_t friend_id ) 1519int msi_invite ( MSISession *session, int32_t *call_index, MSICallType call_type, uint32_t rngsec, uint32_t friend_id )
1317{ 1520{
1318 assert ( session ); 1521 pthread_mutex_lock(&session->mutex);
1522
1523 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id);
1319 1524
1320 MSIMessage *_msg_invite = msi_new_message ( TYPE_REQUEST, stringify_request ( invite ) ); 1525 MSIMessage *_msg_invite = msi_new_message ( TYPE_REQUEST, stringify_request ( invite ) );
1321 1526
1322 session->call = init_call ( session, 1, rngsec ); /* Just one for now */ 1527 MSICall *_call = init_call ( session, 1, rngsec ); /* Just one peer for now */
1323 t_randomstr ( session->call->id, CALL_ID_LEN );
1324 1528
1325 add_peer(session->call, friend_id ); 1529 if ( !_call ) {
1530 pthread_mutex_unlock(&session->mutex);
1531 return -1; /* Cannot handle more calls */
1532 }
1326 1533
1327 session->call->type_local = call_type; 1534 *call_index = _call->call_idx;
1328 /* Do whatever with message */ 1535
1536 t_randomstr ( _call->id, CALL_ID_LEN );
1537
1538 add_peer(_call, friend_id );
1539
1540 _call->type_local = call_type;
1329 1541
1542 /* Do whatever with message */
1330 if ( call_type == type_audio ) { 1543 if ( call_type == type_audio ) {
1331 msi_msg_set_calltype 1544 msi_msg_set_calltype ( _msg_invite, ( const uint8_t * ) CT_AUDIO_HEADER_VALUE, strlen ( CT_AUDIO_HEADER_VALUE ) );
1332 ( _msg_invite, ( const uint8_t * ) CT_AUDIO_HEADER_VALUE, strlen ( CT_AUDIO_HEADER_VALUE ) );
1333 } else { 1545 } else {
1334 msi_msg_set_calltype 1546 msi_msg_set_calltype ( _msg_invite, ( const uint8_t * ) CT_VIDEO_HEADER_VALUE, strlen ( CT_VIDEO_HEADER_VALUE ) );
1335 ( _msg_invite, ( const uint8_t * ) CT_VIDEO_HEADER_VALUE, strlen ( CT_VIDEO_HEADER_VALUE ) );
1336 } 1547 }
1337 1548
1338 send_message ( session, _msg_invite, friend_id ); 1549 send_message ( session, _call, _msg_invite, friend_id );
1339 free_message ( _msg_invite ); 1550 free_message ( _msg_invite );
1340 1551
1341 session->call->state = call_inviting; 1552 _call->state = call_inviting;
1342 1553
1343 session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); 1554 _call->request_timer_id = event.timer_alloc ( handle_timeout, _call, m_deftout );
1555
1556 LOGGER_DEBUG("Invite sent");
1557
1558 pthread_mutex_unlock(&session->mutex);
1344 1559
1345 return 0; 1560 return 0;
1346} 1561}
@@ -1350,30 +1565,43 @@ int msi_invite ( MSISession *session, MSICallType call_type, uint32_t rngsec, ui
1350 * @brief Hangup active call. 1565 * @brief Hangup active call.
1351 * 1566 *
1352 * @param session Control session. 1567 * @param session Control session.
1568 * @param call_id To which call is this action handled.
1353 * @return int 1569 * @return int
1354 * @retval -1 Error occurred. 1570 * @retval -1 Error occurred.
1355 * @retval 0 Success. 1571 * @retval 0 Success.
1356 */ 1572 */
1357int msi_hangup ( MSISession *session ) 1573int msi_hangup ( MSISession *session, int32_t call_index )
1358{ 1574{
1359 assert ( session ); 1575 pthread_mutex_lock(&session->mutex);
1576 LOGGER_DEBUG("Session: %p Hanging up call: %u", session, call_index);
1577
1578 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1579 LOGGER_ERROR("Invalid call index!");
1580 pthread_mutex_unlock(&session->mutex);
1581 return -1;
1582 }
1360 1583
1361 if ( !session->call || session->call->state != call_active ) 1584 if ( !session->calls[call_index] || session->calls[call_index]->state != call_active ) {
1585 LOGGER_ERROR("No call with such index or call is not active!");
1586 pthread_mutex_unlock(&session->mutex);
1362 return -1; 1587 return -1;
1588 }
1363 1589
1364 MSIMessage *_msg_end = msi_new_message ( TYPE_REQUEST, stringify_request ( end ) ); 1590 MSIMessage *_msg_end = msi_new_message ( TYPE_REQUEST, stringify_request ( end ) );
1365 1591
1366 /* hangup for each peer */ 1592 /* hangup for each peer */
1367 int _it = 0; 1593 int _it = 0;
1368 1594
1369 for ( ; _it < session->call->peer_count; _it ++ ) 1595 for ( ; _it < session->calls[call_index]->peer_count; _it ++ )
1370 send_message ( session, _msg_end, session->call->peers[_it] ); 1596 send_message ( session, session->calls[call_index], _msg_end, session->calls[call_index]->peers[_it] );
1371 1597
1372 1598
1373 free_message ( _msg_end ); 1599 free_message ( _msg_end );
1374 1600
1375 session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); 1601 session->calls[call_index]->request_timer_id = event.timer_alloc ( handle_timeout, session->calls[call_index],
1376 1602 m_deftout );
1603
1604 pthread_mutex_unlock(&session->mutex);
1377 return 0; 1605 return 0;
1378} 1606}
1379 1607
@@ -1382,15 +1610,24 @@ int msi_hangup ( MSISession *session )
1382 * @brief Answer active call request. 1610 * @brief Answer active call request.
1383 * 1611 *
1384 * @param session Control session. 1612 * @param session Control session.
1613 * @param call_id To which call is this action handled.
1385 * @param call_type Answer with Audio or Video(both). 1614 * @param call_type Answer with Audio or Video(both).
1386 * @return int 1615 * @return int
1387 */ 1616 */
1388int msi_answer ( MSISession *session, MSICallType call_type ) 1617int msi_answer ( MSISession *session, int32_t call_index, MSICallType call_type )
1389{ 1618{
1390 assert ( session ); 1619 pthread_mutex_lock(&session->mutex);
1620 LOGGER_DEBUG("Session: %p Answering call: %u", session, call_index);
1621
1622 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1623 LOGGER_ERROR("Invalid call index!");
1624 pthread_mutex_unlock(&session->mutex);
1625 return -1;
1626 }
1391 1627
1392 MSIMessage *_msg_starting = msi_new_message ( TYPE_RESPONSE, stringify_response ( starting ) ); 1628 MSIMessage *_msg_starting = msi_new_message ( TYPE_RESPONSE, stringify_response ( starting ) );
1393 session->call->type_local = call_type; 1629
1630 session->calls[call_index]->type_local = call_type;
1394 1631
1395 if ( call_type == type_audio ) { 1632 if ( call_type == type_audio ) {
1396 msi_msg_set_calltype 1633 msi_msg_set_calltype
@@ -1402,20 +1639,22 @@ int msi_answer ( MSISession *session, MSICallType call_type )
1402 1639
1403 /* Now set the local encryption key and pass it with STARTING message */ 1640 /* Now set the local encryption key and pass it with STARTING message */
1404 1641
1405 session->call->key_local = calloc ( sizeof ( uint8_t ), crypto_box_KEYBYTES ); 1642 session->calls[call_index]->key_local = calloc ( sizeof ( uint8_t ), crypto_box_KEYBYTES );
1406 new_symmetric_key ( session->call->key_local ); 1643 new_symmetric_key ( session->calls[call_index]->key_local );
1407 1644
1408 session->call->nonce_local = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES ); 1645 session->calls[call_index]->nonce_local = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES );
1409 new_nonce ( session->call->nonce_local ); 1646 new_nonce ( session->calls[call_index]->nonce_local );
1410 1647
1411 msi_msg_set_cryptokey ( _msg_starting, session->call->key_local, crypto_box_KEYBYTES ); 1648 msi_msg_set_cryptokey ( _msg_starting, session->calls[call_index]->key_local, crypto_box_KEYBYTES );
1412 msi_msg_set_nonce ( _msg_starting, session->call->nonce_local, crypto_box_NONCEBYTES ); 1649 msi_msg_set_nonce ( _msg_starting, session->calls[call_index]->nonce_local, crypto_box_NONCEBYTES );
1413 1650
1414 send_message ( session, _msg_starting, session->call->peers[session->call->peer_count - 1] ); 1651 send_message ( session, session->calls[call_index], _msg_starting,
1652 session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] );
1415 free_message ( _msg_starting ); 1653 free_message ( _msg_starting );
1416 1654
1417 session->call->state = call_active; 1655 session->calls[call_index]->state = call_active;
1418 1656
1657 pthread_mutex_unlock(&session->mutex);
1419 return 0; 1658 return 0;
1420} 1659}
1421 1660
@@ -1424,22 +1663,32 @@ int msi_answer ( MSISession *session, MSICallType call_type )
1424 * @brief Cancel request. 1663 * @brief Cancel request.
1425 * 1664 *
1426 * @param session Control session. 1665 * @param session Control session.
1666 * @param call_id To which call is this action handled.
1427 * @param reason Set optional reason header. Pass NULL if none. 1667 * @param reason Set optional reason header. Pass NULL if none.
1428 * @return int 1668 * @return int
1429 */ 1669 */
1430int msi_cancel ( MSISession *session, uint32_t peer, const char *reason ) 1670int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason )
1431{ 1671{
1432 assert ( session ); 1672 pthread_mutex_lock(&session->mutex);
1673 LOGGER_DEBUG("Session: %p Canceling call: %u; reason:", session, call_index, reason ? reason : "Unknown");
1674
1675 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1676 LOGGER_ERROR("Invalid call index!");
1677 pthread_mutex_unlock(&session->mutex);
1678 return -1;
1679 }
1433 1680
1434 MSIMessage *_msg_cancel = msi_new_message ( TYPE_REQUEST, stringify_request ( cancel ) ); 1681 MSIMessage *_msg_cancel = msi_new_message ( TYPE_REQUEST, stringify_request ( cancel ) );
1435 1682
1436 if ( reason ) msi_msg_set_reason(_msg_cancel, (const uint8_t*)reason, strlen(reason)); 1683 if ( reason ) msi_msg_set_reason(_msg_cancel, (const uint8_t *)reason, strlen(reason));
1437 1684
1438 send_message ( session, _msg_cancel, peer ); 1685 send_message ( session, session->calls[call_index], _msg_cancel, peer );
1439 free_message ( _msg_cancel ); 1686 free_message ( _msg_cancel );
1440 1687
1441 session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); 1688 /*session->calls[call_index]->request_timer_id = event.timer_alloc ( handle_timeout, session->calls[call_index], m_deftout );*/
1442 1689 terminate_call ( session, session->calls[call_index] );
1690 pthread_mutex_unlock(&session->mutex);
1691
1443 return 0; 1692 return 0;
1444} 1693}
1445 1694
@@ -1448,21 +1697,32 @@ int msi_cancel ( MSISession *session, uint32_t peer, const char *reason )
1448 * @brief Reject request. 1697 * @brief Reject request.
1449 * 1698 *
1450 * @param session Control session. 1699 * @param session Control session.
1700 * @param call_id To which call is this action handled.
1451 * @return int 1701 * @return int
1452 */ 1702 */
1453int msi_reject ( MSISession *session, const uint8_t *reason ) 1703int msi_reject ( MSISession *session, int32_t call_index, const uint8_t *reason )
1454{ 1704{
1455 assert ( session ); 1705 pthread_mutex_lock(&session->mutex);
1706 LOGGER_DEBUG("Session: %p Rejecting call: %u; reason:", session, call_index, reason ? (char *)reason : "Unknown");
1707
1708 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1709 LOGGER_ERROR("Invalid call index!");
1710 pthread_mutex_unlock(&session->mutex);
1711 return -1;
1712 }
1456 1713
1457 MSIMessage *_msg_reject = msi_new_message ( TYPE_REQUEST, stringify_request ( reject ) ); 1714 MSIMessage *_msg_reject = msi_new_message ( TYPE_REQUEST, stringify_request ( reject ) );
1458 1715
1459 if ( reason ) msi_msg_set_reason(_msg_reject, reason, strlen((const char *)reason) + 1); 1716 if ( reason ) msi_msg_set_reason(_msg_reject, reason, strlen((const char *)reason) + 1);
1460 1717
1461 send_message ( session, _msg_reject, session->call->peers[session->call->peer_count - 1] ); 1718 send_message ( session, session->calls[call_index], _msg_reject,
1719 session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] );
1462 free_message ( _msg_reject ); 1720 free_message ( _msg_reject );
1463 1721
1464 session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout ); 1722 session->calls[call_index]->request_timer_id = event.timer_alloc ( handle_timeout, session->calls[call_index],
1723 m_deftout );
1465 1724
1725 pthread_mutex_unlock(&session->mutex);
1466 return 0; 1726 return 0;
1467} 1727}
1468 1728
@@ -1471,18 +1731,23 @@ int msi_reject ( MSISession *session, const uint8_t *reason )
1471 * @brief Terminate the current call. 1731 * @brief Terminate the current call.
1472 * 1732 *
1473 * @param session Control session. 1733 * @param session Control session.
1734 * @param call_id To which call is this action handled.
1474 * @return int 1735 * @return int
1475 */ 1736 */
1476int msi_stopcall ( MSISession *session ) 1737int msi_stopcall ( MSISession *session, int32_t call_index )
1477{ 1738{
1478 assert ( session ); 1739 pthread_mutex_lock(&session->mutex);
1740 LOGGER_DEBUG("Session: %p Stopping call index: %u", session, call_index);
1479 1741
1480 if ( !session->call ) 1742 if ( call_index < 0 || call_index >= session->max_calls || !session->calls[call_index] ) {
1743 pthread_mutex_unlock(&session->mutex);
1481 return -1; 1744 return -1;
1745 }
1482 1746
1483 /* just terminate it */ 1747 /* just terminate it */
1484 1748
1485 terminate_call ( session ); 1749 terminate_call ( session, session->calls[call_index] );
1486 1750
1751 pthread_mutex_unlock(&session->mutex);
1487 return 0; 1752 return 0;
1488} 1753}
diff --git a/toxav/msi.h b/toxav/msi.h
index 052126d2..042f3f0f 100755..100644
--- a/toxav/msi.h
+++ b/toxav/msi.h
@@ -33,7 +33,7 @@
33#define CALL_ID_LEN 12 33#define CALL_ID_LEN 12
34 34
35 35
36typedef void ( *MSICallback ) ( void *arg ); 36typedef void ( *MSICallback ) ( int32_t, void *arg );
37 37
38 38
39/** 39/**
@@ -62,32 +62,33 @@ typedef enum {
62 * @brief The call struct. 62 * @brief The call struct.
63 * 63 *
64 */ 64 */
65typedef struct _MSICall { /* Call info structure */ 65typedef struct _MSICall { /* Call info structure */
66 MSICallState state; 66 struct _MSISession *session; /* Session pointer */
67 67
68 MSICallType type_local; /* Type of payload user is ending */ 68 MSICallState state;
69 MSICallType *type_peer; /* Type of payload others are sending */
70 69
71 uint8_t id[CALL_ID_LEN]; /* Random value identifying the call */ 70 MSICallType type_local; /* Type of payload user is ending */
71 MSICallType *type_peer; /* Type of payload others are sending */
72 72
73 uint8_t *key_local; /* The key for encryption */ 73 uint8_t id[CALL_ID_LEN]; /* Random value identifying the call */
74 uint8_t *key_peer; /* The key for decryption */
75 74
76 uint8_t *nonce_local; /* Local nonce */ 75 uint8_t *key_local; /* The key for encryption */
77 uint8_t *nonce_peer; /* Peer nonce */ 76 uint8_t *key_peer; /* The key for decryption */
78 77
79 int ringing_tout_ms; /* Ringing timeout in ms */ 78 uint8_t *nonce_local; /* Local nonce */
79 uint8_t *nonce_peer; /* Peer nonce */
80 80
81 int request_timer_id; /* Timer id for outgoing request/action */ 81 int ringing_tout_ms; /* Ringing timeout in ms */
82 int ringing_timer_id; /* Timer id for ringing timeout */
83 82
84 pthread_mutex_t mutex; /* It's to be assumed that call will have 83 int request_timer_id; /* Timer id for outgoing request/action */
85 * separate thread so add mutex 84 int ringing_timer_id; /* Timer id for ringing timeout */
86 */
87 uint32_t *peers;
88 uint16_t peer_count;
89 85
90 86
87 pthread_mutex_t mutex; /* */
88 uint32_t *peers;
89 uint16_t peer_count;
90
91 int32_t call_idx; /* Index of this call in MSISession */
91} MSICall; 92} MSICall;
92 93
93 94
@@ -97,8 +98,9 @@ typedef struct _MSICall { /* Call info structure */
97 */ 98 */
98typedef struct _MSISession { 99typedef struct _MSISession {
99 100
100 /* Call handler */ 101 /* Call handlers */
101 struct _MSICall *call; 102 struct _MSICall **calls;
103 int32_t max_calls;
102 104
103 int last_error_id; /* Determine the last error */ 105 int last_error_id; /* Determine the last error */
104 const uint8_t *last_error_str; 106 const uint8_t *last_error_str;
@@ -109,7 +111,7 @@ typedef struct _MSISession {
109 uint32_t frequ; 111 uint32_t frequ;
110 uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */ 112 uint32_t call_timeout; /* Time of the timeout for some action to end; 0 if infinite */
111 113
112 114 pthread_mutex_t mutex;
113} MSISession; 115} MSISession;
114 116
115 117
@@ -144,17 +146,18 @@ typedef enum {
144 * @param id The id. 146 * @param id The id.
145 * @return void 147 * @return void
146 */ 148 */
147void msi_register_callback(MSICallback callback, MSICallbackID id, void* userdata); 149void msi_register_callback(MSICallback callback, MSICallbackID id, void *userdata);
148 150
149 151
150/** 152/**
151 * @brief Start the control session. 153 * @brief Start the control session.
152 * 154 *
153 * @param messenger Tox* object. 155 * @param messenger Tox* object.
156 * @param max_calls Amount of calls possible
154 * @return MSISession* The created session. 157 * @return MSISession* The created session.
155 * @retval NULL Error occurred. 158 * @retval NULL Error occurred.
156 */ 159 */
157MSISession *msi_init_session ( Messenger *messenger ); 160MSISession *msi_init_session ( Messenger *messenger, int32_t max_calls );
158 161
159 162
160/** 163/**
@@ -170,62 +173,68 @@ int msi_terminate_session ( MSISession *session );
170 * @brief Send invite request to friend_id. 173 * @brief Send invite request to friend_id.
171 * 174 *
172 * @param session Control session. 175 * @param session Control session.
176 * @param call_index Set to new call index.
173 * @param call_type Type of the call. Audio or Video(both audio and video) 177 * @param call_type Type of the call. Audio or Video(both audio and video)
174 * @param rngsec Ringing timeout. 178 * @param rngsec Ringing timeout.
175 * @param friend_id The friend. 179 * @param friend_id The friend.
176 * @return int 180 * @return int
177 */ 181 */
178int msi_invite ( MSISession *session, MSICallType call_type, uint32_t rngsec, uint32_t friend_id ); 182int msi_invite ( MSISession *session, int32_t *call_index, MSICallType call_type, uint32_t rngsec, uint32_t friend_id );
179 183
180 184
181/** 185/**
182 * @brief Hangup active call. 186 * @brief Hangup active call.
183 * 187 *
184 * @param session Control session. 188 * @param session Control session.
189 * @param call_index To which call is this action handled.
185 * @return int 190 * @return int
186 * @retval -1 Error occurred. 191 * @retval -1 Error occurred.
187 * @retval 0 Success. 192 * @retval 0 Success.
188 */ 193 */
189int msi_hangup ( MSISession *session ); 194int msi_hangup ( MSISession *session, int32_t call_index );
190 195
191 196
192/** 197/**
193 * @brief Answer active call request. 198 * @brief Answer active call request.
194 * 199 *
195 * @param session Control session. 200 * @param session Control session.
201 * @param call_index To which call is this action handled.
196 * @param call_type Answer with Audio or Video(both). 202 * @param call_type Answer with Audio or Video(both).
197 * @return int 203 * @return int
198 */ 204 */
199int msi_answer ( MSISession *session, MSICallType call_type ); 205int msi_answer ( MSISession *session, int32_t call_index, MSICallType call_type );
200 206
201 207
202/** 208/**
203 * @brief Cancel request. 209 * @brief Cancel request.
204 * 210 *
205 * @param session Control session. 211 * @param session Control session.
212 * @param call_index To which call is this action handled.
206 * @param peer To which peer. 213 * @param peer To which peer.
207 * @param reason Set optional reason header. Pass NULL if none. 214 * @param reason Set optional reason header. Pass NULL if none.
208 * @return int 215 * @return int
209 */ 216 */
210int msi_cancel ( MSISession* session, uint32_t peer, const char* reason ); 217int msi_cancel ( MSISession *session, int32_t call_index, uint32_t peer, const char *reason );
211 218
212 219
213/** 220/**
214 * @brief Reject request. 221 * @brief Reject request.
215 * 222 *
216 * @param session Control session. 223 * @param session Control session.
224 * @param call_index To which call is this action handled.
217 * @param reason Set optional reason header. Pass NULL if none. 225 * @param reason Set optional reason header. Pass NULL if none.
218 * @return int 226 * @return int
219 */ 227 */
220int msi_reject ( MSISession *session, const uint8_t *reason ); 228int msi_reject ( MSISession *session, int32_t call_index, const uint8_t *reason );
221 229
222 230
223/** 231/**
224 * @brief Terminate the current call. 232 * @brief Terminate the current call.
225 * 233 *
226 * @param session Control session. 234 * @param session Control session.
235 * @param call_index To which call is this action handled.
227 * @return int 236 * @return int
228 */ 237 */
229int msi_stopcall ( MSISession *session ); 238int msi_stopcall ( MSISession *session, int32_t call_index );
230 239
231#endif /* __TOXMSI */ 240#endif /* __TOXMSI */
diff --git a/toxav/phone.c b/toxav/phone.c
deleted file mode 100755
index 74f743f7..00000000
--- a/toxav/phone.c
+++ /dev/null
@@ -1,1460 +0,0 @@
1/** phone.c
2 *
3 * NOTE NOTE NOTE NOTE NOTE NOTE
4 *
5 * This file is for testing/reference purposes only, hence
6 * it is _poorly_ designed and it does not fully reflect the
7 * quaility of msi nor rtp. Although toxmsi* and toxrtp* are tested
8 * there is always possibility of crashes. If crash occures,
9 * contact me ( mannol ) on either irc channel #tox-dev @ freenode.net:6667
10 * or eniz_vukovic@hotmail.com
11 *
12 * NOTE NOTE NOTE NOTE NOTE NOTE
13 *
14 * Copyright (C) 2013 Tox project All Rights Reserved.
15 *
16 * This file is part of Tox.
17 *
18 * Tox is free software: you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation, either version 3 of the License, or
21 * (at your option) any later version.
22 *
23 * Tox is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
30 *
31 */
32
33#ifdef HAVE_CONFIG_H
34#include "config.h"
35#endif /* HAVE_CONFIG_H */
36
37#define _BSD_SOURCE
38
39#include <stdio.h>
40#include <string.h>
41#include <stdlib.h>
42#include <stdarg.h>
43#include <unistd.h>
44#include <assert.h>
45#include <math.h>
46#include <pthread.h>
47
48//#include "media.h"
49#include "toxav.h"
50#include "event.h"
51#include "../toxcore/tox.h"
52
53#define AUDIO_FRAME_SIZE (av_DefaultSettings.audio_sample_rate * av_DefaultSettings.audio_frame_duration / 1000)
54
55#ifdef TOX_FFMPEG
56/* Video encoding/decoding */
57#include <libavcodec/avcodec.h>
58#include <libavformat/avformat.h>
59#include <libswscale/swscale.h>
60#include <libavdevice/avdevice.h>
61#include <libavutil/opt.h>
62#endif
63
64#include <AL/al.h>
65#include <AL/alc.h>
66#include <SDL/SDL.h>
67#include <SDL/SDL_thread.h>
68
69/* the quit event for SDL */
70#define FF_QUIT_EVENT (SDL_USEREVENT + 2)
71
72#ifdef __linux__
73#define VIDEO_DRIVER "video4linux2"
74#define DEFAULT_WEBCAM "/dev/video0"
75#endif
76
77#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
78#define VIDEO_DRIVER "vfwcap"
79#define DEFAULT_WEBCAM "0"
80#endif
81
82
83/* Define client version */
84#define _USERAGENT "v.0.3.0"
85
86
87struct SDL_Surface *screen;
88
89typedef struct {
90 struct SDL_Overlay *bmp;
91 int width, height;
92} VideoPicture;
93
94
95typedef struct av_friend_s {
96 int _id;
97 int _active; /* 0=false; 1=true; */
98} av_friend_t;
99
100typedef struct av_session_s {
101 /* Encoding/decoding/capturing/playing */
102 ToxAv *av;
103
104 VideoPicture video_picture;
105 struct ALCdevice *audio_capture_device;
106
107 /* context for converting image format to something SDL can use*/
108 struct SwsContext *sws_SDL_r_ctx;
109
110 /* context for converting webcam image format to something the video encoder can use */
111 struct SwsContext *sws_ctx;
112
113 /* Thread running control */
114 int running_decaud, running_encaud,
115 running_decvid, running_encvid;
116
117 pthread_mutex_t _mutex;
118
119 Tox *_messenger;
120 av_friend_t *_friends;
121 int _friend_cout;
122 char _my_public_id[200];
123#ifdef TOX_FFMPEG
124 AVInputFormat *video_input_format;
125 AVFormatContext *video_format_ctx;
126 uint8_t video_stream;
127 AVCodecContext *webcam_decoder_ctx;
128 AVCodec *webcam_decoder;
129#endif
130} av_session_t;
131av_session_t *_phone;
132
133void av_allocate_friend(av_session_t *_phone, int _id, int _active)
134{
135 static int _new_id = 0;
136
137 if ( !_phone->_friends ) {
138 _phone->_friends = calloc(sizeof(av_friend_t), 1);
139 _phone->_friend_cout = 1;
140 } else {
141 _phone->_friend_cout ++;
142 _phone->_friends = realloc(_phone->_friends, sizeof(av_friend_t) * _phone->_friend_cout);
143 }
144
145 if ( _id == -1 ) {
146 _phone->_friends->_id = _new_id;
147 _new_id ++;
148 } else _phone->_friends->_id = _id;
149
150 _phone->_friends->_active = _active;
151}
152av_friend_t *av_get_friend(av_session_t *_phone, int _id)
153{
154 av_friend_t *_friends = _phone->_friends;
155
156 if ( !_friends ) return NULL;
157
158 int _it = 0;
159
160 for (; _it < _phone->_friend_cout; _it ++)
161 if ( _friends[_it]._id == _id )
162 return _friends + _it;
163
164 return NULL;
165}
166
167
168/***************** MISC *****************/
169
170void INFO (const char *_format, ...)
171{
172 printf("\r[!] ");
173 va_list _arg;
174 va_start (_arg, _format);
175 vfprintf (stdout, _format, _arg);
176 va_end (_arg);
177 printf("\n\r >> ");
178 fflush(stdout);
179}
180
181unsigned char *hex_string_to_bin(char hex_string[])
182{
183 size_t i, len = strlen(hex_string);
184 unsigned char *val = calloc(sizeof(unsigned char), len);
185 char *pos = hex_string;
186
187 for (i = 0; i < len; ++i, pos += 2)
188 sscanf(pos, "%2hhx", &val[i]);
189
190 return val;
191}
192
193int getinput( char *_buff, size_t _limit, int *_len )
194{
195 if ( fgets(_buff, _limit, stdin) == NULL )
196 return -1;
197
198 *_len = strlen(_buff) - 1;
199
200 /* Get rid of newline */
201 _buff[*_len] = '\0';
202
203 return 0;
204}
205
206char *trim_spaces ( char *buff )
207{
208
209 int _i = 0, _len = strlen(buff);
210
211 char *container = calloc(sizeof(char), _len);
212 int _ci = 0;
213
214 for ( ; _i < _len; _i++ ) {
215 while ( _i < _len && buff[_i] == ' ' )
216 _i++;
217
218 if ( _i < _len ) {
219 container[_ci] = buff[_i];
220 _ci ++;
221 }
222 }
223
224 memcpy( buff, container, _ci );
225 buff[_ci] = '\0';
226 free(container);
227 return buff;
228}
229
230#define FRADDR_TOSTR_CHUNK_LEN 8
231
232static void fraddr_to_str(uint8_t *id_bin, char *id_str)
233{
234 uint i, delta = 0, pos_extra = 0, sum_extra = 0;
235
236 for (i = 0; i < TOX_FRIEND_ADDRESS_SIZE; i++) {
237 sprintf(&id_str[2 * i + delta], "%02hhX", id_bin[i]);
238
239 if ((i + 1) == TOX_CLIENT_ID_SIZE)
240 pos_extra = 2 * (i + 1) + delta;
241
242 if (i >= TOX_CLIENT_ID_SIZE)
243 sum_extra |= id_bin[i];
244
245 if (!((i + 1) % FRADDR_TOSTR_CHUNK_LEN)) {
246 id_str[2 * (i + 1) + delta] = ' ';
247 delta++;
248 }
249 }
250
251 id_str[2 * i + delta] = 0;
252
253 if (!sum_extra)
254 id_str[pos_extra] = 0;
255}
256
257/*********************************************
258 *********************************************
259 *********************************************
260 *********************************************
261 *********************************************
262 *********************************************
263 *********************************************
264 *********************************************
265 */
266
267
268/*
269 * How av stuff _should_ look like
270 */
271/*
272int display_received_frame(av_session_t* _phone, vpx_image_t *image)
273{
274 CodecState* cs = get_cs_temp(_phone->av);
275 AVPicture pict;
276 SDL_LockYUVOverlay(_phone->video_picture.bmp);
277
278 pict.data[0] = _phone->video_picture.bmp->pixels[0];
279 pict.data[1] = _phone->video_picture.bmp->pixels[2];
280 pict.data[2] = _phone->video_picture.bmp->pixels[1];
281 pict.linesize[0] = _phone->video_picture.bmp->pitches[0];
282 pict.linesize[1] = _phone->video_picture.bmp->pitches[2];
283 pict.linesize[2] = _phone->video_picture.bmp->pitches[1];
284 */
285/* Convert the image into YUV format that SDL uses *//*
286sws_scale(_phone->sws_SDL_r_ctx, (uint8_t const * const *)r_video_frame->data, r_video_frame->linesize, 0,
287 cs->video_decoder_ctx->height, pict.data, pict.linesize );
288
289SDL_UnlockYUVOverlay(_phone->video_picture.bmp);
290SDL_Rect rect;
291rect.x = 0;
292rect.y = 0;
293rect.w = cs->video_decoder_ctx->width;
294rect.h = cs->video_decoder_ctx->height;
295SDL_DisplayYUVOverlay(_phone->video_picture.bmp, &rect);
296return 1;
297}
298*/
299#ifdef TOX_FFMPEG
300void *encode_video_thread(void *arg)
301{
302 INFO("Started encode video thread!");
303
304 av_session_t *_phone = arg;
305
306 _phone->running_encvid = 1;
307 //CodecState *cs = get_cs_temp(_phone->av);
308 AVPacket pkt1, *packet = &pkt1;
309 //int p = 0;
310 //int got_packet;
311 int video_frame_finished;
312 AVFrame *s_video_frame;
313 AVFrame *webcam_frame;
314 s_video_frame = avcodec_alloc_frame();
315 webcam_frame = avcodec_alloc_frame();
316 //AVPacket enc_video_packet;
317
318 uint8_t *buffer;
319 int numBytes;
320 /* Determine required buffer size and allocate buffer */
321 numBytes = avpicture_get_size(PIX_FMT_YUV420P, _phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height);
322 buffer = (uint8_t *)av_calloc(numBytes * sizeof(uint8_t), 1);
323 avpicture_fill((AVPicture *)s_video_frame, buffer, PIX_FMT_YUV420P, _phone->webcam_decoder_ctx->width,
324 _phone->webcam_decoder_ctx->height);
325 _phone->sws_ctx = sws_getContext(_phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height,
326 _phone->webcam_decoder_ctx->pix_fmt, _phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height,
327 PIX_FMT_YUV420P,
328 SWS_BILINEAR, NULL, NULL, NULL);
329
330
331 vpx_image_t *image =
332 vpx_img_alloc(NULL, VPX_IMG_FMT_I420, _phone->webcam_decoder_ctx->width, _phone->webcam_decoder_ctx->height, 1);
333
334 //uint32_t frame_counter = 0;
335 while (_phone->running_encvid) {
336
337 if (av_read_frame(_phone->video_format_ctx, packet) < 0) {
338 printf("error reading frame\n");
339
340 if (_phone->video_format_ctx->pb->error != 0)
341 break;
342
343 continue;
344 }
345
346 if (packet->stream_index == _phone->video_stream) {
347 if (avcodec_decode_video2(_phone->webcam_decoder_ctx, webcam_frame, &video_frame_finished, packet) < 0) {
348 printf("couldn't decode\n");
349 continue;
350 }
351
352 av_free_packet(packet);
353 sws_scale(_phone->sws_ctx, (uint8_t const * const *)webcam_frame->data, webcam_frame->linesize, 0,
354 _phone->webcam_decoder_ctx->height, s_video_frame->data, s_video_frame->linesize);
355 /* create a new I-frame every 60 frames */
356 //++p;
357 /*
358 if (p == 60) {
359
360 s_video_frame->pict_type = AV_PICTURE_TYPE_BI ;
361 } else if (p == 61) {
362 s_video_frame->pict_type = AV_PICTURE_TYPE_I ;
363 p = 0;
364 } else {
365 s_video_frame->pict_type = AV_PICTURE_TYPE_P ;
366 }*/
367
368 if (video_frame_finished) {
369 memcpy(image->planes[VPX_PLANE_Y], s_video_frame->data[0],
370 s_video_frame->linesize[0] * _phone->webcam_decoder_ctx->height);
371 memcpy(image->planes[VPX_PLANE_U], s_video_frame->data[1],
372 s_video_frame->linesize[1] * _phone->webcam_decoder_ctx->height / 2);
373 memcpy(image->planes[VPX_PLANE_V], s_video_frame->data[2],
374 s_video_frame->linesize[2] * _phone->webcam_decoder_ctx->height / 2);
375 toxav_send_video (_phone->av, image);
376 //if (avcodec_encode_video2(cs->video_encoder_ctx, &enc_video_packet, s_video_frame, &got_packet) < 0) {
377 /*if (vpx_codec_encode(&cs->v_encoder, image, frame_counter, 1, 0, 0) != VPX_CODEC_OK) {
378 printf("could not encode video frame\n");
379 continue;
380 }
381 ++frame_counter;
382
383 vpx_codec_iter_t iter = NULL;
384 vpx_codec_cx_pkt_t *pkt;
385 while( (pkt = vpx_codec_get_cx_data(&cs->v_encoder, &iter)) ) {
386 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT)
387 toxav_send_rtp_payload(_phone->av, TypeVideo, pkt->data.frame.buf, pkt->data.frame.sz);
388 }*/
389 //if (!got_packet) {
390 // continue;
391 //}
392
393 //if (!enc_video_packet.data) fprintf(stderr, "video packet data is NULL\n");
394
395 //toxav_send_rtp_payload(_phone->av, TypeVideo, enc_video_packet.data, enc_video_packet.size);
396
397 //av_free_packet(&enc_video_packet);
398 }
399 } else {
400 av_free_packet(packet);
401 }
402 }
403
404 vpx_img_free(image);
405
406 /* clean up codecs */
407 //pthread_mutex_lock(&cs->ctrl_mutex);
408 av_free(buffer);
409 av_free(webcam_frame);
410 av_free(s_video_frame);
411 sws_freeContext(_phone->sws_ctx);
412 //avcodec_close(webcam_decoder_ctx);
413 //avcodec_close(cs->video_encoder_ctx);
414 //pthread_mutex_unlock(&cs->ctrl_mutex);
415
416 _phone->running_encvid = -1;
417
418 pthread_exit ( NULL );
419}
420#endif
421
422void *encode_audio_thread(void *arg)
423{
424 INFO("Started encode audio thread!");
425 av_session_t *_phone = arg;
426 _phone->running_encaud = 1;
427
428 int ret = 0;
429 int16_t frame[4096];
430 int frame_size = AUDIO_FRAME_SIZE;
431 ALint sample = 0;
432 alcCaptureStart((ALCdevice *)_phone->audio_capture_device);
433 while (_phone->running_encaud) {
434
435 alcGetIntegerv((ALCdevice *)_phone->audio_capture_device, ALC_CAPTURE_SAMPLES, (ALCsizei)sizeof(ALint), &sample);
436
437 if (sample >= frame_size) {
438 alcCaptureSamples((ALCdevice *)_phone->audio_capture_device, frame, frame_size);
439
440 ret = toxav_send_audio(_phone->av, frame, frame_size);
441
442 if (ret < 0) printf("Could not encode or send audio packet\n");
443
444 } else {
445 usleep(1000);
446 }
447 }
448
449 /* clean up codecs *
450 pthread_mutex_lock(&cs->ctrl_mutex);* /
451 alcCaptureStop((ALCdevice*)_phone->audio_capture_device);
452 alcCaptureCloseDevice((ALCdevice*)_phone->audio_capture_device);
453 / *pthread_mutex_unlock(&cs->ctrl_mutex);*/
454 _phone->running_encaud = -1;
455 pthread_exit ( NULL );
456}
457
458void convert_to_rgb(vpx_image_t *img, unsigned char *out)
459{
460 const int w = img->d_w;
461 const int w2 = w / 2;
462 const int pstride = w * 3;
463 const int h = img->d_h;
464 const int h2 = h / 2;
465
466 const int strideY = img->stride[0];
467 const int strideU = img->stride[1];
468 const int strideV = img->stride[2];
469 int posy, posx;
470
471 for (posy = 0; posy < h2; posy++) {
472 unsigned char *dst = out + pstride * (posy * 2);
473 unsigned char *dst2 = out + pstride * (posy * 2 + 1);
474 const unsigned char *srcY = img->planes[0] + strideY * posy * 2;
475 const unsigned char *srcY2 = img->planes[0] + strideY * (posy * 2 + 1);
476 const unsigned char *srcU = img->planes[1] + strideU * posy;
477 const unsigned char *srcV = img->planes[2] + strideV * posy;
478
479 for (posx = 0; posx < w2; posx++) {
480 unsigned char Y, U, V;
481 short R, G, B;
482 short iR, iG, iB;
483
484 U = *(srcU++);
485 V = *(srcV++);
486 iR = (351 * (V - 128)) / 256;
487 iG = - (179 * (V - 128)) / 256 - (86 * (U - 128)) / 256;
488 iB = (444 * (U - 128)) / 256;
489
490 Y = *(srcY++);
491 R = Y + iR ;
492 G = Y + iG ;
493 B = Y + iB ;
494 R = (R < 0 ? 0 : (R > 255 ? 255 : R));
495 G = (G < 0 ? 0 : (G > 255 ? 255 : G));
496 B = (B < 0 ? 0 : (B > 255 ? 255 : B));
497 *(dst++) = R;
498 *(dst++) = G;
499 *(dst++) = B;
500
501 Y = *(srcY2++);
502 R = Y + iR ;
503 G = Y + iG ;
504 B = Y + iB ;
505 R = (R < 0 ? 0 : (R > 255 ? 255 : R));
506 G = (G < 0 ? 0 : (G > 255 ? 255 : G));
507 B = (B < 0 ? 0 : (B > 255 ? 255 : B));
508 *(dst2++) = R;
509 *(dst2++) = G;
510 *(dst2++) = B;
511
512 Y = *(srcY++) ;
513 R = Y + iR ;
514 G = Y + iG ;
515 B = Y + iB ;
516 R = (R < 0 ? 0 : (R > 255 ? 255 : R));
517 G = (G < 0 ? 0 : (G > 255 ? 255 : G));
518 B = (B < 0 ? 0 : (B > 255 ? 255 : B));
519 *(dst++) = R;
520 *(dst++) = G;
521 *(dst++) = B;
522
523 Y = *(srcY2++);
524 R = Y + iR ;
525 G = Y + iG ;
526 B = Y + iB ;
527 R = (R < 0 ? 0 : (R > 255 ? 255 : R));
528 G = (G < 0 ? 0 : (G > 255 ? 255 : G));
529 B = (B < 0 ? 0 : (B > 255 ? 255 : B));
530 *(dst2++) = R;
531 *(dst2++) = G;
532 *(dst2++) = B;
533 }
534 }
535}
536
537#define mask32(BYTE) (*(uint32_t *)(uint8_t [4]){ [BYTE] = 0xff })
538
539void *decode_video_thread(void *arg)
540{
541 INFO("Started decode video thread!");
542 av_session_t *_phone = arg;
543 _phone->running_decvid = 1;
544
545 //CodecState *cs = get_cs_temp(_phone->av);
546 //cs->video_stream = 0;
547
548 //int recved_size;
549 //uint8_t dest[RTP_PAYLOAD_SIZE];
550
551 //int dec_frame_finished;
552 //AVFrame *r_video_frame;
553 //r_video_frame = avcodec_alloc_frame();
554 //AVPacket dec_video_packet;
555 //av_new_packet (&dec_video_packet, 65536);
556 int width = 0;
557 int height = 0;
558
559 while (_phone->running_decvid) {
560 //recved_size = toxav_recv_rtp_payload(_phone->av, TypeVideo, dest);
561 //if (recved_size) {
562 vpx_image_t *image = NULL;
563
564 if (toxav_recv_video(_phone->av, &image) == 0 && image) {
565 //memcpy(dec_video_packet.data, dest, recved_size);
566 //dec_video_packet.size = recved_size;
567
568 //avcodec_decode_video2(cs->video_decoder_ctx, r_video_frame, &dec_frame_finished, &dec_video_packet);
569
570 //if (dec_frame_finished) {
571
572 /* Check if size has changed */
573 if (image->d_w != width || image->d_h != height) {
574
575 width = image->d_w;
576 height = image->d_h;
577
578 printf("w: %d h: %d \n", width, height);
579
580 screen = SDL_SetVideoMode(width, height, 0, 0);
581
582 //if (_phone->video_picture.bmp)
583 // SDL_FreeYUVOverlay(_phone->video_picture.bmp);
584
585 //_phone->video_picture.bmp = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, screen);
586 // _phone->sws_SDL_r_ctx = sws_getContext(width, height, cs->video_decoder_ctx->pix_fmt, width, height, PIX_FMT_YUV420P,
587 // SWS_BILINEAR, NULL, NULL, NULL);
588 }
589
590 uint8_t *rgb_image = malloc(width * height * 3);
591 convert_to_rgb(image, rgb_image);
592 SDL_Surface *img_surface = SDL_CreateRGBSurfaceFrom(rgb_image, width, height, 24, width * 3, mask32(0), mask32(1),
593 mask32(2), 0);
594
595 if (SDL_BlitSurface(img_surface, NULL, screen, NULL) == 0)
596 SDL_UpdateRect(screen, 0, 0, 0, 0);
597
598 /*
599 SDL_LockYUVOverlay(_phone->video_picture.bmp);
600 memcpy(_phone->video_picture.bmp->pixels[0], image->planes[VPX_PLANE_Y], _phone->video_picture.bmp->pitches[0] * height);
601 memcpy(_phone->video_picture.bmp->pixels[1], image->planes[VPX_PLANE_V], _phone->video_picture.bmp->pitches[1] * height / 2);
602 memcpy(_phone->video_picture.bmp->pixels[2], image->planes[VPX_PLANE_U], _phone->video_picture.bmp->pitches[2] * height / 2);
603
604 SDL_Rect rect;
605 rect.x = 0;
606 rect.y = 0;
607 rect.w = width;
608 rect.h = height;
609 SDL_DisplayYUVOverlay(_phone->video_picture.bmp, &rect);*/
610 free(rgb_image);
611 //display_received_frame(_phone, image);
612
613 } //else {
614
615 /* TODO: request the sender to create a new i-frame immediately */
616 //printf("Bad video packet\n");
617 //}
618 //}
619
620 usleep(1000);
621 }
622
623 /* clean up codecs */
624 //av_free(r_video_frame);
625
626 //pthread_mutex_lock(&cs->ctrl_mutex);
627 //avcodec_close(cs->video_decoder_ctx);
628 //pthread_mutex_unlock(&cs->ctrl_mutex);
629
630 _phone->running_decvid = -1;
631
632 pthread_exit ( NULL );
633}
634
635void *decode_audio_thread(void *arg)
636{
637 INFO("Started decode audio thread!");
638 av_session_t *_phone = arg;
639 _phone->running_decaud = 1;
640
641 //int recved_size;
642 //uint8_t dest [RTP_PAYLOAD_SIZE];
643
644 int frame_size = AUDIO_FRAME_SIZE;
645 //int data_size;
646
647 ALCdevice *dev;
648 ALCcontext *ctx;
649 ALuint source, *buffers;
650 dev = alcOpenDevice(NULL);
651 ctx = alcCreateContext(dev, NULL);
652 alcMakeContextCurrent(ctx);
653 int openal_buffers = 5;
654
655 buffers = calloc(sizeof(ALuint) * openal_buffers, 1);
656 alGenBuffers(openal_buffers, buffers);
657 alGenSources((ALuint)1, &source);
658 alSourcei(source, AL_LOOPING, AL_FALSE);
659
660 ALuint buffer;
661 ALint ready;
662
663 uint16_t zeros[frame_size];
664 memset(zeros, 0, frame_size);
665 int16_t PCM[frame_size];
666
667 int i;
668
669 for (i = 0; i < openal_buffers; ++i) {
670 alBufferData(buffers[i], AL_FORMAT_MONO16, zeros, frame_size, 48000);
671 }
672
673 alSourceQueueBuffers(source, openal_buffers, buffers);
674 alSourcePlay(source);
675
676 if (alGetError() != AL_NO_ERROR) {
677 fprintf(stderr, "Error starting audio\n");
678 goto ending;
679 }
680
681 int dec_frame_len = 0;
682
683 while (_phone->running_decaud) {
684
685 alGetSourcei(source, AL_BUFFERS_PROCESSED, &ready);
686
687 if (ready <= 0)
688 continue;
689
690 dec_frame_len = toxav_recv_audio(_phone->av, frame_size, PCM);
691
692 /* Play the packet */
693 if (dec_frame_len > 0) {
694 alSourceUnqueueBuffers(source, 1, &buffer);
695 alBufferData(buffer, AL_FORMAT_MONO16, PCM, dec_frame_len * 2 * 1, 48000);
696 int error = alGetError();
697
698 if (error != AL_NO_ERROR) {
699 fprintf(stderr, "Error setting buffer %d\n", error);
700 break;
701 }
702
703 alSourceQueueBuffers(source, 1, &buffer);
704
705 if (alGetError() != AL_NO_ERROR) {
706 fprintf(stderr, "Error: could not buffer audio\n");
707 break;
708 }
709
710 alGetSourcei(source, AL_SOURCE_STATE, &ready);
711
712 if (ready != AL_PLAYING) alSourcePlay(source);
713 }
714
715 usleep(1000);
716 }
717
718
719ending:
720 /* clean up codecs */
721 //pthread_mutex_lock(&cs->ctrl_mutex);
722 /*
723 alDeleteSources(1, &source);
724 alDeleteBuffers(openal_buffers, buffers);
725 alcMakeContextCurrent(NULL);
726 alcDestroyContext(ctx);
727 alcCloseDevice(dev);
728 */
729 //pthread_mutex_unlock(&cs->ctrl_mutex);
730
731 _phone->running_decaud = -1;
732
733 pthread_exit ( NULL );
734}
735
736
737
738void *one_threaded_audio(void *arg)
739{
740 INFO("Started audio thread!");
741 av_session_t *_phone = arg;
742 _phone->running_decaud = 1;
743
744 //int recved_size;
745 //uint8_t dest [RTP_PAYLOAD_SIZE];
746
747 int frame_size = AUDIO_FRAME_SIZE;
748
749 int16_t frame[4096];
750 ALint sample = 0;
751 alcCaptureStart((ALCdevice *)_phone->audio_capture_device);
752
753 ALCdevice *dev;
754 ALCcontext *ctx;
755 ALuint source, *buffers;
756 dev = alcOpenDevice(NULL);
757 ctx = alcCreateContext(dev, NULL);
758 alcMakeContextCurrent(ctx);
759 int openal_buffers = 5;
760
761 buffers = calloc(sizeof(ALuint) * openal_buffers, 1);
762 alGenBuffers(openal_buffers, buffers);
763 alGenSources((ALuint)1, &source);
764 alSourcei(source, AL_LOOPING, AL_FALSE);
765
766 ALuint buffer;
767 ALint ready;
768
769 uint16_t zeros[frame_size];
770 memset(zeros, 0, frame_size);
771 int16_t PCM[frame_size];
772
773 int i;
774
775 for (i = 0; i < openal_buffers; ++i) {
776 alBufferData(buffers[i], AL_FORMAT_MONO16, zeros, frame_size, 48000);
777 }
778
779 alSourceQueueBuffers(source, openal_buffers, buffers);
780 alSourcePlay(source);
781
782 if (alGetError() != AL_NO_ERROR) {
783 fprintf(stderr, "Error starting audio\n");
784 goto ending;
785 }
786
787 int dec_frame_len;
788
789 while (_phone->running_decaud) {
790
791 // combo
792 alcGetIntegerv((ALCdevice *)_phone->audio_capture_device, ALC_CAPTURE_SAMPLES, (ALCsizei)sizeof(ALint), &sample);
793
794 // record and send
795 if (sample >= frame_size) {
796 alcCaptureSamples((ALCdevice *)_phone->audio_capture_device, frame, frame_size);
797
798 if (toxav_send_audio(_phone->av, frame, frame_size) < 0)
799 printf("Could not encode or send audio packet\n");
800
801 } else {
802 usleep(5000);
803 }
804
805 // play received
806
807 alGetSourcei(source, AL_BUFFERS_PROCESSED, &ready);
808
809 if (ready <= 0)
810 continue;
811
812 dec_frame_len = toxav_recv_audio(_phone->av, frame_size, PCM);
813
814 /* Play the packet */
815 if (dec_frame_len > 0) {
816 alSourceUnqueueBuffers(source, 1, &buffer);
817 alBufferData(buffer, AL_FORMAT_MONO16, PCM, dec_frame_len * 2 * 1, 48000);
818 int error = alGetError();
819
820 if (error != AL_NO_ERROR) {
821 fprintf(stderr, "Error setting buffer %d\n", error);
822 break;
823 }
824
825 alSourceQueueBuffers(source, 1, &buffer);
826
827 if (alGetError() != AL_NO_ERROR) {
828 fprintf(stderr, "Error: could not buffer audio\n");
829 break;
830 }
831
832 alGetSourcei(source, AL_SOURCE_STATE, &ready);
833
834 if (ready != AL_PLAYING) alSourcePlay(source);
835 }
836
837 usleep(1000);
838 }
839
840
841 ending:
842 _phone->running_decaud = -1;
843
844 pthread_exit ( NULL );
845}
846
847
848int phone_startmedia_loop ( ToxAv *arg )
849{
850 if ( !arg ) {
851 return -1;
852 }
853
854 toxav_prepare_transmission(arg, 1);
855
856 /*
857 * Rise all threads
858 */
859#ifdef TOX_FFMPEG
860
861 /* Only checks for last peer */
862 if ( toxav_get_peer_transmission_type(arg, 0) == TypeVideo &&
863 0 > event.rise(encode_video_thread, _phone) ) {
864 INFO("Error while starting encode_video_thread()");
865 return -1;
866 }
867
868#endif
869
870 /* Always send audio */
871 /*if ( 0 > event.rise(encode_audio_thread, toxav_get_agent_handler(arg)) ) {
872 INFO("Error while starting encode_audio_thread()");
873 return -1;
874 } */
875
876 /* Only checks for last peer */
877 if ( toxav_get_peer_transmission_type(arg, 0) == TypeVideo &&
878 0 > event.rise(decode_video_thread, _phone) ) {
879 INFO("Error while starting decode_video_thread()");
880 return -1;
881 }
882
883 /*if ( 0 > event.rise(decode_audio_thread, toxav_get_agent_handler(arg)) ) {
884 INFO("Error while starting decode_audio_thread()");
885 return -1;
886 } */
887
888
889 /* One threaded audio */
890
891 if ( 0 > event.rise(one_threaded_audio, _phone) ) {
892 INFO ("Shit-head");
893 return -1;
894 }
895
896 return 0;
897}
898
899
900
901
902
903
904/*********************************************
905 *********************************************
906 *********************************************
907 *********************************************
908 *********************************************
909 *********************************************
910 *********************************************
911 *********************************************
912 */
913
914
915/* Some example callbacks */
916
917void callback_recv_invite ( void *_arg )
918{
919 assert(_arg);
920
921 switch ( toxav_get_peer_transmission_type(_arg, 0) ) {
922 case TypeAudio:
923 INFO( "Incoming audio call!");
924 break;
925
926 case TypeVideo:
927 INFO( "Incoming video call!");
928 break;
929 }
930
931}
932void callback_recv_ringing ( void *_arg )
933{
934 INFO ( "Ringing!" );
935}
936void callback_recv_starting ( void *_arg )
937{
938 if ( 0 != phone_startmedia_loop(_arg) ) {
939 INFO("Starting call failed!");
940 } else {
941 INFO ("Call started! ( press h to hangup )");
942 }
943
944}
945void callback_recv_ending ( void *_arg )
946{
947 INFO ( "Call ended!" );
948 _phone->running_encaud = 0;
949 _phone->running_decaud = 0;
950 _phone->running_encvid = 0;
951 _phone->running_decvid = 0;
952
953 /* Wait until all threads are done */
954 usleep(100000);
955
956 INFO ( "Call ended!" );
957}
958
959void callback_recv_error ( void *_arg )
960{
961 /*MSISession* _session = _arg;
962
963 INFO( "Error: %s", _session->last_error_str ); */
964}
965
966void callback_call_started ( void *_arg )
967{
968 if ( 0 != phone_startmedia_loop(_arg) ) {
969 INFO("Starting call failed!");
970 } else {
971 INFO ("Call started! ( press h to hangup )");
972 }
973
974}
975void callback_call_canceled ( void *_arg )
976{
977 INFO ( "Call canceled!" );
978}
979void callback_call_rejected ( void *_arg )
980{
981 INFO ( "Call rejected!" );
982}
983void callback_call_ended ( void *_arg )
984{
985 _phone->running_encaud = 0;
986 _phone->running_decaud = 0;
987 _phone->running_encvid = 0;
988 _phone->running_decvid = 0;
989
990 /* Wait until all threads are done
991
992 while ( _phone->running_encaud != -1 ||
993 _phone->running_decaud != -1 ||
994 _phone->running_encvid != -1 ||
995 _phone->running_decvid != -1 )
996
997 usleep(1000000);*/
998
999 while (_phone->running_decaud != -1) usleep(1000000);
1000
1001 toxav_kill_transmission(_phone->av);
1002 INFO ( "Call ended!" );
1003}
1004
1005void callback_requ_timeout ( void *_arg )
1006{
1007 INFO( "No answer! " );
1008}
1009
1010av_session_t *av_init_session()
1011{
1012 av_session_t *_retu = malloc(sizeof(av_session_t));
1013
1014 /* Initialize our mutex */
1015 pthread_mutex_init ( &_retu->_mutex, NULL );
1016
1017 _retu->_messenger = tox_new(1);
1018
1019 if ( !_retu->_messenger ) {
1020 fprintf ( stderr, "tox_new() failed!\n" );
1021 return NULL;
1022 }
1023
1024 _retu->_friends = NULL;
1025
1026
1027 const ALchar *_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
1028 int i = 0;
1029 const ALchar *device_names[20];
1030
1031 if ( _device_list ) {
1032 INFO("\nAvailable Capture Devices are:");
1033
1034 while (*_device_list ) {
1035 device_names[i] = _device_list;
1036 INFO("%d) %s", i, device_names[i]);
1037 _device_list += strlen( _device_list ) + 1;
1038 ++i;
1039 }
1040 }
1041
1042 INFO("Enter capture device number");
1043
1044 char dev[2];
1045 char *left;
1046 char *warned_ = fgets(dev, 2, stdin);
1047 (void)warned_;
1048 long selection = strtol(dev, &left, 10);
1049
1050 if ( *left ) {
1051 printf("'%s' is not a number!", dev);
1052 fflush(stdout);
1053 exit(EXIT_FAILURE);
1054 } else {
1055 INFO("Selected: %d ( %s )", selection, device_names[selection]);
1056 }
1057
1058 _retu->audio_capture_device =
1059 (struct ALCdevice *)alcCaptureOpenDevice(
1060 device_names[selection], av_DefaultSettings.audio_sample_rate, AL_FORMAT_MONO16, AUDIO_FRAME_SIZE * 4);
1061
1062
1063 if (alcGetError((ALCdevice *)_retu->audio_capture_device) != AL_NO_ERROR) {
1064 printf("Could not start capture device! %d\n", alcGetError((ALCdevice *)_retu->audio_capture_device));
1065 return 0;
1066 }
1067
1068 uint16_t height = 0, width = 0;
1069#ifdef TOX_FFMPEG
1070 avdevice_register_all();
1071 avcodec_register_all();
1072 av_register_all();
1073
1074 _retu->video_input_format = av_find_input_format(VIDEO_DRIVER);
1075
1076 if (avformat_open_input(&_retu->video_format_ctx, DEFAULT_WEBCAM, _retu->video_input_format, NULL) != 0) {
1077 fprintf(stderr, "Opening video_input_format failed!\n");
1078 //return -1;
1079 goto failed_init_ffmpeg;
1080 }
1081
1082 avformat_find_stream_info(_retu->video_format_ctx, NULL);
1083 av_dump_format(_retu->video_format_ctx, 0, DEFAULT_WEBCAM, 0);
1084
1085 for (i = 0; i < _retu->video_format_ctx->nb_streams; ++i) {
1086 if (_retu->video_format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
1087 _retu->video_stream = i;
1088 break;
1089 }
1090 }
1091
1092 _retu->webcam_decoder_ctx = _retu->video_format_ctx->streams[_retu->video_stream]->codec;
1093 _retu->webcam_decoder = avcodec_find_decoder(_retu->webcam_decoder_ctx->codec_id);
1094
1095 if (_retu->webcam_decoder == NULL) {
1096 fprintf(stderr, "Unsupported codec!\n");
1097 //return -1;
1098 goto failed_init_ffmpeg;
1099 }
1100
1101 if (_retu->webcam_decoder_ctx == NULL) {
1102 fprintf(stderr, "Init webcam_decoder_ctx failed!\n");
1103 //return -1;
1104 goto failed_init_ffmpeg;
1105 }
1106
1107 if (avcodec_open2(_retu->webcam_decoder_ctx, _retu->webcam_decoder, NULL) < 0) {
1108 fprintf(stderr, "Opening webcam decoder failed!\n");
1109 //return -1;
1110 goto failed_init_ffmpeg;
1111 }
1112
1113 width = _retu->webcam_decoder_ctx->width;
1114 height = _retu->webcam_decoder_ctx->height;
1115
1116failed_init_ffmpeg: ;
1117#endif
1118 uint8_t _byte_address[TOX_FRIEND_ADDRESS_SIZE];
1119 tox_get_address(_retu->_messenger, _byte_address );
1120 fraddr_to_str( _byte_address, _retu->_my_public_id );
1121
1122 ToxAvCodecSettings cs = av_DefaultSettings;
1123 cs.video_height = height;
1124 cs.video_width = width;
1125 _retu->av = toxav_new(_retu->_messenger, &cs);
1126
1127 /* ------------------ */
1128
1129 toxav_register_callstate_callback(callback_call_started, av_OnStart, _retu->av);
1130 toxav_register_callstate_callback(callback_call_canceled, av_OnCancel, _retu->av);
1131 toxav_register_callstate_callback(callback_call_rejected, av_OnReject, _retu->av);
1132 toxav_register_callstate_callback(callback_call_ended, av_OnEnd, _retu->av);
1133 toxav_register_callstate_callback(callback_recv_invite, av_OnInvite, _retu->av);
1134
1135 toxav_register_callstate_callback(callback_recv_ringing, av_OnRinging, _retu->av);
1136 toxav_register_callstate_callback(callback_recv_starting, av_OnStarting, _retu->av);
1137 toxav_register_callstate_callback(callback_recv_ending, av_OnEnding, _retu->av);
1138
1139 toxav_register_callstate_callback(callback_recv_error, av_OnError, _retu->av);
1140 toxav_register_callstate_callback(callback_requ_timeout, av_OnRequestTimeout, _retu->av);
1141
1142 /* ------------------ */
1143
1144 return _retu;
1145}
1146
1147int av_terminate_session(av_session_t *_phone)
1148{
1149 _phone->running_decaud = 0;
1150 usleep(100000); /* Wait for tox_poll to end */
1151
1152 toxav_kill(_phone->av);
1153 printf("\r[i] KILLED AV ARGH!\n");
1154
1155 usleep(1000000); /* Wait for cancel request to be sent */
1156 Tox *_p = _phone->_messenger;
1157 _phone->_messenger = NULL;
1158 tox_kill(_p);
1159
1160
1161 free(_phone->_friends);
1162 pthread_mutex_destroy ( &_phone->_mutex );
1163
1164 free(_phone);
1165
1166 printf("\r[i] Quit!\n");
1167 return 0;
1168}
1169
1170/****** AV HELPER FUNCTIONS ******/
1171
1172/* Auto accept friend request */
1173void av_friend_requ(Tox *_messenger, uint8_t *_public_key, uint8_t *_data, uint16_t _length, void *_userdata)
1174{
1175 av_session_t *_phone = _userdata;
1176 av_allocate_friend (_phone, -1, 0);
1177
1178 INFO("Got friend request with message: %s", _data);
1179
1180 tox_add_friend_norequest(_phone->_messenger, _public_key);
1181
1182 INFO("Auto-accepted! Friend id: %d", _phone->_friends->_id );
1183}
1184
1185void av_friend_active(Tox *_messenger, int _friendnumber, uint8_t *_string, uint16_t _length, void *_userdata)
1186{
1187 av_session_t *_phone = _userdata;
1188 INFO("Friend no. %d is online", _friendnumber);
1189
1190 av_friend_t *_this_friend = av_get_friend(_phone, _friendnumber);
1191
1192 if ( !_this_friend ) {
1193 INFO("But it's not registered!");
1194 return;
1195 }
1196
1197 (*_this_friend)._active = 1;
1198}
1199
1200int av_add_friend(av_session_t *_phone, char *_friend_hash)
1201{
1202 trim_spaces(_friend_hash);
1203
1204 unsigned char *_bin_string = hex_string_to_bin(_friend_hash);
1205 int _number = tox_add_friend(_phone->_messenger, _bin_string, (uint8_t *)"Tox phone "_USERAGENT,
1206 sizeof("Tox phone "_USERAGENT));
1207 free(_bin_string);
1208
1209 if ( _number >= 0) {
1210 INFO("Added friend as %d", _number );
1211 av_allocate_friend(_phone, _number, 0);
1212 } else
1213 INFO("Unknown error %i", _number );
1214
1215 return _number;
1216}
1217
1218int av_connect_to_dht(av_session_t *_phone, char *_dht_key, const char *_dht_addr, unsigned short _dht_port)
1219{
1220 unsigned char *_binary_string = hex_string_to_bin(_dht_key);
1221
1222 uint16_t _port = htons(_dht_port);
1223
1224 int _if = tox_bootstrap_from_address(_phone->_messenger, _dht_addr, 1, _port, _binary_string );
1225
1226 free(_binary_string);
1227
1228 return _if ? 0 : -1;
1229}
1230
1231/*********************************/
1232
1233void do_phone ( av_session_t *_phone )
1234{
1235 INFO("Welcome to tox_phone version: " _USERAGENT "\n"
1236 "Usage: \n"
1237 "f [pubkey] (add friend)\n"
1238 "c [a/v] (type) [friend] (friend id) (calls friend if online)\n"
1239 "h (if call is active hang up)\n"
1240 "a [a/v] (answer incoming call: a - audio / v - audio + video (audio is default))\n"
1241 "r (reject incoming call)\n"
1242 "q (quit)\n"
1243 "================================================================================"
1244 );
1245
1246 while ( 1 ) {
1247 char _line [ 1500 ];
1248 int _len;
1249
1250 if ( -1 == getinput(_line, 1500, &_len) ) {
1251 printf(" >> ");
1252 fflush(stdout);
1253 continue;
1254 }
1255
1256 if ( _len > 1 && _line[1] != ' ' && _line[1] != '\n' ) {
1257 INFO("Invalid input!");
1258 continue;
1259 }
1260
1261 switch (_line[0]) {
1262
1263 case 'f': {
1264 char _id [128];
1265 strncpy(_id, _line + 2, 128);
1266
1267 av_add_friend(_phone, _id);
1268
1269 }
1270 break;
1271
1272 case 'c': {
1273 ToxAvCallType _ctype;
1274
1275 if ( _len < 5 ) {
1276 INFO("Invalid input; usage: c a/v [friend]");
1277 break;
1278 } else if ( _line[2] == 'a' || _line[2] != 'v' ) { /* default and audio */
1279 _ctype = TypeAudio;
1280 } else { /* video */
1281 _ctype = TypeVideo;
1282 }
1283
1284 char *_end;
1285 int _friend = strtol(_line + 4, &_end, 10);
1286
1287 if ( *_end ) {
1288 INFO("Friend num has to be numerical value");
1289 break;
1290 }
1291
1292 if ( toxav_call(_phone->av, _friend, _ctype, 30) == ErrorAlreadyInCall ) {
1293 INFO("Already in a call");
1294 break;
1295 } else INFO("Calling friend: %d!", _friend);
1296
1297 }
1298 break;
1299
1300 case 'h': {
1301 if ( toxav_hangup(_phone->av) == ErrorNoCall ) {
1302 INFO("No call!");
1303 break;
1304 } else INFO("Hung up...");
1305
1306 }
1307 break;
1308
1309 case 'a': {
1310 ToxAvError rc;
1311
1312 if ( _len > 1 && _line[2] == 'v' ) {
1313 rc = toxav_answer(_phone->av, TypeVideo);
1314 } else
1315 rc = toxav_answer(_phone->av, TypeAudio);
1316
1317 if ( rc == ErrorInvalidState ) {
1318 INFO("No call to answer!");
1319 }
1320
1321 }
1322 break;
1323
1324 case 'r': {
1325 if ( toxav_reject(_phone->av, "User action") == ErrorInvalidState )
1326 INFO("No state to cancel!");
1327 else INFO("Call Rejected...");
1328
1329 }
1330 break;
1331
1332 case 'q': {
1333 INFO("Quitting!");
1334 return;
1335 }
1336
1337 case '\n': {
1338 }
1339
1340 default: {
1341 } break;
1342
1343 }
1344
1345 }
1346}
1347
1348void *tox_poll (void *_messenger_p)
1349{
1350 Tox **_messenger = _messenger_p;
1351
1352 while ( *_messenger ) {
1353 tox_do(*_messenger);
1354 usleep(10000);
1355 }
1356
1357 pthread_exit(NULL);
1358}
1359
1360int av_wait_dht(av_session_t *_phone, int _wait_seconds, const char *_ip, char *_key, unsigned short _port)
1361{
1362 if ( !_wait_seconds )
1363 return -1;
1364
1365 int _waited = 0;
1366
1367 while ( !tox_isconnected(_phone->_messenger) ) {
1368
1369 if ( -1 == av_connect_to_dht(_phone, _key, _ip, _port) ) {
1370 INFO("Could not connect to: %s", _ip);
1371 av_terminate_session(_phone);
1372 return -1;
1373 }
1374
1375 if ( _waited >= _wait_seconds ) return 0;
1376
1377 printf(".");
1378 fflush(stdout);
1379
1380 _waited ++;
1381 usleep(1000000);
1382 }
1383
1384 int _r = _wait_seconds - _waited;
1385 return _r ? _r : 1;
1386}
1387/* ---------------------- */
1388
1389int print_help ( const char *_name )
1390{
1391 printf ( "Usage: %s [IP] [PORT] [KEY]\n"
1392 "\t[IP] (DHT ip)\n"
1393 "\t[PORT] (DHT port)\n"
1394 "\t[KEY] (DHT public key)\n"
1395 "P.S. Friends and key are stored in ./tox_phone.conf\n"
1396 , _name );
1397 return 1;
1398}
1399
1400int main ( int argc, char *argv [] )
1401{
1402 if ( argc < 1 || argc < 4 )
1403 return print_help(argv[0]);
1404
1405 char *_convertable;
1406
1407
1408 const char *_ip = argv[1];
1409 char *_key = argv[3];
1410 unsigned short _port = strtol(argv[2], &_convertable, 10);
1411
1412 if ( *_convertable ) {
1413 printf("Invalid port: cannot convert string to long: %s", _convertable);
1414 return 1;
1415 }
1416
1417 _phone = av_init_session();
1418
1419 assert ( _phone );
1420
1421 tox_callback_friend_request(_phone->_messenger, av_friend_requ, _phone);
1422 tox_callback_status_message(_phone->_messenger, av_friend_active, _phone);
1423
1424
1425 INFO("\r================================================================================\n"
1426 "[!] Trying dht@%s:%d"
1427 , _ip, _port);
1428
1429 /* Start tox protocol */
1430 event.rise( tox_poll, &_phone->_messenger );
1431
1432 /* Just clean one line */
1433 printf("\r \r");
1434 fflush(stdout);
1435
1436 int _r;
1437 int _wait_seconds = 5;
1438
1439 for ( _r = 0; _r == 0; _r = av_wait_dht(_phone, _wait_seconds, _ip, _key, _port) ) _wait_seconds --;
1440
1441
1442 if ( -1 == _r ) {
1443 INFO("Error while connecting to dht: %s:%d", _ip, _port);
1444 av_terminate_session(_phone);
1445 return 1;
1446 }
1447
1448 INFO("CONNECTED!\n"
1449 "================================================================================\n"
1450 "%s\n"
1451 "================================================================================"
1452 , trim_spaces(_phone->_my_public_id) );
1453
1454
1455 do_phone (_phone);
1456
1457 av_terminate_session(_phone);
1458
1459 return 0;
1460}
diff --git a/toxav/rtp.c b/toxav/rtp.c
index d96712b3..f44b2bfe 100755..100644
--- a/toxav/rtp.c
+++ b/toxav/rtp.c
@@ -25,6 +25,8 @@
25#include "config.h" 25#include "config.h"
26#endif /* HAVE_CONFIG_H */ 26#endif /* HAVE_CONFIG_H */
27 27
28#include "../toxcore/logger.h"
29
28#include "rtp.h" 30#include "rtp.h"
29#include <assert.h> 31#include <assert.h>
30#include <stdlib.h> 32#include <stdlib.h>
@@ -227,6 +229,7 @@ static const uint32_t payload_table[] = {
227RTPHeader *extract_header ( const uint8_t *payload, int length ) 229RTPHeader *extract_header ( const uint8_t *payload, int length )
228{ 230{
229 if ( !payload || !length ) { 231 if ( !payload || !length ) {
232 LOGGER_WARNING("No payload to extract!");
230 return NULL; 233 return NULL;
231 } 234 }
232 235
@@ -245,6 +248,7 @@ RTPHeader *extract_header ( const uint8_t *payload, int length )
245 248
246 if ( GET_FLAG_VERSION(_retu) != RTP_VERSION ) { 249 if ( GET_FLAG_VERSION(_retu) != RTP_VERSION ) {
247 /* Deallocate */ 250 /* Deallocate */
251 LOGGER_WARNING("Invalid version!");
248 free(_retu); 252 free(_retu);
249 return NULL; 253 return NULL;
250 } 254 }
@@ -258,12 +262,13 @@ RTPHeader *extract_header ( const uint8_t *payload, int length )
258 262
259 if ( length < _length ) { 263 if ( length < _length ) {
260 /* Deallocate */ 264 /* Deallocate */
265 LOGGER_WARNING("Length invalid!");
261 free(_retu); 266 free(_retu);
262 return NULL; 267 return NULL;
263 } 268 }
264 269
265 memset(_retu->csrc, 0, 16 * sizeof (uint32_t)); 270 memset(_retu->csrc, 0, 16 * sizeof (uint32_t));
266 271
267 _retu->marker_payloadt = *_it; 272 _retu->marker_payloadt = *_it;
268 ++_it; 273 ++_it;
269 _retu->length = _length; 274 _retu->length = _length;
@@ -304,6 +309,7 @@ RTPExtHeader *extract_ext_header ( const uint8_t *payload, uint16_t length )
304 309
305 310
306 if ( length < ( _ext_length * sizeof(uint32_t) ) ) { 311 if ( length < ( _ext_length * sizeof(uint32_t) ) ) {
312 LOGGER_WARNING("Length invalid!");
307 free(_retu); 313 free(_retu);
308 return NULL; 314 return NULL;
309 } 315 }
@@ -415,9 +421,9 @@ RTPHeader *build_header ( RTPSession *session )
415 421
416 int i; 422 int i;
417 423
418 for ( i = 0; i < session->cc; i++ ) 424 for ( i = 0; i < session->cc; i++ )
419 _retu->csrc[i] = session->csrc[i]; 425 _retu->csrc[i] = session->csrc[i];
420 426
421 _retu->length = 12 /* Minimum header len */ + ( session->cc * size_32 ); 427 _retu->length = 12 /* Minimum header len */ + ( session->cc * size_32 );
422 428
423 return _retu; 429 return _retu;
@@ -443,6 +449,7 @@ RTPMessage *msg_parse ( uint16_t sequnum, const uint8_t *data, int length )
443 _retu->header = extract_header ( data, length ); /* It allocates memory and all */ 449 _retu->header = extract_header ( data, length ); /* It allocates memory and all */
444 450
445 if ( !_retu->header ) { 451 if ( !_retu->header ) {
452 LOGGER_WARNING("Header failed to extract!");
446 free(_retu); 453 free(_retu);
447 return NULL; 454 return NULL;
448 } 455 }
@@ -461,6 +468,7 @@ RTPMessage *msg_parse ( uint16_t sequnum, const uint8_t *data, int length )
461 _retu->length -= ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 ); 468 _retu->length -= ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 );
462 _from_pos += ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 ); 469 _from_pos += ( 4 /* Minimum ext header len */ + _retu->ext_header->length * size_32 );
463 } else { /* Error */ 470 } else { /* Error */
471 LOGGER_WARNING("Ext Header failed to extract!");
464 rtp_free_msg(NULL, _retu); 472 rtp_free_msg(NULL, _retu);
465 return NULL; 473 return NULL;
466 } 474 }
@@ -471,6 +479,7 @@ RTPMessage *msg_parse ( uint16_t sequnum, const uint8_t *data, int length )
471 if ( length - _from_pos <= MAX_RTP_SIZE ) 479 if ( length - _from_pos <= MAX_RTP_SIZE )
472 memcpy ( _retu->data, data + _from_pos, length - _from_pos ); 480 memcpy ( _retu->data, data + _from_pos, length - _from_pos );
473 else { 481 else {
482 LOGGER_WARNING("Invalid length!");
474 rtp_free_msg(NULL, _retu); 483 rtp_free_msg(NULL, _retu);
475 return NULL; 484 return NULL;
476 } 485 }
@@ -496,8 +505,15 @@ int rtp_handle_packet ( void *object, uint8_t *data, uint32_t length )
496 RTPSession *_session = object; 505 RTPSession *_session = object;
497 RTPMessage *_msg; 506 RTPMessage *_msg;
498 507
499 if ( !_session || length < 13 + crypto_box_MACBYTES) /* 12 is the minimum length for rtp + desc. byte */ 508 if ( !_session || length < 13 + crypto_box_MACBYTES) { /* 12 is the minimum length for rtp + desc. byte */
509 LOGGER_WARNING("No session or invalid length of received buffer!");
500 return -1; 510 return -1;
511 }
512
513 if ( _session->queue_limit <= _session->queue_size ) {
514 LOGGER_WARNING("Queue limit reached!");
515 return -1;
516 }
501 517
502 uint8_t _plain[MAX_UDP_PACKET_SIZE]; 518 uint8_t _plain[MAX_UDP_PACKET_SIZE];
503 519
@@ -524,7 +540,10 @@ int rtp_handle_packet ( void *object, uint8_t *data, uint32_t length )
524 _decrypted_length = decrypt_data_symmetric( 540 _decrypted_length = decrypt_data_symmetric(
525 (uint8_t *)_session->decrypt_key, _session->nonce_cycle, data + 3, length - 3, _plain ); 541 (uint8_t *)_session->decrypt_key, _session->nonce_cycle, data + 3, length - 3, _plain );
526 542
527 if ( _decrypted_length == -1 ) return -1; /* This packet is not encrypted properly */ 543 if ( _decrypted_length == -1 ) {
544 LOGGER_WARNING("Packet not ecrypted properly!");
545 return -1; /* This packet is not encrypted properly */
546 }
528 547
529 /* Otherwise, if decryption is ok with new cycle, set new cycle 548 /* Otherwise, if decryption is ok with new cycle, set new cycle
530 */ 549 */
@@ -533,7 +552,10 @@ int rtp_handle_packet ( void *object, uint8_t *data, uint32_t length )
533 _decrypted_length = decrypt_data_symmetric( 552 _decrypted_length = decrypt_data_symmetric(
534 (uint8_t *)_session->decrypt_key, _calculated, data + 3, length - 3, _plain ); 553 (uint8_t *)_session->decrypt_key, _calculated, data + 3, length - 3, _plain );
535 554
536 if ( _decrypted_length == -1 ) return -1; /* This is just an error */ 555 if ( _decrypted_length == -1 ) {
556 LOGGER_WARNING("Error decrypting!");
557 return -1; /* This is just an error */
558 }
537 559
538 /* A new cycle setting. */ 560 /* A new cycle setting. */
539 memcpy(_session->nonce_cycle, _session->decrypt_nonce, crypto_box_NONCEBYTES); 561 memcpy(_session->nonce_cycle, _session->decrypt_nonce, crypto_box_NONCEBYTES);
@@ -543,7 +565,10 @@ int rtp_handle_packet ( void *object, uint8_t *data, uint32_t length )
543 565
544 _msg = msg_parse ( _sequnum, _plain, _decrypted_length ); 566 _msg = msg_parse ( _sequnum, _plain, _decrypted_length );
545 567
546 if ( !_msg ) return -1; 568 if ( !_msg ) {
569 LOGGER_WARNING("Could not parse message!");
570 return -1;
571 }
547 572
548 /* Check if message came in late */ 573 /* Check if message came in late */
549 if ( check_late_message(_session, _msg) < 0 ) { /* Not late */ 574 if ( check_late_message(_session, _msg) < 0 ) { /* Not late */
@@ -560,6 +585,8 @@ int rtp_handle_packet ( void *object, uint8_t *data, uint32_t length )
560 _session->last_msg = _session->oldest_msg = _msg; 585 _session->last_msg = _session->oldest_msg = _msg;
561 } 586 }
562 587
588 _session->queue_size++;
589
563 pthread_mutex_unlock(&_session->mutex); 590 pthread_mutex_unlock(&_session->mutex);
564 591
565 return 0; 592 return 0;
@@ -579,8 +606,10 @@ int rtp_handle_packet ( void *object, uint8_t *data, uint32_t length )
579 */ 606 */
580RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t length ) 607RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t length )
581{ 608{
582 if ( !session ) 609 if ( !session ) {
610 LOGGER_WARNING("No session!");
583 return NULL; 611 return NULL;
612 }
584 613
585 uint8_t *_from_pos; 614 uint8_t *_from_pos;
586 RTPMessage *_retu = calloc(1, sizeof (RTPMessage)); 615 RTPMessage *_retu = calloc(1, sizeof (RTPMessage));
@@ -619,36 +648,6 @@ RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t
619 648
620 649
621 650
622
623
624
625
626/********************************************************************************************************************
627 ********************************************************************************************************************
628 ********************************************************************************************************************
629 ********************************************************************************************************************
630 ********************************************************************************************************************
631 *
632 *
633 *
634 * PUBLIC API FUNCTIONS IMPLEMENTATIONS
635 *
636 *
637 *
638 ********************************************************************************************************************
639 ********************************************************************************************************************
640 ********************************************************************************************************************
641 ********************************************************************************************************************
642 ********************************************************************************************************************/
643
644
645
646
647
648
649
650
651
652/** 651/**
653 * @brief Release all messages held by session. 652 * @brief Release all messages held by session.
654 * 653 *
@@ -660,6 +659,7 @@ RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t
660int rtp_release_session_recv ( RTPSession *session ) 659int rtp_release_session_recv ( RTPSession *session )
661{ 660{
662 if ( !session ) { 661 if ( !session ) {
662 LOGGER_WARNING("No session!");
663 return -1; 663 return -1;
664 } 664 }
665 665
@@ -673,6 +673,7 @@ int rtp_release_session_recv ( RTPSession *session )
673 } 673 }
674 674
675 session->last_msg = session->oldest_msg = NULL; 675 session->last_msg = session->oldest_msg = NULL;
676 session->queue_size = 0;
676 677
677 pthread_mutex_unlock(&session->mutex); 678 pthread_mutex_unlock(&session->mutex);
678 679
@@ -681,6 +682,31 @@ int rtp_release_session_recv ( RTPSession *session )
681 682
682 683
683/** 684/**
685 * @brief Call this to change queue limit
686 *
687 * @param session The session
688 * @param limit new limit
689 * @return void
690 */
691void rtp_queue_adjust_limit(RTPSession *session, uint64_t limit)
692{
693 RTPMessage *_tmp, * _it;
694 pthread_mutex_lock(&session->mutex);
695
696 for ( _it = session->oldest_msg; session->queue_size > limit; _it = _tmp ) {
697 _tmp = _it->next;
698 rtp_free_msg( session, _it);
699 session->queue_size --;
700 }
701
702 session->oldest_msg = _it;
703 session->queue_limit = limit;
704
705 pthread_mutex_unlock(&session->mutex);
706}
707
708
709/**
684 * @brief Gets oldest message in the list. 710 * @brief Gets oldest message in the list.
685 * 711 *
686 * @param session Where the list is. 712 * @param session Where the list is.
@@ -689,21 +715,32 @@ int rtp_release_session_recv ( RTPSession *session )
689 */ 715 */
690RTPMessage *rtp_recv_msg ( RTPSession *session ) 716RTPMessage *rtp_recv_msg ( RTPSession *session )
691{ 717{
692 if ( !session ) 718 if ( !session ) {
719 LOGGER_WARNING("No session!");
693 return NULL; 720 return NULL;
694 721 }
695 RTPMessage *_retu = session->oldest_msg;
696 722
697 pthread_mutex_lock(&session->mutex); 723 pthread_mutex_lock(&session->mutex);
698 724
699 if ( _retu ) 725 if ( session->queue_size == 0 ) {
700 session->oldest_msg = _retu->next; 726 pthread_mutex_unlock(&session->mutex);
727 return NULL;
728 }
729
730
731 RTPMessage *_retu = session->oldest_msg;
732
733 /*if (_retu)*/
734 session->oldest_msg = _retu->next;
701 735
702 if ( !session->oldest_msg ) 736 if ( !session->oldest_msg )
703 session->last_msg = NULL; 737 session->last_msg = NULL;
704 738
739 session->queue_size --;
740
705 pthread_mutex_unlock(&session->mutex); 741 pthread_mutex_unlock(&session->mutex);
706 742
743
707 return _retu; 744 return _retu;
708} 745}
709 746
@@ -723,7 +760,10 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat
723{ 760{
724 RTPMessage *msg = rtp_new_message (session, data, length); 761 RTPMessage *msg = rtp_new_message (session, data, length);
725 762
726 if ( !msg ) return -1; 763 if ( !msg ) {
764 LOGGER_WARNING("No session!");
765 return -1;
766 }
727 767
728 uint8_t _send_data [ MAX_UDP_PACKET_SIZE ]; 768 uint8_t _send_data [ MAX_UDP_PACKET_SIZE ];
729 769
@@ -738,15 +778,13 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat
738 int encrypted_length = encrypt_data_symmetric( /* TODO: msg->length - 2 (fix this properly)*/ 778 int encrypted_length = encrypt_data_symmetric( /* TODO: msg->length - 2 (fix this properly)*/
739 (uint8_t *) session->encrypt_key, _calculated, msg->data + 2, msg->length, _send_data + 3 ); 779 (uint8_t *) session->encrypt_key, _calculated, msg->data + 2, msg->length, _send_data + 3 );
740 780
741 int full_length = encrypted_length + 3;
742 781
743 _send_data[1] = msg->data[0]; 782 _send_data[1] = msg->data[0];
744 _send_data[2] = msg->data[1]; 783 _send_data[2] = msg->data[1];
745 784
746 785
747 /*if ( full_length != sendpacket ( messenger->net, *((IP_Port*) &session->dest), _send_data, full_length) ) {*/ 786 if ( -1 == send_custom_lossy_packet(messenger, session->dest, _send_data, encrypted_length + 3) ) {
748 if ( 0 != send_custom_lossy_packet(messenger, session->dest, _send_data, full_length) ) { 787 LOGGER_WARNING("Failed to send full packet! std error: %s", strerror(errno));
749 /*fprintf(stderr, "Rtp error: %s\n", strerror(errno));*/
750 rtp_free_msg ( session, msg ); 788 rtp_free_msg ( session, msg );
751 return -1; 789 return -1;
752 } 790 }
@@ -761,6 +799,7 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat
761 } 799 }
762 800
763 rtp_free_msg ( session, msg ); 801 rtp_free_msg ( session, msg );
802
764 return 0; 803 return 0;
765} 804}
766 805
@@ -817,13 +856,15 @@ RTPSession *rtp_init_session ( int payload_type,
817 RTPSession *_retu = calloc(1, sizeof(RTPSession)); 856 RTPSession *_retu = calloc(1, sizeof(RTPSession));
818 assert(_retu); 857 assert(_retu);
819 858
820 /*networking_registerhandler(messenger->net, payload_type, rtp_handle_packet, _retu);*/ 859 if ( -1 == custom_lossy_packet_registerhandler(messenger, friend_num, payload_type, rtp_handle_packet, _retu) ||
821 if ( -1 == custom_lossy_packet_registerhandler(messenger, friend_num, payload_type, rtp_handle_packet, _retu) ) { 860 !encrypt_key || !decrypt_key || !encrypt_nonce || !decrypt_nonce) {
822 /*fprintf(stderr, "Error setting custom register handler for rtp session\n");*/ 861 LOGGER_ERROR("Error setting custom register handler for rtp session");
823 free(_retu); 862 free(_retu);
824 return NULL; 863 return NULL;
825 } 864 }
826 865
866 LOGGER_DEBUG("Registered packet handler: pt: %d; fid: %d", payload_type, friend_num);
867
827 _retu->version = RTP_VERSION; /* It's always 2 */ 868 _retu->version = RTP_VERSION; /* It's always 2 */
828 _retu->padding = 0; /* If some additional data is needed about the packet */ 869 _retu->padding = 0; /* If some additional data is needed about the packet */
829 _retu->extension = 0; /* If extension to header is needed */ 870 _retu->extension = 0; /* If extension to header is needed */
@@ -838,8 +879,6 @@ RTPSession *rtp_init_session ( int payload_type,
838 _retu->rsequnum = _retu->sequnum = 1; 879 _retu->rsequnum = _retu->sequnum = 1;
839 880
840 _retu->ext_header = NULL; /* When needed allocate */ 881 _retu->ext_header = NULL; /* When needed allocate */
841 _retu->framerate = -1;
842 _retu->resolution = -1;
843 882
844 _retu->encrypt_key = encrypt_key; 883 _retu->encrypt_key = encrypt_key;
845 _retu->decrypt_key = decrypt_key; 884 _retu->decrypt_key = decrypt_key;
@@ -865,6 +904,8 @@ RTPSession *rtp_init_session ( int payload_type,
865 _retu->prefix = payload_type; 904 _retu->prefix = payload_type;
866 905
867 _retu->oldest_msg = _retu->last_msg = NULL; 906 _retu->oldest_msg = _retu->last_msg = NULL;
907 _retu->queue_limit = 100; /* Default */
908 _retu->queue_size = 0;
868 909
869 pthread_mutex_init(&_retu->mutex, NULL); 910 pthread_mutex_init(&_retu->mutex, NULL);
870 /* 911 /*
@@ -885,15 +926,17 @@ RTPSession *rtp_init_session ( int payload_type,
885 */ 926 */
886int rtp_terminate_session ( RTPSession *session, Messenger *messenger ) 927int rtp_terminate_session ( RTPSession *session, Messenger *messenger )
887{ 928{
888 if ( !session ) 929 if ( !session ) {
930 LOGGER_WARNING("No session!");
889 return -1; 931 return -1;
890 932 }
933
891 custom_lossy_packet_registerhandler(messenger, session->dest, session->prefix, NULL, NULL); 934 custom_lossy_packet_registerhandler(messenger, session->dest, session->prefix, NULL, NULL);
892 935
893 rtp_release_session_recv(session); 936 rtp_release_session_recv(session);
894 937
895 pthread_mutex_lock(&session->mutex); 938 pthread_mutex_lock(&session->mutex);
896 939
897 free ( session->ext_header ); 940 free ( session->ext_header );
898 free ( session->csrc ); 941 free ( session->csrc );
899 free ( session->decrypt_nonce ); 942 free ( session->decrypt_nonce );
@@ -901,7 +944,7 @@ int rtp_terminate_session ( RTPSession *session, Messenger *messenger )
901 free ( session->nonce_cycle ); 944 free ( session->nonce_cycle );
902 945
903 pthread_mutex_unlock(&session->mutex); 946 pthread_mutex_unlock(&session->mutex);
904 947
905 pthread_mutex_destroy(&session->mutex); 948 pthread_mutex_destroy(&session->mutex);
906 949
907 /* And finally free session */ 950 /* And finally free session */
diff --git a/toxav/rtp.h b/toxav/rtp.h
index 40532391..45cf83b6 100755..100644
--- a/toxav/rtp.h
+++ b/toxav/rtp.h
@@ -107,10 +107,6 @@ typedef struct _RTPSession {
107 */ 107 */
108 RTPExtHeader *ext_header; 108 RTPExtHeader *ext_header;
109 109
110 /* External header identifiers */
111 int resolution;
112 int framerate;
113
114 110
115 /* Since these are only references of the 111 /* Since these are only references of the
116 * call structure don't allocate or free 112 * call structure don't allocate or free
@@ -126,6 +122,9 @@ typedef struct _RTPSession {
126 RTPMessage *oldest_msg; 122 RTPMessage *oldest_msg;
127 RTPMessage *last_msg; /* tail */ 123 RTPMessage *last_msg; /* tail */
128 124
125 uint64_t queue_limit;/* Default 100; modify per thy liking */
126 uint64_t queue_size; /* currently holding << messages */
127
129 /* Msg prefix for core to know when recving */ 128 /* Msg prefix for core to know when recving */
130 uint8_t prefix; 129 uint8_t prefix;
131 130
@@ -147,6 +146,15 @@ int rtp_release_session_recv ( RTPSession *session );
147 146
148 147
149/** 148/**
149 * @brief Call this to change queue limit
150 *
151 * @param session The session
152 * @param limit new limit
153 * @return void
154 */
155void rtp_queue_adjust_limit ( RTPSession *session, uint64_t limit );
156
157/**
150 * @brief Get's oldest message in the list. 158 * @brief Get's oldest message in the list.
151 * 159 *
152 * @param session Where the list is. 160 * @param session Where the list is.
@@ -194,7 +202,7 @@ void rtp_free_msg ( RTPSession *session, RTPMessage *msg );
194 * @retval NULL Error occurred. 202 * @retval NULL Error occurred.
195 */ 203 */
196RTPSession *rtp_init_session ( int payload_type, 204RTPSession *rtp_init_session ( int payload_type,
197 Messenger *messenger, 205 Messenger *messenger,
198 int friend_num, 206 int friend_num,
199 const uint8_t *encrypt_key, 207 const uint8_t *encrypt_key,
200 const uint8_t *decrypt_key, 208 const uint8_t *decrypt_key,
diff --git a/toxav/toxav.c b/toxav/toxav.c
index 4cdc38ba..06b7596e 100755..100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -25,15 +25,20 @@
25#include "config.h" 25#include "config.h"
26#endif /* HAVE_CONFIG_H */ 26#endif /* HAVE_CONFIG_H */
27 27
28
29#define _GNU_SOURCE /* implicit declaration warning */
30
28#include "rtp.h" 31#include "rtp.h"
29#include "media.h" 32#include "media.h"
30#include "msi.h" 33#include "msi.h"
34#include "toxav.h"
31 35
36#include "../toxcore/logger.h"
37
38
39#include <assert.h>
32#include <stdlib.h> 40#include <stdlib.h>
33#include <string.h> 41#include <string.h>
34#include <assert.h>
35
36#include "toxav.h"
37 42
38/* Assume 60 fps*/ 43/* Assume 60 fps*/
39#define MAX_ENCODE_TIME_US ((1000 / 60) * 1000) 44#define MAX_ENCODE_TIME_US ((1000 / 60) * 1000)
@@ -43,26 +48,39 @@
43 48
44static const uint8_t audio_index = 0, video_index = 1; 49static const uint8_t audio_index = 0, video_index = 1;
45 50
51typedef struct _CallSpecific {
52 RTPSession *crtps[2]; /** Audio is first and video is second */
53 CodecState *cs;/** Each call have its own encoders and decoders.
54 * You can, but don't have to, reuse encoders for
55 * multiple calls. If you choose to reuse encoders,
56 * make sure to also reuse encoded payload for every call.
57 * Decoders have to be unique for each call. FIXME: Now add refcounted encoders and
58 * reuse them really.
59 */
60 JitterBuffer *j_buf; /** Jitter buffer for audio */
61} CallSpecific;
46 62
47typedef enum {
48 ts_closing,
49 ts_running,
50 ts_closed
51
52} ThreadState;
53 63
54struct _ToxAv { 64struct _ToxAv {
55 Messenger *messenger; 65 Messenger *messenger;
56
57 MSISession *msi_session; /** Main msi session */ 66 MSISession *msi_session; /** Main msi session */
67 CallSpecific *calls; /** Per-call params */
68 uint32_t max_calls;
69};
58 70
59 RTPSession *rtp_sessions[2]; /* Audio is first and video is second */ 71const ToxAvCodecSettings av_DefaultSettings = {
60 72 1000000,
61 struct jitter_buffer *j_buf; 73 800,
62 CodecState *cs; 74 600,
63 75
76 64000,
77 20,
78 48000,
79 1,
80 20
64}; 81};
65 82
83
66/** 84/**
67 * @brief Start new A/V session. There can only be one session at the time. If you register more 85 * @brief Start new A/V session. There can only be one session at the time. If you register more
68 * it will result in undefined behaviour. 86 * it will result in undefined behaviour.
@@ -74,30 +92,22 @@ struct _ToxAv {
74 * @return ToxAv* 92 * @return ToxAv*
75 * @retval NULL On error. 93 * @retval NULL On error.
76 */ 94 */
77ToxAv *toxav_new( Tox* messenger, ToxAvCodecSettings* codec_settings) 95ToxAv *toxav_new( Tox *messenger, int32_t max_calls)
78{ 96{
79 ToxAv *av = calloc ( sizeof(ToxAv), 1); 97 ToxAv *av = calloc ( sizeof(ToxAv), 1);
80 98
81 if (av == NULL) 99 if (av == NULL) {
100 LOGGER_WARNING("Allocation failed!");
82 return NULL; 101 return NULL;
102 }
83 103
84 av->messenger = (Messenger *)messenger; 104 av->messenger = (Messenger *)messenger;
85 105
86 av->msi_session = msi_init_session(av->messenger); 106 av->msi_session = msi_init_session(av->messenger, max_calls);
87 av->msi_session->agent_handler = av; 107 av->msi_session->agent_handler = av;
88 108
89 av->rtp_sessions[0] = av->rtp_sessions [1] = NULL; 109 av->calls = calloc(sizeof(CallSpecific), max_calls);
90 110 av->max_calls = max_calls;
91 /* NOTE: This should be user defined or? */
92 av->j_buf = create_queue(codec_settings->jbuf_capacity);
93
94 av->cs = codec_init_session(codec_settings->audio_bitrate,
95 codec_settings->audio_frame_duration,
96 codec_settings->audio_sample_rate,
97 codec_settings->audio_channels,
98 codec_settings->video_width,
99 codec_settings->video_height,
100 codec_settings->video_bitrate);
101 111
102 return av; 112 return av;
103} 113}
@@ -112,16 +122,24 @@ void toxav_kill ( ToxAv *av )
112{ 122{
113 msi_terminate_session(av->msi_session); 123 msi_terminate_session(av->msi_session);
114 124
115 if ( av->rtp_sessions[audio_index] ) { 125 int i = 0;
116 rtp_terminate_session(av->rtp_sessions[audio_index], av->msi_session->messenger_handle);
117 }
118 126
119 if ( av->rtp_sessions[video_index] ) { 127 for (; i < av->max_calls; i ++) {
120 rtp_terminate_session(av->rtp_sessions[video_index], av->msi_session->messenger_handle); 128 if ( av->calls[i].crtps[audio_index] )
121 } 129 rtp_terminate_session(av->calls[i].crtps[audio_index], av->msi_session->messenger_handle);
130
131
132 if ( av->calls[i].crtps[video_index] )
133 rtp_terminate_session(av->calls[i].crtps[video_index], av->msi_session->messenger_handle);
122 134
123 codec_terminate_session(av->cs);
124 135
136
137 if ( av->calls[i].j_buf ) terminate_queue(av->calls[i].j_buf);
138
139 if ( av->calls[i].cs ) codec_terminate_session(av->calls[i].cs);
140 }
141
142 free(av->calls);
125 free(av); 143 free(av);
126} 144}
127 145
@@ -132,7 +150,7 @@ void toxav_kill ( ToxAv *av )
132 * @param id One of the ToxAvCallbackID values 150 * @param id One of the ToxAvCallbackID values
133 * @return void 151 * @return void
134 */ 152 */
135void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID id, void* userdata ) 153void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID id, void *userdata )
136{ 154{
137 msi_register_callback((MSICallback)callback, (MSICallbackID) id, userdata); 155 msi_register_callback((MSICallback)callback, (MSICallbackID) id, userdata);
138} 156}
@@ -148,13 +166,9 @@ void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID
148 * @retval 0 Success. 166 * @retval 0 Success.
149 * @retval ToxAvError On error. 167 * @retval ToxAvError On error.
150 */ 168 */
151int toxav_call (ToxAv *av, int user, ToxAvCallType call_type, int ringing_seconds ) 169int toxav_call (ToxAv *av, int32_t *call_index, int user, ToxAvCallType call_type, int ringing_seconds )
152{ 170{
153 if ( av->msi_session->call ) { 171 return msi_invite(av->msi_session, call_index, call_type, ringing_seconds * 1000, user);
154 return ErrorAlreadyInCall;
155 }
156
157 return msi_invite(av->msi_session, call_type, ringing_seconds * 1000, user);
158} 172}
159 173
160/** 174/**
@@ -165,17 +179,17 @@ int toxav_call (ToxAv *av, int user, ToxAvCallType call_type, int ringing_second
165 * @retval 0 Success. 179 * @retval 0 Success.
166 * @retval ToxAvError On error. 180 * @retval ToxAvError On error.
167 */ 181 */
168int toxav_hangup ( ToxAv *av ) 182int toxav_hangup ( ToxAv *av, int32_t call_index )
169{ 183{
170 if ( !av->msi_session->call ) { 184 if ( !av->msi_session->calls[call_index] ) {
171 return ErrorNoCall; 185 return ErrorNoCall;
172 } 186 }
173 187
174 if ( av->msi_session->call->state != call_active ) { 188 if ( av->msi_session->calls[call_index]->state != call_active ) {
175 return ErrorInvalidState; 189 return ErrorInvalidState;
176 } 190 }
177 191
178 return msi_hangup(av->msi_session); 192 return msi_hangup(av->msi_session, call_index);
179} 193}
180 194
181/** 195/**
@@ -187,17 +201,17 @@ int toxav_hangup ( ToxAv *av )
187 * @retval 0 Success. 201 * @retval 0 Success.
188 * @retval ToxAvError On error. 202 * @retval ToxAvError On error.
189 */ 203 */
190int toxav_answer ( ToxAv *av, ToxAvCallType call_type ) 204int toxav_answer ( ToxAv *av, int32_t call_index, ToxAvCallType call_type )
191{ 205{
192 if ( !av->msi_session->call ) { 206 if ( !av->msi_session->calls[call_index] ) {
193 return ErrorNoCall; 207 return ErrorNoCall;
194 } 208 }
195 209
196 if ( av->msi_session->call->state != call_starting ) { 210 if ( av->msi_session->calls[call_index]->state != call_starting ) {
197 return ErrorInvalidState; 211 return ErrorInvalidState;
198 } 212 }
199 213
200 return msi_answer(av->msi_session, call_type); 214 return msi_answer(av->msi_session, call_index, call_type);
201} 215}
202 216
203/** 217/**
@@ -209,17 +223,17 @@ int toxav_answer ( ToxAv *av, ToxAvCallType call_type )
209 * @retval 0 Success. 223 * @retval 0 Success.
210 * @retval ToxAvError On error. 224 * @retval ToxAvError On error.
211 */ 225 */
212int toxav_reject ( ToxAv *av, const char *reason ) 226int toxav_reject ( ToxAv *av, int32_t call_index, const char *reason )
213{ 227{
214 if ( !av->msi_session->call ) { 228 if ( !av->msi_session->calls[call_index] ) {
215 return ErrorNoCall; 229 return ErrorNoCall;
216 } 230 }
217 231
218 if ( av->msi_session->call->state != call_starting ) { 232 if ( av->msi_session->calls[call_index]->state != call_starting ) {
219 return ErrorInvalidState; 233 return ErrorInvalidState;
220 } 234 }
221 235
222 return msi_reject(av->msi_session, (const uint8_t *) reason); 236 return msi_reject(av->msi_session, call_index, (const uint8_t *) reason);
223} 237}
224 238
225/** 239/**
@@ -232,13 +246,13 @@ int toxav_reject ( ToxAv *av, const char *reason )
232 * @retval 0 Success. 246 * @retval 0 Success.
233 * @retval ToxAvError On error. 247 * @retval ToxAvError On error.
234 */ 248 */
235int toxav_cancel ( ToxAv *av, int peer_id, const char *reason ) 249int toxav_cancel ( ToxAv *av, int32_t call_index, int peer_id, const char *reason )
236{ 250{
237 if ( !av->msi_session->call ) { 251 if ( !av->msi_session->calls[call_index] ) {
238 return ErrorNoCall; 252 return ErrorNoCall;
239 } 253 }
240 254
241 return msi_cancel(av->msi_session, peer_id, reason); 255 return msi_cancel(av->msi_session, call_index, peer_id, reason);
242} 256}
243 257
244/** 258/**
@@ -249,13 +263,13 @@ int toxav_cancel ( ToxAv *av, int peer_id, const char *reason )
249 * @retval 0 Success. 263 * @retval 0 Success.
250 * @retval ToxAvError On error. 264 * @retval ToxAvError On error.
251 */ 265 */
252int toxav_stop_call ( ToxAv *av ) 266int toxav_stop_call ( ToxAv *av, int32_t call_index )
253{ 267{
254 if ( !av->msi_session->call ) { 268 if ( !av->msi_session->calls[call_index] ) {
255 return ErrorNoCall; 269 return ErrorNoCall;
256 } 270 }
257 271
258 return msi_stopcall(av->msi_session); 272 return msi_stopcall(av->msi_session, call_index);
259} 273}
260 274
261/** 275/**
@@ -266,48 +280,61 @@ int toxav_stop_call ( ToxAv *av )
266 * @retval 0 Success. 280 * @retval 0 Success.
267 * @retval ToxAvError On error. 281 * @retval ToxAvError On error.
268 */ 282 */
269int toxav_prepare_transmission ( ToxAv* av, int support_video ) 283int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video )
270{ 284{
271 assert(av->msi_session); 285 if ( !av->msi_session || av->msi_session->max_calls <= call_index || !av->msi_session->calls[call_index] ) {
272 286 /*fprintf(stderr, "Error while starting audio RTP session: invalid call!\n");*/
273 if ( !av->msi_session || !av->msi_session->call ) { 287 return ErrorInternal;
274 return ErrorNoCall;
275 } 288 }
276 289
277 av->rtp_sessions[audio_index] = rtp_init_session( 290 CallSpecific *call = &av->calls[call_index];
278 type_audio, 291
279 av->messenger, 292 call->crtps[audio_index] =
280 av->msi_session->call->peers[0], 293 rtp_init_session(
281 av->msi_session->call->key_peer, 294 type_audio,
282 av->msi_session->call->key_local, 295 av->messenger,
283 av->msi_session->call->nonce_peer, 296 av->msi_session->calls[call_index]->peers[0],
284 av->msi_session->call->nonce_local 297 av->msi_session->calls[call_index]->key_peer,
285 ); 298 av->msi_session->calls[call_index]->key_local,
299 av->msi_session->calls[call_index]->nonce_peer,
300 av->msi_session->calls[call_index]->nonce_local);
286 301
287 302
288 if ( !av->rtp_sessions[audio_index] ) { 303 if ( !call->crtps[audio_index] ) {
289 fprintf(stderr, "Error while starting audio RTP session!\n"); 304 /*fprintf(stderr, "Error while starting audio RTP session!\n");*/
290 return ErrorStartingAudioRtp; 305 return ErrorStartingAudioRtp;
291 } 306 }
292 307
308
293 if ( support_video ) { 309 if ( support_video ) {
294 av->rtp_sessions[video_index] = rtp_init_session ( 310 call->crtps[video_index] =
295 type_video, 311 rtp_init_session (
296 av->messenger, 312 type_video,
297 av->msi_session->call->peers[0], 313 av->messenger,
298 av->msi_session->call->key_peer, 314 av->msi_session->calls[call_index]->peers[0],
299 av->msi_session->call->key_local, 315 av->msi_session->calls[call_index]->key_peer,
300 av->msi_session->call->nonce_peer, 316 av->msi_session->calls[call_index]->key_local,
301 av->msi_session->call->nonce_local 317 av->msi_session->calls[call_index]->nonce_peer,
302 ); 318 av->msi_session->calls[call_index]->nonce_local);
303 319
304 320
305 if ( !av->rtp_sessions[video_index] ) { 321 if ( !call->crtps[video_index] ) {
306 fprintf(stderr, "Error while starting video RTP session!\n"); 322 /*fprintf(stderr, "Error while starting video RTP session!\n");*/
307 return ErrorStartingVideoRtp; 323 return ErrorStartingVideoRtp;
308 } 324 }
309 } 325 }
310 return ErrorNone; 326
327 if ( !(call->j_buf = create_queue(codec_settings->jbuf_capacity)) ) return ErrorInternal;
328
329 call->cs = codec_init_session(codec_settings->audio_bitrate,
330 codec_settings->audio_frame_duration,
331 codec_settings->audio_sample_rate,
332 codec_settings->audio_channels,
333 codec_settings->video_width,
334 codec_settings->video_height,
335 codec_settings->video_bitrate);
336
337 return call->cs ? ErrorNone : ErrorInternal;
311} 338}
312 339
313/** 340/**
@@ -318,22 +345,35 @@ int toxav_prepare_transmission ( ToxAv* av, int support_video )
318 * @retval 0 Success. 345 * @retval 0 Success.
319 * @retval ToxAvError On error. 346 * @retval ToxAvError On error.
320 */ 347 */
321int toxav_kill_transmission ( ToxAv *av ) 348int toxav_kill_transmission ( ToxAv *av, int32_t call_index )
322{ 349{
323 if ( av->rtp_sessions[audio_index] && -1 == rtp_terminate_session(av->rtp_sessions[audio_index], av->messenger) ) { 350 CallSpecific *call = &av->calls[call_index];
324 fprintf(stderr, "Error while terminating audio RTP session!\n"); 351
352 if ( call->crtps[audio_index] && -1 == rtp_terminate_session(call->crtps[audio_index], av->messenger) ) {
353 /*fprintf(stderr, "Error while terminating audio RTP session!\n");*/
325 return ErrorTerminatingAudioRtp; 354 return ErrorTerminatingAudioRtp;
326 } 355 }
327 356
328 if ( av->rtp_sessions[video_index] && -1 == rtp_terminate_session(av->rtp_sessions[video_index], av->messenger) ) { 357 if ( call->crtps[video_index] && -1 == rtp_terminate_session(call->crtps[video_index], av->messenger) ) {
329 fprintf(stderr, "Error while terminating video RTP session!\n"); 358 /*fprintf(stderr, "Error while terminating video RTP session!\n");*/
330 return ErrorTerminatingVideoRtp; 359 return ErrorTerminatingVideoRtp;
331 } 360 }
332 361
333 av->rtp_sessions[audio_index] = NULL; 362 call->crtps[audio_index] = NULL;
334 av->rtp_sessions[video_index] = NULL; 363 call->crtps[video_index] = NULL;
335 364
336 365 if ( call->j_buf ) {
366 terminate_queue(call->j_buf);
367 call->j_buf = NULL;
368 LOGGER_DEBUG("Terminated j queue");
369 } else LOGGER_DEBUG("No j queue");
370
371 if ( call->cs ) {
372 codec_terminate_session(call->cs);
373 call->cs = NULL;
374 LOGGER_DEBUG("Terminated codec session");
375 } else LOGGER_DEBUG("No codec session");
376
337 return ErrorNone; 377 return ErrorNone;
338} 378}
339 379
@@ -349,10 +389,12 @@ int toxav_kill_transmission ( ToxAv *av )
349 * @retval 0 Success. 389 * @retval 0 Success.
350 * @retval -1 Failure. 390 * @retval -1 Failure.
351 */ 391 */
352inline__ int toxav_send_rtp_payload ( ToxAv *av, ToxAvCallType type, const uint8_t *payload, uint16_t length ) 392inline__ int toxav_send_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, const uint8_t *payload,
393 uint16_t length )
353{ 394{
354 if ( av->rtp_sessions[type - TypeAudio] ) 395 if ( av->calls[call_index].crtps[type - TypeAudio] )
355 return rtp_send_msg ( av->rtp_sessions[type - TypeAudio], av->msi_session->messenger_handle, payload, length ); 396 return rtp_send_msg ( av->calls[call_index].crtps[type - TypeAudio], av->msi_session->messenger_handle, payload,
397 length );
356 else return -1; 398 else return -1;
357} 399}
358 400
@@ -366,31 +408,33 @@ inline__ int toxav_send_rtp_payload ( ToxAv *av, ToxAvCallType type, const uint8
366 * @retval ToxAvError On Error. 408 * @retval ToxAvError On Error.
367 * @retval >=0 Size of received payload. 409 * @retval >=0 Size of received payload.
368 */ 410 */
369inline__ int toxav_recv_rtp_payload ( ToxAv *av, ToxAvCallType type, uint8_t *dest ) 411inline__ int toxav_recv_rtp_payload ( ToxAv *av, int32_t call_index, ToxAvCallType type, uint8_t *dest )
370{ 412{
371 if ( !dest ) return ErrorInternal; 413 if ( !dest ) return ErrorInternal;
372 414
373 if ( !av->rtp_sessions[type - TypeAudio] ) return ErrorNoRtpSession; 415 CallSpecific *call = &av->calls[call_index];
416
417 if ( !call->crtps[type - TypeAudio] ) return ErrorNoRtpSession;
374 418
375 RTPMessage *message; 419 RTPMessage *message;
376 420
377 if ( type == TypeAudio ) { 421 if ( type == TypeAudio ) {
378 422
379 do { 423 do {
380 message = rtp_recv_msg(av->rtp_sessions[audio_index]); 424 message = rtp_recv_msg(call->crtps[audio_index]);
381 425
382 if (message) { 426 if (message) {
383 /* push the packet into the queue */ 427 /* push the packet into the queue */
384 queue(av->j_buf, message); 428 queue(call->j_buf, message);
385 } 429 }
386 } while (message); 430 } while (message);
387 431
388 int success = 0; 432 int success = 0;
389 message = dequeue(av->j_buf, &success); 433 message = dequeue(call->j_buf, &success);
390 434
391 if ( success == 2) return ErrorAudioPacketLost; 435 if ( success == 2) return ErrorAudioPacketLost;
392 } else { 436 } else {
393 message = rtp_recv_msg(av->rtp_sessions[video_index]); 437 message = rtp_recv_msg(call->crtps[video_index]);
394 } 438 }
395 439
396 if ( message ) { 440 if ( message ) {
@@ -415,30 +459,31 @@ inline__ int toxav_recv_rtp_payload ( ToxAv *av, ToxAvCallType type, uint8_t *de
415 * @retval 0 Success. 459 * @retval 0 Success.
416 * @retval ToxAvError On Error. 460 * @retval ToxAvError On Error.
417 */ 461 */
418inline__ int toxav_recv_video ( ToxAv *av, vpx_image_t **output) 462inline__ int toxav_recv_video ( ToxAv *av, int32_t call_index, vpx_image_t **output)
419{ 463{
420 if ( !output ) return ErrorInternal; 464 if ( !output ) return ErrorInternal;
421 465
422 uint8_t packet [RTP_PAYLOAD_SIZE]; 466 uint8_t packet [RTP_PAYLOAD_SIZE];
423 int recved_size = 0; 467 int recved_size = 0;
424 int error; 468 int rc;
425 469 CallSpecific *call = &av->calls[call_index];
470
426 do { 471 do {
427 recved_size = toxav_recv_rtp_payload(av, TypeVideo, packet); 472 recved_size = toxav_recv_rtp_payload(av, call_index, TypeVideo, packet);
473
474 if (recved_size > 0 && ( rc = vpx_codec_decode(&call->cs->v_decoder, packet, recved_size, NULL, 0) ) != VPX_CODEC_OK) {
475 /*fprintf(stderr, "Error decoding video: %s\n", vpx_codec_err_to_string(rc));*/
476 return ErrorInternal;
477 }
428 478
429 if (recved_size > 0 && ( error = vpx_codec_decode(&av->cs->v_decoder, packet, recved_size, NULL, 0) ) != VPX_CODEC_OK)
430 fprintf(stderr, "Error decoding: %s\n", vpx_codec_err_to_string(error));
431
432 } while (recved_size > 0); 479 } while (recved_size > 0);
433 480
434 vpx_codec_iter_t iter = NULL; 481 vpx_codec_iter_t iter = NULL;
435 vpx_image_t *img; 482 vpx_image_t *img;
436 img = vpx_codec_get_frame(&av->cs->v_decoder, &iter); 483 img = vpx_codec_get_frame(&call->cs->v_decoder, &iter);
437 484
438 *output = img; 485 *output = img;
439 return 0; 486 return 0;
440 /* Yeah, i set output to be NULL if nothing received
441 */
442} 487}
443 488
444/** 489/**
@@ -450,30 +495,49 @@ inline__ int toxav_recv_video ( ToxAv *av, vpx_image_t **output)
450 * @retval 0 Success. 495 * @retval 0 Success.
451 * @retval ToxAvError On error. 496 * @retval ToxAvError On error.
452 */ 497 */
453inline__ int toxav_send_video ( ToxAv *av, vpx_image_t *input) 498inline__ int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size)
499{
500 return toxav_send_rtp_payload(av, call_index, TypeVideo, frame, frame_size);
501}
502
503/**
504 * @brief Encode video frame
505 *
506 * @param av Handler
507 * @param dest Where to
508 * @param dest_max Max size
509 * @param input What to encode
510 * @return int
511 * @retval ToxAvError On error.
512 * @retval >0 On success
513 */
514inline__ int toxav_prepare_video_frame(ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input)
454{ 515{
455 if (vpx_codec_encode(&av->cs->v_encoder, input, av->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US) != VPX_CODEC_OK) { 516 CallSpecific *call = &av->calls[call_index];
456 fprintf(stderr, "Could not encode video frame\n"); 517
518 int rc = vpx_codec_encode(&call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US);
519
520 if ( rc != VPX_CODEC_OK) {
521 fprintf(stderr, "Could not encode video frame: %s\n", vpx_codec_err_to_string(rc));
457 return ErrorInternal; 522 return ErrorInternal;
458 } 523 }
459 524
460 ++av->cs->frame_counter; 525 ++call->cs->frame_counter;
461 526
462 vpx_codec_iter_t iter = NULL; 527 vpx_codec_iter_t iter = NULL;
463 const vpx_codec_cx_pkt_t *pkt; 528 const vpx_codec_cx_pkt_t *pkt;
464 int sent = 0; 529 int copied = 0;
465 530
466 while ( (pkt = vpx_codec_get_cx_data(&av->cs->v_encoder, &iter)) ) { 531 while ( (pkt = vpx_codec_get_cx_data(&call->cs->v_encoder, &iter)) ) {
467 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { 532 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
468 if (toxav_send_rtp_payload(av, TypeVideo, pkt->data.frame.buf, pkt->data.frame.sz) != -1) 533 if ( copied + pkt->data.frame.sz > dest_max ) return ErrorPacketTooLarge;
469 ++sent; 534
535 mempcpy(dest + copied, pkt->data.frame.buf, pkt->data.frame.sz);
536 copied += pkt->data.frame.sz;
470 } 537 }
471 } 538 }
472 539
473 if (sent > 0) 540 return copied;
474 return 0;
475
476 return ErrorInternal;
477} 541}
478 542
479/** 543/**
@@ -488,25 +552,38 @@ inline__ int toxav_send_video ( ToxAv *av, vpx_image_t *input)
488 * @retval >=0 Size of received data in frames/samples. 552 * @retval >=0 Size of received data in frames/samples.
489 * @retval ToxAvError On error. 553 * @retval ToxAvError On error.
490 */ 554 */
491inline__ int toxav_recv_audio ( ToxAv *av, int frame_size, int16_t *dest ) 555inline__ int toxav_recv_audio ( ToxAv *av, int32_t call_index, int frame_size, int16_t *dest )
492{ 556{
493 if ( !dest ) return ErrorInternal; 557 if ( !dest ) return ErrorInternal;
494 558
559 CallSpecific *call = &av->calls[call_index];
560
495 uint8_t packet [RTP_PAYLOAD_SIZE]; 561 uint8_t packet [RTP_PAYLOAD_SIZE];
496 562
497 int recved_size = toxav_recv_rtp_payload(av, TypeAudio, packet); 563 int recved_size = toxav_recv_rtp_payload(av, call_index, TypeAudio, packet);
498 564
499 if ( recved_size == ErrorAudioPacketLost ) { 565 if ( recved_size == ErrorAudioPacketLost ) {
500 return opus_decode(av->cs->audio_decoder, NULL, 0, dest, frame_size, 1); 566 int dec_size = opus_decode(call->cs->audio_decoder, NULL, 0, dest, frame_size, 1);
567
568 if ( dec_size < 0 ) {
569 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
570 return ErrorInternal;
571 } else return dec_size;
572
501 } else if ( recved_size ) { 573 } else if ( recved_size ) {
502 return opus_decode(av->cs->audio_decoder, packet, recved_size, dest, frame_size, 0); 574 int dec_size = opus_decode(call->cs->audio_decoder, packet, recved_size, dest, frame_size, 0);
575
576 if ( dec_size < 0 ) {
577 LOGGER_WARNING("Decoding error: %s", opus_strerror(dec_size));
578 return ErrorInternal;
579 } else return dec_size;
503 } else { 580 } else {
504 return 0; /* Nothing received */ 581 return 0; /* Nothing received */
505 } 582 }
506} 583}
507 584
508/** 585/**
509 * @brief Encode and send audio frame. 586 * @brief Send audio frame.
510 * 587 *
511 * @param av Handler. 588 * @param av Handler.
512 * @param frame The frame (raw 16 bit signed pcm with AUDIO_CHANNELS channels audio.) 589 * @param frame The frame (raw 16 bit signed pcm with AUDIO_CHANNELS channels audio.)
@@ -516,15 +593,34 @@ inline__ int toxav_recv_audio ( ToxAv *av, int frame_size, int16_t *dest )
516 * @retval 0 Success. 593 * @retval 0 Success.
517 * @retval ToxAvError On error. 594 * @retval ToxAvError On error.
518 */ 595 */
519inline__ int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size) 596inline__ int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size)
597{
598 return toxav_send_rtp_payload(av, call_index, TypeAudio, frame, frame_size);
599}
600
601/**
602 * @brief Encode audio frame
603 *
604 * @param av Handler
605 * @param dest dest
606 * @param dest_max Max dest size
607 * @param frame The frame
608 * @param frame_size The frame size
609 * @return int
610 * @retval ToxAvError On error.
611 * @retval >0 On success
612 */
613inline__ int toxav_prepare_audio_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max,
614 const int16_t *frame, int frame_size)
520{ 615{
521 uint8_t temp_data[RTP_PAYLOAD_SIZE]; 616 int32_t rc = opus_encode(av->calls[call_index].cs->audio_encoder, frame, frame_size, dest, dest_max);
522 int32_t ret = opus_encode(av->cs->audio_encoder, frame, frame_size, temp_data, sizeof(temp_data));
523 617
524 if (ret <= 0) 618 if (rc < 0) {
619 fprintf(stderr, "Failed to encode payload: %s\n", opus_strerror(rc));
525 return ErrorInternal; 620 return ErrorInternal;
621 }
526 622
527 return toxav_send_rtp_payload(av, TypeAudio, temp_data, ret); 623 return rc;
528} 624}
529 625
530/** 626/**
@@ -536,54 +632,85 @@ inline__ int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size)
536 * @retval ToxAvCallType On success. 632 * @retval ToxAvCallType On success.
537 * @retval ToxAvError On error. 633 * @retval ToxAvError On error.
538 */ 634 */
539int toxav_get_peer_transmission_type ( ToxAv *av, int peer ) 635int toxav_get_peer_transmission_type ( ToxAv *av, int32_t call_index, int peer )
540{ 636{
541 assert(av->msi_session); 637 assert(av->msi_session);
542 638
543 if ( peer < 0 || !av->msi_session->call || av->msi_session->call->peer_count <= peer ) 639 if ( peer < 0 || !av->msi_session->calls[call_index] || av->msi_session->calls[call_index]->peer_count <= peer )
544 return ErrorInternal; 640 return ErrorInternal;
545 641
546 return av->msi_session->call->type_peer[peer]; 642 return av->msi_session->calls[call_index]->type_peer[peer];
547} 643}
548 644
549/** 645/**
550 * @brief Get id of peer participating in conversation 646 * @brief Get id of peer participating in conversation
551 * 647 *
552 * @param av Handler 648 * @param av Handler
553 * @param peer peer index 649 * @param peer peer index
554 * @return int 650 * @return int
555 * @retval ToxAvError No peer id 651 * @retval ToxAvError No peer id
556 */ 652 */
557int toxav_get_peer_id ( ToxAv* av, int peer ) 653int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer )
558{ 654{
559 assert(av->msi_session); 655 assert(av->msi_session);
560 656
561 if ( peer < 0 || !av->msi_session->call || av->msi_session->call->peer_count <= peer ) 657 if ( peer < 0 || !av->msi_session->calls[call_index] || av->msi_session->calls[call_index]->peer_count <= peer )
562 return ErrorInternal; 658 return ErrorInternal;
563 659
564 return av->msi_session->call->peers[peer]; 660 return av->msi_session->calls[call_index]->peers[peer];
565} 661}
566 662
567/** 663/**
568 * @brief Is certain capability supported 664 * @brief Is certain capability supported
569 * 665 *
570 * @param av Handler 666 * @param av Handler
571 * @return int 667 * @return int
572 * @retval 1 Yes. 668 * @retval 1 Yes.
573 * @retval 0 No. 669 * @retval 0 No.
574 */ 670 */
575inline__ int toxav_capability_supported ( ToxAv* av, ToxAvCapabilities capability ) 671inline__ int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability )
576{ 672{
577 return av->cs->capabilities & (Capabilities) capability; 673 return av->calls[call_index].cs ? av->calls[call_index].cs->capabilities & (Capabilities) capability : 0;
674 /* 0 is error here */
578} 675}
579 676
580/** 677/**
581 * @brief Get messenger handle 678 * @brief Set queue limit
582 * 679 *
583 * @param av Handler. 680 * @param av Handler
584 * @return Tox* 681 * @param call_index index
682 * @param limit the limit
683 * @return void
585 */ 684 */
586inline__ Tox* toxav_get_tox ( ToxAv* av ) 685inline__ int toxav_set_audio_queue_limit(ToxAv *av, int32_t call_index, uint64_t limit)
587{ 686{
588 return (Tox*)av->messenger; 687 if ( av->calls[call_index].crtps[audio_index] )
688 rtp_queue_adjust_limit(av->calls[call_index].crtps[audio_index], limit);
689 else
690 return ErrorNoRtpSession;
691
692 return ErrorNone;
589} 693}
694
695/**
696 * @brief Set queue limit
697 *
698 * @param av Handler
699 * @param call_index index
700 * @param limit the limit
701 * @return void
702 */
703inline__ int toxav_set_video_queue_limit(ToxAv *av, int32_t call_index, uint64_t limit)
704{
705 if ( av->calls[call_index].crtps[video_index] )
706 rtp_queue_adjust_limit(av->calls[call_index].crtps[video_index], limit);
707 else
708 return ErrorNoRtpSession;
709
710 return ErrorNone;
711}
712
713inline__ Tox *toxav_get_tox(ToxAv *av)
714{
715 return (Tox *)av->messenger;
716} \ No newline at end of file
diff --git a/toxav/toxav.h b/toxav/toxav.h
index 349e9498..aa604285 100755..100644
--- a/toxav/toxav.h
+++ b/toxav/toxav.h
@@ -29,7 +29,7 @@
29/* vpx_image_t */ 29/* vpx_image_t */
30#include <vpx/vpx_image.h> 30#include <vpx/vpx_image.h>
31 31
32typedef void ( *ToxAVCallback ) ( void *arg ); 32typedef void ( *ToxAVCallback ) ( int32_t, void *arg );
33typedef struct _ToxAv ToxAv; 33typedef struct _ToxAv ToxAv;
34 34
35#ifndef __TOX_DEFINED__ 35#ifndef __TOX_DEFINED__
@@ -67,7 +67,7 @@ typedef enum {
67 * @brief Call type identifier. 67 * @brief Call type identifier.
68 */ 68 */
69typedef enum { 69typedef enum {
70 TypeAudio = 70, 70 TypeAudio = 192,
71 TypeVideo 71 TypeVideo
72} ToxAvCallType; 72} ToxAvCallType;
73 73
@@ -87,6 +87,7 @@ typedef enum {
87 ErrorStartingVideoRtp = -8 , /* Error in toxav_prepare_transmission() */ 87 ErrorStartingVideoRtp = -8 , /* Error in toxav_prepare_transmission() */
88 ErrorTerminatingAudioRtp = -9, /* Returned in toxav_kill_transmission() */ 88 ErrorTerminatingAudioRtp = -9, /* Returned in toxav_kill_transmission() */
89 ErrorTerminatingVideoRtp = -10, /* Returned in toxav_kill_transmission() */ 89 ErrorTerminatingVideoRtp = -10, /* Returned in toxav_kill_transmission() */
90 ErrorPacketTooLarge = -11, /* Buffer exceeds size while encoding */
90 91
91} ToxAvError; 92} ToxAvError;
92 93
@@ -110,26 +111,16 @@ typedef struct _ToxAvCodecSettings {
110 uint32_t video_bitrate; /* In bits/s */ 111 uint32_t video_bitrate; /* In bits/s */
111 uint16_t video_width; /* In px */ 112 uint16_t video_width; /* In px */
112 uint16_t video_height; /* In px */ 113 uint16_t video_height; /* In px */
113 114
114 uint32_t audio_bitrate; /* In bits/s */ 115 uint32_t audio_bitrate; /* In bits/s */
115 uint16_t audio_frame_duration; /* In ms */ 116 uint16_t audio_frame_duration; /* In ms */
116 uint32_t audio_sample_rate; /* In Hz */ 117 uint32_t audio_sample_rate; /* In Hz */
117 uint32_t audio_channels; 118 uint32_t audio_channels;
118 119
119 uint32_t jbuf_capacity; /* Size of jitter buffer */ 120 uint32_t jbuf_capacity; /* Size of jitter buffer */
120} ToxAvCodecSettings; 121} ToxAvCodecSettings;
121 122
122static const ToxAvCodecSettings av_DefaultSettings = { 123extern const ToxAvCodecSettings av_DefaultSettings;
123 1000000,
124 800,
125 600,
126
127 64000,
128 20,
129 48000,
130 1,
131 20
132};
133 124
134/** 125/**
135 * @brief Start new A/V session. There can only be one session at the time. If you register more 126 * @brief Start new A/V session. There can only be one session at the time. If you register more
@@ -142,7 +133,7 @@ static const ToxAvCodecSettings av_DefaultSettings = {
142 * @return ToxAv* 133 * @return ToxAv*
143 * @retval NULL On error. 134 * @retval NULL On error.
144 */ 135 */
145ToxAv *toxav_new(Tox *messenger, ToxAvCodecSettings* codec_settings); 136ToxAv *toxav_new(Tox *messenger, int32_t max_calls);
146 137
147/** 138/**
148 * @brief Remove A/V session. 139 * @brief Remove A/V session.
@@ -172,7 +163,7 @@ void toxav_register_callstate_callback (ToxAVCallback callback, ToxAvCallbackID
172 * @retval 0 Success. 163 * @retval 0 Success.
173 * @retval ToxAvError On error. 164 * @retval ToxAvError On error.
174 */ 165 */
175int toxav_call(ToxAv *av, int user, ToxAvCallType call_type, int ringing_seconds); 166int toxav_call(ToxAv *av, int32_t *call_index, int user, ToxAvCallType call_type, int ringing_seconds);
176 167
177/** 168/**
178 * @brief Hangup active call. 169 * @brief Hangup active call.
@@ -182,7 +173,7 @@ int toxav_call(ToxAv *av, int user, ToxAvCallType call_type, int ringing_seconds
182 * @retval 0 Success. 173 * @retval 0 Success.
183 * @retval ToxAvError On error. 174 * @retval ToxAvError On error.
184 */ 175 */
185int toxav_hangup(ToxAv *av); 176int toxav_hangup(ToxAv *av, int32_t call_index);
186 177
187/** 178/**
188 * @brief Answer incomming call. 179 * @brief Answer incomming call.
@@ -193,7 +184,7 @@ int toxav_hangup(ToxAv *av);
193 * @retval 0 Success. 184 * @retval 0 Success.
194 * @retval ToxAvError On error. 185 * @retval ToxAvError On error.
195 */ 186 */
196int toxav_answer(ToxAv *av, ToxAvCallType call_type ); 187int toxav_answer(ToxAv *av, int32_t call_index, ToxAvCallType call_type );
197 188
198/** 189/**
199 * @brief Reject incomming call. 190 * @brief Reject incomming call.
@@ -204,7 +195,7 @@ int toxav_answer(ToxAv *av, ToxAvCallType call_type );
204 * @retval 0 Success. 195 * @retval 0 Success.
205 * @retval ToxAvError On error. 196 * @retval ToxAvError On error.
206 */ 197 */
207int toxav_reject(ToxAv *av, const char *reason); 198int toxav_reject(ToxAv *av, int32_t call_index, const char *reason);
208 199
209/** 200/**
210 * @brief Cancel outgoing request. 201 * @brief Cancel outgoing request.
@@ -216,7 +207,7 @@ int toxav_reject(ToxAv *av, const char *reason);
216 * @retval 0 Success. 207 * @retval 0 Success.
217 * @retval ToxAvError On error. 208 * @retval ToxAvError On error.
218 */ 209 */
219int toxav_cancel(ToxAv* av, int peer_id, const char* reason); 210int toxav_cancel(ToxAv *av, int32_t call_index, int peer_id, const char *reason);
220 211
221/** 212/**
222 * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer. 213 * @brief Terminate transmission. Note that transmission will be terminated without informing remote peer.
@@ -226,7 +217,7 @@ int toxav_cancel(ToxAv* av, int peer_id, const char* reason);
226 * @retval 0 Success. 217 * @retval 0 Success.
227 * @retval ToxAvError On error. 218 * @retval ToxAvError On error.
228 */ 219 */
229int toxav_stop_call(ToxAv *av); 220int toxav_stop_call(ToxAv *av, int32_t call_index);
230 221
231/** 222/**
232 * @brief Must be call before any RTP transmission occurs. 223 * @brief Must be call before any RTP transmission occurs.
@@ -237,7 +228,7 @@ int toxav_stop_call(ToxAv *av);
237 * @retval 0 Success. 228 * @retval 0 Success.
238 * @retval ToxAvError On error. 229 * @retval ToxAvError On error.
239 */ 230 */
240int toxav_prepare_transmission(ToxAv *av, int support_video); 231int toxav_prepare_transmission(ToxAv *av, int32_t call_index, ToxAvCodecSettings *codec_settings, int support_video);
241 232
242/** 233/**
243 * @brief Call this at the end of the transmission. 234 * @brief Call this at the end of the transmission.
@@ -247,7 +238,7 @@ int toxav_prepare_transmission(ToxAv *av, int support_video);
247 * @retval 0 Success. 238 * @retval 0 Success.
248 * @retval ToxAvError On error. 239 * @retval ToxAvError On error.
249 */ 240 */
250int toxav_kill_transmission(ToxAv *av); 241int toxav_kill_transmission(ToxAv *av, int32_t call_index);
251 242
252/** 243/**
253 * @brief Receive decoded video packet. 244 * @brief Receive decoded video packet.
@@ -258,7 +249,7 @@ int toxav_kill_transmission(ToxAv *av);
258 * @retval 0 Success. 249 * @retval 0 Success.
259 * @retval ToxAvError On Error. 250 * @retval ToxAvError On Error.
260 */ 251 */
261int toxav_recv_video ( ToxAv *av, vpx_image_t **output); 252int toxav_recv_video ( ToxAv *av, int32_t call_index, vpx_image_t **output);
262 253
263/** 254/**
264 * @brief Receive decoded audio frame. 255 * @brief Receive decoded audio frame.
@@ -272,21 +263,22 @@ int toxav_recv_video ( ToxAv *av, vpx_image_t **output);
272 * @retval >=0 Size of received data in frames/samples. 263 * @retval >=0 Size of received data in frames/samples.
273 * @retval ToxAvError On error. 264 * @retval ToxAvError On error.
274 */ 265 */
275int toxav_recv_audio( ToxAv *av, int frame_size, int16_t *dest ); 266int toxav_recv_audio( ToxAv *av, int32_t call_index, int frame_size, int16_t *dest );
276 267
277/** 268/**
278 * @brief Encode and send video packet. 269 * @brief Encode and send video packet.
279 * 270 *
280 * @param av Handler. 271 * @param av Handler.
281 * @param input The packet. 272 * @param frame The encoded frame.
273 * @param frame_size The size of the encoded frame.
282 * @return int 274 * @return int
283 * @retval 0 Success. 275 * @retval 0 Success.
284 * @retval ToxAvError On error. 276 * @retval ToxAvError On error.
285 */ 277 */
286int toxav_send_video ( ToxAv *av, vpx_image_t *input); 278int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size);
287 279
288/** 280/**
289 * @brief Encode and send audio frame. 281 * @brief Send audio frame.
290 * 282 *
291 * @param av Handler. 283 * @param av Handler.
292 * @param frame The frame (raw 16 bit signed pcm with AUDIO_CHANNELS channels audio.) 284 * @param frame The frame (raw 16 bit signed pcm with AUDIO_CHANNELS channels audio.)
@@ -296,7 +288,35 @@ int toxav_send_video ( ToxAv *av, vpx_image_t *input);
296 * @retval 0 Success. 288 * @retval 0 Success.
297 * @retval ToxAvError On error. 289 * @retval ToxAvError On error.
298 */ 290 */
299int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size); 291int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *frame, int frame_size);
292
293/**
294 * @brief Encode video frame
295 *
296 * @param av Handler
297 * @param dest Where to
298 * @param dest_max Max size
299 * @param input What to encode
300 * @return int
301 * @retval ToxAvError On error.
302 * @retval >0 On success
303 */
304int toxav_prepare_video_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input );
305
306/**
307 * @brief Encode audio frame
308 *
309 * @param av Handler
310 * @param dest dest
311 * @param dest_max Max dest size
312 * @param frame The frame
313 * @param frame_size The frame size
314 * @return int
315 * @retval ToxAvError On error.
316 * @retval >0 On success
317 */
318int toxav_prepare_audio_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, const int16_t *frame,
319 int frame_size);
300 320
301/** 321/**
302 * @brief Get peer transmission type. It can either be audio or video. 322 * @brief Get peer transmission type. It can either be audio or video.
@@ -307,34 +327,48 @@ int toxav_send_audio ( ToxAv *av, const int16_t *frame, int frame_size);
307 * @retval ToxAvCallType On success. 327 * @retval ToxAvCallType On success.
308 * @retval ToxAvError On error. 328 * @retval ToxAvError On error.
309 */ 329 */
310int toxav_get_peer_transmission_type ( ToxAv *av, int peer ); 330int toxav_get_peer_transmission_type ( ToxAv *av, int32_t call_index, int peer );
311 331
312/** 332/**
313 * @brief Get id of peer participating in conversation 333 * @brief Get id of peer participating in conversation
314 * 334 *
315 * @param av Handler 335 * @param av Handler
316 * @param peer peer index 336 * @param peer peer index
317 * @return int 337 * @return int
318 * @retval ToxAvError No peer id 338 * @retval ToxAvError No peer id
319 */ 339 */
320int toxav_get_peer_id ( ToxAv* av, int peer ); 340int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer );
321 341
322/** 342/**
323 * @brief Is certain capability supported 343 * @brief Is certain capability supported
324 * 344 *
325 * @param av Handler 345 * @param av Handler
326 * @return int 346 * @return int
327 * @retval 1 Yes. 347 * @retval 1 Yes.
328 * @retval 0 No. 348 * @retval 0 No.
329 */ 349 */
330int toxav_capability_supported ( ToxAv* av, ToxAvCapabilities capability ); 350int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability );
331 351
332/** 352/**
333 * @brief Get messenger handle 353 * @brief Set queue limit
334 * 354 *
335 * @param av Handler. 355 * @param av Handler
336 * @return Tox* 356 * @param call_index index
357 * @param limit the limit
358 * @return void
337 */ 359 */
338Tox* toxav_get_tox ( ToxAv* av ); 360int toxav_set_audio_queue_limit ( ToxAv *av, int32_t call_index, uint64_t limit );
361
362/**
363 * @brief Set queue limit
364 *
365 * @param av Handler
366 * @param call_index index
367 * @param limit the limit
368 * @return void
369 */
370int toxav_set_video_queue_limit ( ToxAv *av, int32_t call_index, uint64_t limit );
371
339 372
373Tox *toxav_get_tox(ToxAv *av);
340#endif /* __TOXAV */ \ No newline at end of file 374#endif /* __TOXAV */ \ No newline at end of file