summaryrefslogtreecommitdiff
path: root/toxav
diff options
context:
space:
mode:
authormannol <eniz_vukovic@hotmail.com>2015-04-29 01:01:25 +0200
committermannol <eniz_vukovic@hotmail.com>2015-04-29 01:01:25 +0200
commit9bba7a0434d0967d5dd76b8afc7783ea2edad0cf (patch)
tree6486c250acb38429a63a62e54cd1e4bcb0a029ee /toxav
parente4a020333d76bc30172f54f2545677f01bdd54b6 (diff)
Done
Diffstat (limited to 'toxav')
-rw-r--r--toxav/Makefile.inc21
-rw-r--r--toxav/audio.c35
-rw-r--r--toxav/audio.h33
-rw-r--r--toxav/av_test.c976
-rw-r--r--toxav/msi.c124
-rw-r--r--toxav/msi.h24
-rw-r--r--toxav/rtp.c67
-rw-r--r--toxav/rtp.h11
-rw-r--r--toxav/toxav.c132
-rw-r--r--toxav/toxav.h40
-rw-r--r--toxav/video.c25
-rw-r--r--toxav/video.h36
12 files changed, 266 insertions, 1258 deletions
diff --git a/toxav/Makefile.inc b/toxav/Makefile.inc
index 0434a3c6..3907951e 100644
--- a/toxav/Makefile.inc
+++ b/toxav/Makefile.inc
@@ -37,25 +37,4 @@ libtoxav_la_LIBADD = libtoxcore.la \
37 $(PTHREAD_LIBS) \ 37 $(PTHREAD_LIBS) \
38 $(AV_LIBS) 38 $(AV_LIBS)
39 39
40
41
42#noinst_PROGRAMS += av_test
43
44#av_test_SOURCES = ../toxav/av_test.c
45
46#av_test_CFLAGS = $(LIBSODIUM_CFLAGS) \
47 $(NACL_CFLAGS)
48
49#av_test_LDADD = $(LIBSODIUM_LDFLAGS) \
50 $(NACL_LDFLAGS) \
51 libtoxav.la \
52 libtoxcore.la \
53 $(LIBSODIUM_LIBS) \
54 $(NACL_OBJECTS) \
55 -lopenal \
56 -lopencv_calib3d -lopencv_contrib -lopencv_core -lopencv_features2d -lopencv_flann -lopencv_gpu -lopencv_highgui -lopencv_imgproc -lopencv_legacy -lopencv_ml -lopencv_objdetect -lopencv_ocl -lopencv_photo -lopencv_stitching -lopencv_superres -lopencv_ts -lopencv_video -lopencv_videostab \
57 -lsndfile \
58 $(NACL_LIBS)
59
60
61endif \ No newline at end of file 40endif \ No newline at end of file
diff --git a/toxav/audio.c b/toxav/audio.c
index 2f068c85..c592a7da 100644
--- a/toxav/audio.c
+++ b/toxav/audio.c
@@ -31,14 +31,14 @@ static void jbuf_clear(struct JitterBuffer *q);
31static void jbuf_free(struct JitterBuffer *q); 31static void jbuf_free(struct JitterBuffer *q);
32static int jbuf_write(struct JitterBuffer *q, RTPMessage *m); 32static int jbuf_write(struct JitterBuffer *q, RTPMessage *m);
33static RTPMessage *jbuf_read(struct JitterBuffer *q, int32_t *success); 33static RTPMessage *jbuf_read(struct JitterBuffer *q, int32_t *success);
34 34OpusEncoder* create_audio_encoder (int32_t bit_rate, int32_t sampling_rate, int32_t channel_count);
35OpusEncoder* create_audio_encoder (int32_t bitrate, int32_t sampling_rate, int32_t channel_count);
36bool reconfigure_audio_encoder(OpusEncoder** e, int32_t new_br, int32_t new_sr, uint8_t new_ch, 35bool reconfigure_audio_encoder(OpusEncoder** e, int32_t new_br, int32_t new_sr, uint8_t new_ch,
37 int32_t *old_br, int32_t *old_sr, int32_t *old_ch); 36 int32_t *old_br, int32_t *old_sr, int32_t *old_ch);
38bool reconfigure_audio_decoder(ACSession* ac, int32_t sampling_rate, int8_t channels); 37bool reconfigure_audio_decoder(ACSession* ac, int32_t sampling_rate, int8_t channels);
39 38
40 39
41ACSession* ac_new(ToxAV* av, uint32_t friend_id, toxav_receive_audio_frame_cb *cb, void *cb_data) 40
41ACSession* ac_new(ToxAV* av, uint32_t friend_number, toxav_receive_audio_frame_cb *cb, void *cb_data)
42{ 42{
43 ACSession *ac = calloc(sizeof(ACSession), 1); 43 ACSession *ac = calloc(sizeof(ACSession), 1);
44 44
@@ -78,11 +78,11 @@ ACSession* ac_new(ToxAV* av, uint32_t friend_id, toxav_receive_audio_frame_cb *c
78 goto DECODER_CLEANUP; 78 goto DECODER_CLEANUP;
79 } 79 }
80 80
81 ac->last_encoding_bitrate = 48000; 81 ac->last_encoding_bit_rate = 48000;
82 ac->last_encoding_sampling_rate = 48000; 82 ac->last_encoding_sampling_rate = 48000;
83 ac->last_encoding_channel_count = 2; 83 ac->last_encoding_channel_count = 2;
84 84
85 ac->last_test_encoding_bitrate = 48000; 85 ac->last_test_encoding_bit_rate = 48000;
86 ac->last_test_encoding_sampling_rate = 48000; 86 ac->last_test_encoding_sampling_rate = 48000;
87 ac->last_test_encoding_channel_count = 2; 87 ac->last_test_encoding_channel_count = 2;
88 88
@@ -97,7 +97,7 @@ ACSession* ac_new(ToxAV* av, uint32_t friend_id, toxav_receive_audio_frame_cb *c
97 ac->last_packet_channel_count = 1; 97 ac->last_packet_channel_count = 1;
98 98
99 ac->av = av; 99 ac->av = av;
100 ac->friend_id = friend_id; 100 ac->friend_number = friend_number;
101 ac->acb.first = cb; 101 ac->acb.first = cb;
102 ac->acb.second = cb_data; 102 ac->acb.second = cb_data;
103 103
@@ -181,7 +181,7 @@ void ac_do(ACSession* ac)
181 } else if (ac->acb.first) { 181 } else if (ac->acb.first) {
182 ac->last_packet_frame_duration = (rc * 1000) / ac->last_packet_sampling_rate; 182 ac->last_packet_frame_duration = (rc * 1000) / ac->last_packet_sampling_rate;
183 183
184 ac->acb.first(ac->av, ac->friend_id, tmp, rc * ac->last_packet_channel_count, 184 ac->acb.first(ac->av, ac->friend_number, tmp, rc * ac->last_packet_channel_count,
185 ac->last_packet_channel_count, ac->last_packet_sampling_rate, ac->acb.second); 185 ac->last_packet_channel_count, ac->last_packet_sampling_rate, ac->acb.second);
186 } 186 }
187 187
@@ -220,28 +220,27 @@ int ac_queue_message(void* acp, struct RTPMessage_s *msg)
220 220
221 return 0; 221 return 0;
222} 222}
223int ac_reconfigure_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels) 223int ac_reconfigure_encoder(ACSession* ac, int32_t bit_rate, int32_t sampling_rate, uint8_t channels)
224{ 224{
225 if (!ac || !reconfigure_audio_encoder(&ac->encoder, bitrate, sampling_rate, channels, 225 if (!ac || !reconfigure_audio_encoder(&ac->encoder, bit_rate, sampling_rate, channels,
226 &ac->last_encoding_bitrate, &ac->last_encoding_sampling_rate, &ac->last_encoding_channel_count)) 226 &ac->last_encoding_bit_rate, &ac->last_encoding_sampling_rate, &ac->last_encoding_channel_count))
227 return -1; 227 return -1;
228 228
229 LOGGER_DEBUG ("Reconfigured audio encoder br: %d sr: %d cc:%d", bitrate, sampling_rate, channels); 229 LOGGER_DEBUG ("Reconfigured audio encoder br: %d sr: %d cc:%d", bit_rate, sampling_rate, channels);
230 return 0; 230 return 0;
231} 231}
232int ac_reconfigure_test_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels) 232int ac_reconfigure_test_encoder(ACSession* ac, int32_t bit_rate, int32_t sampling_rate, uint8_t channels)
233{ 233{
234 if (!ac || !reconfigure_audio_encoder(&ac->test_encoder, bitrate, sampling_rate, channels, 234 if (!ac || !reconfigure_audio_encoder(&ac->test_encoder, bit_rate, sampling_rate, channels,
235 &ac->last_encoding_bitrate, &ac->last_encoding_sampling_rate, &ac->last_encoding_channel_count)) 235 &ac->last_encoding_bit_rate, &ac->last_encoding_sampling_rate, &ac->last_encoding_channel_count))
236 return -1; 236 return -1;
237 237
238 LOGGER_DEBUG ("Reconfigured test audio encoder br: %d sr: %d cc:%d", bitrate, sampling_rate, channels); 238 LOGGER_DEBUG ("Reconfigured test audio encoder br: %d sr: %d cc:%d", bit_rate, sampling_rate, channels);
239 return 0; 239 return 0;
240} 240}
241 241
242 242
243 243
244/* JITTER BUFFER WORK */
245struct JitterBuffer { 244struct JitterBuffer {
246 RTPMessage **queue; 245 RTPMessage **queue;
247 uint32_t size; 246 uint32_t size;
@@ -340,7 +339,7 @@ static RTPMessage *jbuf_read(struct JitterBuffer *q, int32_t *success)
340 *success = 0; 339 *success = 0;
341 return NULL; 340 return NULL;
342} 341}
343OpusEncoder* create_audio_encoder (int32_t bitrate, int32_t sampling_rate, int32_t channel_count) 342OpusEncoder* create_audio_encoder (int32_t bit_rate, int32_t sampling_rate, int32_t channel_count)
344{ 343{
345 int status = OPUS_OK; 344 int status = OPUS_OK;
346 OpusEncoder* rc = opus_encoder_create(sampling_rate, channel_count, OPUS_APPLICATION_AUDIO, &status); 345 OpusEncoder* rc = opus_encoder_create(sampling_rate, channel_count, OPUS_APPLICATION_AUDIO, &status);
@@ -350,7 +349,7 @@ OpusEncoder* create_audio_encoder (int32_t bitrate, int32_t sampling_rate, int32
350 return NULL; 349 return NULL;
351 } 350 }
352 351
353 status = opus_encoder_ctl(rc, OPUS_SET_BITRATE(bitrate)); 352 status = opus_encoder_ctl(rc, OPUS_SET_BITRATE(bit_rate));
354 353
355 if ( status != OPUS_OK ) { 354 if ( status != OPUS_OK ) {
356 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(status)); 355 LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(status));
diff --git a/toxav/audio.h b/toxav/audio.h
index a36396f1..c003bac0 100644
--- a/toxav/audio.h
+++ b/toxav/audio.h
@@ -31,18 +31,21 @@
31 31
32struct RTPMessage_s; 32struct RTPMessage_s;
33 33
34/*
35 * Base Audio Codec session type.
36 */
34typedef struct ACSession_s { 37typedef struct ACSession_s {
35 /* encoding */ 38 /* encoding */
36 OpusEncoder *encoder; 39 OpusEncoder *encoder;
37 int32_t last_encoding_sampling_rate; 40 int32_t last_encoding_sampling_rate;
38 int32_t last_encoding_channel_count; 41 int32_t last_encoding_channel_count;
39 int32_t last_encoding_bitrate; 42 int32_t last_encoding_bit_rate;
40 43
41 /* Testing encoder for dynamic bitrate streaming */ 44 /* Testing encoder for dynamic bit rate streaming */
42 OpusEncoder *test_encoder; 45 OpusEncoder *test_encoder;
43 int32_t last_test_encoding_sampling_rate; 46 int32_t last_test_encoding_sampling_rate;
44 int32_t last_test_encoding_channel_count; 47 int32_t last_test_encoding_channel_count;
45 int32_t last_test_encoding_bitrate; 48 int32_t last_test_encoding_bit_rate;
46 49
47 /* decoding */ 50 /* decoding */
48 OpusDecoder *decoder; 51 OpusDecoder *decoder;
@@ -57,14 +60,30 @@ typedef struct ACSession_s {
57 pthread_mutex_t queue_mutex[1]; 60 pthread_mutex_t queue_mutex[1];
58 61
59 ToxAV* av; 62 ToxAV* av;
60 uint32_t friend_id; 63 uint32_t friend_number;
61 PAIR(toxav_receive_audio_frame_cb *, void *) acb; /* Audio frame receive callback */ 64 PAIR(toxav_receive_audio_frame_cb *, void *) acb; /* Audio frame receive callback */
62} ACSession; 65} ACSession;
63 66
64ACSession* ac_new(ToxAV* av, uint32_t friend_id, toxav_receive_audio_frame_cb *cb, void *cb_data); 67/*
68 * Create new Audio Codec session.
69 */
70ACSession* ac_new(ToxAV* av, uint32_t friend_number, toxav_receive_audio_frame_cb *cb, void *cb_data);
71/*
72 * Kill the Audio Codec session.
73 */
65void ac_kill(ACSession* ac); 74void ac_kill(ACSession* ac);
75/*
76 * Do periodic work. Work is consisted out of decoding only.
77 */
66void ac_do(ACSession* ac); 78void ac_do(ACSession* ac);
79/*
80 * Queue new rtp message.
81 */
67int ac_queue_message(void *acp, struct RTPMessage_s *msg); 82int ac_queue_message(void *acp, struct RTPMessage_s *msg);
68int ac_reconfigure_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels); 83/*
69int ac_reconfigure_test_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels); 84 * Set new values to the encoders.
85 */
86int ac_reconfigure_encoder(ACSession* ac, int32_t bit_rate, int32_t sampling_rate, uint8_t channels);
87int ac_reconfigure_test_encoder(ACSession* ac, int32_t bit_rate, int32_t sampling_rate, uint8_t channels);
88
70#endif /* AUDIO_H */ \ No newline at end of file 89#endif /* AUDIO_H */ \ No newline at end of file
diff --git a/toxav/av_test.c b/toxav/av_test.c
deleted file mode 100644
index 86deebdf..00000000
--- a/toxav/av_test.c
+++ /dev/null
@@ -1,976 +0,0 @@
1/** av_test.c
2 *
3 * Copyright (C) 2013-2015 Tox project All Rights Reserved.
4 *
5 * This file is part of Tox.
6 *
7 * Tox is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * Tox is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Tox. If not, see <http://www.gnu.org/licenses/>.
19 *
20 * Compile with (Linux only; in newly created directory toxcore/dir_name):
21 * gcc -o av_test ../toxav/av_test.c ../build/.libs/libtox*.a -lopencv_core \
22 * -lopencv_highgui -lopencv_imgproc -lsndfile -pthread -lvpx -lopus -lsodium -lportaudio
23 */
24
25
26#include "../toxav/toxav.h"
27#include "../toxcore/tox.h"
28#include "../toxcore/util.h"
29#include "../toxcore/network.h" /* current_time_monotonic() */
30
31#define LOGGING
32#include "../toxcore/logger.h"
33
34/* Playing audio data */
35#include <portaudio.h>
36/* Reading audio */
37#include <sndfile.h>
38
39/* Reading and Displaying video data */
40#include <opencv/cv.h>
41#include <opencv/highgui.h>
42#include <opencv/cvwimage.h>
43
44#include <sys/stat.h>
45#include <assert.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <time.h>
49#include <string.h>
50#include <errno.h>
51#include <unistd.h>
52
53#define c_sleep(x) usleep(1000*x)
54
55
56#define CLIP(X) ( (X) > 255 ? 255 : (X) < 0 ? 0 : X)
57
58// RGB -> YUV
59#define RGB2Y(R, G, B) CLIP(( ( 66 * (R) + 129 * (G) + 25 * (B) + 128) >> 8) + 16)
60#define RGB2U(R, G, B) CLIP(( ( -38 * (R) - 74 * (G) + 112 * (B) + 128) >> 8) + 128)
61#define RGB2V(R, G, B) CLIP(( ( 112 * (R) - 94 * (G) - 18 * (B) + 128) >> 8) + 128)
62
63// YUV -> RGB
64#define C(Y) ( (Y) - 16 )
65#define D(U) ( (U) - 128 )
66#define E(V) ( (V) - 128 )
67
68#define YUV2R(Y, U, V) CLIP(( 298 * C(Y) + 409 * E(V) + 128) >> 8)
69#define YUV2G(Y, U, V) CLIP(( 298 * C(Y) - 100 * D(U) - 208 * E(V) + 128) >> 8)
70#define YUV2B(Y, U, V) CLIP(( 298 * C(Y) + 516 * D(U) + 128) >> 8)
71
72
73/* Enable/disable tests */
74#define TEST_REGULAR_AV 0
75#define TEST_REGULAR_A 0
76#define TEST_REGULAR_V 0
77#define TEST_REJECT 0
78#define TEST_CANCEL 0
79#define TEST_MUTE_UNMUTE 0
80#define TEST_TRANSFER_A 0
81#define TEST_TRANSFER_V 1
82
83
84typedef struct {
85 bool incoming;
86 uint32_t state;
87 pthread_mutex_t arb_mutex[1];
88 RingBuffer* arb; /* Audio ring buffer */
89
90} CallControl;
91
92struct toxav_thread_data {
93 ToxAV* AliceAV;
94 ToxAV* BobAV;
95 int32_t sig;
96};
97
98const char* vdout = "AV Test"; /* Video output */
99PaStream* adout = NULL; /* Audio output */
100
101
102typedef struct {
103 uint16_t size;
104 int16_t data[];
105} frame;
106
107void* pa_write_thread (void* d)
108{
109 /* The purpose of this thread is to make sure Pa_WriteStream will not block
110 * toxav_iterate thread
111 */
112 CallControl* cc = d;
113
114 while (Pa_IsStreamActive(adout)) {
115 frame* f;
116 pthread_mutex_lock(cc->arb_mutex);
117 if (rb_read(cc->arb, (void**)&f)) {
118 pthread_mutex_unlock(cc->arb_mutex);
119 Pa_WriteStream(adout, f->data, f->size);
120 free(f);
121 } else {
122 pthread_mutex_unlock(cc->arb_mutex);
123 c_sleep(10);
124 }
125 }
126}
127
128
129/**
130 * Callbacks
131 */
132void t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data)
133{
134 printf("Handling CALL callback\n");
135 ((CallControl*)user_data)->incoming = true;
136}
137void t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data)
138{
139 printf("Handling CALL STATE callback: %d\n", state);
140 ((CallControl*)user_data)->state = state;
141}
142void t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
143 uint16_t width, uint16_t height,
144 uint8_t const *y, uint8_t const *u, uint8_t const *v,
145 int32_t ystride, int32_t ustride, int32_t vstride,
146 void *user_data)
147{
148 uint16_t *img_data = malloc(height * width * 6);
149
150 unsigned long int i, j;
151 for (i = 0; i < height; ++i) {
152 for (j = 0; j < width; ++j) {
153 uint8_t *point = (uint8_t*) img_data + 3 * ((i * width) + j);
154 int yx = y[(i * ystride) + j];
155 int ux = u[((i / 2) * ustride) + (j / 2)];
156 int vx = v[((i / 2) * vstride) + (j / 2)];
157
158 point[0] = YUV2R(yx, ux, vx);
159 point[1] = YUV2G(yx, ux, vx);
160 point[2] = YUV2B(yx, ux, vx);
161 }
162 }
163
164
165 CvMat mat = cvMat(height, width, CV_8UC3, img_data);
166
167 CvSize sz = {.height = height, .width = width};
168
169 IplImage* header = cvCreateImageHeader(sz, 1, 3);
170 IplImage* img = cvGetImage(&mat, header);
171 cvShowImage(vdout, img);
172 free(img_data);
173}
174void t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
175 int16_t const *pcm,
176 size_t sample_count,
177 uint8_t channels,
178 uint32_t sampling_rate,
179 void *user_data)
180{
181 CallControl* cc = user_data;
182 frame* f = malloc(sizeof(uint16_t) + sample_count * sizeof(int16_t));
183 memcpy(f->data, pcm, sample_count * sizeof(int16_t));
184 f->size = sample_count/channels;
185
186 pthread_mutex_lock(cc->arb_mutex);
187 free(rb_write(cc->arb, f));
188 pthread_mutex_unlock(cc->arb_mutex);
189}
190void t_toxav_audio_bitrate_control_cb(ToxAV *av, uint32_t friend_number,
191 bool good, uint32_t bit_rate, void *user_data)
192{
193 if (good)
194 printf ("Set new audio bitrate to: %d\n", bit_rate);
195 else
196 printf ("The network is overly saturated with audio bitrate at: %d\n", bit_rate);
197}
198void t_toxav_video_bitrate_control_cb(ToxAV *av, uint32_t friend_number,
199 bool good, uint32_t bit_rate, void *user_data)
200{
201 if (good)
202 printf ("Set new video bitrate to: %d", bit_rate);
203 else
204 printf ("The network is overly saturated with video bitrate at: %d", bit_rate);
205}
206void t_accept_friend_request_cb(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
207{
208 if (length == 7 && memcmp("gentoo", data, 7) == 0) {
209 assert(tox_friend_add_norequest(m, public_key, NULL) != (uint32_t) ~0);
210 }
211}
212
213
214/**
215 */
216void initialize_tox(Tox** bootstrap, ToxAV** AliceAV, CallControl* AliceCC, ToxAV** BobAV, CallControl* BobCC)
217{
218 Tox* Alice;
219 Tox* Bob;
220
221 struct Tox_Options opts;
222 tox_options_default(&opts);
223
224 opts.end_port = 0;
225
226 {
227 TOX_ERR_NEW error;
228
229 opts.start_port = 33445;
230 *bootstrap = tox_new(&opts, NULL, 0, &error);
231 assert(error == TOX_ERR_NEW_OK);
232
233 opts.start_port = 33455;
234 Alice = tox_new(&opts, NULL, 0, &error);
235 assert(error == TOX_ERR_NEW_OK);
236
237 opts.start_port = 33465;
238 Bob = tox_new(&opts, NULL, 0, &error);
239 assert(error == TOX_ERR_NEW_OK);
240 }
241
242 printf("Created 3 instances of Tox\n");
243 printf("Preparing network...\n");
244 long long unsigned int cur_time = time(NULL);
245
246 uint32_t to_compare = 974536;
247 uint8_t address[TOX_ADDRESS_SIZE];
248
249 tox_callback_friend_request(Alice, t_accept_friend_request_cb, &to_compare);
250 tox_self_get_address(Alice, address);
251
252
253 assert(tox_friend_add(Bob, address, (uint8_t *)"gentoo", 7, NULL) != (uint32_t) ~0);
254
255 uint8_t off = 1;
256
257 while (1) {
258 tox_iterate(*bootstrap);
259 tox_iterate(Alice);
260 tox_iterate(Bob);
261
262 if (tox_self_get_connection_status(*bootstrap) &&
263 tox_self_get_connection_status(Alice) &&
264 tox_self_get_connection_status(Bob) && off) {
265 printf("Toxes are online, took %llu seconds\n", time(NULL) - cur_time);
266 off = 0;
267 }
268
269 if (tox_friend_get_connection_status(Alice, 0, NULL) == TOX_CONNECTION_UDP &&
270 tox_friend_get_connection_status(Bob, 0, NULL) == TOX_CONNECTION_UDP)
271 break;
272
273 c_sleep(20);
274 }
275
276
277 TOXAV_ERR_NEW rc;
278 *AliceAV = toxav_new(Alice, &rc);
279 assert(rc == TOXAV_ERR_NEW_OK);
280
281 *BobAV = toxav_new(Bob, &rc);
282 assert(rc == TOXAV_ERR_NEW_OK);
283
284
285 /* Alice */
286 toxav_callback_call(*AliceAV, t_toxav_call_cb, AliceCC);
287 toxav_callback_call_state(*AliceAV, t_toxav_call_state_cb, AliceCC);
288 toxav_callback_receive_video_frame(*AliceAV, t_toxav_receive_video_frame_cb, AliceCC);
289 toxav_callback_receive_audio_frame(*AliceAV, t_toxav_receive_audio_frame_cb, AliceCC);
290 toxav_callback_audio_bitrate_control(*AliceAV, t_toxav_audio_bitrate_control_cb, AliceCC);
291 toxav_callback_video_bitrate_control(*AliceAV, t_toxav_video_bitrate_control_cb, AliceCC);
292
293 /* Bob */
294 toxav_callback_call(*BobAV, t_toxav_call_cb, BobCC);
295 toxav_callback_call_state(*BobAV, t_toxav_call_state_cb, BobCC);
296 toxav_callback_receive_video_frame(*BobAV, t_toxav_receive_video_frame_cb, BobCC);
297 toxav_callback_receive_audio_frame(*BobAV, t_toxav_receive_audio_frame_cb, BobCC);
298 toxav_callback_audio_bitrate_control(*BobAV, t_toxav_audio_bitrate_control_cb, BobCC);
299 toxav_callback_video_bitrate_control(*BobAV, t_toxav_video_bitrate_control_cb, BobCC);
300
301
302 printf("Created 2 instances of ToxAV\n");
303 printf("All set after %llu seconds!\n", time(NULL) - cur_time);
304}
305int iterate_tox(Tox* bootstrap, ToxAV* AliceAV, ToxAV* BobAV)
306{
307 tox_iterate(bootstrap);
308 tox_iterate(toxav_get_tox(AliceAV));
309 tox_iterate(toxav_get_tox(BobAV));
310
311 return MIN(tox_iteration_interval(toxav_get_tox(AliceAV)), tox_iteration_interval(toxav_get_tox(BobAV)));
312}
313void* iterate_toxav (void * data)
314{
315 struct toxav_thread_data* data_cast = data;
316#if defined TEST_TRANSFER_V && TEST_TRANSFER_V == 1
317 cvNamedWindow(vdout, CV_WINDOW_AUTOSIZE);
318#endif
319
320 while (data_cast->sig == 0) {
321 toxav_iterate(data_cast->AliceAV);
322 toxav_iterate(data_cast->BobAV);
323 int rc = MIN(toxav_iteration_interval(data_cast->AliceAV), toxav_iteration_interval(data_cast->BobAV));
324
325 printf("\rIteration interval: %d ", rc);
326 fflush(stdout);
327
328#if defined TEST_TRANSFER_V && TEST_TRANSFER_V == 1
329 cvWaitKey(rc);
330#else
331 c_sleep(rc);
332#endif
333 }
334
335 data_cast->sig = 1;
336
337#if defined TEST_TRANSFER_V && TEST_TRANSFER_V == 1
338 cvDestroyWindow(vdout);
339#endif
340
341 pthread_exit(NULL);
342}
343
344int send_opencv_img(ToxAV* av, uint32_t friend_number, const IplImage* img)
345{
346 int32_t strides[3] = { 1280, 640, 640 };
347 uint8_t* planes[3] = {
348 malloc(img->height * img->width),
349 malloc(img->height * img->width / 2),
350 malloc(img->height * img->width / 2),
351 };
352
353 int x_chroma_shift = 1;
354 int y_chroma_shift = 1;
355
356 int x, y;
357 for (y = 0; y < img->height; ++y) {
358 for (x = 0; x < img->width; ++x) {
359 uint8_t r = img->imageData[(x + y * img->width) * 3 + 0];
360 uint8_t g = img->imageData[(x + y * img->width) * 3 + 1];
361 uint8_t b = img->imageData[(x + y * img->width) * 3 + 2];
362
363 planes[0][x + y * strides[0]] = RGB2Y(r, g, b);
364 if (!(x % (1 << x_chroma_shift)) && !(y % (1 << y_chroma_shift))) {
365 const int i = x / (1 << x_chroma_shift);
366 const int j = y / (1 << y_chroma_shift);
367 planes[1][i + j * strides[1]] = RGB2U(r, g, b);
368 planes[2][i + j * strides[2]] = RGB2V(r, g, b);
369 }
370 }
371 }
372
373
374 int rc = toxav_send_video_frame(av, friend_number, img->width, img->height, planes[0], planes[1], planes[2], NULL);
375 free(planes[0]);
376 free(planes[1]);
377 free(planes[2]);
378 return rc;
379}
380
381int print_audio_devices()
382{
383 int i = 0;
384 for (i = 0; i < Pa_GetDeviceCount(); ++i) {
385 const PaDeviceInfo* info = Pa_GetDeviceInfo(i);
386 if (info)
387 printf("%d) %s\n", i, info->name);
388 }
389
390 return 0;
391}
392
393int print_help (const char* name)
394{
395 printf("Usage: %s -[a:v:o:dh]\n"
396 "-a <path> audio input file\n"
397 "-b <ms> audio frame duration\n"
398 "-v <path> video input file\n"
399 "-x <ms> video frame duration\n"
400 "-o <idx> output audio device index\n"
401 "-d print output audio devices\n"
402 "-h print this help\n", name);
403
404 return 0;
405}
406
407
408int main (int argc, char** argv)
409{
410 freopen("/dev/zero", "w", stderr);
411 Pa_Initialize();
412
413 struct stat st;
414
415 /* AV files for testing */
416 const char* af_name = NULL;
417 const char* vf_name = NULL;
418 long audio_out_dev_idx = -1;
419
420 int32_t audio_frame_duration = 20;
421 int32_t video_frame_duration = 10;
422
423 /* Parse settings */
424 CHECK_ARG: switch (getopt(argc, argv, "a:b:v:x:o:dh")) {
425 case 'a':
426 af_name = optarg;
427 goto CHECK_ARG;
428 case 'b':{
429 char *d;
430 audio_frame_duration = strtol(optarg, &d, 10);
431 if (*d) {
432 printf("Invalid value for argument: 'b'");
433 exit(1);
434 }
435 goto CHECK_ARG;
436 }
437 case 'v':
438 vf_name = optarg;
439 goto CHECK_ARG;
440 case 'x':{
441 char *d;
442 video_frame_duration = strtol(optarg, &d, 10);
443 if (*d) {
444 printf("Invalid value for argument: 'x'");
445 exit(1);
446 }
447 goto CHECK_ARG;
448 }
449 case 'o': {
450 char *d;
451 audio_out_dev_idx = strtol(optarg, &d, 10);
452 if (*d) {
453 printf("Invalid value for argument: 'o'");
454 exit(1);
455 }
456 goto CHECK_ARG;
457 }
458 case 'd':
459 return print_audio_devices();
460 case 'h':
461 return print_help(argv[0]);
462 case '?':
463 exit(1);
464 case -1:;
465 }
466
467 { /* Check files */
468 if (!af_name) {
469 printf("Required audio input file!\n");
470 exit(1);
471 }
472
473 if (!vf_name) {
474 printf("Required video input file!\n");
475 exit(1);
476 }
477
478 /* Check for files */
479 if(stat(af_name, &st) != 0 || !S_ISREG(st.st_mode))
480 {
481 printf("%s doesn't seem to be a regular file!\n", af_name);
482 exit(1);
483 }
484
485 if(stat(vf_name, &st) != 0 || !S_ISREG(st.st_mode))
486 {
487 printf("%s doesn't seem to be a regular file!\n", vf_name);
488 exit(1);
489 }
490 }
491
492 if (audio_out_dev_idx < 0)
493 audio_out_dev_idx = Pa_GetDefaultOutputDevice();
494
495 const PaDeviceInfo* audio_dev = Pa_GetDeviceInfo(audio_out_dev_idx);
496 if (!audio_dev) {
497 fprintf(stderr, "Device under index: %ld invalid", audio_out_dev_idx);
498 return 1;
499 }
500
501 printf("Using audio device: %s\n", audio_dev->name);
502 printf("Using audio file: %s\n", af_name);
503 printf("Using video file: %s\n", vf_name);
504
505 /* START TOX NETWORK */
506
507 Tox *bootstrap;
508 ToxAV *AliceAV;
509 ToxAV *BobAV;
510
511 CallControl AliceCC;
512 CallControl BobCC;
513
514 initialize_tox(&bootstrap, &AliceAV, &AliceCC, &BobAV, &BobCC);
515
516#define REGULAR_CALL_FLOW(A_BR, V_BR) \
517 do { \
518 memset(&AliceCC, 0, sizeof(CallControl)); \
519 memset(&BobCC, 0, sizeof(CallControl)); \
520 \
521 TOXAV_ERR_CALL rc; \
522 toxav_call(AliceAV, 0, A_BR, V_BR, &rc); \
523 \
524 if (rc != TOXAV_ERR_CALL_OK) { \
525 printf("toxav_call failed: %d\n", rc); \
526 exit(1); \
527 } \
528 \
529 \
530 long long unsigned int start_time = time(NULL); \
531 \
532 \
533 while (BobCC.state != TOXAV_CALL_STATE_END) { \
534 \
535 if (BobCC.incoming) { \
536 TOXAV_ERR_ANSWER rc; \
537 toxav_answer(BobAV, 0, A_BR, V_BR, &rc); \
538 \
539 if (rc != TOXAV_ERR_ANSWER_OK) { \
540 printf("toxav_answer failed: %d\n", rc); \
541 exit(1); \
542 } \
543 BobCC.incoming = false; \
544 } else { \
545 /* TODO rtp */ \
546 \
547 if (time(NULL) - start_time == 5) { \
548 \
549 TOXAV_ERR_CALL_CONTROL rc; \
550 toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc); \
551 \
552 if (rc != TOXAV_ERR_CALL_CONTROL_OK) { \
553 printf("toxav_call_control failed: %d\n", rc); \
554 exit(1); \
555 } \
556 } \
557 } \
558 \
559 iterate_tox(bootstrap, AliceAV, BobAV); \
560 } \
561 printf("Success!\n");\
562 } while(0)
563
564 if (TEST_REGULAR_AV) {
565 printf("\nTrying regular call (Audio and Video)...\n");
566 REGULAR_CALL_FLOW(48, 4000);
567 }
568
569 if (TEST_REGULAR_A) {
570 printf("\nTrying regular call (Audio only)...\n");
571 REGULAR_CALL_FLOW(48, 0);
572 }
573
574 if (TEST_REGULAR_V) {
575 printf("\nTrying regular call (Video only)...\n");
576 REGULAR_CALL_FLOW(0, 4000);
577 }
578
579#undef REGULAR_CALL_FLOW
580
581 if (TEST_REJECT) { /* Alice calls; Bob rejects */
582 printf("\nTrying reject flow...\n");
583
584 memset(&AliceCC, 0, sizeof(CallControl));
585 memset(&BobCC, 0, sizeof(CallControl));
586
587 {
588 TOXAV_ERR_CALL rc;
589 toxav_call(AliceAV, 0, 48, 0, &rc);
590
591 if (rc != TOXAV_ERR_CALL_OK) {
592 printf("toxav_call failed: %d\n", rc);
593 exit(1);
594 }
595 }
596
597 while (!BobCC.incoming)
598 iterate_tox(bootstrap, AliceAV, BobAV);
599
600 /* Reject */
601 {
602 TOXAV_ERR_CALL_CONTROL rc;
603 toxav_call_control(BobAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
604
605 if (rc != TOXAV_ERR_CALL_CONTROL_OK) {
606 printf("toxav_call_control failed: %d\n", rc);
607 exit(1);
608 }
609 }
610
611 while (AliceCC.state != TOXAV_CALL_STATE_END)
612 iterate_tox(bootstrap, AliceAV, BobAV);
613
614 printf("Success!\n");
615 }
616
617 if (TEST_CANCEL) { /* Alice calls; Alice cancels while ringing */
618 printf("\nTrying cancel (while ringing) flow...\n");
619
620 memset(&AliceCC, 0, sizeof(CallControl));
621 memset(&BobCC, 0, sizeof(CallControl));
622
623 {
624 TOXAV_ERR_CALL rc;
625 toxav_call(AliceAV, 0, 48, 0, &rc);
626
627 if (rc != TOXAV_ERR_CALL_OK) {
628 printf("toxav_call failed: %d\n", rc);
629 exit(1);
630 }
631 }
632
633 while (!BobCC.incoming)
634 iterate_tox(bootstrap, AliceAV, BobAV);
635
636 /* Cancel */
637 {
638 TOXAV_ERR_CALL_CONTROL rc;
639 toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
640
641 if (rc != TOXAV_ERR_CALL_CONTROL_OK) {
642 printf("toxav_call_control failed: %d\n", rc);
643 exit(1);
644 }
645 }
646
647 /* Alice will not receive end state */
648 while (BobCC.state != TOXAV_CALL_STATE_END)
649 iterate_tox(bootstrap, AliceAV, BobAV);
650
651 printf("Success!\n");
652 }
653
654 if (TEST_MUTE_UNMUTE) { /* Check Mute-Unmute etc */
655 printf("\nTrying mute functionality...\n");
656
657 memset(&AliceCC, 0, sizeof(CallControl));
658 memset(&BobCC, 0, sizeof(CallControl));
659
660 /* Assume sending audio and video */
661 {
662 TOXAV_ERR_CALL rc;
663 toxav_call(AliceAV, 0, 48, 1000, &rc);
664
665 if (rc != TOXAV_ERR_CALL_OK) {
666 printf("toxav_call failed: %d\n", rc);
667 exit(1);
668 }
669 }
670
671 while (!BobCC.incoming)
672 iterate_tox(bootstrap, AliceAV, BobAV);
673
674 /* At first try all stuff while in invalid state */
675 assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL));
676 assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_RESUME, NULL));
677 assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL));
678 assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_VIDEO, NULL));
679
680 {
681 TOXAV_ERR_ANSWER rc;
682 toxav_answer(BobAV, 0, 48, 4000, &rc);
683
684 if (rc != TOXAV_ERR_ANSWER_OK) {
685 printf("toxav_answer failed: %d\n", rc);
686 exit(1);
687 }
688 }
689
690 iterate_tox(bootstrap, AliceAV, BobAV);
691
692 /* Pause and Resume */
693 printf("Pause and Resume\n");
694 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL));
695 iterate_tox(bootstrap, AliceAV, BobAV);
696 assert(BobCC.state == TOXAV_CALL_STATE_PAUSED);
697 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_RESUME, NULL));
698 iterate_tox(bootstrap, AliceAV, BobAV);
699 assert(BobCC.state & (TOXAV_CALL_STATE_SENDING_A | TOXAV_CALL_STATE_SENDING_V));
700
701 /* Mute/Unmute single */
702 printf("Mute/Unmute single\n");
703 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL));
704 iterate_tox(bootstrap, AliceAV, BobAV);
705 assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_A);
706 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL));
707 iterate_tox(bootstrap, AliceAV, BobAV);
708 assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_A);
709
710 /* Mute/Unmute both */
711 printf("Mute/Unmute both\n");
712 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL));
713 iterate_tox(bootstrap, AliceAV, BobAV);
714 assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_A);
715 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_VIDEO, NULL));
716 iterate_tox(bootstrap, AliceAV, BobAV);
717 assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_V);
718 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL));
719 iterate_tox(bootstrap, AliceAV, BobAV);
720 assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_A);
721 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_VIDEO, NULL));
722 iterate_tox(bootstrap, AliceAV, BobAV);
723 assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_V);
724
725 {
726 TOXAV_ERR_CALL_CONTROL rc;
727 toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
728
729 if (rc != TOXAV_ERR_CALL_CONTROL_OK) {
730 printf("toxav_call_control failed: %d\n", rc);
731 exit(1);
732 }
733 }
734
735 iterate_tox(bootstrap, AliceAV, BobAV);
736 assert(BobCC.state == TOXAV_CALL_STATE_END);
737
738 printf("Success!\n");
739 }
740
741 if (TEST_TRANSFER_A) { /* Audio encoding/decoding and transfer */
742 SNDFILE* af_handle;
743 SF_INFO af_info;
744
745 printf("\nTrying audio enc/dec...\n");
746
747 memset(&AliceCC, 0, sizeof(CallControl));
748 memset(&BobCC, 0, sizeof(CallControl));
749
750 pthread_mutex_init(AliceCC.arb_mutex, NULL);
751 pthread_mutex_init(BobCC.arb_mutex, NULL);
752
753 AliceCC.arb = rb_new(16);
754 BobCC.arb = rb_new(16);
755
756 { /* Call */
757 TOXAV_ERR_CALL rc;
758 toxav_call(AliceAV, 0, 48, 0, &rc);
759
760 if (rc != TOXAV_ERR_CALL_OK) {
761 printf("toxav_call failed: %d\n", rc);
762 exit(1);
763 }
764 }
765
766 while (!BobCC.incoming)
767 iterate_tox(bootstrap, AliceAV, BobAV);
768
769 { /* Answer */
770 TOXAV_ERR_ANSWER rc;
771 toxav_answer(BobAV, 0, 48, 0, &rc);
772
773 if (rc != TOXAV_ERR_ANSWER_OK) {
774 printf("toxav_answer failed: %d\n", rc);
775 exit(1);
776 }
777 }
778
779 while (AliceCC.state == 0)
780 iterate_tox(bootstrap, AliceAV, BobAV);
781
782 /* Open audio file */
783 af_handle = sf_open(af_name, SFM_READ, &af_info);
784 if (af_handle == NULL) {
785 printf("Failed to open the file.\n");
786 exit(1);
787 }
788
789 int16_t PCM[5760];
790
791 time_t start_time = time(NULL);
792 time_t expected_time = af_info.frames / af_info.samplerate + 2;
793
794
795 /* Start decode thread */
796 struct toxav_thread_data data = {
797 .AliceAV = AliceAV,
798 .BobAV = BobAV,
799 .sig = 0
800 };
801
802 pthread_t dect;
803 pthread_create(&dect, NULL, iterate_toxav, &data);
804 pthread_detach(dect);
805
806 int frame_size = (af_info.samplerate * audio_frame_duration / 1000) * af_info.channels;
807
808 struct PaStreamParameters output;
809 output.device = audio_out_dev_idx;
810 output.channelCount = af_info.channels;
811 output.sampleFormat = paInt16;
812 output.suggestedLatency = audio_dev->defaultHighOutputLatency;
813 output.hostApiSpecificStreamInfo = NULL;
814
815 PaError err = Pa_OpenStream(&adout, NULL, &output, af_info.samplerate, frame_size, paNoFlag, NULL, NULL);
816 assert(err == paNoError);
817
818 err = Pa_StartStream(adout);
819 assert(err == paNoError);
820
821 toxav_set_audio_bit_rate(AliceAV, 0, 64, false, NULL);
822
823 /* Start write thread */
824 pthread_t t;
825 pthread_create(&t, NULL, pa_write_thread, &BobCC);
826 pthread_detach(t);
827
828 printf("Sample rate %d\n", af_info.samplerate);
829 while ( start_time + expected_time > time(NULL) ) {
830 uint64_t enc_start_time = current_time_monotonic();
831 int64_t count = sf_read_short(af_handle, PCM, frame_size);
832 if (count > 0) {
833 TOXAV_ERR_SEND_FRAME rc;
834 if (toxav_send_audio_frame(AliceAV, 0, PCM, count/af_info.channels, af_info.channels, af_info.samplerate, &rc) == false) {
835 printf("Error sending frame of size %ld: %d\n", count, rc);
836 }
837 }
838 iterate_tox(bootstrap, AliceAV, BobAV);
839 c_sleep(abs(audio_frame_duration - (current_time_monotonic() - enc_start_time) - 1));
840 }
841
842 printf("Played file in: %lu; stopping stream...\n", time(NULL) - start_time);
843
844 Pa_StopStream(adout);
845 sf_close(af_handle);
846
847 { /* Hangup */
848 TOXAV_ERR_CALL_CONTROL rc;
849 toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
850
851 if (rc != TOXAV_ERR_CALL_CONTROL_OK) {
852 printf("toxav_call_control failed: %d\n", rc);
853 exit(1);
854 }
855 }
856
857 iterate_tox(bootstrap, AliceAV, BobAV);
858 assert(BobCC.state == TOXAV_CALL_STATE_END);
859
860 /* Stop decode thread */
861 data.sig = -1;
862 while(data.sig != 1)
863 pthread_yield();
864
865 pthread_mutex_destroy(AliceCC.arb_mutex);
866 pthread_mutex_destroy(BobCC.arb_mutex);
867
868 void* f = NULL;
869 while(rb_read(AliceCC.arb, &f))
870 free(f);
871
872 while(rb_read(BobCC.arb, &f))
873 free(f);
874
875 printf("Success!");
876 }
877
878 if (TEST_TRANSFER_V) {
879 printf("\nTrying video enc/dec...\n");
880
881 memset(&AliceCC, 0, sizeof(CallControl));
882 memset(&BobCC, 0, sizeof(CallControl));
883
884 { /* Call */
885 TOXAV_ERR_CALL rc;
886 toxav_call(AliceAV, 0, 0, 3000, &rc);
887
888 if (rc != TOXAV_ERR_CALL_OK) {
889 printf("toxav_call failed: %d\n", rc);
890 exit(1);
891 }
892 }
893
894 while (!BobCC.incoming)
895 iterate_tox(bootstrap, AliceAV, BobAV);
896
897 { /* Answer */
898 TOXAV_ERR_ANSWER rc;
899 toxav_answer(BobAV, 0, 0, 500, &rc);
900
901 if (rc != TOXAV_ERR_ANSWER_OK) {
902 printf("toxav_answer failed: %d\n", rc);
903 exit(1);
904 }
905 }
906
907 iterate_tox(bootstrap, AliceAV, BobAV);
908
909 /* Start decode thread */
910 struct toxav_thread_data data = {
911 .AliceAV = AliceAV,
912 .BobAV = BobAV,
913 .sig = 0
914 };
915
916 pthread_t dect;
917 pthread_create(&dect, NULL, iterate_toxav, &data);
918 pthread_detach(dect);
919
920 CvCapture* capture = cvCreateFileCapture(vf_name);
921 if (!capture) {
922 printf("Failed to open video file: %s\n", vf_name);
923 exit(1);
924 }
925
926 toxav_set_video_bit_rate(AliceAV, 0, 5000, false, NULL);
927
928 time_t start_time = time(NULL);
929 while(start_time + 90 > time(NULL)) {
930 IplImage* frame = cvQueryFrame( capture );
931 if (!frame)
932 break;
933
934 send_opencv_img(AliceAV, 0, frame);
935 iterate_tox(bootstrap, AliceAV, BobAV);
936 c_sleep(video_frame_duration);
937 }
938
939 cvReleaseCapture(&capture);
940
941 { /* Hangup */
942 TOXAV_ERR_CALL_CONTROL rc;
943 toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
944
945 if (rc != TOXAV_ERR_CALL_CONTROL_OK) {
946 printf("toxav_call_control failed: %d\n", rc);
947 exit(1);
948 }
949 }
950
951 iterate_tox(bootstrap, AliceAV, BobAV);
952 assert(BobCC.state == TOXAV_CALL_STATE_END);
953
954 /* Stop decode thread */
955 printf("Stopping decode thread\n");
956 data.sig = -1;
957 while(data.sig != 1)
958 pthread_yield();
959
960 printf("Success!");
961 }
962
963
964 Tox* Alice = toxav_get_tox(AliceAV);
965 Tox* Bob = toxav_get_tox(BobAV);
966 toxav_kill(BobAV);
967 toxav_kill(AliceAV);
968 tox_kill(Bob);
969 tox_kill(Alice);
970 tox_kill(bootstrap);
971
972 printf("\nTest successful!\n");
973
974 Pa_Terminate();
975 return 0;
976}
diff --git a/toxav/msi.c b/toxav/msi.c
index 0bd04c56..f8bc8451 100644
--- a/toxav/msi.c
+++ b/toxav/msi.c
@@ -75,37 +75,37 @@ typedef struct {
75 MSIHeaderRequest request; 75 MSIHeaderRequest request;
76 MSIHeaderError error; 76 MSIHeaderError error;
77 MSIHeaderCapabilities capabilities; 77 MSIHeaderCapabilities capabilities;
78 MSIHeaderVFPSZ vfpsz; /* Video frame piece size. NOTE: Value must be in network b-order */ 78 MSIHeaderVFPSZ vfpsz; /* Video frame piece size. NOTE: Value must be in network b-order TODO: get rid of this eventually */
79} MSIMessage; 79} MSIMessage;
80 80
81 81
82void msg_init (MSIMessage *dest, MSIRequest request); 82void msg_init (MSIMessage *dest, MSIRequest request);
83int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length ); 83int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length );
84uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length ); 84uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length );
85int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg ); 85int send_message ( Messenger* m, uint32_t friend_number, const MSIMessage *msg );
86int send_error ( Messenger* m, uint32_t friend_id, MSIError error ); 86int send_error ( Messenger* m, uint32_t friend_number, MSIError error );
87static int invoke_callback(MSICall* call, MSICallbackID cb); 87static int invoke_callback(MSICall* call, MSICallbackID cb);
88static MSICall *get_call ( MSISession *session, uint32_t friend_id ); 88static MSICall *get_call ( MSISession *session, uint32_t friend_number );
89MSICall *new_call ( MSISession *session, uint32_t friend_id ); 89MSICall *new_call ( MSISession *session, uint32_t friend_number );
90void kill_call ( MSICall *call ); 90void kill_call ( MSICall *call );
91void on_peer_status(Messenger *m, uint32_t friend_id, uint8_t status, void *data); 91void on_peer_status(Messenger *m, uint32_t friend_number, uint8_t status, void *data);
92void handle_push ( MSICall *call, const MSIMessage *msg ); 92void handle_push ( MSICall *call, const MSIMessage *msg );
93void handle_pop ( MSICall *call, const MSIMessage *msg ); 93void handle_pop ( MSICall *call, const MSIMessage *msg );
94void handle_msi_packet ( Messenger *m, uint32_t friend_id, const uint8_t *data, uint16_t length, void *object ); 94void handle_msi_packet ( Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object );
95 95
96 96
97/** 97/**
98 * Public functions 98 * Public functions
99 */ 99 */
100void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id) 100void msi_register_callback ( MSISession* session, msi_action_cb* callback, MSICallbackID id)
101{ 101{
102 pthread_mutex_lock(session->mutex); 102 pthread_mutex_lock(session->mutex);
103 session->callbacks[id] = callback; 103 session->callbacks[id] = callback;
104 pthread_mutex_unlock(session->mutex); 104 pthread_mutex_unlock(session->mutex);
105} 105}
106MSISession *msi_new ( Messenger *messenger ) 106MSISession *msi_new ( Messenger *m )
107{ 107{
108 if (messenger == NULL) { 108 if (m == NULL) {
109 LOGGER_ERROR("Could not init session on empty messenger!"); 109 LOGGER_ERROR("Could not init session on empty messenger!");
110 return NULL; 110 return NULL;
111 } 111 }
@@ -123,12 +123,12 @@ MSISession *msi_new ( Messenger *messenger )
123 return NULL; 123 return NULL;
124 } 124 }
125 125
126 retu->messenger = messenger; 126 retu->messenger = m;
127 127
128 m_callback_msi_packet(messenger, handle_msi_packet, retu ); 128 m_callback_msi_packet(m, handle_msi_packet, retu );
129 129
130 /* This is called when remote terminates session */ 130 /* This is called when remote terminates session */
131 m_callback_connectionstatus_internal_av(messenger, on_peer_status, retu); 131 m_callback_connectionstatus_internal_av(m, on_peer_status, retu);
132 132
133 LOGGER_DEBUG("New msi session: %p ", retu); 133 LOGGER_DEBUG("New msi session: %p ", retu);
134 return retu; 134 return retu;
@@ -149,7 +149,7 @@ int msi_kill ( MSISession *session )
149 149
150 MSICall* it = get_call(session, session->calls_head); 150 MSICall* it = get_call(session, session->calls_head);
151 for (; it; it = it->next) { 151 for (; it; it = it->next) {
152 send_message(session->messenger, it->friend_id, &msg); 152 send_message(session->messenger, it->friend_number, &msg);
153 kill_call(it); /* This will eventually free session->calls */ 153 kill_call(it); /* This will eventually free session->calls */
154 } 154 }
155 } 155 }
@@ -161,18 +161,18 @@ int msi_kill ( MSISession *session )
161 free ( session ); 161 free ( session );
162 return 0; 162 return 0;
163} 163}
164int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_t capabilities ) 164int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_number, uint8_t capabilities )
165{ 165{
166 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_id); 166 LOGGER_DEBUG("Session: %p Inviting friend: %u", session, friend_number);
167 167
168 pthread_mutex_lock(session->mutex); 168 pthread_mutex_lock(session->mutex);
169 if (get_call(session, friend_id) != NULL) { 169 if (get_call(session, friend_number) != NULL) {
170 LOGGER_ERROR("Already in a call"); 170 LOGGER_ERROR("Already in a call");
171 pthread_mutex_unlock(session->mutex); 171 pthread_mutex_unlock(session->mutex);
172 return -1; 172 return -1;
173 } 173 }
174 174
175 (*call) = new_call ( session, friend_id ); 175 (*call) = new_call ( session, friend_number );
176 176
177 if ( *call == NULL ) { 177 if ( *call == NULL ) {
178 pthread_mutex_unlock(session->mutex); 178 pthread_mutex_unlock(session->mutex);
@@ -190,7 +190,7 @@ int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_
190 msg.vfpsz.exists = true; 190 msg.vfpsz.exists = true;
191 msg.vfpsz.value = VIDEOFRAME_PIECE_SIZE; 191 msg.vfpsz.value = VIDEOFRAME_PIECE_SIZE;
192 192
193 send_message ( (*call)->session->messenger, (*call)->friend_id, &msg ); 193 send_message ( (*call)->session->messenger, (*call)->friend_number, &msg );
194 194
195 (*call)->state = msi_CallRequesting; 195 (*call)->state = msi_CallRequesting;
196 196
@@ -200,7 +200,7 @@ int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_
200} 200}
201int msi_hangup ( MSICall* call ) 201int msi_hangup ( MSICall* call )
202{ 202{
203 LOGGER_DEBUG("Session: %p Hanging up call with friend: %u", call->session, call->friend_id); 203 LOGGER_DEBUG("Session: %p Hanging up call with friend: %u", call->session, call->friend_number);
204 204
205 MSISession* session = call->session; 205 MSISession* session = call->session;
206 pthread_mutex_lock(session->mutex); 206 pthread_mutex_lock(session->mutex);
@@ -208,7 +208,7 @@ int msi_hangup ( MSICall* call )
208 MSIMessage msg; 208 MSIMessage msg;
209 msg_init(&msg, requ_pop); 209 msg_init(&msg, requ_pop);
210 210
211 send_message ( session->messenger, call->friend_id, &msg ); 211 send_message ( session->messenger, call->friend_number, &msg );
212 212
213 kill_call(call); 213 kill_call(call);
214 pthread_mutex_unlock(session->mutex); 214 pthread_mutex_unlock(session->mutex);
@@ -216,7 +216,7 @@ int msi_hangup ( MSICall* call )
216} 216}
217int msi_answer ( MSICall* call, uint8_t capabilities ) 217int msi_answer ( MSICall* call, uint8_t capabilities )
218{ 218{
219 LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_id); 219 LOGGER_DEBUG("Session: %p Answering call from: %u", call->session, call->friend_number);
220 220
221 MSISession* session = call->session; 221 MSISession* session = call->session;
222 pthread_mutex_lock(session->mutex); 222 pthread_mutex_lock(session->mutex);
@@ -240,7 +240,7 @@ int msi_answer ( MSICall* call, uint8_t capabilities )
240 msg.vfpsz.exists = true; 240 msg.vfpsz.exists = true;
241 msg.vfpsz.value = VIDEOFRAME_PIECE_SIZE; 241 msg.vfpsz.value = VIDEOFRAME_PIECE_SIZE;
242 242
243 send_message ( session->messenger, call->friend_id, &msg ); 243 send_message ( session->messenger, call->friend_number, &msg );
244 244
245 call->state = msi_CallActive; 245 call->state = msi_CallActive;
246 pthread_mutex_unlock(session->mutex); 246 pthread_mutex_unlock(session->mutex);
@@ -249,7 +249,7 @@ int msi_answer ( MSICall* call, uint8_t capabilities )
249} 249}
250int msi_change_capabilities( MSICall* call, uint8_t capabilities ) 250int msi_change_capabilities( MSICall* call, uint8_t capabilities )
251{ 251{
252 LOGGER_DEBUG("Session: %p Trying to change capabilities to friend %u", call->session, call->friend_id); 252 LOGGER_DEBUG("Session: %p Trying to change capabilities to friend %u", call->session, call->friend_number);
253 253
254 MSISession* session = call->session; 254 MSISession* session = call->session;
255 pthread_mutex_lock(session->mutex); 255 pthread_mutex_lock(session->mutex);
@@ -275,7 +275,7 @@ int msi_change_capabilities( MSICall* call, uint8_t capabilities )
275 msg.capabilities.exists = true; 275 msg.capabilities.exists = true;
276 msg.capabilities.value = capabilities; 276 msg.capabilities.value = capabilities;
277 277
278 send_message ( call->session->messenger, call->friend_id, &msg ); 278 send_message ( call->session->messenger, call->friend_number, &msg );
279 279
280 pthread_mutex_unlock(session->mutex); 280 pthread_mutex_unlock(session->mutex);
281 return 0; 281 return 0;
@@ -394,7 +394,7 @@ uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value
394 394
395 return dest + value_len; /* Set to next position ready to be written */ 395 return dest + value_len; /* Set to next position ready to be written */
396} 396}
397int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg ) 397int send_message ( Messenger* m, uint32_t friend_number, const MSIMessage *msg )
398{ 398{
399 /* Parse and send message */ 399 /* Parse and send message */
400 assert(m); 400 assert(m);
@@ -438,19 +438,19 @@ int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg )
438 *it = 0; 438 *it = 0;
439 size ++; 439 size ++;
440 440
441 if ( m_msi_packet(m, friend_id, parsed, size) ) { 441 if ( m_msi_packet(m, friend_number, parsed, size) ) {
442 LOGGER_DEBUG("Sent message"); 442 LOGGER_DEBUG("Sent message");
443 return 0; 443 return 0;
444 } 444 }
445 445
446 return -1; 446 return -1;
447} 447}
448int send_error ( Messenger* m, uint32_t friend_id, MSIError error ) 448int send_error ( Messenger* m, uint32_t friend_number, MSIError error )
449{ 449{
450 /* Send error message */ 450 /* Send error message */
451 assert(m); 451 assert(m);
452 452
453 LOGGER_DEBUG("Sending error: %d to friend: %d", error, friend_id); 453 LOGGER_DEBUG("Sending error: %d to friend: %d", error, friend_number);
454 454
455 MSIMessage msg; 455 MSIMessage msg;
456 msg_init(&msg, requ_pop); 456 msg_init(&msg, requ_pop);
@@ -458,7 +458,7 @@ int send_error ( Messenger* m, uint32_t friend_id, MSIError error )
458 msg.error.exists = true; 458 msg.error.exists = true;
459 msg.error.value = error; 459 msg.error.value = error;
460 460
461 send_message ( m, friend_id, &msg ); 461 send_message ( m, friend_number, &msg );
462 return 0; 462 return 0;
463} 463}
464int invoke_callback(MSICall* call, MSICallbackID cb) 464int invoke_callback(MSICall* call, MSICallbackID cb)
@@ -484,16 +484,16 @@ FAILURE:
484 call->error = msi_EHandle; 484 call->error = msi_EHandle;
485 return -1; 485 return -1;
486} 486}
487static MSICall *get_call ( MSISession *session, uint32_t friend_id ) 487static MSICall *get_call ( MSISession *session, uint32_t friend_number )
488{ 488{
489 assert(session); 489 assert(session);
490 490
491 if (session->calls == NULL || session->calls_tail < friend_id) 491 if (session->calls == NULL || session->calls_tail < friend_number)
492 return NULL; 492 return NULL;
493 493
494 return session->calls[friend_id]; 494 return session->calls[friend_number];
495} 495}
496MSICall *new_call ( MSISession *session, uint32_t friend_id ) 496MSICall *new_call ( MSISession *session, uint32_t friend_number )
497{ 497{
498 assert(session); 498 assert(session);
499 499
@@ -503,20 +503,20 @@ MSICall *new_call ( MSISession *session, uint32_t friend_id )
503 return NULL; 503 return NULL;
504 504
505 rc->session = session; 505 rc->session = session;
506 rc->friend_id = friend_id; 506 rc->friend_number = friend_number;
507 507
508 if (session->calls == NULL) { /* Creating */ 508 if (session->calls == NULL) { /* Creating */
509 session->calls = calloc (sizeof(MSICall*), friend_id + 1); 509 session->calls = calloc (sizeof(MSICall*), friend_number + 1);
510 510
511 if (session->calls == NULL) { 511 if (session->calls == NULL) {
512 free(rc); 512 free(rc);
513 return NULL; 513 return NULL;
514 } 514 }
515 515
516 session->calls_tail = session->calls_head = friend_id; 516 session->calls_tail = session->calls_head = friend_number;
517 517
518 } else if (session->calls_tail < friend_id) { /* Appending */ 518 } else if (session->calls_tail < friend_number) { /* Appending */
519 void* tmp = realloc(session->calls, sizeof(MSICall*) * friend_id + 1); 519 void* tmp = realloc(session->calls, sizeof(MSICall*) * friend_number + 1);
520 520
521 if (tmp == NULL) { 521 if (tmp == NULL) {
522 free(rc); 522 free(rc);
@@ -526,22 +526,22 @@ MSICall *new_call ( MSISession *session, uint32_t friend_id )
526 session->calls = tmp; 526 session->calls = tmp;
527 527
528 /* Set fields in between to null */ 528 /* Set fields in between to null */
529 int32_t i = session->calls_tail; 529 int32_t i = session->calls_tail + 1;
530 for (; i < friend_id; i ++) 530 for (; i < friend_number; i ++)
531 session->calls[i] = NULL; 531 session->calls[i] = NULL;
532 532
533 rc->prev = session->calls[session->calls_tail]; 533 rc->prev = session->calls[session->calls_tail];
534 session->calls[session->calls_tail]->next = rc; 534 session->calls[session->calls_tail]->next = rc;
535 535
536 session->calls_tail = friend_id; 536 session->calls_tail = friend_number;
537 537
538 } else if (session->calls_head > friend_id) { /* Inserting at front */ 538 } else if (session->calls_head > friend_number) { /* Inserting at front */
539 rc->next = session->calls[session->calls_head]; 539 rc->next = session->calls[session->calls_head];
540 session->calls[session->calls_head]->prev = rc; 540 session->calls[session->calls_head]->prev = rc;
541 session->calls_head = friend_id; 541 session->calls_head = friend_number;
542 } 542 }
543 543
544 session->calls[friend_id] = rc; 544 session->calls[friend_number] = rc;
545 return rc; 545 return rc;
546} 546}
547void kill_call ( MSICall *call ) 547void kill_call ( MSICall *call )
@@ -560,16 +560,16 @@ void kill_call ( MSICall *call )
560 if (prev) 560 if (prev)
561 prev->next = next; 561 prev->next = next;
562 else if (next) 562 else if (next)
563 session->calls_head = next->friend_id; 563 session->calls_head = next->friend_number;
564 else goto CLEAR_CONTAINER; 564 else goto CLEAR_CONTAINER;
565 565
566 if (next) 566 if (next)
567 next->prev = prev; 567 next->prev = prev;
568 else if (prev) 568 else if (prev)
569 session->calls_tail = prev->friend_id; 569 session->calls_tail = prev->friend_number;
570 else goto CLEAR_CONTAINER; 570 else goto CLEAR_CONTAINER;
571 571
572 session->calls[call->friend_id] = NULL; 572 session->calls[call->friend_number] = NULL;
573 free(call); 573 free(call);
574 return; 574 return;
575 575
@@ -579,17 +579,17 @@ CLEAR_CONTAINER:
579 free(call); 579 free(call);
580 session->calls = NULL; 580 session->calls = NULL;
581} 581}
582void on_peer_status(Messenger* m, uint32_t friend_id, uint8_t status, void* data) 582void on_peer_status(Messenger* m, uint32_t friend_number, uint8_t status, void* data)
583{ 583{
584 (void)m; 584 (void)m;
585 MSISession *session = data; 585 MSISession *session = data;
586 586
587 switch ( status ) { 587 switch ( status ) {
588 case 0: { /* Friend is now offline */ 588 case 0: { /* Friend is now offline */
589 LOGGER_DEBUG("Friend %d is now offline", friend_id); 589 LOGGER_DEBUG("Friend %d is now offline", friend_number);
590 590
591 pthread_mutex_lock(session->mutex); 591 pthread_mutex_lock(session->mutex);
592 MSICall* call = get_call(session, friend_id); 592 MSICall* call = get_call(session, friend_number);
593 593
594 if (call == NULL) { 594 if (call == NULL) {
595 pthread_mutex_unlock(session->mutex); 595 pthread_mutex_unlock(session->mutex);
@@ -610,9 +610,7 @@ void handle_push ( MSICall *call, const MSIMessage *msg )
610{ 610{
611 assert(call); 611 assert(call);
612 612
613 MSISession* session = call->session; 613 LOGGER_DEBUG("Session: %p Handling 'push' friend: %d", call->session, call->friend_number);
614
615 LOGGER_DEBUG("Session: %p Handling 'push' friend: %d", call->session, call->friend_id);
616 614
617 if (!msg->capabilities.exists) { 615 if (!msg->capabilities.exists) {
618 LOGGER_WARNING("Session: %p Invalid capabilities on 'push'"); 616 LOGGER_WARNING("Session: %p Invalid capabilities on 'push'");
@@ -670,7 +668,7 @@ void handle_push ( MSICall *call, const MSIMessage *msg )
670 msg.vfpsz.exists = true; 668 msg.vfpsz.exists = true;
671 msg.vfpsz.value = VIDEOFRAME_PIECE_SIZE; 669 msg.vfpsz.value = VIDEOFRAME_PIECE_SIZE;
672 670
673 send_message ( call->session->messenger, call->friend_id, &msg ); 671 send_message ( call->session->messenger, call->friend_number, &msg );
674 672
675 /* If peer changed capabilities during re-call they will 673 /* If peer changed capabilities during re-call they will
676 * be handled accordingly during the next step 674 * be handled accordingly during the next step
@@ -708,14 +706,14 @@ void handle_push ( MSICall *call, const MSIMessage *msg )
708 return; 706 return;
709 707
710FAILURE: 708FAILURE:
711 send_error(call->session->messenger, call->friend_id, call->error); 709 send_error(call->session->messenger, call->friend_number, call->error);
712 kill_call(call); 710 kill_call(call);
713} 711}
714void handle_pop ( MSICall *call, const MSIMessage *msg ) 712void handle_pop ( MSICall *call, const MSIMessage *msg )
715{ 713{
716 assert(call); 714 assert(call);
717 715
718 LOGGER_DEBUG("Session: %p Handling 'pop', friend id: %d", call->session, call->friend_id); 716 LOGGER_DEBUG("Session: %p Handling 'pop', friend id: %d", call->session, call->friend_number);
719 717
720 /* callback errors are ignored */ 718 /* callback errors are ignored */
721 719
@@ -751,7 +749,7 @@ void handle_pop ( MSICall *call, const MSIMessage *msg )
751 749
752 kill_call ( call ); 750 kill_call ( call );
753} 751}
754void handle_msi_packet ( Messenger* m, uint32_t friend_id, const uint8_t* data, uint16_t length, void* object ) 752void handle_msi_packet ( Messenger* m, uint32_t friend_number, const uint8_t* data, uint16_t length, void* object )
755{ 753{
756 LOGGER_DEBUG("Got msi message"); 754 LOGGER_DEBUG("Got msi message");
757 755
@@ -760,25 +758,25 @@ void handle_msi_packet ( Messenger* m, uint32_t friend_id, const uint8_t* data,
760 758
761 if ( msg_parse_in ( &msg, data, length ) == -1 ) { 759 if ( msg_parse_in ( &msg, data, length ) == -1 ) {
762 LOGGER_WARNING("Error parsing message"); 760 LOGGER_WARNING("Error parsing message");
763 send_error(m, friend_id, msi_EInvalidMessage); 761 send_error(m, friend_number, msi_EInvalidMessage);
764 return; 762 return;
765 } else { 763 } else {
766 LOGGER_DEBUG("Successfully parsed message"); 764 LOGGER_DEBUG("Successfully parsed message");
767 } 765 }
768 766
769 pthread_mutex_lock(session->mutex); 767 pthread_mutex_lock(session->mutex);
770 MSICall *call = get_call(session, friend_id); 768 MSICall *call = get_call(session, friend_number);
771 769
772 if (call == NULL) { 770 if (call == NULL) {
773 if (msg.request.value != requ_push) { 771 if (msg.request.value != requ_push) {
774 send_error(m, friend_id, msi_EStrayMessage); 772 send_error(m, friend_number, msi_EStrayMessage);
775 pthread_mutex_unlock(session->mutex); 773 pthread_mutex_unlock(session->mutex);
776 return; 774 return;
777 } 775 }
778 776
779 call = new_call(session, friend_id); 777 call = new_call(session, friend_number);
780 if (call == NULL) { 778 if (call == NULL) {
781 send_error(m, friend_id, msi_ESystem); 779 send_error(m, friend_number, msi_ESystem);
782 pthread_mutex_unlock(session->mutex); 780 pthread_mutex_unlock(session->mutex);
783 return; 781 return;
784 } 782 }
diff --git a/toxav/msi.h b/toxav/msi.h
index 457d3148..4836ae89 100644
--- a/toxav/msi.h
+++ b/toxav/msi.h
@@ -89,7 +89,7 @@ typedef struct MSICall_s {
89 uint8_t peer_capabilities; /* Peer capabilities */ 89 uint8_t peer_capabilities; /* Peer capabilities */
90 uint8_t self_capabilities; /* Self capabilities */ 90 uint8_t self_capabilities; /* Self capabilities */
91 uint16_t peer_vfpsz; /* Video frame piece size */ 91 uint16_t peer_vfpsz; /* Video frame piece size */
92 uint32_t friend_id; /* Index of this call in MSISession */ 92 uint32_t friend_number; /* Index of this call in MSISession */
93 MSIError error; /* Last error */ 93 MSIError error; /* Last error */
94 94
95 void* av_call; /* Pointer to av call handler */ 95 void* av_call; /* Pointer to av call handler */
@@ -100,12 +100,11 @@ typedef struct MSICall_s {
100 100
101 101
102/** 102/**
103 * Msi callback type. 'agent' is a pointer to ToxAv.
104 * Expected return on success is 0, if any other number is 103 * Expected return on success is 0, if any other number is
105 * returned the call is considered errored and will be handled 104 * returned the call is considered errored and will be handled
106 * as such which means it will be terminated without any notice. 105 * as such which means it will be terminated without any notice.
107 */ 106 */
108typedef int ( *MSICallbackType ) ( void *agent, MSICall* call); 107typedef int msi_action_cb ( void *av, MSICall* call);
109 108
110/** 109/**
111 * Control session struct. Please do not modify outside msi.c 110 * Control session struct. Please do not modify outside msi.c
@@ -119,43 +118,34 @@ typedef struct MSISession_s {
119 void *av; 118 void *av;
120 Messenger *messenger; 119 Messenger *messenger;
121 120
122 /* The mutex controls async access from control
123 * thread(s) and core thread.
124 */
125 pthread_mutex_t mutex[1]; 121 pthread_mutex_t mutex[1];
126 MSICallbackType callbacks[7]; 122 msi_action_cb* callbacks[7];
127} MSISession; 123} MSISession;
128 124
129/** 125/**
130 * Start the control session. 126 * Start the control session.
131 */ 127 */
132MSISession *msi_new ( Messenger *messenger ); 128MSISession *msi_new ( Messenger *m );
133
134/** 129/**
135 * Terminate control session. NOTE: all calls will be freed 130 * Terminate control session. NOTE: all calls will be freed
136 */ 131 */
137int msi_kill ( MSISession *session ); 132int msi_kill ( MSISession *session );
138
139/** 133/**
140 * Callback setter. 134 * Callback setter.
141 */ 135 */
142void msi_register_callback(MSISession *session, MSICallbackType callback, MSICallbackID id); 136void msi_register_callback(MSISession *session, msi_action_cb* callback, MSICallbackID id);
143
144/** 137/**
145 * Send invite request to friend_id. 138 * Send invite request to friend_number.
146 */ 139 */
147int msi_invite ( MSISession* session, MSICall** call, uint32_t friend_id, uint8_t capabilities ); 140int msi_invite ( MSISession* session, MSICall** call, uint32_t friend_number, uint8_t capabilities );
148
149/** 141/**
150 * Hangup call. NOTE: 'call' will be freed 142 * Hangup call. NOTE: 'call' will be freed
151 */ 143 */
152int msi_hangup ( MSICall* call ); 144int msi_hangup ( MSICall* call );
153
154/** 145/**
155 * Answer call request. 146 * Answer call request.
156 */ 147 */
157int msi_answer ( MSICall* call, uint8_t capabilities ); 148int msi_answer ( MSICall* call, uint8_t capabilities );
158
159/** 149/**
160 * Change capabilities of the call. 150 * Change capabilities of the call.
161 */ 151 */
diff --git a/toxav/rtp.c b/toxav/rtp.c
index 6c603f79..2219805b 100644
--- a/toxav/rtp.c
+++ b/toxav/rtp.c
@@ -78,11 +78,11 @@ int handle_rtcp_packet ( Messenger *m, uint32_t friendnumber, const uint8_t *dat
78void send_rtcp_report ( RTCPSession* session, Messenger* m, uint32_t friendnumber ); 78void send_rtcp_report ( RTCPSession* session, Messenger* m, uint32_t friendnumber );
79 79
80 80
81RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num, void* cs, int (*mcb) (void*, RTPMessage*) ) 81RTPSession *rtp_new ( int payload_type, Messenger *m, int friend_num, void* cs, int (*mcb) (void*, RTPMessage*) )
82{ 82{
83 assert(mcb); 83 assert(mcb);
84 assert(cs); 84 assert(cs);
85 assert(messenger); 85 assert(m);
86 86
87 RTPSession *retu = calloc(1, sizeof(RTPSession)); 87 RTPSession *retu = calloc(1, sizeof(RTPSession));
88 88
@@ -95,8 +95,8 @@ RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num, vo
95 retu->ssrc = random_int(); 95 retu->ssrc = random_int();
96 retu->payload_type = payload_type % 128; 96 retu->payload_type = payload_type % 128;
97 97
98 retu->m = messenger; 98 retu->m = m;
99 retu->friend_id = friend_num; 99 retu->friend_number = friend_num;
100 100
101 if ( !(retu->csrc = calloc(1, sizeof(uint32_t))) ) { 101 if ( !(retu->csrc = calloc(1, sizeof(uint32_t))) ) {
102 LOGGER_WARNING("Alloc failed! Program might misbehave!"); 102 LOGGER_WARNING("Alloc failed! Program might misbehave!");
@@ -161,7 +161,7 @@ int rtp_do(RTPSession *session)
161 return rtp_StateNormal; 161 return rtp_StateNormal;
162 162
163 if (current_time_monotonic() - session->rtcp_session->last_sent_report_ts >= RTCP_REPORT_INTERVAL_MS) { 163 if (current_time_monotonic() - session->rtcp_session->last_sent_report_ts >= RTCP_REPORT_INTERVAL_MS) {
164 send_rtcp_report(session->rtcp_session, session->m, session->friend_id); 164 send_rtcp_report(session->rtcp_session, session->m, session->friend_number);
165 } 165 }
166 166
167 if (rb_full(session->rtcp_session->pl_stats)) { 167 if (rb_full(session->rtcp_session->pl_stats)) {
@@ -209,15 +209,15 @@ int rtp_start_receiving(RTPSession* session)
209 if (session == NULL) 209 if (session == NULL)
210 return -1; 210 return -1;
211 211
212 if (m_callback_rtp_packet(session->m, session->friend_id, session->prefix, 212 if (m_callback_rtp_packet(session->m, session->friend_number, session->prefix,
213 handle_rtp_packet, session) == -1) { 213 handle_rtp_packet, session) == -1) {
214 LOGGER_WARNING("Failed to register rtp receive handler"); 214 LOGGER_WARNING("Failed to register rtp receive handler");
215 return -1; 215 return -1;
216 } 216 }
217 if (m_callback_rtp_packet(session->m, session->friend_id, session->rtcp_session->prefix, 217 if (m_callback_rtp_packet(session->m, session->friend_number, session->rtcp_session->prefix,
218 handle_rtcp_packet, session->rtcp_session) == -1) { 218 handle_rtcp_packet, session->rtcp_session) == -1) {
219 LOGGER_WARNING("Failed to register rtcp receive handler"); 219 LOGGER_WARNING("Failed to register rtcp receive handler");
220 m_callback_rtp_packet(session->m, session->friend_id, session->prefix, NULL, NULL); 220 m_callback_rtp_packet(session->m, session->friend_number, session->prefix, NULL, NULL);
221 return -1; 221 return -1;
222 } 222 }
223 223
@@ -228,8 +228,8 @@ int rtp_stop_receiving(RTPSession* session)
228 if (session == NULL) 228 if (session == NULL)
229 return -1; 229 return -1;
230 230
231 m_callback_rtp_packet(session->m, session->friend_id, session->prefix, NULL, NULL); 231 m_callback_rtp_packet(session->m, session->friend_number, session->prefix, NULL, NULL);
232 m_callback_rtp_packet(session->m, session->friend_id, session->rtcp_session->prefix, NULL, NULL); /* RTCP */ 232 m_callback_rtp_packet(session->m, session->friend_number, session->rtcp_session->prefix, NULL, NULL); /* RTCP */
233 233
234 return 0; 234 return 0;
235} 235}
@@ -243,7 +243,8 @@ int rtp_send_data ( RTPSession *session, const uint8_t *data, uint16_t length, b
243 uint8_t parsed[MAX_RTP_SIZE]; 243 uint8_t parsed[MAX_RTP_SIZE];
244 uint8_t *it; 244 uint8_t *it;
245 245
246 RTPHeader header[1]; 246 RTPHeader header[1] = {0};
247
247 ADD_FLAG_VERSION ( header, session->version ); 248 ADD_FLAG_VERSION ( header, session->version );
248 ADD_FLAG_PADDING ( header, session->padding ); 249 ADD_FLAG_PADDING ( header, session->padding );
249 ADD_FLAG_EXTENSION ( header, session->extension ); 250 ADD_FLAG_EXTENSION ( header, session->extension );
@@ -278,12 +279,11 @@ int rtp_send_data ( RTPSession *session, const uint8_t *data, uint16_t length, b
278 279
279 memcpy(it, data, length); 280 memcpy(it, data, length);
280 281
281 if ( -1 == send_custom_lossy_packet(session->m, session->friend_id, parsed, parsed_len) ) { 282 if ( -1 == send_custom_lossy_packet(session->m, session->friend_number, parsed, parsed_len) ) {
282 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno)); 283 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno));
283 return -1; 284 return -1;
284 } 285 }
285 286
286 /* Set sequ number */
287 session->sequnum = session->sequnum >= MAX_SEQU_NUM ? 0 : session->sequnum + 1; 287 session->sequnum = session->sequnum >= MAX_SEQU_NUM ? 0 : session->sequnum + 1;
288 return 0; 288 return 0;
289} 289}
@@ -300,7 +300,6 @@ void rtp_free_msg ( RTPMessage *msg )
300 300
301 301
302 302
303
304RTPHeader *parse_header_in ( const uint8_t *payload, int length ) 303RTPHeader *parse_header_in ( const uint8_t *payload, int length )
305{ 304{
306 if ( !payload || !length ) { 305 if ( !payload || !length ) {
@@ -322,12 +321,7 @@ RTPHeader *parse_header_in ( const uint8_t *payload, int length )
322 321
323 retu->flags = *it; 322 retu->flags = *it;
324 ++it; 323 ++it;
325 324
326 /* This indicates if the first 2 bits are valid.
327 * Now it may happen that this is out of order but
328 * it cuts down chances of parsing some invalid value
329 */
330
331 if ( GET_FLAG_VERSION(retu) != RTP_VERSION ) { 325 if ( GET_FLAG_VERSION(retu) != RTP_VERSION ) {
332 /* Deallocate */ 326 /* Deallocate */
333 LOGGER_WARNING("Invalid version!"); 327 LOGGER_WARNING("Invalid version!");
@@ -335,15 +329,10 @@ RTPHeader *parse_header_in ( const uint8_t *payload, int length )
335 return NULL; 329 return NULL;
336 } 330 }
337 331
338 /*
339 * Added a check for the size of the header little sooner so
340 * I don't need to parse the other stuff if it's bad
341 */
342 uint8_t cc = GET_FLAG_CSRCC ( retu ); 332 uint8_t cc = GET_FLAG_CSRCC ( retu );
343 int total = 12 /* Minimum header len */ + ( cc * 4 ); 333 int total = 12 /* Minimum header len */ + ( cc * 4 );
344 334
345 if ( length < total ) { 335 if ( length < total ) {
346 /* Deallocate */
347 LOGGER_WARNING("Length invalid!"); 336 LOGGER_WARNING("Length invalid!");
348 free(retu); 337 free(retu);
349 return NULL; 338 return NULL;
@@ -355,9 +344,10 @@ RTPHeader *parse_header_in ( const uint8_t *payload, int length )
355 344
356 345
357 memcpy(&retu->timestamp, it, sizeof(retu->timestamp)); 346 memcpy(&retu->timestamp, it, sizeof(retu->timestamp));
358 retu->timestamp = ntohl(retu->timestamp);
359 it += 4; 347 it += 4;
360 memcpy(&retu->ssrc, it, sizeof(retu->ssrc)); 348 memcpy(&retu->ssrc, it, sizeof(retu->ssrc));
349
350 retu->timestamp = ntohl(retu->timestamp);
361 retu->ssrc = ntohl(retu->ssrc); 351 retu->ssrc = ntohl(retu->ssrc);
362 352
363 uint8_t x; 353 uint8_t x;
@@ -380,34 +370,31 @@ RTPExtHeader *parse_ext_header_in ( const uint8_t *payload, uint16_t length )
380 return NULL; 370 return NULL;
381 } 371 }
382 372
383 uint16_t ext_length; 373 memcpy(&retu->length, it, sizeof(retu->length));
384 memcpy(&ext_length, it, sizeof(ext_length)); 374 retu->length = ntohs(retu->length);
385 ext_length = ntohs(ext_length);
386 it += 2; 375 it += 2;
387 376
388 377 if ( length < ( retu->length * sizeof(uint32_t) ) ) {
389 if ( length < ( ext_length * sizeof(uint32_t) ) ) {
390 LOGGER_WARNING("Length invalid!"); 378 LOGGER_WARNING("Length invalid!");
391 free(retu); 379 free(retu);
392 return NULL; 380 return NULL;
393 } 381 }
394 382
395 retu->length = ext_length;
396 memcpy(&retu->type, it, sizeof(retu->type)); 383 memcpy(&retu->type, it, sizeof(retu->type));
397 retu->type = ntohs(retu->type); 384 retu->type = ntohs(retu->type);
385
398 it += 2; 386 it += 2;
399 387
400 if ( !(retu->table = calloc(ext_length, sizeof (uint32_t))) ) { 388 if ( !(retu->table = calloc(retu->length, sizeof (uint32_t))) ) {
401 LOGGER_WARNING("Alloc failed! Program might misbehave!"); 389 LOGGER_WARNING("Alloc failed! Program might misbehave!");
402 free(retu); 390 free(retu);
403 return NULL; 391 return NULL;
404 } 392 }
405 393
406 uint16_t x; 394 uint16_t x;
407 395 for ( x = 0; x < retu->length; x++ ) {
408 for ( x = 0; x < ext_length; x++ ) {
409 it += 4; 396 it += 4;
410 memcpy(&(retu->table[x]), it, sizeof(retu->table[x])); 397 memcpy(retu->table + x, it, sizeof(*retu->table));
411 retu->table[x] = ntohl(retu->table[x]); 398 retu->table[x] = ntohl(retu->table[x]);
412 } 399 }
413 400
@@ -433,7 +420,6 @@ uint8_t *parse_header_out ( const RTPHeader *header, uint8_t *payload )
433 *it = header->marker_payloadt; 420 *it = header->marker_payloadt;
434 ++it; 421 ++it;
435 422
436
437 timestamp = htonl(header->timestamp); 423 timestamp = htonl(header->timestamp);
438 memcpy(it, &timestamp, sizeof(timestamp)); 424 memcpy(it, &timestamp, sizeof(timestamp));
439 it += 4; 425 it += 4;
@@ -579,7 +565,6 @@ int handle_rtcp_packet ( Messenger* m, uint32_t friendnumber, const uint8_t* dat
579 report->received_packets = ntohl(report->received_packets); 565 report->received_packets = ntohl(report->received_packets);
580 report->expected_packets = ntohl(report->expected_packets); 566 report->expected_packets = ntohl(report->expected_packets);
581 567
582 /* Invalid values */
583 if (report->expected_packets == 0 || report->received_packets > report->expected_packets) { 568 if (report->expected_packets == 0 || report->received_packets > report->expected_packets) {
584 LOGGER_WARNING("Malformed rtcp report! %d %d", report->expected_packets, report->received_packets); 569 LOGGER_WARNING("Malformed rtcp report! %d %d", report->expected_packets, report->received_packets);
585 free(report); 570 free(report);
diff --git a/toxav/rtp.h b/toxav/rtp.h
index c973d262..a158d724 100644
--- a/toxav/rtp.h
+++ b/toxav/rtp.h
@@ -113,10 +113,9 @@ typedef struct {
113 uint8_t prefix; 113 uint8_t prefix;
114 114
115 Messenger *m; 115 Messenger *m;
116 int friend_id; 116 int friend_number;
117 struct RTCPSession_s *rtcp_session; 117 struct RTCPSession_s *rtcp_session;
118 118
119
120 void *cs; 119 void *cs;
121 int (*mcb) (void*, RTPMessage* msg); 120 int (*mcb) (void*, RTPMessage* msg);
122 121
@@ -125,33 +124,27 @@ typedef struct {
125/** 124/**
126 * Must be called before calling any other rtp function. 125 * Must be called before calling any other rtp function.
127 */ 126 */
128RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num, void* cs, int (*mcb) (void*, RTPMessage*) ); 127RTPSession *rtp_new ( int payload_type, Messenger *m, int friend_num, void* cs, int (*mcb) (void*, RTPMessage*) );
129
130/** 128/**
131 * Terminate the session. 129 * Terminate the session.
132 */ 130 */
133void rtp_kill ( RTPSession* session ); 131void rtp_kill ( RTPSession* session );
134
135/** 132/**
136 * Do periodical rtp work. 133 * Do periodical rtp work.
137 */ 134 */
138int rtp_do(RTPSession *session); 135int rtp_do(RTPSession *session);
139
140/** 136/**
141 * By default rtp is in receiving state 137 * By default rtp is in receiving state
142 */ 138 */
143int rtp_start_receiving (RTPSession *session); 139int rtp_start_receiving (RTPSession *session);
144
145/** 140/**
146 * Pause rtp receiving mode. 141 * Pause rtp receiving mode.
147 */ 142 */
148int rtp_stop_receiving (RTPSession *session); 143int rtp_stop_receiving (RTPSession *session);
149
150/** 144/**
151 * Sends msg to RTPSession::dest 145 * Sends msg to RTPSession::dest
152 */ 146 */
153int rtp_send_data ( RTPSession* session, const uint8_t* data, uint16_t length, bool dummy ); 147int rtp_send_data ( RTPSession* session, const uint8_t* data, uint16_t length, bool dummy );
154
155/** 148/**
156 * Dealloc msg. 149 * Dealloc msg.
157 */ 150 */
diff --git a/toxav/toxav.c b/toxav/toxav.c
index 8d47f5cd..25a2857c 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -58,10 +58,10 @@ typedef struct ToxAVCall_s {
58 58
59 bool active; 59 bool active;
60 MSICall* msi_call; 60 MSICall* msi_call;
61 uint32_t friend_id; 61 uint32_t friend_number;
62 62
63 uint32_t audio_bit_rate; /* Sending audio bitrate */ 63 uint32_t audio_bit_rate; /* Sending audio bit rate */
64 uint32_t video_bit_rate; /* Sending video bitrate */ 64 uint32_t video_bit_rate; /* Sending video bit rate */
65 65
66 ToxAvBitrateAdapter aba; 66 ToxAvBitrateAdapter aba;
67 ToxAvBitrateAdapter vba; 67 ToxAvBitrateAdapter vba;
@@ -93,8 +93,8 @@ struct toxAV {
93 PAIR(toxav_call_state_cb *, void *) scb; /* Call state callback */ 93 PAIR(toxav_call_state_cb *, void *) scb; /* Call state callback */
94 PAIR(toxav_receive_audio_frame_cb *, void *) acb; /* Audio frame receive callback */ 94 PAIR(toxav_receive_audio_frame_cb *, void *) acb; /* Audio frame receive callback */
95 PAIR(toxav_receive_video_frame_cb *, void *) vcb; /* Video frame receive callback */ 95 PAIR(toxav_receive_video_frame_cb *, void *) vcb; /* Video frame receive callback */
96 PAIR(toxav_audio_bitrate_control_cb *, void *) abcb; /* Audio bitrate control callback */ 96 PAIR(toxav_audio_bit_rate_status_cb *, void *) abcb; /* Audio bit rate control callback */
97 PAIR(toxav_video_bitrate_control_cb *, void *) vbcb; /* Video bitrate control callback */ 97 PAIR(toxav_video_bit_rate_status_cb *, void *) vbcb; /* Video bit rate control callback */
98 98
99 /** Decode time measures */ 99 /** Decode time measures */
100 int32_t dmssc; /** Measure count */ 100 int32_t dmssc; /** Measure count */
@@ -111,8 +111,8 @@ int callback_end(void* toxav_inst, MSICall* call);
111int callback_error(void* toxav_inst, MSICall* call); 111int callback_error(void* toxav_inst, MSICall* call);
112int callback_capabilites(void* toxav_inst, MSICall* call); 112int callback_capabilites(void* toxav_inst, MSICall* call);
113 113
114bool audio_bitrate_invalid(uint32_t bitrate); 114bool audio_bit_rate_invalid(uint32_t bit_rate);
115bool video_bitrate_invalid(uint32_t bitrate); 115bool video_bit_rate_invalid(uint32_t bit_rate);
116void invoke_call_state(ToxAV* av, uint32_t friend_number, uint32_t state); 116void invoke_call_state(ToxAV* av, uint32_t friend_number, uint32_t state);
117ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error); 117ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error);
118ToxAVCall* call_get(ToxAV* av, uint32_t friend_number); 118ToxAVCall* call_get(ToxAV* av, uint32_t friend_number);
@@ -129,12 +129,12 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error)
129 129
130 if (tox == NULL) { 130 if (tox == NULL) {
131 rc = TOXAV_ERR_NEW_NULL; 131 rc = TOXAV_ERR_NEW_NULL;
132 goto FAILURE; 132 goto END;
133 } 133 }
134 134
135 if (((Messenger*)tox)->msi_packet) { 135 if (((Messenger*)tox)->msi_packet) {
136 rc = TOXAV_ERR_NEW_MULTIPLE; 136 rc = TOXAV_ERR_NEW_MULTIPLE;
137 goto FAILURE; 137 goto END;
138 } 138 }
139 139
140 av = calloc (sizeof(ToxAV), 1); 140 av = calloc (sizeof(ToxAV), 1);
@@ -142,13 +142,13 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error)
142 if (av == NULL) { 142 if (av == NULL) {
143 LOGGER_WARNING("Allocation failed!"); 143 LOGGER_WARNING("Allocation failed!");
144 rc = TOXAV_ERR_NEW_MALLOC; 144 rc = TOXAV_ERR_NEW_MALLOC;
145 goto FAILURE; 145 goto END;
146 } 146 }
147 147
148 if (create_recursive_mutex(av->mutex) != 0) { 148 if (create_recursive_mutex(av->mutex) != 0) {
149 LOGGER_WARNING("Mutex creation failed!"); 149 LOGGER_WARNING("Mutex creation failed!");
150 rc = TOXAV_ERR_NEW_MALLOC; 150 rc = TOXAV_ERR_NEW_MALLOC;
151 goto FAILURE; 151 goto END;
152 } 152 }
153 153
154 av->m = (Messenger *)tox; 154 av->m = (Messenger *)tox;
@@ -157,7 +157,7 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error)
157 if (av->msi == NULL) { 157 if (av->msi == NULL) {
158 pthread_mutex_destroy(av->mutex); 158 pthread_mutex_destroy(av->mutex);
159 rc = TOXAV_ERR_NEW_MALLOC; 159 rc = TOXAV_ERR_NEW_MALLOC;
160 goto FAILURE; 160 goto END;
161 } 161 }
162 162
163 av->interval = 200; 163 av->interval = 200;
@@ -170,19 +170,16 @@ ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error)
170 msi_register_callback(av->msi, callback_error, msi_OnPeerTimeout); 170 msi_register_callback(av->msi, callback_error, msi_OnPeerTimeout);
171 msi_register_callback(av->msi, callback_capabilites, msi_OnCapabilities); 171 msi_register_callback(av->msi, callback_capabilites, msi_OnCapabilities);
172 172
173 173END:
174 if (error)
175 *error = rc;
176
177 return av;
178
179FAILURE:
180 if (error) 174 if (error)
181 *error = rc; 175 *error = rc;
182 176
183 free(av); 177 if (rc != TOXAV_ERR_NEW_OK) {
178 free(av);
179 av = NULL;
180 }
184 181
185 return NULL; 182 return av;
186} 183}
187 184
188void toxav_kill(ToxAV* av) 185void toxav_kill(ToxAV* av)
@@ -249,14 +246,14 @@ void toxav_iterate(ToxAV* av)
249 246
250 /* Notify app */ 247 /* Notify app */
251 if (av->abcb.first) 248 if (av->abcb.first)
252 av->abcb.first (av, i->friend_id, false, bb, av->abcb.second); 249 av->abcb.first (av, i->friend_number, false, bb, av->abcb.second);
253 } else if (i->aba.active && i->aba.end_time < current_time_monotonic()) { 250 } else if (i->aba.active && i->aba.end_time < current_time_monotonic()) {
254 251
255 i->audio_bit_rate = i->aba.bit_rate; 252 i->audio_bit_rate = i->aba.bit_rate;
256 253
257 /* Notify user about the new bitrate */ 254 /* Notify user about the new bit rate */
258 if (av->abcb.first) 255 if (av->abcb.first)
259 av->abcb.first (av, i->friend_id, true, i->aba.bit_rate, av->abcb.second); 256 av->abcb.first (av, i->friend_number, true, i->aba.bit_rate, av->abcb.second);
260 257
261 /* Stop sending dummy packets */ 258 /* Stop sending dummy packets */
262 memset(&i->aba, 0, sizeof(i->aba)); 259 memset(&i->aba, 0, sizeof(i->aba));
@@ -275,15 +272,15 @@ void toxav_iterate(ToxAV* av)
275 272
276 /* Notify app */ 273 /* Notify app */
277 if (av->vbcb.first) 274 if (av->vbcb.first)
278 av->vbcb.first (av, i->friend_id, false, bb, av->vbcb.second); 275 av->vbcb.first (av, i->friend_number, false, bb, av->vbcb.second);
279 276
280 } else if (i->vba.active && i->vba.end_time < current_time_monotonic()) { 277 } else if (i->vba.active && i->vba.end_time < current_time_monotonic()) {
281 278
282 i->video_bit_rate = i->vba.bit_rate; 279 i->video_bit_rate = i->vba.bit_rate;
283 280
284 /* Notify user about the new bitrate */ 281 /* Notify user about the new bit rate */
285 if (av->vbcb.first) 282 if (av->vbcb.first)
286 av->vbcb.first (av, i->friend_id, true, i->vba.bit_rate, av->vbcb.second); 283 av->vbcb.first (av, i->friend_number, true, i->vba.bit_rate, av->vbcb.second);
287 284
288 /* Stop sending dummy packets */ 285 /* Stop sending dummy packets */
289 memset(&i->vba, 0, sizeof(i->vba)); 286 memset(&i->vba, 0, sizeof(i->vba));
@@ -297,7 +294,7 @@ void toxav_iterate(ToxAV* av)
297 i->msi_call->peer_capabilities & msi_CapSVideo) 294 i->msi_call->peer_capabilities & msi_CapSVideo)
298 rc = MIN(i->video.second->lcfd, rc); 295 rc = MIN(i->video.second->lcfd, rc);
299 296
300 uint32_t fid = i->friend_id; 297 uint32_t fid = i->friend_number;
301 298
302 pthread_mutex_unlock(i->mutex); 299 pthread_mutex_unlock(i->mutex);
303 pthread_mutex_lock(av->mutex); 300 pthread_mutex_lock(av->mutex);
@@ -356,7 +353,7 @@ void toxav_callback_call(ToxAV* av, toxav_call_cb* function, void* user_data)
356 av->ccb.first = function; 353 av->ccb.first = function;
357 av->ccb.second = user_data; 354 av->ccb.second = user_data;
358 pthread_mutex_unlock(av->mutex); 355 pthread_mutex_unlock(av->mutex);
359}/** Required for monitoring */ 356}
360 357
361bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_ANSWER* error) 358bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_ANSWER* error)
362{ 359{
@@ -368,8 +365,8 @@ bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, ui
368 goto END; 365 goto END;
369 } 366 }
370 367
371 if ((audio_bit_rate && audio_bitrate_invalid(audio_bit_rate)) 368 if ((audio_bit_rate && audio_bit_rate_invalid(audio_bit_rate))
372 ||(video_bit_rate && video_bitrate_invalid(video_bit_rate)) 369 ||(video_bit_rate && video_bit_rate_invalid(video_bit_rate))
373 ) { 370 ) {
374 rc = TOXAV_ERR_CALL_INVALID_BIT_RATE; 371 rc = TOXAV_ERR_CALL_INVALID_BIT_RATE;
375 goto END; 372 goto END;
@@ -561,7 +558,7 @@ END:
561 return rc == TOXAV_ERR_CALL_CONTROL_OK; 558 return rc == TOXAV_ERR_CALL_CONTROL_OK;
562} 559}
563 560
564void toxav_callback_video_bitrate_control(ToxAV* av, toxav_video_bitrate_control_cb* function, void* user_data) 561void toxav_callback_video_bit_rate_status(ToxAV* av, toxav_video_bit_rate_status_cb* function, void* user_data)
565{ 562{
566 pthread_mutex_lock(av->mutex); 563 pthread_mutex_lock(av->mutex);
567 av->vbcb.first = function; 564 av->vbcb.first = function;
@@ -579,7 +576,7 @@ bool toxav_set_video_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t video_
579 goto END; 576 goto END;
580 } 577 }
581 578
582 if (video_bitrate_invalid(video_bit_rate)) { 579 if (video_bit_rate_invalid(video_bit_rate)) {
583 rc = TOXAV_ERR_BIT_RATE_INVALID; 580 rc = TOXAV_ERR_BIT_RATE_INVALID;
584 goto END; 581 goto END;
585 } 582 }
@@ -605,7 +602,7 @@ bool toxav_set_video_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t video_
605 call->video_bit_rate = video_bit_rate; 602 call->video_bit_rate = video_bit_rate;
606 603
607 if (!force && av->vbcb.first) 604 if (!force && av->vbcb.first)
608 av->vbcb.first (av, call->friend_id, true, video_bit_rate, av->vbcb.second); 605 av->vbcb.first (av, call->friend_number, true, video_bit_rate, av->vbcb.second);
609 } 606 }
610 607
611 pthread_mutex_unlock(call->mutex); 608 pthread_mutex_unlock(call->mutex);
@@ -618,7 +615,7 @@ END:
618 return rc == TOXAV_ERR_BIT_RATE_OK; 615 return rc == TOXAV_ERR_BIT_RATE_OK;
619} 616}
620 617
621void toxav_callback_audio_bitrate_control(ToxAV* av, toxav_audio_bitrate_control_cb* function, void* user_data) 618void toxav_callback_audio_bit_rate_status(ToxAV* av, toxav_audio_bit_rate_status_cb* function, void* user_data)
622{ 619{
623 pthread_mutex_lock(av->mutex); 620 pthread_mutex_lock(av->mutex);
624 av->abcb.first = function; 621 av->abcb.first = function;
@@ -636,7 +633,7 @@ bool toxav_set_audio_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t audio_
636 goto END; 633 goto END;
637 } 634 }
638 635
639 if (audio_bitrate_invalid(audio_bit_rate)) { 636 if (audio_bit_rate_invalid(audio_bit_rate)) {
640 rc = TOXAV_ERR_BIT_RATE_INVALID; 637 rc = TOXAV_ERR_BIT_RATE_INVALID;
641 goto END; 638 goto END;
642 } 639 }
@@ -662,7 +659,7 @@ bool toxav_set_audio_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t audio_
662 call->audio_bit_rate = audio_bit_rate; 659 call->audio_bit_rate = audio_bit_rate;
663 660
664 if (!force && av->abcb.first) 661 if (!force && av->abcb.first)
665 av->abcb.first (av, call->friend_id, true, audio_bit_rate, av->abcb.second); 662 av->abcb.first (av, call->friend_number, true, audio_bit_rate, av->abcb.second);
666 } 663 }
667 664
668 pthread_mutex_unlock(call->mutex); 665 pthread_mutex_unlock(call->mutex);
@@ -897,11 +894,11 @@ bool toxav_send_audio_frame(ToxAV* av, uint32_t friend_number, const int16_t* pc
897 } 894 }
898 895
899 896
900 /* For bitrate measurement; send dummy packet */ 897 /* For bit rate measurement; send dummy packet */
901 if (ba_shoud_send_dummy(&call->aba)) { 898 if (ba_shoud_send_dummy(&call->aba)) {
902 sampling_rate = ntohl(sampling_rate); 899 sampling_rate = ntohl(sampling_rate);
903 if (ac_reconfigure_test_encoder(call->audio.second, call->audio_bit_rate * 1000, sampling_rate, channels) != 0) { 900 if (ac_reconfigure_test_encoder(call->audio.second, call->audio_bit_rate * 1000, sampling_rate, channels) != 0) {
904 /* FIXME should the bitrate changing fail here? */ 901 /* FIXME should the bit rate changing fail here? */
905 pthread_mutex_unlock(call->mutex_audio); 902 pthread_mutex_unlock(call->mutex_audio);
906 rc = TOXAV_ERR_SEND_FRAME_INVALID; 903 rc = TOXAV_ERR_SEND_FRAME_INVALID;
907 goto END; 904 goto END;
@@ -966,7 +963,7 @@ int callback_invite(void* toxav_inst, MSICall* call)
966 ToxAV* toxav = toxav_inst; 963 ToxAV* toxav = toxav_inst;
967 pthread_mutex_lock(toxav->mutex); 964 pthread_mutex_lock(toxav->mutex);
968 965
969 ToxAVCall* av_call = call_new(toxav, call->friend_id, NULL); 966 ToxAVCall* av_call = call_new(toxav, call->friend_number, NULL);
970 if (av_call == NULL) { 967 if (av_call == NULL) {
971 LOGGER_WARNING("Failed to initialize call..."); 968 LOGGER_WARNING("Failed to initialize call...");
972 pthread_mutex_unlock(toxav->mutex); 969 pthread_mutex_unlock(toxav->mutex);
@@ -977,7 +974,7 @@ int callback_invite(void* toxav_inst, MSICall* call)
977 av_call->msi_call = call; 974 av_call->msi_call = call;
978 975
979 if (toxav->ccb.first) 976 if (toxav->ccb.first)
980 toxav->ccb.first(toxav, call->friend_id, call->peer_capabilities & msi_CapSAudio, 977 toxav->ccb.first(toxav, call->friend_number, call->peer_capabilities & msi_CapSAudio,
981 call->peer_capabilities & msi_CapSVideo, toxav->ccb.second); 978 call->peer_capabilities & msi_CapSVideo, toxav->ccb.second);
982 979
983 pthread_mutex_unlock(toxav->mutex); 980 pthread_mutex_unlock(toxav->mutex);
@@ -989,7 +986,7 @@ int callback_start(void* toxav_inst, MSICall* call)
989 ToxAV* toxav = toxav_inst; 986 ToxAV* toxav = toxav_inst;
990 pthread_mutex_lock(toxav->mutex); 987 pthread_mutex_lock(toxav->mutex);
991 988
992 ToxAVCall* av_call = call_get(toxav, call->friend_id); 989 ToxAVCall* av_call = call_get(toxav, call->friend_number);
993 990
994 if (av_call == NULL) { 991 if (av_call == NULL) {
995 /* Should this ever happen? */ 992 /* Should this ever happen? */
@@ -1004,7 +1001,7 @@ int callback_start(void* toxav_inst, MSICall* call)
1004 return -1; 1001 return -1;
1005 } 1002 }
1006 1003
1007 invoke_call_state(toxav, call->friend_id, call->peer_capabilities); 1004 invoke_call_state(toxav, call->friend_number, call->peer_capabilities);
1008 1005
1009 pthread_mutex_unlock(toxav->mutex); 1006 pthread_mutex_unlock(toxav->mutex);
1010 return 0; 1007 return 0;
@@ -1015,7 +1012,7 @@ int callback_end(void* toxav_inst, MSICall* call)
1015 ToxAV* toxav = toxav_inst; 1012 ToxAV* toxav = toxav_inst;
1016 pthread_mutex_lock(toxav->mutex); 1013 pthread_mutex_lock(toxav->mutex);
1017 1014
1018 invoke_call_state(toxav, call->friend_id, TOXAV_CALL_STATE_END); 1015 invoke_call_state(toxav, call->friend_number, TOXAV_CALL_STATE_END);
1019 1016
1020 call_kill_transmission(call->av_call); 1017 call_kill_transmission(call->av_call);
1021 call_remove(call->av_call); 1018 call_remove(call->av_call);
@@ -1029,7 +1026,7 @@ int callback_error(void* toxav_inst, MSICall* call)
1029 ToxAV* toxav = toxav_inst; 1026 ToxAV* toxav = toxav_inst;
1030 pthread_mutex_lock(toxav->mutex); 1027 pthread_mutex_lock(toxav->mutex);
1031 1028
1032 invoke_call_state(toxav, call->friend_id, TOXAV_CALL_STATE_ERROR); 1029 invoke_call_state(toxav, call->friend_number, TOXAV_CALL_STATE_ERROR);
1033 1030
1034 call_kill_transmission(call->av_call); 1031 call_kill_transmission(call->av_call);
1035 call_remove(call->av_call); 1032 call_remove(call->av_call);
@@ -1043,21 +1040,21 @@ int callback_capabilites(void* toxav_inst, MSICall* call)
1043 ToxAV* toxav = toxav_inst; 1040 ToxAV* toxav = toxav_inst;
1044 pthread_mutex_lock(toxav->mutex); 1041 pthread_mutex_lock(toxav->mutex);
1045 1042
1046 invoke_call_state(toxav, call->friend_id, call->peer_capabilities); 1043 invoke_call_state(toxav, call->friend_number, call->peer_capabilities);
1047 1044
1048 pthread_mutex_unlock(toxav->mutex); 1045 pthread_mutex_unlock(toxav->mutex);
1049 return 0; 1046 return 0;
1050} 1047}
1051 1048
1052bool audio_bitrate_invalid(uint32_t bitrate) 1049bool audio_bit_rate_invalid(uint32_t bit_rate)
1053{ 1050{
1054 /* Opus RFC 6716 section-2.1.1 dictates the following: 1051 /* Opus RFC 6716 section-2.1.1 dictates the following:
1055 * Opus supports all bitrates from 6 kbit/s to 510 kbit/s. 1052 * Opus supports all bit rates from 6 kbit/s to 510 kbit/s.
1056 */ 1053 */
1057 return bitrate < 6 || bitrate > 510; 1054 return bit_rate < 6 || bit_rate > 510;
1058} 1055}
1059 1056
1060bool video_bitrate_invalid(uint32_t bitrate) 1057bool video_bit_rate_invalid(uint32_t bit_rate)
1061{ 1058{
1062 /* TODO: If anyone knows the answer to this one please fill it up */ 1059 /* TODO: If anyone knows the answer to this one please fill it up */
1063 return false; 1060 return false;
@@ -1099,7 +1096,7 @@ ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error)
1099 } 1096 }
1100 1097
1101 call->av = av; 1098 call->av = av;
1102 call->friend_id = friend_number; 1099 call->friend_number = friend_number;
1103 1100
1104 if (av->calls == NULL) { /* Creating */ 1101 if (av->calls == NULL) { /* Creating */
1105 av->calls = calloc (sizeof(ToxAVCall*), friend_number + 1); 1102 av->calls = calloc (sizeof(ToxAVCall*), friend_number + 1);
@@ -1126,7 +1123,7 @@ ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error)
1126 av->calls = tmp; 1123 av->calls = tmp;
1127 1124
1128 /* Set fields in between to null */ 1125 /* Set fields in between to null */
1129 int32_t i = av->calls_tail; 1126 int32_t i = av->calls_tail + 1;
1130 for (; i < friend_number; i ++) 1127 for (; i < friend_number; i ++)
1131 av->calls[i] = NULL; 1128 av->calls[i] = NULL;
1132 1129
@@ -1164,7 +1161,7 @@ void call_remove(ToxAVCall* call)
1164 if (call == NULL) 1161 if (call == NULL)
1165 return; 1162 return;
1166 1163
1167 uint32_t friend_id = call->friend_id; 1164 uint32_t friend_number = call->friend_number;
1168 ToxAV* av = call->av; 1165 ToxAV* av = call->av;
1169 1166
1170 ToxAVCall* prev = call->prev; 1167 ToxAVCall* prev = call->prev;
@@ -1175,16 +1172,16 @@ void call_remove(ToxAVCall* call)
1175 if (prev) 1172 if (prev)
1176 prev->next = next; 1173 prev->next = next;
1177 else if (next) 1174 else if (next)
1178 av->calls_head = next->friend_id; 1175 av->calls_head = next->friend_number;
1179 else goto CLEAR; 1176 else goto CLEAR;
1180 1177
1181 if (next) 1178 if (next)
1182 next->prev = prev; 1179 next->prev = prev;
1183 else if (prev) 1180 else if (prev)
1184 av->calls_tail = prev->friend_id; 1181 av->calls_tail = prev->friend_number;
1185 else goto CLEAR; 1182 else goto CLEAR;
1186 1183
1187 av->calls[friend_id] = NULL; 1184 av->calls[friend_number] = NULL;
1188 return; 1185 return;
1189 1186
1190CLEAR: 1187CLEAR:
@@ -1214,17 +1211,16 @@ bool call_prepare_transmission(ToxAVCall* call)
1214 if (create_recursive_mutex(call->mutex_audio) != 0) 1211 if (create_recursive_mutex(call->mutex_audio) != 0)
1215 return false; 1212 return false;
1216 1213
1217 if (create_recursive_mutex(call->mutex_video) != 0) { 1214 if (create_recursive_mutex(call->mutex_video) != 0)
1218 goto AUDIO_SENDING_MUTEX_CLEANUP; 1215 goto FAILURE_3;
1219 } 1216
1217 if (create_recursive_mutex(call->mutex) != 0)
1218 goto FAILURE_2;
1220 1219
1221 if (create_recursive_mutex(call->mutex) != 0) {
1222 goto VIDEO_SENDING_MUTEX_CLEANUP;
1223 }
1224 1220
1225 { /* Prepare audio */ 1221 { /* Prepare audio */
1226 call->audio.second = ac_new(av, call->friend_id, av->acb.first, av->acb.second); 1222 call->audio.second = ac_new(av, call->friend_number, av->acb.first, av->acb.second);
1227 call->audio.first = rtp_new(rtp_TypeAudio, av->m, call->friend_id, call->audio.second, ac_queue_message); 1223 call->audio.first = rtp_new(rtp_TypeAudio, av->m, call->friend_number, call->audio.second, ac_queue_message);
1228 1224
1229 if ( !call->audio.first || !call->audio.second ) { 1225 if ( !call->audio.first || !call->audio.second ) {
1230 LOGGER_ERROR("Error while starting audio!\n"); 1226 LOGGER_ERROR("Error while starting audio!\n");
@@ -1233,8 +1229,8 @@ bool call_prepare_transmission(ToxAVCall* call)
1233 } 1229 }
1234 1230
1235 { /* Prepare video */ 1231 { /* Prepare video */
1236 call->video.second = vc_new(av, call->friend_id, av->vcb.first, av->vcb.second, call->msi_call->peer_vfpsz); 1232 call->video.second = vc_new(av, call->friend_number, av->vcb.first, av->vcb.second, call->msi_call->peer_vfpsz);
1237 call->video.first = rtp_new(rtp_TypeVideo, av->m, call->friend_id, call->video.second, vc_queue_message); 1233 call->video.first = rtp_new(rtp_TypeVideo, av->m, call->friend_number, call->video.second, vc_queue_message);
1238 1234
1239 if ( !call->video.first || !call->video.second ) { 1235 if ( !call->video.first || !call->video.second ) {
1240 LOGGER_ERROR("Error while starting video!\n"); 1236 LOGGER_ERROR("Error while starting video!\n");
@@ -1255,9 +1251,9 @@ FAILURE:
1255 call->video.first = NULL; 1251 call->video.first = NULL;
1256 call->video.second = NULL; 1252 call->video.second = NULL;
1257 pthread_mutex_destroy(call->mutex); 1253 pthread_mutex_destroy(call->mutex);
1258VIDEO_SENDING_MUTEX_CLEANUP: 1254FAILURE_2:
1259 pthread_mutex_destroy(call->mutex_video); 1255 pthread_mutex_destroy(call->mutex_video);
1260AUDIO_SENDING_MUTEX_CLEANUP: 1256FAILURE_3:
1261 pthread_mutex_destroy(call->mutex_audio); 1257 pthread_mutex_destroy(call->mutex_audio);
1262 return false; 1258 return false;
1263} 1259}
diff --git a/toxav/toxav.h b/toxav/toxav.h
index f2c3b2b3..b8db223e 100644
--- a/toxav/toxav.h
+++ b/toxav/toxav.h
@@ -333,23 +333,23 @@ typedef enum TOXAV_ERR_BIT_RATE {
333 TOXAV_ERR_BIT_RATE_FRIEND_NOT_IN_CALL 333 TOXAV_ERR_BIT_RATE_FRIEND_NOT_IN_CALL
334} TOXAV_ERR_BIT_RATE; 334} TOXAV_ERR_BIT_RATE;
335/** 335/**
336 * The function type for the `audio_bitrate_control` callback. 336 * The function type for the `audio_bit_rate_status` callback.
337 * 337 *
338 * @param friend_number The friend number of the friend for which to set the 338 * @param friend_number The friend number of the friend for which to set the
339 * audio bit rate. 339 * audio bit rate.
340 * @param good Is the stream good enough to keep the said bitrate. Upon failed 340 * @param stable Is the stream stable enough to keep the bit rate.
341 * non forceful bit rate setup this will be set to false and 'bit_rate' 341 * Upon successful, non forceful, bit rate change, this is set to
342 * will be set to the bit rate that failed, otherwise 'good' will be set to 342 * true and 'bit_rate' is set to new bit rate.
343 * true with 'bit_rate' set to new bit rate. If the stream becomes bad, 343 * The stable is set to false with bit_rate set to the unstable
344 * the 'good' wil be set to false with 'bit_rate' set to the current bit rate. 344 * bit rate when either current stream is unstable with said bit rate
345 * This callback will never be called when the stream is good. 345 * or the non forceful change failed.
346 * @param bit_rate The bit rate in Kb/sec. 346 * @param bit_rate The bit rate in Kb/sec.
347 */ 347 */
348typedef void toxav_audio_bitrate_control_cb(ToxAV *av, uint32_t friend_number, bool good, uint32_t bit_rate, void *user_data); 348typedef void toxav_audio_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, bool stable, uint32_t bit_rate, void *user_data);
349/** 349/**
350 * Set the callback for the `audio_bitrate_control` event. Pass NULL to unset. 350 * Set the callback for the `audio_bit_rate_status` event. Pass NULL to unset.
351 */ 351 */
352void toxav_callback_audio_bitrate_control(ToxAV *av, toxav_audio_bitrate_control_cb *function, void *user_data); 352void toxav_callback_audio_bit_rate_status(ToxAV *av, toxav_audio_bit_rate_status_cb *function, void *user_data);
353/** 353/**
354 * Set the audio bit rate to be used in subsequent audio frames. 354 * Set the audio bit rate to be used in subsequent audio frames.
355 * 355 *
@@ -362,23 +362,23 @@ void toxav_callback_audio_bitrate_control(ToxAV *av, toxav_audio_bitrate_control
362 */ 362 */
363bool toxav_set_audio_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, bool force, TOXAV_ERR_BIT_RATE *error); 363bool toxav_set_audio_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, bool force, TOXAV_ERR_BIT_RATE *error);
364/** 364/**
365 * The function type for the `video_bitrate_control` callback. 365 * The function type for the `video_bit_rate_status` callback.
366 * 366 *
367 * @param friend_number The friend number of the friend for which to set the 367 * @param friend_number The friend number of the friend for which to set the
368 * video bit rate. 368 * video bit rate.
369 * @param good Is the stream good enough to keep the said bitrate. Upon failed 369 * @param stable Is the stream stable enough to keep the bit rate.
370 * non forceful bit rate setup this will be set to false and 'bit_rate' 370 * Upon successful, non forceful, bit rate change, this is set to
371 * will be set to the bit rate that failed, otherwise 'good' will be set to 371 * true and 'bit_rate' is set to new bit rate.
372 * true with 'bit_rate' set to new bit rate. If the stream becomes bad, 372 * The stable is set to false with bit_rate set to the unstable
373 * the 'good' wil be set to false with 'bit_rate' set to the current bit rate. 373 * bit rate when either current stream is unstable with said bit rate
374 * This callback will never be called when the stream is good. 374 * or the non forceful change failed.
375 * @param bit_rate The bit rate in Kb/sec. 375 * @param bit_rate The bit rate in Kb/sec.
376 */ 376 */
377typedef void toxav_video_bitrate_control_cb(ToxAV *av, uint32_t friend_number, bool good, uint32_t bit_rate, void *user_data); 377typedef void toxav_video_bit_rate_status_cb(ToxAV *av, uint32_t friend_number, bool stable, uint32_t bit_rate, void *user_data);
378/** 378/**
379 * Set the callback for the `video_bitrate_control` event. Pass NULL to unset. 379 * Set the callback for the `video_bit_rate_status` event. Pass NULL to unset.
380 */ 380 */
381void toxav_callback_video_bitrate_control(ToxAV *av, toxav_video_bitrate_control_cb *function, void *user_data); 381void toxav_callback_video_bit_rate_status(ToxAV *av, toxav_video_bit_rate_status_cb *function, void *user_data);
382/** 382/**
383 * Set the video bit rate to be used in subsequent video frames. 383 * Set the video bit rate to be used in subsequent video frames.
384 * 384 *
diff --git a/toxav/video.c b/toxav/video.c
index c540af3b..22ca2bee 100644
--- a/toxav/video.c
+++ b/toxav/video.c
@@ -35,15 +35,14 @@
35#define MAX_VIDEOFRAME_SIZE 0x40000 /* 256KiB */ 35#define MAX_VIDEOFRAME_SIZE 0x40000 /* 256KiB */
36#define VIDEOFRAME_HEADER_SIZE 0x2 36#define VIDEOFRAME_HEADER_SIZE 0x2
37 37
38/* FIXME: Might not be enough? NOTE: I think it is enough */
39#define VIDEO_DECODE_BUFFER_SIZE 20 38#define VIDEO_DECODE_BUFFER_SIZE 20
40 39
41typedef struct { uint16_t size; uint8_t data[]; } Payload; 40typedef struct { uint16_t size; uint8_t data[]; } Payload;
42 41
43bool create_video_encoder (vpx_codec_ctx_t* dest, int32_t bitrate); 42bool create_video_encoder (vpx_codec_ctx_t* dest, int32_t bit_rate);
44 43
45 44
46VCSession* vc_new(ToxAV* av, uint32_t friend_id, toxav_receive_video_frame_cb* cb, void* cb_data, uint32_t mvfpsz) 45VCSession* vc_new(ToxAV* av, uint32_t friend_number, toxav_receive_video_frame_cb* cb, void* cb_data, uint32_t mvfpsz)
47{ 46{
48 VCSession *vc = calloc(sizeof(VCSession), 1); 47 VCSession *vc = calloc(sizeof(VCSession), 1);
49 48
@@ -86,7 +85,7 @@ VCSession* vc_new(ToxAV* av, uint32_t friend_id, toxav_receive_video_frame_cb* c
86 vc->lcfd = 60; 85 vc->lcfd = 60;
87 vc->vcb.first = cb; 86 vc->vcb.first = cb;
88 vc->vcb.second = cb_data; 87 vc->vcb.second = cb_data;
89 vc->friend_id = friend_id; 88 vc->friend_number = friend_number;
90 vc->peer_video_frame_piece_size = mvfpsz; 89 vc->peer_video_frame_piece_size = mvfpsz;
91 90
92 return vc; 91 return vc;
@@ -140,7 +139,7 @@ void vc_do(VCSession* vc)
140 /* Play decoded images */ 139 /* Play decoded images */
141 for (; dest; dest = vpx_codec_get_frame(vc->decoder, &iter)) { 140 for (; dest; dest = vpx_codec_get_frame(vc->decoder, &iter)) {
142 if (vc->vcb.first) 141 if (vc->vcb.first)
143 vc->vcb.first(vc->av, vc->friend_id, dest->d_w, dest->d_h, 142 vc->vcb.first(vc->av, vc->friend_number, dest->d_w, dest->d_h,
144 (const uint8_t*)dest->planes[0], (const uint8_t*)dest->planes[1], (const uint8_t*)dest->planes[2], 143 (const uint8_t*)dest->planes[0], (const uint8_t*)dest->planes[1], (const uint8_t*)dest->planes[2],
145 dest->stride[0], dest->stride[1], dest->stride[2], vc->vcb.second); 144 dest->stride[0], dest->stride[1], dest->stride[2], vc->vcb.second);
146 145
@@ -289,16 +288,16 @@ end:
289 rtp_free_msg(msg); 288 rtp_free_msg(msg);
290 return 0; 289 return 0;
291} 290}
292int vc_reconfigure_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint16_t height) 291int vc_reconfigure_encoder(VCSession* vc, int32_t bit_rate, uint16_t width, uint16_t height)
293{ 292{
294 if (!vc) 293 if (!vc)
295 return -1; 294 return -1;
296 295
297 vpx_codec_enc_cfg_t cfg = *vc->encoder->config.enc; 296 vpx_codec_enc_cfg_t cfg = *vc->encoder->config.enc;
298 if (cfg.rc_target_bitrate == bitrate && cfg.g_w == width && cfg.g_h == height) 297 if (cfg.rc_target_bitrate == bit_rate && cfg.g_w == width && cfg.g_h == height)
299 return 0; /* Nothing changed */ 298 return 0; /* Nothing changed */
300 299
301 cfg.rc_target_bitrate = bitrate; 300 cfg.rc_target_bitrate = bit_rate;
302 cfg.g_w = width; 301 cfg.g_w = width;
303 cfg.g_h = height; 302 cfg.g_h = height;
304 303
@@ -310,16 +309,16 @@ int vc_reconfigure_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint1
310 309
311 return 0; 310 return 0;
312} 311}
313int vc_reconfigure_test_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint16_t height) 312int vc_reconfigure_test_encoder(VCSession* vc, int32_t bit_rate, uint16_t width, uint16_t height)
314{ 313{
315 if (!vc) 314 if (!vc)
316 return -1; 315 return -1;
317 316
318 vpx_codec_enc_cfg_t cfg = *vc->test_encoder->config.enc; 317 vpx_codec_enc_cfg_t cfg = *vc->test_encoder->config.enc;
319 if (cfg.rc_target_bitrate == bitrate && cfg.g_w == width && cfg.g_h == height) 318 if (cfg.rc_target_bitrate == bit_rate && cfg.g_w == width && cfg.g_h == height)
320 return 0; /* Nothing changed */ 319 return 0; /* Nothing changed */
321 320
322 cfg.rc_target_bitrate = bitrate; 321 cfg.rc_target_bitrate = bit_rate;
323 cfg.g_w = width; 322 cfg.g_w = width;
324 cfg.g_h = height; 323 cfg.g_h = height;
325 324
@@ -334,7 +333,7 @@ int vc_reconfigure_test_encoder(VCSession* vc, int32_t bitrate, uint16_t width,
334 333
335 334
336 335
337bool create_video_encoder (vpx_codec_ctx_t* dest, int32_t bitrate) 336bool create_video_encoder (vpx_codec_ctx_t* dest, int32_t bit_rate)
338{ 337{
339 assert(dest); 338 assert(dest);
340 339
@@ -354,7 +353,7 @@ bool create_video_encoder (vpx_codec_ctx_t* dest, int32_t bitrate)
354 return false; 353 return false;
355 } 354 }
356 355
357 cfg.rc_target_bitrate = bitrate; 356 cfg.rc_target_bitrate = bit_rate;
358 cfg.g_w = 800; 357 cfg.g_w = 800;
359 cfg.g_h = 600; 358 cfg.g_h = 600;
360 cfg.g_pass = VPX_RC_ONE_PASS; 359 cfg.g_pass = VPX_RC_ONE_PASS;
diff --git a/toxav/video.h b/toxav/video.h
index 78003ef3..8da15578 100644
--- a/toxav/video.h
+++ b/toxav/video.h
@@ -38,6 +38,9 @@
38 38
39struct RTPMessage_s; 39struct RTPMessage_s;
40 40
41/*
42 * Base Video Codec session type.
43 */
41typedef struct VCSession_s { 44typedef struct VCSession_s {
42 45
43 /* encoding */ 46 /* encoding */
@@ -65,23 +68,46 @@ typedef struct VCSession_s {
65 const uint8_t *processing_video_frame; 68 const uint8_t *processing_video_frame;
66 uint16_t processing_video_frame_size; 69 uint16_t processing_video_frame_size;
67 70
68
69 ToxAV *av; 71 ToxAV *av;
70 int32_t friend_id; 72 uint32_t friend_number;
71 73
72 PAIR(toxav_receive_video_frame_cb *, void *) vcb; /* Video frame receive callback */ 74 PAIR(toxav_receive_video_frame_cb *, void *) vcb; /* Video frame receive callback */
73 75
74 pthread_mutex_t queue_mutex[1]; 76 pthread_mutex_t queue_mutex[1];
75} VCSession; 77} VCSession;
76 78
77VCSession* vc_new(ToxAV* av, uint32_t friend_id, toxav_receive_video_frame_cb *cb, void *cb_data, uint32_t mvfpsz); 79/*
80 * Create new Video Codec session.
81 */
82VCSession* vc_new(ToxAV* av, uint32_t friend_number, toxav_receive_video_frame_cb *cb, void *cb_data, uint32_t mvfpsz);
83/*
84 * Kill the Video Codec session.
85 */
78void vc_kill(VCSession* vc); 86void vc_kill(VCSession* vc);
87/*
88 * Do periodic work. Work is consisted out of decoding only.
89 */
79void vc_do(VCSession* vc); 90void vc_do(VCSession* vc);
91/*
92 * Set new video splitting cycle. This is requirement in order to send video packets.
93 */
80void vc_init_video_splitter_cycle(VCSession* vc); 94void vc_init_video_splitter_cycle(VCSession* vc);
95/*
96 * Update the video splitter cycle with new data.
97 */
81int vc_update_video_splitter_cycle(VCSession* vc, const uint8_t* payload, uint16_t length); 98int vc_update_video_splitter_cycle(VCSession* vc, const uint8_t* payload, uint16_t length);
99/*
100 * Iterate over splitted cycle.
101 */
82const uint8_t *vc_iterate_split_video_frame(VCSession* vc, uint16_t *size); 102const uint8_t *vc_iterate_split_video_frame(VCSession* vc, uint16_t *size);
103/*
104 * Queue new rtp message.
105 */
83int vc_queue_message(void *vcp, struct RTPMessage_s *msg); 106int vc_queue_message(void *vcp, struct RTPMessage_s *msg);
84int vc_reconfigure_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint16_t height); 107/*
85int vc_reconfigure_test_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint16_t height); 108 * Set new values to the encoders.
109 */
110int vc_reconfigure_encoder(VCSession* vc, int32_t bit_rate, uint16_t width, uint16_t height);
111int vc_reconfigure_test_encoder(VCSession* vc, int32_t bit_rate, uint16_t width, uint16_t height);
86 112
87#endif /* VIDEO_H */ \ No newline at end of file 113#endif /* VIDEO_H */ \ No newline at end of file