diff options
Diffstat (limited to 'toxav')
-rw-r--r-- | toxav/Makefile.inc | 1 | ||||
-rw-r--r-- | toxav/av_test.c | 270 | ||||
-rw-r--r-- | toxav/codec.c | 1 | ||||
-rw-r--r-- | toxav/msi.c | 2 | ||||
-rw-r--r-- | toxav/toxav_new_1.c | 688 | ||||
-rw-r--r-- | toxav/toxav_new_1.h | 329 |
6 files changed, 256 insertions, 1035 deletions
diff --git a/toxav/Makefile.inc b/toxav/Makefile.inc index 6458260d..b61c1ea0 100644 --- a/toxav/Makefile.inc +++ b/toxav/Makefile.inc | |||
@@ -49,6 +49,7 @@ av_test_LDADD = $(LIBSODIUM_LDFLAGS) \ | |||
49 | libtoxcore.la \ | 49 | libtoxcore.la \ |
50 | $(LIBSODIUM_LIBS) \ | 50 | $(LIBSODIUM_LIBS) \ |
51 | $(NACL_OBJECTS) \ | 51 | $(NACL_OBJECTS) \ |
52 | -lopenal \ | ||
52 | $(NACL_LIBS) | 53 | $(NACL_LIBS) |
53 | 54 | ||
54 | 55 | ||
diff --git a/toxav/av_test.c b/toxav/av_test.c index bb79eedc..01484249 100644 --- a/toxav/av_test.c +++ b/toxav/av_test.c | |||
@@ -1,6 +1,18 @@ | |||
1 | #include "toxav.h" | 1 | #include "toxav.h" |
2 | #include "../toxcore/tox.h" | 2 | #include "../toxcore/tox.h" |
3 | 3 | ||
4 | #ifdef __APPLE__ | ||
5 | # include <OpenAL/al.h> | ||
6 | # include <OpenAL/alc.h> | ||
7 | #else | ||
8 | # include <AL/al.h> | ||
9 | # include <AL/alc.h> | ||
10 | /* compatibility with older versions of OpenAL */ | ||
11 | # ifndef ALC_ALL_DEVICES_SPECIFIER | ||
12 | # include <AL/alext.h> | ||
13 | # endif /* ALC_ALL_DEVICES_SPECIFIER */ | ||
14 | #endif /* __APPLE__ */ | ||
15 | |||
4 | #include <assert.h> | 16 | #include <assert.h> |
5 | #include <stdio.h> | 17 | #include <stdio.h> |
6 | #include <stdlib.h> | 18 | #include <stdlib.h> |
@@ -14,6 +26,16 @@ | |||
14 | #define c_sleep(x) usleep(1000*x) | 26 | #define c_sleep(x) usleep(1000*x) |
15 | #endif | 27 | #endif |
16 | 28 | ||
29 | /* Enable/disable tests */ | ||
30 | #define TEST_REGULAR_AV 0 | ||
31 | #define TEST_REGULAR_A 0 | ||
32 | #define TEST_REGULAR_V 0 | ||
33 | #define TEST_REJECT 0 | ||
34 | #define TEST_CANCEL 0 | ||
35 | #define TEST_MUTE_UNMUTE 0 | ||
36 | #define TEST_TRANSFER_A 1 | ||
37 | |||
38 | |||
17 | typedef struct { | 39 | typedef struct { |
18 | bool incoming; | 40 | bool incoming; |
19 | uint32_t state; | 41 | uint32_t state; |
@@ -134,9 +156,201 @@ void iterate(Tox* Bsn, ToxAV* AliceAV, ToxAV* BobAV) | |||
134 | c_sleep(20); | 156 | c_sleep(20); |
135 | } | 157 | } |
136 | 158 | ||
159 | int device_read_frame(ALCdevice* device, int32_t frame_dur, int16_t* PCM, size_t max_size) | ||
160 | { | ||
161 | int f_size = (48000 * frame_dur / 1000); | ||
162 | |||
163 | if (max_size < f_size) | ||
164 | return -1; | ||
165 | |||
166 | /* Don't block if not enough data */ | ||
167 | int32_t samples; | ||
168 | alcGetIntegerv(device, ALC_CAPTURE_SAMPLES, sizeof(int32_t), &samples); | ||
169 | if (samples < f_size) | ||
170 | return 0; | ||
171 | |||
172 | alcCaptureSamples(device, PCM, f_size); | ||
173 | return f_size; | ||
174 | } | ||
175 | |||
176 | int device_play_frame(uint32_t source, int16_t* PCM, size_t size) | ||
177 | { | ||
178 | uint32_t bufid; | ||
179 | int32_t processed, queued; | ||
180 | alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed); | ||
181 | alGetSourcei(source, AL_BUFFERS_QUEUED, &queued); | ||
182 | |||
183 | if(processed) { | ||
184 | uint32_t bufids[processed]; | ||
185 | alSourceUnqueueBuffers(source, processed, bufids); | ||
186 | alDeleteBuffers(processed - 1, bufids + 1); | ||
187 | bufid = bufids[0]; | ||
188 | } | ||
189 | else if(queued < 16) | ||
190 | alGenBuffers(1, &bufid); | ||
191 | else | ||
192 | return 0; | ||
193 | |||
194 | |||
195 | alBufferData(bufid, AL_FORMAT_STEREO16, PCM, size * 2 * 2, 48000); | ||
196 | alSourceQueueBuffers(source, 1, &bufid); | ||
197 | |||
198 | int32_t state; | ||
199 | alGetSourcei(source, AL_SOURCE_STATE, &state); | ||
200 | |||
201 | if(state != AL_PLAYING) | ||
202 | alSourcePlay(source); | ||
203 | return 1; | ||
204 | } | ||
205 | |||
206 | int print_devices() | ||
207 | { | ||
208 | const char* default_input; | ||
209 | const char* default_output; | ||
210 | |||
211 | const char *device; | ||
212 | |||
213 | printf("Default input device: %s\n", alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER)); | ||
214 | printf("Default output device: %s\n", alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER)); | ||
215 | |||
216 | printf("\n"); | ||
217 | |||
218 | printf("Input devices:\n"); | ||
219 | |||
220 | int i = 0; | ||
221 | for(device = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); *device; | ||
222 | device += strlen( device ) + 1, ++i) { | ||
223 | printf("%d) %s\n", i, device); | ||
224 | } | ||
225 | |||
226 | printf("\n"); | ||
227 | printf("Output devices:\n"); | ||
228 | |||
229 | i = 0; | ||
230 | for(device = alcGetString(NULL, ALC_DEVICE_SPECIFIER); *device; | ||
231 | device += strlen( device ) + 1, ++i) { | ||
232 | printf("%d) %s\n", i, device); | ||
233 | } | ||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | int print_help(const char* name, int rc) | ||
239 | { | ||
240 | fprintf(stderr, "Usage: %s [-h] <in device> <out device>\n", name); | ||
241 | return rc; | ||
242 | } | ||
243 | |||
244 | long get_device_idx(const char* arg) | ||
245 | { | ||
246 | if (strcmp(arg, "-") == 0) | ||
247 | return -1; /* Default */ | ||
248 | |||
249 | char *p; | ||
250 | long res = strtol(arg, &p, 10); | ||
251 | |||
252 | if (*p) { | ||
253 | fprintf(stderr, "Invalid device!"); | ||
254 | exit(1); | ||
255 | } | ||
256 | |||
257 | return res; | ||
258 | } | ||
137 | 259 | ||
138 | int main (int argc, char** argv) | 260 | int main (int argc, char** argv) |
139 | { | 261 | { |
262 | if (argc == 2) { | ||
263 | if (strcmp(argv[1], "-d") == 0 || strcmp(argv[1], "--devices") == 0) { | ||
264 | return print_devices(); | ||
265 | } | ||
266 | if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) { | ||
267 | return print_help(argv[0], 0); | ||
268 | } | ||
269 | } | ||
270 | |||
271 | if (argc != 3) { | ||
272 | fprintf(stderr, "Invalid input!\n"); | ||
273 | return print_help(argv[0], 1); | ||
274 | } | ||
275 | |||
276 | int i; | ||
277 | |||
278 | const char* in_device_name = ""; | ||
279 | const char* out_device_name = ""; | ||
280 | |||
281 | { | ||
282 | long dev = get_device_idx(argv[1]); | ||
283 | if (dev == -1) | ||
284 | in_device_name = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); | ||
285 | else | ||
286 | { | ||
287 | const char* tmp; | ||
288 | i = -1; | ||
289 | for(tmp = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); *tmp && i != dev; | ||
290 | tmp += strlen( tmp ) + 1, ++i) | ||
291 | in_device_name = tmp; | ||
292 | } | ||
293 | |||
294 | printf("Input device: %s\n", in_device_name); | ||
295 | } | ||
296 | |||
297 | { | ||
298 | long dev = get_device_idx(argv[1]); | ||
299 | if (dev == -1) | ||
300 | out_device_name = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); | ||
301 | else | ||
302 | { | ||
303 | const char* tmp; | ||
304 | i = -1; | ||
305 | for(tmp = alcGetString(NULL, ALC_DEVICE_SPECIFIER); *tmp && i != dev; | ||
306 | tmp += strlen( tmp ) + 1, ++i) | ||
307 | out_device_name = tmp; | ||
308 | } | ||
309 | |||
310 | printf("Output device: %s\n", out_device_name); | ||
311 | } | ||
312 | |||
313 | ALCdevice* out_device; | ||
314 | ALCcontext* out_ctx; | ||
315 | uint32_t source; | ||
316 | uint32_t buffers[5]; | ||
317 | |||
318 | { /* Open output device */ | ||
319 | out_device = alcOpenDevice(out_device_name); | ||
320 | if ( !out_device ) { | ||
321 | fprintf(stderr, "Failed to open playback device: %s: %d\n", out_device_name, alGetError()); | ||
322 | return 1; | ||
323 | } | ||
324 | |||
325 | out_ctx = alcCreateContext(out_device, NULL); | ||
326 | alcMakeContextCurrent(out_ctx); | ||
327 | |||
328 | alGenBuffers(5, buffers); | ||
329 | alGenSources((uint32_t)1, &source); | ||
330 | alSourcei(source, AL_LOOPING, AL_FALSE); | ||
331 | |||
332 | uint16_t zeros[10000]; | ||
333 | memset(zeros, 0, 10000); | ||
334 | |||
335 | for ( i = 0; i < 5; ++i ) | ||
336 | alBufferData(buffers[i], AL_FORMAT_STEREO16, zeros, 10000, 48000); | ||
337 | |||
338 | alSourceQueueBuffers(source, 5, buffers); | ||
339 | alSourcePlay(source); | ||
340 | } | ||
341 | |||
342 | ALCdevice* in_device; | ||
343 | |||
344 | { /* Open input device */ | ||
345 | in_device = alcCaptureOpenDevice(in_device_name, 48000, AL_FORMAT_STEREO16, 10000); | ||
346 | if ( !in_device ) { | ||
347 | fprintf(stderr, "Failed to open capture device: %s: %d\n", in_device_name, alGetError()); | ||
348 | return 1; | ||
349 | } | ||
350 | |||
351 | alcCaptureStart(in_device); | ||
352 | } | ||
353 | |||
140 | Tox *Bsn = tox_new(0); | 354 | Tox *Bsn = tox_new(0); |
141 | Tox *Alice = tox_new(0); | 355 | Tox *Alice = tox_new(0); |
142 | Tox *Bob = tox_new(0); | 356 | Tox *Bob = tox_new(0); |
@@ -163,7 +377,7 @@ int main (int argc, char** argv) | |||
163 | 377 | ||
164 | 378 | ||
165 | #define REGULAR_CALL_FLOW(A_BR, V_BR) \ | 379 | #define REGULAR_CALL_FLOW(A_BR, V_BR) \ |
166 | { \ | 380 | do { \ |
167 | memset(&AliceCC, 0, sizeof(CallControl)); \ | 381 | memset(&AliceCC, 0, sizeof(CallControl)); \ |
168 | memset(&BobCC, 0, sizeof(CallControl)); \ | 382 | memset(&BobCC, 0, sizeof(CallControl)); \ |
169 | \ | 383 | \ |
@@ -208,20 +422,26 @@ int main (int argc, char** argv) | |||
208 | iterate(Bsn, AliceAV, BobAV); \ | 422 | iterate(Bsn, AliceAV, BobAV); \ |
209 | } \ | 423 | } \ |
210 | printf("Success!\n");\ | 424 | printf("Success!\n");\ |
211 | } | 425 | } while(0) |
212 | |||
213 | printf("\nTrying regular call (Audio and Video)...\n"); | ||
214 | REGULAR_CALL_FLOW(48, 4000); | ||
215 | |||
216 | printf("\nTrying regular call (Audio only)...\n"); | ||
217 | REGULAR_CALL_FLOW(48, 0); | ||
218 | |||
219 | printf("\nTrying regular call (Video only)...\n"); | ||
220 | REGULAR_CALL_FLOW(0, 4000); | ||
221 | 426 | ||
427 | if (TEST_REGULAR_AV) { | ||
428 | printf("\nTrying regular call (Audio and Video)...\n"); | ||
429 | REGULAR_CALL_FLOW(48, 4000); | ||
430 | } | ||
431 | |||
432 | if (TEST_REGULAR_A) { | ||
433 | printf("\nTrying regular call (Audio only)...\n"); | ||
434 | REGULAR_CALL_FLOW(48, 0); | ||
435 | } | ||
436 | |||
437 | if (TEST_REGULAR_V) { | ||
438 | printf("\nTrying regular call (Video only)...\n"); | ||
439 | REGULAR_CALL_FLOW(0, 4000); | ||
440 | } | ||
441 | |||
222 | #undef REGULAR_CALL_FLOW | 442 | #undef REGULAR_CALL_FLOW |
223 | 443 | ||
224 | { /* Alice calls; Bob rejects */ | 444 | if (TEST_REJECT) { /* Alice calls; Bob rejects */ |
225 | printf("\nTrying reject flow...\n"); | 445 | printf("\nTrying reject flow...\n"); |
226 | 446 | ||
227 | memset(&AliceCC, 0, sizeof(CallControl)); | 447 | memset(&AliceCC, 0, sizeof(CallControl)); |
@@ -257,7 +477,7 @@ int main (int argc, char** argv) | |||
257 | printf("Success!\n"); | 477 | printf("Success!\n"); |
258 | } | 478 | } |
259 | 479 | ||
260 | { /* Alice calls; Alice cancels while ringing */ | 480 | if (TEST_CANCEL) { /* Alice calls; Alice cancels while ringing */ |
261 | printf("\nTrying cancel (while ringing) flow...\n"); | 481 | printf("\nTrying cancel (while ringing) flow...\n"); |
262 | 482 | ||
263 | memset(&AliceCC, 0, sizeof(CallControl)); | 483 | memset(&AliceCC, 0, sizeof(CallControl)); |
@@ -294,10 +514,9 @@ int main (int argc, char** argv) | |||
294 | printf("Success!\n"); | 514 | printf("Success!\n"); |
295 | } | 515 | } |
296 | 516 | ||
297 | { /* Check Mute-Unmute etc */ | 517 | if (TEST_MUTE_UNMUTE) { /* Check Mute-Unmute etc */ |
298 | printf("\nTrying mute functionality...\n"); | 518 | printf("\nTrying mute functionality...\n"); |
299 | 519 | ||
300 | |||
301 | memset(&AliceCC, 0, sizeof(CallControl)); | 520 | memset(&AliceCC, 0, sizeof(CallControl)); |
302 | memset(&BobCC, 0, sizeof(CallControl)); | 521 | memset(&BobCC, 0, sizeof(CallControl)); |
303 | 522 | ||
@@ -382,7 +601,23 @@ int main (int argc, char** argv) | |||
382 | printf("Success!\n"); | 601 | printf("Success!\n"); |
383 | } | 602 | } |
384 | 603 | ||
385 | 604 | if (TEST_TRANSFER_A) { /* Audio encoding/decoding and transfer */ | |
605 | printf("\nTrying audio enc/dec...\n"); | ||
606 | |||
607 | int16_t PCM[10000]; | ||
608 | time_t start_time = time(NULL); | ||
609 | |||
610 | /* Run for 5 seconds */ | ||
611 | while ( start_time + 10 > time(NULL) ) { | ||
612 | int frame_size = device_read_frame(in_device, 20, PCM, sizeof(PCM)); | ||
613 | if (frame_size > 0) | ||
614 | device_play_frame(source, PCM, frame_size); | ||
615 | // c_sleep(20); | ||
616 | } | ||
617 | |||
618 | printf("Success!"); | ||
619 | } | ||
620 | |||
386 | toxav_kill(BobAV); | 621 | toxav_kill(BobAV); |
387 | toxav_kill(AliceAV); | 622 | toxav_kill(AliceAV); |
388 | tox_kill(Bob); | 623 | tox_kill(Bob); |
@@ -390,5 +625,8 @@ int main (int argc, char** argv) | |||
390 | tox_kill(Bsn); | 625 | tox_kill(Bsn); |
391 | 626 | ||
392 | printf("\nTest successful!\n"); | 627 | printf("\nTest successful!\n"); |
628 | |||
629 | alcCloseDevice(out_device); | ||
630 | alcCaptureCloseDevice(in_device); | ||
393 | return 0; | 631 | return 0; |
394 | } \ No newline at end of file | 632 | } \ No newline at end of file |
diff --git a/toxav/codec.c b/toxav/codec.c index 95e0beb4..bf94115e 100644 --- a/toxav/codec.c +++ b/toxav/codec.c | |||
@@ -41,7 +41,6 @@ | |||
41 | #define DEFAULT_JBUF 6 | 41 | #define DEFAULT_JBUF 6 |
42 | 42 | ||
43 | /* Good quality encode. */ | 43 | /* Good quality encode. */ |
44 | #define MAX_ENCODE_TIME_US VPX_DL_GOOD_QUALITY | ||
45 | #define MAX_DECODE_TIME_US 0 | 44 | #define MAX_DECODE_TIME_US 0 |
46 | 45 | ||
47 | #define MAX_VIDEOFRAME_SIZE 0x40000 /* 256KiB */ | 46 | #define MAX_VIDEOFRAME_SIZE 0x40000 /* 256KiB */ |
diff --git a/toxav/msi.c b/toxav/msi.c index ac900dac..e21ec948 100644 --- a/toxav/msi.c +++ b/toxav/msi.c | |||
@@ -783,4 +783,4 @@ void handle_msi_packet ( Messenger *m, int friend_id, const uint8_t *data, uint1 | |||
783 | handle_pop(call, &msg); /* always kills the call */ | 783 | handle_pop(call, &msg); /* always kills the call */ |
784 | 784 | ||
785 | pthread_mutex_unlock(session->mutex); | 785 | pthread_mutex_unlock(session->mutex); |
786 | } \ No newline at end of file | 786 | } |
diff --git a/toxav/toxav_new_1.c b/toxav/toxav_new_1.c deleted file mode 100644 index 145dcf48..00000000 --- a/toxav/toxav_new_1.c +++ /dev/null | |||
@@ -1,688 +0,0 @@ | |||
1 | /** toxav.c | ||
2 | * | ||
3 | * Copyright (C) 2013 Tox project All Rights Reserved. | ||
4 | * | ||
5 | * This file is part of Tox. | ||
6 | * | ||
7 | * Tox is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation, either version 3 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * Tox is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifdef HAVE_CONFIG_H | ||
23 | #include "config.h" | ||
24 | #endif /* HAVE_CONFIG_H */ | ||
25 | |||
26 | #define __TOX_DEFINED__ | ||
27 | typedef struct Messenger Tox; | ||
28 | |||
29 | #define _GNU_SOURCE /* implicit declaration warning */ | ||
30 | |||
31 | #include "codec.h" | ||
32 | #include "msi.h" | ||
33 | #include "group.h" | ||
34 | |||
35 | #include "../toxcore/logger.h" | ||
36 | #include "../toxcore/util.h" | ||
37 | |||
38 | #include <assert.h> | ||
39 | #include <stdlib.h> | ||
40 | #include <string.h> | ||
41 | |||
42 | /* Assume 24 fps*/ | ||
43 | #define MAX_ENCODE_TIME_US ((1000 / 24) * 1000) | ||
44 | |||
45 | /* true if invalid call index */ | ||
46 | #define CALL_INVALID_INDEX(idx, max) (idx < 0 || idx >= max) | ||
47 | |||
48 | const ToxAvCSettings av_DefaultSettings = { | ||
49 | av_TypeAudio, | ||
50 | |||
51 | 500, | ||
52 | 1280, | ||
53 | 720, | ||
54 | |||
55 | 32000, | ||
56 | 20, | ||
57 | 48000, | ||
58 | 1 | ||
59 | }; | ||
60 | |||
61 | static const uint32_t jbuf_capacity = 6; | ||
62 | static const uint8_t audio_index = 0, video_index = 1; | ||
63 | |||
64 | typedef struct _ToxAvCall { | ||
65 | pthread_mutex_t mutex_control[1]; | ||
66 | pthread_mutex_t mutex_encoding_audio[1]; | ||
67 | pthread_mutex_t mutex_encoding_video[1]; | ||
68 | pthread_mutex_t mutex_do[1]; | ||
69 | RTPSession *crtps[2]; /** Audio is first and video is second */ | ||
70 | CSSession *cs; | ||
71 | _Bool active; | ||
72 | } ToxAvCall; | ||
73 | |||
74 | struct _ToxAv { | ||
75 | Messenger *messenger; | ||
76 | MSISession *msi_session; /** Main msi session */ | ||
77 | ToxAvCall *calls; /** Per-call params */ | ||
78 | uint32_t max_calls; | ||
79 | |||
80 | PAIR(ToxAvAudioCallback, void *) acb; | ||
81 | PAIR(ToxAvVideoCallback, void *) vcb; | ||
82 | |||
83 | /* Decode time measure */ | ||
84 | int32_t dectmsscount; /** Measure count */ | ||
85 | int32_t dectmsstotal; /** Last cycle total */ | ||
86 | int32_t avgdectms; /** Average decoding time in ms */ | ||
87 | }; | ||
88 | |||
89 | static const MSICSettings *msicsettings_cast (const ToxAvCSettings *from) | ||
90 | { | ||
91 | assert(sizeof(MSICSettings) == sizeof(ToxAvCSettings)); | ||
92 | return (const MSICSettings *) from; | ||
93 | } | ||
94 | |||
95 | static const ToxAvCSettings *toxavcsettings_cast (const MSICSettings *from) | ||
96 | { | ||
97 | assert(sizeof(MSICSettings) == sizeof(ToxAvCSettings)); | ||
98 | return (const ToxAvCSettings *) from; | ||
99 | |||
100 | } | ||
101 | |||
102 | ToxAv *toxav_new( Tox *messenger, int32_t max_calls) | ||
103 | { | ||
104 | ToxAv *av = calloc ( sizeof(ToxAv), 1); | ||
105 | |||
106 | if (av == NULL) { | ||
107 | LOGGER_WARNING("Allocation failed!"); | ||
108 | return NULL; | ||
109 | } | ||
110 | |||
111 | av->messenger = (Messenger *)messenger; | ||
112 | av->msi_session = msi_new(av->messenger, max_calls); | ||
113 | av->msi_session->agent_handler = av; | ||
114 | av->calls = calloc(sizeof(ToxAvCall), max_calls); | ||
115 | av->max_calls = max_calls; | ||
116 | |||
117 | unsigned int i; | ||
118 | |||
119 | for (i = 0; i < max_calls; ++i) { | ||
120 | if (create_recursive_mutex(av->calls[i].mutex_control) != 0 ) { | ||
121 | LOGGER_WARNING("Failed to init call(%u) mutex!", i); | ||
122 | msi_kill(av->msi_session); | ||
123 | |||
124 | free(av->calls); | ||
125 | free(av); | ||
126 | return NULL; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | return av; | ||
131 | } | ||
132 | |||
133 | void toxav_kill ( ToxAv *av ) | ||
134 | { | ||
135 | uint32_t i; | ||
136 | |||
137 | for (i = 0; i < av->max_calls; i ++) { | ||
138 | if ( av->calls[i].crtps[audio_index] ) | ||
139 | rtp_kill(av->calls[i].crtps[audio_index], av->msi_session->messenger_handle); | ||
140 | |||
141 | |||
142 | if ( av->calls[i].crtps[video_index] ) | ||
143 | rtp_kill(av->calls[i].crtps[video_index], av->msi_session->messenger_handle); | ||
144 | |||
145 | if ( av->calls[i].cs ) | ||
146 | cs_kill(av->calls[i].cs); | ||
147 | |||
148 | pthread_mutex_destroy(av->calls[i].mutex_control); | ||
149 | } | ||
150 | |||
151 | msi_kill(av->msi_session); | ||
152 | |||
153 | free(av->calls); | ||
154 | free(av); | ||
155 | } | ||
156 | |||
157 | uint32_t toxav_do_interval(ToxAv *av) | ||
158 | { | ||
159 | int i = 0; | ||
160 | uint32_t rc = 200 + av->avgdectms; /* Return 200 if no call is active */ | ||
161 | |||
162 | for (; i < av->max_calls; i ++) { | ||
163 | pthread_mutex_lock(av->calls[i].mutex_control); | ||
164 | |||
165 | if (av->calls[i].active) { | ||
166 | /* This should work. Video payload will always come in greater intervals */ | ||
167 | rc = MIN(av->calls[i].cs->audio_decoder_frame_duration, rc); | ||
168 | } | ||
169 | |||
170 | pthread_mutex_unlock(av->calls[i].mutex_control); | ||
171 | } | ||
172 | |||
173 | return rc < av->avgdectms ? 0 : rc - av->avgdectms; | ||
174 | } | ||
175 | |||
176 | void toxav_do(ToxAv *av) | ||
177 | { | ||
178 | msi_do(av->msi_session); | ||
179 | |||
180 | uint64_t start = current_time_monotonic(); | ||
181 | |||
182 | uint32_t i = 0; | ||
183 | |||
184 | for (; i < av->max_calls; i ++) { | ||
185 | pthread_mutex_lock(av->calls[i].mutex_control); | ||
186 | |||
187 | if (av->calls[i].active) { | ||
188 | pthread_mutex_lock(av->calls[i].mutex_do); | ||
189 | pthread_mutex_unlock(av->calls[i].mutex_control); | ||
190 | cs_do(av->calls[i].cs); | ||
191 | pthread_mutex_unlock(av->calls[i].mutex_do); | ||
192 | } else { | ||
193 | pthread_mutex_unlock(av->calls[i].mutex_control); | ||
194 | } | ||
195 | } | ||
196 | |||
197 | uint64_t end = current_time_monotonic(); | ||
198 | |||
199 | /* TODO maybe use variable for sizes */ | ||
200 | av->dectmsstotal += end - start; | ||
201 | |||
202 | if (++av->dectmsscount == 3) { | ||
203 | av->avgdectms = av->dectmsstotal / 3 + 2 /* NOTE Magic Offset */; | ||
204 | av->dectmsscount = 0; | ||
205 | av->dectmsstotal = 0; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | void toxav_register_callstate_callback ( ToxAv *av, ToxAVCallback cb, ToxAvCallbackID id, void *userdata ) | ||
210 | { | ||
211 | msi_register_callback(av->msi_session, (MSICallbackType)cb, (MSICallbackID) id, userdata); | ||
212 | } | ||
213 | |||
214 | void toxav_register_audio_callback(ToxAv *av, ToxAvAudioCallback cb, void *userdata) | ||
215 | { | ||
216 | av->acb.first = cb; | ||
217 | av->acb.second = userdata; | ||
218 | } | ||
219 | |||
220 | void toxav_register_video_callback(ToxAv *av, ToxAvVideoCallback cb, void *userdata) | ||
221 | { | ||
222 | av->vcb.first = cb; | ||
223 | av->vcb.second = userdata; | ||
224 | } | ||
225 | |||
226 | int toxav_call (ToxAv *av, | ||
227 | int32_t *call_index, | ||
228 | int user, | ||
229 | const ToxAvCSettings *csettings, | ||
230 | int ringing_seconds ) | ||
231 | { | ||
232 | return msi_invite(av->msi_session, call_index, msicsettings_cast(csettings), ringing_seconds * 1000, user); | ||
233 | } | ||
234 | |||
235 | int toxav_hangup ( ToxAv *av, int32_t call_index ) | ||
236 | { | ||
237 | return msi_hangup(av->msi_session, call_index); | ||
238 | } | ||
239 | |||
240 | int toxav_answer ( ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings ) | ||
241 | { | ||
242 | return msi_answer(av->msi_session, call_index, msicsettings_cast(csettings)); | ||
243 | } | ||
244 | |||
245 | int toxav_reject ( ToxAv *av, int32_t call_index, const char *reason ) | ||
246 | { | ||
247 | return msi_reject(av->msi_session, call_index, reason); | ||
248 | } | ||
249 | |||
250 | int toxav_cancel ( ToxAv *av, int32_t call_index, int peer_id, const char *reason ) | ||
251 | { | ||
252 | return msi_cancel(av->msi_session, call_index, peer_id, reason); | ||
253 | } | ||
254 | |||
255 | int toxav_change_settings(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings) | ||
256 | { | ||
257 | return msi_change_csettings(av->msi_session, call_index, msicsettings_cast(csettings)); | ||
258 | } | ||
259 | |||
260 | int toxav_stop_call ( ToxAv *av, int32_t call_index ) | ||
261 | { | ||
262 | return msi_stopcall(av->msi_session, call_index); | ||
263 | } | ||
264 | |||
265 | int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, int support_video ) | ||
266 | { | ||
267 | if ( !av->msi_session || CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) || | ||
268 | !av->msi_session->calls[call_index] || !av->msi_session->calls[call_index]->csettings_peer) { | ||
269 | LOGGER_ERROR("Error while starting RTP session: invalid call!\n"); | ||
270 | return av_ErrorNoCall; | ||
271 | } | ||
272 | |||
273 | ToxAvCall *call = &av->calls[call_index]; | ||
274 | |||
275 | pthread_mutex_lock(call->mutex_control); | ||
276 | |||
277 | if (call->active) { | ||
278 | pthread_mutex_unlock(call->mutex_control); | ||
279 | LOGGER_ERROR("Error while starting RTP session: call already active!\n"); | ||
280 | return av_ErrorAlreadyInCallWithPeer; | ||
281 | } | ||
282 | |||
283 | if (pthread_mutex_init(call->mutex_encoding_audio, NULL) != 0 | ||
284 | || pthread_mutex_init(call->mutex_encoding_video, NULL) != 0 || pthread_mutex_init(call->mutex_do, NULL) != 0) { | ||
285 | pthread_mutex_unlock(call->mutex_control); | ||
286 | LOGGER_ERROR("Error while starting RTP session: mutex initializing failed!\n"); | ||
287 | return av_ErrorUnknown; | ||
288 | } | ||
289 | |||
290 | const ToxAvCSettings *c_peer = toxavcsettings_cast | ||
291 | (&av->msi_session->calls[call_index]->csettings_peer[0]); | ||
292 | const ToxAvCSettings *c_self = toxavcsettings_cast | ||
293 | (&av->msi_session->calls[call_index]->csettings_local); | ||
294 | |||
295 | LOGGER_DEBUG( | ||
296 | "Type: %u(s) %u(p)\n" | ||
297 | "Video bitrate: %u(s) %u(p)\n" | ||
298 | "Video height: %u(s) %u(p)\n" | ||
299 | "Video width: %u(s) %u(p)\n" | ||
300 | "Audio bitrate: %u(s) %u(p)\n" | ||
301 | "Audio framedur: %u(s) %u(p)\n" | ||
302 | "Audio sample rate: %u(s) %u(p)\n" | ||
303 | "Audio channels: %u(s) %u(p)\n", | ||
304 | c_self->call_type, c_peer->call_type, | ||
305 | c_self->video_bitrate, c_peer->video_bitrate, | ||
306 | c_self->max_video_height, c_peer->max_video_height, | ||
307 | c_self->max_video_width, c_peer->max_video_width, | ||
308 | c_self->audio_bitrate, c_peer->audio_bitrate, | ||
309 | c_self->audio_frame_duration, c_peer->audio_frame_duration, | ||
310 | c_self->audio_sample_rate, c_peer->audio_sample_rate, | ||
311 | c_self->audio_channels, c_peer->audio_channels ); | ||
312 | |||
313 | if ( !(call->cs = cs_new(c_self, c_peer, jbuf_capacity, support_video)) ) { | ||
314 | LOGGER_ERROR("Error while starting Codec State!\n"); | ||
315 | pthread_mutex_unlock(call->mutex_control); | ||
316 | return av_ErrorInitializingCodecs; | ||
317 | } | ||
318 | |||
319 | call->cs->agent = av; | ||
320 | |||
321 | call->cs->acb.first = av->acb.first; | ||
322 | call->cs->acb.second = av->acb.second; | ||
323 | |||
324 | call->cs->vcb.first = av->vcb.first; | ||
325 | call->cs->vcb.second = av->vcb.second; | ||
326 | |||
327 | |||
328 | call->crtps[audio_index] = | ||
329 | rtp_new(msi_TypeAudio, av->messenger, av->msi_session->calls[call_index]->peers[0]); | ||
330 | |||
331 | if ( !call->crtps[audio_index] ) { | ||
332 | LOGGER_ERROR("Error while starting audio RTP session!\n"); | ||
333 | goto error; | ||
334 | } | ||
335 | |||
336 | call->crtps[audio_index]->cs = call->cs; | ||
337 | |||
338 | if ( support_video ) { | ||
339 | call->crtps[video_index] = | ||
340 | rtp_new(msi_TypeVideo, av->messenger, av->msi_session->calls[call_index]->peers[0]); | ||
341 | |||
342 | if ( !call->crtps[video_index] ) { | ||
343 | LOGGER_ERROR("Error while starting video RTP session!\n"); | ||
344 | goto error; | ||
345 | } | ||
346 | |||
347 | call->crtps[video_index]->cs = call->cs; | ||
348 | } | ||
349 | |||
350 | call->active = 1; | ||
351 | pthread_mutex_unlock(call->mutex_control); | ||
352 | return av_ErrorNone; | ||
353 | error: | ||
354 | rtp_kill(call->crtps[audio_index], av->messenger); | ||
355 | call->crtps[audio_index] = NULL; | ||
356 | rtp_kill(call->crtps[video_index], av->messenger); | ||
357 | call->crtps[video_index] = NULL; | ||
358 | cs_kill(call->cs); | ||
359 | call->cs = NULL; | ||
360 | call->active = 0; | ||
361 | pthread_mutex_destroy(call->mutex_encoding_audio); | ||
362 | pthread_mutex_destroy(call->mutex_encoding_video); | ||
363 | pthread_mutex_destroy(call->mutex_do); | ||
364 | |||
365 | pthread_mutex_unlock(call->mutex_control); | ||
366 | return av_ErrorCreatingRtpSessions; | ||
367 | } | ||
368 | |||
369 | int toxav_kill_transmission ( ToxAv *av, int32_t call_index ) | ||
370 | { | ||
371 | if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) { | ||
372 | LOGGER_WARNING("Invalid call index: %d", call_index); | ||
373 | return av_ErrorNoCall; | ||
374 | } | ||
375 | |||
376 | ToxAvCall *call = &av->calls[call_index]; | ||
377 | |||
378 | pthread_mutex_lock(call->mutex_control); | ||
379 | |||
380 | if (!call->active) { | ||
381 | pthread_mutex_unlock(call->mutex_control); | ||
382 | LOGGER_WARNING("Action on inactive call: %d", call_index); | ||
383 | return av_ErrorInvalidState; | ||
384 | } | ||
385 | |||
386 | call->active = 0; | ||
387 | |||
388 | pthread_mutex_lock(call->mutex_encoding_audio); | ||
389 | pthread_mutex_unlock(call->mutex_encoding_audio); | ||
390 | pthread_mutex_lock(call->mutex_encoding_video); | ||
391 | pthread_mutex_unlock(call->mutex_encoding_video); | ||
392 | pthread_mutex_lock(call->mutex_do); | ||
393 | pthread_mutex_unlock(call->mutex_do); | ||
394 | |||
395 | rtp_kill(call->crtps[audio_index], av->messenger); | ||
396 | call->crtps[audio_index] = NULL; | ||
397 | rtp_kill(call->crtps[video_index], av->messenger); | ||
398 | call->crtps[video_index] = NULL; | ||
399 | cs_kill(call->cs); | ||
400 | call->cs = NULL; | ||
401 | |||
402 | pthread_mutex_destroy(call->mutex_encoding_audio); | ||
403 | pthread_mutex_destroy(call->mutex_encoding_video); | ||
404 | pthread_mutex_destroy(call->mutex_do); | ||
405 | |||
406 | pthread_mutex_unlock(call->mutex_control); | ||
407 | |||
408 | return av_ErrorNone; | ||
409 | } | ||
410 | |||
411 | static int toxav_send_rtp_payload(ToxAv *av, | ||
412 | ToxAvCall *call, | ||
413 | ToxAvCallType type, | ||
414 | const uint8_t *payload, | ||
415 | unsigned int length) | ||
416 | { | ||
417 | if (call->crtps[type - av_TypeAudio]) { | ||
418 | |||
419 | /* Audio */ | ||
420 | if (type == av_TypeAudio) | ||
421 | return rtp_send_msg(call->crtps[audio_index], av->messenger, payload, length); | ||
422 | |||
423 | /* Video */ | ||
424 | int parts = cs_split_video_payload(call->cs, payload, length); | ||
425 | |||
426 | if (parts < 0) return parts; | ||
427 | |||
428 | uint16_t part_size; | ||
429 | const uint8_t *iter; | ||
430 | |||
431 | int i; | ||
432 | |||
433 | for (i = 0; i < parts; i++) { | ||
434 | iter = cs_iterate_split_video_frame(call->cs, &part_size); | ||
435 | |||
436 | if (rtp_send_msg(call->crtps[video_index], av->messenger, iter, part_size) < 0) | ||
437 | return av_ErrorSendingPayload; | ||
438 | } | ||
439 | |||
440 | return av_ErrorNone; | ||
441 | |||
442 | } else return av_ErrorNoRtpSession; | ||
443 | } | ||
444 | |||
445 | int toxav_prepare_video_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input) | ||
446 | { | ||
447 | if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) { | ||
448 | LOGGER_WARNING("Invalid call index: %d", call_index); | ||
449 | return av_ErrorNoCall; | ||
450 | } | ||
451 | |||
452 | |||
453 | ToxAvCall *call = &av->calls[call_index]; | ||
454 | pthread_mutex_lock(call->mutex_control); | ||
455 | |||
456 | if (!call->active) { | ||
457 | pthread_mutex_unlock(call->mutex_control); | ||
458 | LOGGER_WARNING("Action on inactive call: %d", call_index); | ||
459 | return av_ErrorInvalidState; | ||
460 | } | ||
461 | |||
462 | if (cs_set_sending_video_resolution(call->cs, input->d_w, input->d_h) < 0) { | ||
463 | pthread_mutex_unlock(call->mutex_control); | ||
464 | return av_ErrorSettingVideoResolution; | ||
465 | } | ||
466 | |||
467 | pthread_mutex_lock(call->mutex_encoding_video); | ||
468 | pthread_mutex_unlock(call->mutex_control); | ||
469 | |||
470 | int rc = vpx_codec_encode(call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US); | ||
471 | |||
472 | if ( rc != VPX_CODEC_OK) { | ||
473 | LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(rc)); | ||
474 | pthread_mutex_unlock(call->mutex_encoding_video); | ||
475 | return av_ErrorEncodingVideo; | ||
476 | } | ||
477 | |||
478 | ++call->cs->frame_counter; | ||
479 | |||
480 | vpx_codec_iter_t iter = NULL; | ||
481 | const vpx_codec_cx_pkt_t *pkt; | ||
482 | int copied = 0; | ||
483 | |||
484 | while ( (pkt = vpx_codec_get_cx_data(call->cs->v_encoder, &iter)) ) { | ||
485 | if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { | ||
486 | if ( copied + pkt->data.frame.sz > dest_max ) { | ||
487 | pthread_mutex_unlock(call->mutex_encoding_video); | ||
488 | return av_ErrorPacketTooLarge; | ||
489 | } | ||
490 | |||
491 | memcpy(dest + copied, pkt->data.frame.buf, pkt->data.frame.sz); | ||
492 | copied += pkt->data.frame.sz; | ||
493 | } | ||
494 | } | ||
495 | |||
496 | pthread_mutex_unlock(call->mutex_encoding_video); | ||
497 | return copied; | ||
498 | } | ||
499 | |||
500 | int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int frame_size) | ||
501 | { | ||
502 | |||
503 | if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) { | ||
504 | LOGGER_WARNING("Invalid call index: %d", call_index); | ||
505 | return av_ErrorNoCall; | ||
506 | } | ||
507 | |||
508 | ToxAvCall *call = &av->calls[call_index]; | ||
509 | pthread_mutex_lock(call->mutex_control); | ||
510 | |||
511 | |||
512 | if (!call->active) { | ||
513 | pthread_mutex_unlock(call->mutex_control); | ||
514 | LOGGER_WARNING("Action on inactive call: %d", call_index); | ||
515 | return av_ErrorInvalidState; | ||
516 | } | ||
517 | |||
518 | int rc = toxav_send_rtp_payload(av, call, av_TypeVideo, frame, frame_size); | ||
519 | pthread_mutex_unlock(call->mutex_control); | ||
520 | |||
521 | return rc; | ||
522 | } | ||
523 | |||
524 | int toxav_prepare_audio_frame ( ToxAv *av, | ||
525 | int32_t call_index, | ||
526 | uint8_t *dest, | ||
527 | int dest_max, | ||
528 | const int16_t *frame, | ||
529 | int frame_size) | ||
530 | { | ||
531 | if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) { | ||
532 | LOGGER_WARNING("Action on nonexisting call: %d", call_index); | ||
533 | return av_ErrorNoCall; | ||
534 | } | ||
535 | |||
536 | ToxAvCall *call = &av->calls[call_index]; | ||
537 | pthread_mutex_lock(call->mutex_control); | ||
538 | |||
539 | if (!call->active) { | ||
540 | pthread_mutex_unlock(call->mutex_control); | ||
541 | LOGGER_WARNING("Action on inactive call: %d", call_index); | ||
542 | return av_ErrorInvalidState; | ||
543 | } | ||
544 | |||
545 | pthread_mutex_lock(call->mutex_encoding_audio); | ||
546 | pthread_mutex_unlock(call->mutex_control); | ||
547 | int32_t rc = opus_encode(call->cs->audio_encoder, frame, frame_size, dest, dest_max); | ||
548 | pthread_mutex_unlock(call->mutex_encoding_audio); | ||
549 | |||
550 | if (rc < 0) { | ||
551 | LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc)); | ||
552 | return av_ErrorEncodingAudio; | ||
553 | } | ||
554 | |||
555 | return rc; | ||
556 | } | ||
557 | |||
558 | int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *data, unsigned int size) | ||
559 | { | ||
560 | if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) { | ||
561 | LOGGER_WARNING("Action on nonexisting call: %d", call_index); | ||
562 | return av_ErrorNoCall; | ||
563 | } | ||
564 | |||
565 | ToxAvCall *call = &av->calls[call_index]; | ||
566 | pthread_mutex_lock(call->mutex_control); | ||
567 | |||
568 | |||
569 | if (!call->active) { | ||
570 | pthread_mutex_unlock(call->mutex_control); | ||
571 | LOGGER_WARNING("Action on inactive call: %d", call_index); | ||
572 | return av_ErrorInvalidState; | ||
573 | } | ||
574 | |||
575 | int rc = toxav_send_rtp_payload(av, call, av_TypeAudio, data, size); | ||
576 | pthread_mutex_unlock(call->mutex_control); | ||
577 | return rc; | ||
578 | } | ||
579 | |||
580 | int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSettings *dest ) | ||
581 | { | ||
582 | if ( peer < 0 || CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) || | ||
583 | !av->msi_session->calls[call_index] || av->msi_session->calls[call_index]->peer_count <= peer ) | ||
584 | return av_ErrorNoCall; | ||
585 | |||
586 | *dest = *toxavcsettings_cast(&av->msi_session->calls[call_index]->csettings_peer[peer]); | ||
587 | return av_ErrorNone; | ||
588 | } | ||
589 | |||
590 | int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer ) | ||
591 | { | ||
592 | if ( peer < 0 || CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) || !av->msi_session->calls[call_index] | ||
593 | || av->msi_session->calls[call_index]->peer_count <= peer ) | ||
594 | return av_ErrorNoCall; | ||
595 | |||
596 | return av->msi_session->calls[call_index]->peers[peer]; | ||
597 | } | ||
598 | |||
599 | ToxAvCallState toxav_get_call_state(ToxAv *av, int32_t call_index) | ||
600 | { | ||
601 | if ( CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) || !av->msi_session->calls[call_index] ) | ||
602 | return av_CallNonExistent; | ||
603 | |||
604 | return av->msi_session->calls[call_index]->state; | ||
605 | |||
606 | } | ||
607 | |||
608 | int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability ) | ||
609 | { | ||
610 | } | ||
611 | |||
612 | Tox *toxav_get_tox(ToxAv *av) | ||
613 | { | ||
614 | return (Tox *)av->messenger; | ||
615 | } | ||
616 | |||
617 | int toxav_get_active_count(ToxAv *av) | ||
618 | { | ||
619 | if (!av) return -1; | ||
620 | |||
621 | int rc = 0, i = 0; | ||
622 | |||
623 | for (; i < av->max_calls; i++) { | ||
624 | pthread_mutex_lock(av->calls[i].mutex_control); | ||
625 | |||
626 | if (av->calls[i].active) rc++; | ||
627 | |||
628 | pthread_mutex_unlock(av->calls[i].mutex_control); | ||
629 | } | ||
630 | |||
631 | return rc; | ||
632 | } | ||
633 | |||
634 | /* Create a new toxav group. | ||
635 | * | ||
636 | * return group number on success. | ||
637 | * return -1 on failure. | ||
638 | * | ||
639 | * Audio data callback format: | ||
640 | * audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata) | ||
641 | * | ||
642 | * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). | ||
643 | */ | ||
644 | int toxav_add_av_groupchat(Tox *tox, void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int, | ||
645 | uint8_t, unsigned int, void *), void *userdata) | ||
646 | { | ||
647 | Messenger *m = tox; | ||
648 | return add_av_groupchat(m->group_chat_object, audio_callback, userdata); | ||
649 | } | ||
650 | |||
651 | /* Join a AV group (you need to have been invited first.) | ||
652 | * | ||
653 | * returns group number on success | ||
654 | * returns -1 on failure. | ||
655 | * | ||
656 | * Audio data callback format (same as the one for toxav_add_av_groupchat()): | ||
657 | * audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata) | ||
658 | * | ||
659 | * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). | ||
660 | */ | ||
661 | int toxav_join_av_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length, | ||
662 | void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *), | ||
663 | void *userdata) | ||
664 | { | ||
665 | Messenger *m = tox; | ||
666 | return join_av_groupchat(m->group_chat_object, friendnumber, data, length, audio_callback, userdata); | ||
667 | } | ||
668 | |||
669 | /* Send audio to the group chat. | ||
670 | * | ||
671 | * return 0 on success. | ||
672 | * return -1 on failure. | ||
673 | * | ||
674 | * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). | ||
675 | * | ||
676 | * Valid number of samples are ((sample rate) * (audio length (Valid ones are: 2.5, 5, 10, 20, 40 or 60 ms)) / 1000) | ||
677 | * Valid number of channels are 1 or 2. | ||
678 | * Valid sample rates are 8000, 12000, 16000, 24000, or 48000. | ||
679 | * | ||
680 | * Recommended values are: samples = 960, channels = 1, sample_rate = 48000 | ||
681 | */ | ||
682 | int toxav_group_send_audio(Tox *tox, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels, | ||
683 | unsigned int sample_rate) | ||
684 | { | ||
685 | Messenger *m = tox; | ||
686 | return group_send_audio(m->group_chat_object, groupnumber, pcm, samples, channels, sample_rate); | ||
687 | } | ||
688 | |||
diff --git a/toxav/toxav_new_1.h b/toxav/toxav_new_1.h deleted file mode 100644 index 3696f961..00000000 --- a/toxav/toxav_new_1.h +++ /dev/null | |||
@@ -1,329 +0,0 @@ | |||
1 | /** toxav.h | ||
2 | * | ||
3 | * Copyright (C) 2013 Tox project All Rights Reserved. | ||
4 | * | ||
5 | * This file is part of Tox. | ||
6 | * | ||
7 | * Tox is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation, either version 3 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * Tox is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | |||
23 | #ifndef __TOXAV | ||
24 | #define __TOXAV | ||
25 | #include <inttypes.h> | ||
26 | |||
27 | #ifdef __cplusplus | ||
28 | extern "C" { | ||
29 | #endif | ||
30 | |||
31 | typedef struct _ToxAv ToxAv; | ||
32 | |||
33 | /* vpx_image_t */ | ||
34 | #include <vpx/vpx_image.h> | ||
35 | |||
36 | typedef void ( *ToxAVCallback ) ( void *agent, int32_t call_idx, void *arg ); | ||
37 | typedef void ( *ToxAvAudioCallback ) (void *agent, int32_t call_idx, const int16_t *PCM, uint16_t size, void *data); | ||
38 | typedef void ( *ToxAvVideoCallback ) (void *agent, int32_t call_idx, const vpx_image_t *img, void *data); | ||
39 | |||
40 | #ifndef __TOX_DEFINED__ | ||
41 | #define __TOX_DEFINED__ | ||
42 | typedef struct Tox Tox; | ||
43 | #endif | ||
44 | |||
45 | #define RTP_PAYLOAD_SIZE 65535 | ||
46 | |||
47 | |||
48 | /** | ||
49 | * Callbacks ids that handle the call states. | ||
50 | */ | ||
51 | typedef enum { | ||
52 | av_OnInvite, /* Incoming call */ | ||
53 | av_OnRinging, /* When peer is ready to accept/reject the call */ | ||
54 | av_OnStart, /* Call (RTP transmission) started */ | ||
55 | av_OnCancel, /* The side that initiated call canceled invite */ | ||
56 | av_OnReject, /* The side that was invited rejected the call */ | ||
57 | av_OnEnd, /* Call that was active ended */ | ||
58 | av_OnRequestTimeout, /* When the requested action didn't get response in specified time */ | ||
59 | av_OnPeerTimeout, /* Peer timed out; stop the call */ | ||
60 | av_OnPeerCSChange, /* Peer changing Csettings. Prepare for changed AV */ | ||
61 | av_OnSelfCSChange /* Csettings change confirmation. Once triggered peer is ready to recv changed AV */ | ||
62 | } ToxAvCallbackID; | ||
63 | |||
64 | |||
65 | /** | ||
66 | * Call type identifier. | ||
67 | */ | ||
68 | typedef enum { | ||
69 | av_TypeAudio = 192, | ||
70 | av_TypeVideo | ||
71 | } ToxAvCallType; | ||
72 | |||
73 | |||
74 | typedef enum { | ||
75 | av_CallNonExistent = -1, | ||
76 | av_CallInviting, /* when sending call invite */ | ||
77 | av_CallStarting, /* when getting call invite */ | ||
78 | av_CallActive, | ||
79 | av_CallHold, | ||
80 | av_CallHungUp | ||
81 | } ToxAvCallState; | ||
82 | |||
83 | /** | ||
84 | * Error indicators. Values under -20 are reserved for toxcore. | ||
85 | */ | ||
86 | typedef enum { | ||
87 | av_ErrorNone = 0, | ||
88 | av_ErrorUnknown = -1, /* Unknown error */ | ||
89 | av_ErrorNoCall = -20, /* Trying to perform call action while not in a call */ | ||
90 | av_ErrorInvalidState = -21, /* Trying to perform call action while in invalid state*/ | ||
91 | av_ErrorAlreadyInCallWithPeer = -22, /* Trying to call peer when already in a call with peer */ | ||
92 | av_ErrorReachedCallLimit = -23, /* Cannot handle more calls */ | ||
93 | av_ErrorInitializingCodecs = -30, /* Failed creating CSSession */ | ||
94 | av_ErrorSettingVideoResolution = -31, /* Error setting resolution */ | ||
95 | av_ErrorSettingVideoBitrate = -32, /* Error setting bitrate */ | ||
96 | av_ErrorSplittingVideoPayload = -33, /* Error splitting video payload */ | ||
97 | av_ErrorEncodingVideo = -34, /* vpx_codec_encode failed */ | ||
98 | av_ErrorEncodingAudio = -35, /* opus_encode failed */ | ||
99 | av_ErrorSendingPayload = -40, /* Sending lossy packet failed */ | ||
100 | av_ErrorCreatingRtpSessions = -41, /* One of the rtp sessions failed to initialize */ | ||
101 | av_ErrorNoRtpSession = -50, /* Trying to perform rtp action on invalid session */ | ||
102 | av_ErrorInvalidCodecState = -51, /* Codec state not initialized */ | ||
103 | av_ErrorPacketTooLarge = -52, /* Split packet exceeds it's limit */ | ||
104 | } ToxAvError; | ||
105 | |||
106 | |||
107 | /** | ||
108 | * Locally supported capabilities. | ||
109 | */ | ||
110 | typedef enum { | ||
111 | av_AudioEncoding = 1 << 0, | ||
112 | av_AudioDecoding = 1 << 1, | ||
113 | av_VideoEncoding = 1 << 2, | ||
114 | av_VideoDecoding = 1 << 3 | ||
115 | } ToxAvCapabilities; | ||
116 | |||
117 | |||
118 | /** | ||
119 | * Encoding settings. | ||
120 | */ | ||
121 | typedef struct _ToxAvCSettings { | ||
122 | ToxAvCallType call_type; | ||
123 | |||
124 | uint32_t video_bitrate; /* In kbits/s */ | ||
125 | uint16_t max_video_width; /* In px */ | ||
126 | uint16_t max_video_height; /* In px */ | ||
127 | |||
128 | uint32_t audio_bitrate; /* In bits/s */ | ||
129 | uint16_t audio_frame_duration; /* In ms */ | ||
130 | uint32_t audio_sample_rate; /* In Hz */ | ||
131 | uint32_t audio_channels; | ||
132 | } ToxAvCSettings; | ||
133 | |||
134 | extern const ToxAvCSettings av_DefaultSettings; | ||
135 | |||
136 | /** | ||
137 | * Start new A/V session. There can only be one session at the time. | ||
138 | */ | ||
139 | ToxAv *toxav_new(Tox *messenger, int32_t max_calls); | ||
140 | |||
141 | /** | ||
142 | * Remove A/V session. | ||
143 | */ | ||
144 | void toxav_kill(ToxAv *av); | ||
145 | |||
146 | /** | ||
147 | * Returns the interval in milliseconds when the next toxav_do() should be called. | ||
148 | * If no call is active at the moment returns 200. | ||
149 | */ | ||
150 | uint32_t toxav_do_interval(ToxAv *av); | ||
151 | |||
152 | /** | ||
153 | * Main loop for the session. Best called right after tox_do(); | ||
154 | */ | ||
155 | void toxav_do(ToxAv *av); | ||
156 | |||
157 | /** | ||
158 | * Register callback for call state. | ||
159 | */ | ||
160 | void toxav_register_callstate_callback (ToxAv *av, ToxAVCallback cb, ToxAvCallbackID id, void *userdata); | ||
161 | |||
162 | /** | ||
163 | * Register callback for audio data. | ||
164 | */ | ||
165 | void toxav_register_audio_callback (ToxAv *av, ToxAvAudioCallback cb, void *userdata); | ||
166 | |||
167 | /** | ||
168 | * Register callback for video data. | ||
169 | */ | ||
170 | void toxav_register_video_callback (ToxAv *av, ToxAvVideoCallback cb, void *userdata); | ||
171 | |||
172 | /** | ||
173 | * Call user. Use its friend_id. | ||
174 | */ | ||
175 | int toxav_call(ToxAv *av, | ||
176 | int32_t *call_index, | ||
177 | int friend_id, | ||
178 | const ToxAvCSettings *csettings, | ||
179 | int ringing_seconds); | ||
180 | |||
181 | /** | ||
182 | * Hangup active call. | ||
183 | */ | ||
184 | int toxav_hangup(ToxAv *av, int32_t call_index); | ||
185 | |||
186 | /** | ||
187 | * Answer incoming call. Pass the csettings that you will use. | ||
188 | */ | ||
189 | int toxav_answer(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings ); | ||
190 | |||
191 | /** | ||
192 | * Reject incoming call. | ||
193 | */ | ||
194 | int toxav_reject(ToxAv *av, int32_t call_index, const char *reason); | ||
195 | |||
196 | /** | ||
197 | * Cancel outgoing request. | ||
198 | */ | ||
199 | int toxav_cancel(ToxAv *av, int32_t call_index, int peer_id, const char *reason); | ||
200 | |||
201 | /** | ||
202 | * Notify peer that we are changing codec settings. | ||
203 | */ | ||
204 | int toxav_change_settings(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings); | ||
205 | |||
206 | /** | ||
207 | * Terminate transmission. Note that transmission will be | ||
208 | * terminated without informing remote peer. Usually called when we can't inform peer. | ||
209 | */ | ||
210 | int toxav_stop_call(ToxAv *av, int32_t call_index); | ||
211 | |||
212 | /** | ||
213 | * Allocates transmission data. Must be call before calling toxav_prepare_* and toxav_send_*. | ||
214 | * Also, it must be called when call is started | ||
215 | */ | ||
216 | int toxav_prepare_transmission(ToxAv *av, int32_t call_index, int support_video); | ||
217 | |||
218 | /** | ||
219 | * Clears transmission data. Call this at the end of the transmission. | ||
220 | */ | ||
221 | int toxav_kill_transmission(ToxAv *av, int32_t call_index); | ||
222 | |||
223 | /** | ||
224 | * Encode video frame. | ||
225 | */ | ||
226 | int toxav_prepare_video_frame ( ToxAv *av, | ||
227 | int32_t call_index, | ||
228 | uint8_t *dest, | ||
229 | int dest_max, | ||
230 | vpx_image_t *input); | ||
231 | |||
232 | /** | ||
233 | * Send encoded video packet. | ||
234 | */ | ||
235 | int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, uint32_t frame_size); | ||
236 | |||
237 | /** | ||
238 | * Encode audio frame. | ||
239 | */ | ||
240 | int toxav_prepare_audio_frame ( ToxAv *av, | ||
241 | int32_t call_index, | ||
242 | uint8_t *dest, | ||
243 | int dest_max, | ||
244 | const int16_t *frame, | ||
245 | int frame_size); | ||
246 | |||
247 | /** | ||
248 | * Send encoded audio frame. | ||
249 | */ | ||
250 | int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int size); | ||
251 | |||
252 | /** | ||
253 | * Get codec settings from the peer. These were exchanged during call initialization | ||
254 | * or when peer send us new csettings. | ||
255 | */ | ||
256 | int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSettings *dest ); | ||
257 | |||
258 | /** | ||
259 | * Get friend id of peer participating in conversation. | ||
260 | */ | ||
261 | int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer ); | ||
262 | |||
263 | /** | ||
264 | * Get current call state. | ||
265 | */ | ||
266 | ToxAvCallState toxav_get_call_state ( ToxAv *av, int32_t call_index ); | ||
267 | |||
268 | /** | ||
269 | * Is certain capability supported. Used to determine if encoding/decoding is ready. | ||
270 | */ | ||
271 | int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability ); | ||
272 | |||
273 | /** | ||
274 | * Returns tox reference. | ||
275 | */ | ||
276 | Tox *toxav_get_tox (ToxAv *av); | ||
277 | |||
278 | /** | ||
279 | * Returns number of active calls or -1 on error. | ||
280 | */ | ||
281 | int toxav_get_active_count (ToxAv *av); | ||
282 | |||
283 | /* Create a new toxav group. | ||
284 | * | ||
285 | * return group number on success. | ||
286 | * return -1 on failure. | ||
287 | * | ||
288 | * Audio data callback format: | ||
289 | * audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata) | ||
290 | * | ||
291 | * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). | ||
292 | */ | ||
293 | int toxav_add_av_groupchat(Tox *tox, void (*audio_callback)(Tox *, int, int, const int16_t *, unsigned int, uint8_t, | ||
294 | unsigned int, void *), void *userdata); | ||
295 | |||
296 | /* Join a AV group (you need to have been invited first.) | ||
297 | * | ||
298 | * returns group number on success | ||
299 | * returns -1 on failure. | ||
300 | * | ||
301 | * Audio data callback format (same as the one for toxav_add_av_groupchat()): | ||
302 | * audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata) | ||
303 | * | ||
304 | * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). | ||
305 | */ | ||
306 | int toxav_join_av_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length, | ||
307 | void (*audio_callback)(Tox *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *), void *userdata); | ||
308 | |||
309 | /* Send audio to the group chat. | ||
310 | * | ||
311 | * return 0 on success. | ||
312 | * return -1 on failure. | ||
313 | * | ||
314 | * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). | ||
315 | * | ||
316 | * Valid number of samples are ((sample rate) * (audio length (Valid ones are: 2.5, 5, 10, 20, 40 or 60 ms)) / 1000) | ||
317 | * Valid number of channels are 1 or 2. | ||
318 | * Valid sample rates are 8000, 12000, 16000, 24000, or 48000. | ||
319 | * | ||
320 | * Recommended values are: samples = 960, channels = 1, sample_rate = 48000 | ||
321 | */ | ||
322 | int toxav_group_send_audio(Tox *tox, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels, | ||
323 | unsigned int sample_rate); | ||
324 | |||
325 | #ifdef __cplusplus | ||
326 | } | ||
327 | #endif | ||
328 | |||
329 | #endif /* __TOXAV */ | ||