diff options
author | mannol <eniz_vukovic@hotmail.com> | 2015-04-29 01:01:25 +0200 |
---|---|---|
committer | mannol <eniz_vukovic@hotmail.com> | 2015-04-29 01:01:25 +0200 |
commit | 9bba7a0434d0967d5dd76b8afc7783ea2edad0cf (patch) | |
tree | 6486c250acb38429a63a62e54cd1e4bcb0a029ee /toxav | |
parent | e4a020333d76bc30172f54f2545677f01bdd54b6 (diff) |
Done
Diffstat (limited to 'toxav')
-rw-r--r-- | toxav/Makefile.inc | 21 | ||||
-rw-r--r-- | toxav/audio.c | 35 | ||||
-rw-r--r-- | toxav/audio.h | 33 | ||||
-rw-r--r-- | toxav/av_test.c | 976 | ||||
-rw-r--r-- | toxav/msi.c | 124 | ||||
-rw-r--r-- | toxav/msi.h | 24 | ||||
-rw-r--r-- | toxav/rtp.c | 67 | ||||
-rw-r--r-- | toxav/rtp.h | 11 | ||||
-rw-r--r-- | toxav/toxav.c | 132 | ||||
-rw-r--r-- | toxav/toxav.h | 40 | ||||
-rw-r--r-- | toxav/video.c | 25 | ||||
-rw-r--r-- | toxav/video.h | 36 |
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 | |||
61 | endif \ No newline at end of file | 40 | endif \ 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); | |||
31 | static void jbuf_free(struct JitterBuffer *q); | 31 | static void jbuf_free(struct JitterBuffer *q); |
32 | static int jbuf_write(struct JitterBuffer *q, RTPMessage *m); | 32 | static int jbuf_write(struct JitterBuffer *q, RTPMessage *m); |
33 | static RTPMessage *jbuf_read(struct JitterBuffer *q, int32_t *success); | 33 | static RTPMessage *jbuf_read(struct JitterBuffer *q, int32_t *success); |
34 | 34 | OpusEncoder* create_audio_encoder (int32_t bit_rate, int32_t sampling_rate, int32_t channel_count); | |
35 | OpusEncoder* create_audio_encoder (int32_t bitrate, int32_t sampling_rate, int32_t channel_count); | ||
36 | bool reconfigure_audio_encoder(OpusEncoder** e, int32_t new_br, int32_t new_sr, uint8_t new_ch, | 35 | bool 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); |
38 | bool reconfigure_audio_decoder(ACSession* ac, int32_t sampling_rate, int8_t channels); | 37 | bool reconfigure_audio_decoder(ACSession* ac, int32_t sampling_rate, int8_t channels); |
39 | 38 | ||
40 | 39 | ||
41 | ACSession* ac_new(ToxAV* av, uint32_t friend_id, toxav_receive_audio_frame_cb *cb, void *cb_data) | 40 | |
41 | ACSession* 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 | } |
223 | int ac_reconfigure_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels) | 223 | int 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 | } |
232 | int ac_reconfigure_test_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels) | 232 | int 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 */ | ||
245 | struct JitterBuffer { | 244 | struct 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 | } |
343 | OpusEncoder* create_audio_encoder (int32_t bitrate, int32_t sampling_rate, int32_t channel_count) | 342 | OpusEncoder* 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 | ||
32 | struct RTPMessage_s; | 32 | struct RTPMessage_s; |
33 | 33 | ||
34 | /* | ||
35 | * Base Audio Codec session type. | ||
36 | */ | ||
34 | typedef struct ACSession_s { | 37 | typedef 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 | ||
64 | ACSession* 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 | */ | ||
70 | ACSession* 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 | */ | ||
65 | void ac_kill(ACSession* ac); | 74 | void ac_kill(ACSession* ac); |
75 | /* | ||
76 | * Do periodic work. Work is consisted out of decoding only. | ||
77 | */ | ||
66 | void ac_do(ACSession* ac); | 78 | void ac_do(ACSession* ac); |
79 | /* | ||
80 | * Queue new rtp message. | ||
81 | */ | ||
67 | int ac_queue_message(void *acp, struct RTPMessage_s *msg); | 82 | int ac_queue_message(void *acp, struct RTPMessage_s *msg); |
68 | int ac_reconfigure_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels); | 83 | /* |
69 | int ac_reconfigure_test_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels); | 84 | * Set new values to the encoders. |
85 | */ | ||
86 | int ac_reconfigure_encoder(ACSession* ac, int32_t bit_rate, int32_t sampling_rate, uint8_t channels); | ||
87 | int 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 | |||
84 | typedef 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 | |||
92 | struct toxav_thread_data { | ||
93 | ToxAV* AliceAV; | ||
94 | ToxAV* BobAV; | ||
95 | int32_t sig; | ||
96 | }; | ||
97 | |||
98 | const char* vdout = "AV Test"; /* Video output */ | ||
99 | PaStream* adout = NULL; /* Audio output */ | ||
100 | |||
101 | |||
102 | typedef struct { | ||
103 | uint16_t size; | ||
104 | int16_t data[]; | ||
105 | } frame; | ||
106 | |||
107 | void* 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 | */ | ||
132 | void 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 | } | ||
137 | void 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 | } | ||
142 | void 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 | } | ||
174 | void 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 | } | ||
190 | void 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 | } | ||
198 | void 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 | } | ||
206 | void 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 | */ | ||
216 | void 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 | } | ||
305 | int 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 | } | ||
313 | void* 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 | |||
344 | int 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 | |||
381 | int 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 | |||
393 | int 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 | |||
408 | int 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 | ||
82 | void msg_init (MSIMessage *dest, MSIRequest request); | 82 | void msg_init (MSIMessage *dest, MSIRequest request); |
83 | int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length ); | 83 | int msg_parse_in ( MSIMessage *dest, const uint8_t *data, uint16_t length ); |
84 | uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length ); | 84 | uint8_t *msg_parse_header_out ( MSIHeaderID id, uint8_t *dest, const void *value, uint8_t value_len, uint16_t *length ); |
85 | int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg ); | 85 | int send_message ( Messenger* m, uint32_t friend_number, const MSIMessage *msg ); |
86 | int send_error ( Messenger* m, uint32_t friend_id, MSIError error ); | 86 | int send_error ( Messenger* m, uint32_t friend_number, MSIError error ); |
87 | static int invoke_callback(MSICall* call, MSICallbackID cb); | 87 | static int invoke_callback(MSICall* call, MSICallbackID cb); |
88 | static MSICall *get_call ( MSISession *session, uint32_t friend_id ); | 88 | static MSICall *get_call ( MSISession *session, uint32_t friend_number ); |
89 | MSICall *new_call ( MSISession *session, uint32_t friend_id ); | 89 | MSICall *new_call ( MSISession *session, uint32_t friend_number ); |
90 | void kill_call ( MSICall *call ); | 90 | void kill_call ( MSICall *call ); |
91 | void on_peer_status(Messenger *m, uint32_t friend_id, uint8_t status, void *data); | 91 | void on_peer_status(Messenger *m, uint32_t friend_number, uint8_t status, void *data); |
92 | void handle_push ( MSICall *call, const MSIMessage *msg ); | 92 | void handle_push ( MSICall *call, const MSIMessage *msg ); |
93 | void handle_pop ( MSICall *call, const MSIMessage *msg ); | 93 | void handle_pop ( MSICall *call, const MSIMessage *msg ); |
94 | void handle_msi_packet ( Messenger *m, uint32_t friend_id, const uint8_t *data, uint16_t length, void *object ); | 94 | void 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 | */ |
100 | void msi_register_callback ( MSISession *session, MSICallbackType callback, MSICallbackID id) | 100 | void 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 | } |
106 | MSISession *msi_new ( Messenger *messenger ) | 106 | MSISession *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 | } |
164 | int msi_invite ( MSISession *session, MSICall **call, uint32_t friend_id, uint8_t capabilities ) | 164 | int 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 | } |
201 | int msi_hangup ( MSICall* call ) | 201 | int 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 | } |
217 | int msi_answer ( MSICall* call, uint8_t capabilities ) | 217 | int 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 | } |
250 | int msi_change_capabilities( MSICall* call, uint8_t capabilities ) | 250 | int 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 | } |
397 | int send_message ( Messenger* m, uint32_t friend_id, const MSIMessage *msg ) | 397 | int 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 | } |
448 | int send_error ( Messenger* m, uint32_t friend_id, MSIError error ) | 448 | int 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 | } |
464 | int invoke_callback(MSICall* call, MSICallbackID cb) | 464 | int 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 | } |
487 | static MSICall *get_call ( MSISession *session, uint32_t friend_id ) | 487 | static 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 | } |
496 | MSICall *new_call ( MSISession *session, uint32_t friend_id ) | 496 | MSICall *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 | } |
547 | void kill_call ( MSICall *call ) | 547 | void 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 | } |
582 | void on_peer_status(Messenger* m, uint32_t friend_id, uint8_t status, void* data) | 582 | void 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 | ||
710 | FAILURE: | 708 | FAILURE: |
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 | } |
714 | void handle_pop ( MSICall *call, const MSIMessage *msg ) | 712 | void 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 | } |
754 | void handle_msi_packet ( Messenger* m, uint32_t friend_id, const uint8_t* data, uint16_t length, void* object ) | 752 | void 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 | */ |
108 | typedef int ( *MSICallbackType ) ( void *agent, MSICall* call); | 107 | typedef 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 | */ |
132 | MSISession *msi_new ( Messenger *messenger ); | 128 | MSISession *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 | */ |
137 | int msi_kill ( MSISession *session ); | 132 | int msi_kill ( MSISession *session ); |
138 | |||
139 | /** | 133 | /** |
140 | * Callback setter. | 134 | * Callback setter. |
141 | */ | 135 | */ |
142 | void msi_register_callback(MSISession *session, MSICallbackType callback, MSICallbackID id); | 136 | void 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 | */ |
147 | int msi_invite ( MSISession* session, MSICall** call, uint32_t friend_id, uint8_t capabilities ); | 140 | int 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 | */ |
152 | int msi_hangup ( MSICall* call ); | 144 | int msi_hangup ( MSICall* call ); |
153 | |||
154 | /** | 145 | /** |
155 | * Answer call request. | 146 | * Answer call request. |
156 | */ | 147 | */ |
157 | int msi_answer ( MSICall* call, uint8_t capabilities ); | 148 | int 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 | |||
78 | void send_rtcp_report ( RTCPSession* session, Messenger* m, uint32_t friendnumber ); | 78 | void send_rtcp_report ( RTCPSession* session, Messenger* m, uint32_t friendnumber ); |
79 | 79 | ||
80 | 80 | ||
81 | RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num, void* cs, int (*mcb) (void*, RTPMessage*) ) | 81 | RTPSession *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 | |||
304 | RTPHeader *parse_header_in ( const uint8_t *payload, int length ) | 303 | RTPHeader *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, ×tamp, sizeof(timestamp)); | 424 | memcpy(it, ×tamp, 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 | */ |
128 | RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num, void* cs, int (*mcb) (void*, RTPMessage*) ); | 127 | RTPSession *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 | */ |
133 | void rtp_kill ( RTPSession* session ); | 131 | void rtp_kill ( RTPSession* session ); |
134 | |||
135 | /** | 132 | /** |
136 | * Do periodical rtp work. | 133 | * Do periodical rtp work. |
137 | */ | 134 | */ |
138 | int rtp_do(RTPSession *session); | 135 | int 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 | */ |
143 | int rtp_start_receiving (RTPSession *session); | 139 | int rtp_start_receiving (RTPSession *session); |
144 | |||
145 | /** | 140 | /** |
146 | * Pause rtp receiving mode. | 141 | * Pause rtp receiving mode. |
147 | */ | 142 | */ |
148 | int rtp_stop_receiving (RTPSession *session); | 143 | int rtp_stop_receiving (RTPSession *session); |
149 | |||
150 | /** | 144 | /** |
151 | * Sends msg to RTPSession::dest | 145 | * Sends msg to RTPSession::dest |
152 | */ | 146 | */ |
153 | int rtp_send_data ( RTPSession* session, const uint8_t* data, uint16_t length, bool dummy ); | 147 | int 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); | |||
111 | int callback_error(void* toxav_inst, MSICall* call); | 111 | int callback_error(void* toxav_inst, MSICall* call); |
112 | int callback_capabilites(void* toxav_inst, MSICall* call); | 112 | int callback_capabilites(void* toxav_inst, MSICall* call); |
113 | 113 | ||
114 | bool audio_bitrate_invalid(uint32_t bitrate); | 114 | bool audio_bit_rate_invalid(uint32_t bit_rate); |
115 | bool video_bitrate_invalid(uint32_t bitrate); | 115 | bool video_bit_rate_invalid(uint32_t bit_rate); |
116 | void invoke_call_state(ToxAV* av, uint32_t friend_number, uint32_t state); | 116 | void invoke_call_state(ToxAV* av, uint32_t friend_number, uint32_t state); |
117 | ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error); | 117 | ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error); |
118 | ToxAVCall* call_get(ToxAV* av, uint32_t friend_number); | 118 | ToxAVCall* 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 | 173 | END: | |
174 | if (error) | ||
175 | *error = rc; | ||
176 | |||
177 | return av; | ||
178 | |||
179 | FAILURE: | ||
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 | ||
188 | void toxav_kill(ToxAV* av) | 185 | void 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 | ||
361 | bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_ANSWER* error) | 358 | bool 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 | ||
564 | void toxav_callback_video_bitrate_control(ToxAV* av, toxav_video_bitrate_control_cb* function, void* user_data) | 561 | void 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 | ||
621 | void toxav_callback_audio_bitrate_control(ToxAV* av, toxav_audio_bitrate_control_cb* function, void* user_data) | 618 | void 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 | ||
1052 | bool audio_bitrate_invalid(uint32_t bitrate) | 1049 | bool 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 | ||
1060 | bool video_bitrate_invalid(uint32_t bitrate) | 1057 | bool 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 | ||
1190 | CLEAR: | 1187 | CLEAR: |
@@ -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); |
1258 | VIDEO_SENDING_MUTEX_CLEANUP: | 1254 | FAILURE_2: |
1259 | pthread_mutex_destroy(call->mutex_video); | 1255 | pthread_mutex_destroy(call->mutex_video); |
1260 | AUDIO_SENDING_MUTEX_CLEANUP: | 1256 | FAILURE_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 | */ |
348 | typedef void toxav_audio_bitrate_control_cb(ToxAV *av, uint32_t friend_number, bool good, uint32_t bit_rate, void *user_data); | 348 | typedef 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 | */ |
352 | void toxav_callback_audio_bitrate_control(ToxAV *av, toxav_audio_bitrate_control_cb *function, void *user_data); | 352 | void 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 | */ |
363 | bool toxav_set_audio_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, bool force, TOXAV_ERR_BIT_RATE *error); | 363 | bool 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 | */ |
377 | typedef void toxav_video_bitrate_control_cb(ToxAV *av, uint32_t friend_number, bool good, uint32_t bit_rate, void *user_data); | 377 | typedef 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 | */ |
381 | void toxav_callback_video_bitrate_control(ToxAV *av, toxav_video_bitrate_control_cb *function, void *user_data); | 381 | void 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 | ||
41 | typedef struct { uint16_t size; uint8_t data[]; } Payload; | 40 | typedef struct { uint16_t size; uint8_t data[]; } Payload; |
42 | 41 | ||
43 | bool create_video_encoder (vpx_codec_ctx_t* dest, int32_t bitrate); | 42 | bool create_video_encoder (vpx_codec_ctx_t* dest, int32_t bit_rate); |
44 | 43 | ||
45 | 44 | ||
46 | VCSession* vc_new(ToxAV* av, uint32_t friend_id, toxav_receive_video_frame_cb* cb, void* cb_data, uint32_t mvfpsz) | 45 | VCSession* 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 | } |
292 | int vc_reconfigure_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint16_t height) | 291 | int 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 | } |
313 | int vc_reconfigure_test_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint16_t height) | 312 | int 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 | ||
337 | bool create_video_encoder (vpx_codec_ctx_t* dest, int32_t bitrate) | 336 | bool 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 | ||
39 | struct RTPMessage_s; | 39 | struct RTPMessage_s; |
40 | 40 | ||
41 | /* | ||
42 | * Base Video Codec session type. | ||
43 | */ | ||
41 | typedef struct VCSession_s { | 44 | typedef 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 | ||
77 | VCSession* 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 | */ | ||
82 | VCSession* 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 | */ | ||
78 | void vc_kill(VCSession* vc); | 86 | void vc_kill(VCSession* vc); |
87 | /* | ||
88 | * Do periodic work. Work is consisted out of decoding only. | ||
89 | */ | ||
79 | void vc_do(VCSession* vc); | 90 | void vc_do(VCSession* vc); |
91 | /* | ||
92 | * Set new video splitting cycle. This is requirement in order to send video packets. | ||
93 | */ | ||
80 | void vc_init_video_splitter_cycle(VCSession* vc); | 94 | void vc_init_video_splitter_cycle(VCSession* vc); |
95 | /* | ||
96 | * Update the video splitter cycle with new data. | ||
97 | */ | ||
81 | int vc_update_video_splitter_cycle(VCSession* vc, const uint8_t* payload, uint16_t length); | 98 | int vc_update_video_splitter_cycle(VCSession* vc, const uint8_t* payload, uint16_t length); |
99 | /* | ||
100 | * Iterate over splitted cycle. | ||
101 | */ | ||
82 | const uint8_t *vc_iterate_split_video_frame(VCSession* vc, uint16_t *size); | 102 | const uint8_t *vc_iterate_split_video_frame(VCSession* vc, uint16_t *size); |
103 | /* | ||
104 | * Queue new rtp message. | ||
105 | */ | ||
83 | int vc_queue_message(void *vcp, struct RTPMessage_s *msg); | 106 | int vc_queue_message(void *vcp, struct RTPMessage_s *msg); |
84 | int vc_reconfigure_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint16_t height); | 107 | /* |
85 | int vc_reconfigure_test_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint16_t height); | 108 | * Set new values to the encoders. |
109 | */ | ||
110 | int vc_reconfigure_encoder(VCSession* vc, int32_t bit_rate, uint16_t width, uint16_t height); | ||
111 | int 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 |