summaryrefslogtreecommitdiff
path: root/toxav
diff options
context:
space:
mode:
Diffstat (limited to 'toxav')
-rw-r--r--toxav/Makefile.inc1
-rw-r--r--toxav/av_test.c270
-rw-r--r--toxav/codec.c1
-rw-r--r--toxav/msi.c2
-rw-r--r--toxav/toxav_new_1.c688
-rw-r--r--toxav/toxav_new_1.h329
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
17typedef struct { 39typedef 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
159int 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
176int 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
206int 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
238int 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
244long 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
138int main (int argc, char** argv) 260int 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__
27typedef 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
48const ToxAvCSettings av_DefaultSettings = {
49 av_TypeAudio,
50
51 500,
52 1280,
53 720,
54
55 32000,
56 20,
57 48000,
58 1
59};
60
61static const uint32_t jbuf_capacity = 6;
62static const uint8_t audio_index = 0, video_index = 1;
63
64typedef 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
74struct _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
89static const MSICSettings *msicsettings_cast (const ToxAvCSettings *from)
90{
91 assert(sizeof(MSICSettings) == sizeof(ToxAvCSettings));
92 return (const MSICSettings *) from;
93}
94
95static const ToxAvCSettings *toxavcsettings_cast (const MSICSettings *from)
96{
97 assert(sizeof(MSICSettings) == sizeof(ToxAvCSettings));
98 return (const ToxAvCSettings *) from;
99
100}
101
102ToxAv *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
133void 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
157uint32_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
176void 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
209void 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
214void toxav_register_audio_callback(ToxAv *av, ToxAvAudioCallback cb, void *userdata)
215{
216 av->acb.first = cb;
217 av->acb.second = userdata;
218}
219
220void toxav_register_video_callback(ToxAv *av, ToxAvVideoCallback cb, void *userdata)
221{
222 av->vcb.first = cb;
223 av->vcb.second = userdata;
224}
225
226int 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
235int toxav_hangup ( ToxAv *av, int32_t call_index )
236{
237 return msi_hangup(av->msi_session, call_index);
238}
239
240int 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
245int toxav_reject ( ToxAv *av, int32_t call_index, const char *reason )
246{
247 return msi_reject(av->msi_session, call_index, reason);
248}
249
250int 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
255int 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
260int toxav_stop_call ( ToxAv *av, int32_t call_index )
261{
262 return msi_stopcall(av->msi_session, call_index);
263}
264
265int 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;
353error:
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
369int 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
411static 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
445int 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
500int 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
524int 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
558int 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
580int 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
590int 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
599ToxAvCallState 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
608int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability )
609{
610}
611
612Tox *toxav_get_tox(ToxAv *av)
613{
614 return (Tox *)av->messenger;
615}
616
617int 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 */
644int 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 */
661int 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 */
682int 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
28extern "C" {
29#endif
30
31typedef struct _ToxAv ToxAv;
32
33/* vpx_image_t */
34#include <vpx/vpx_image.h>
35
36typedef void ( *ToxAVCallback ) ( void *agent, int32_t call_idx, void *arg );
37typedef void ( *ToxAvAudioCallback ) (void *agent, int32_t call_idx, const int16_t *PCM, uint16_t size, void *data);
38typedef void ( *ToxAvVideoCallback ) (void *agent, int32_t call_idx, const vpx_image_t *img, void *data);
39
40#ifndef __TOX_DEFINED__
41#define __TOX_DEFINED__
42typedef struct Tox Tox;
43#endif
44
45#define RTP_PAYLOAD_SIZE 65535
46
47
48/**
49 * Callbacks ids that handle the call states.
50 */
51typedef 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 */
68typedef enum {
69 av_TypeAudio = 192,
70 av_TypeVideo
71} ToxAvCallType;
72
73
74typedef 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 */
86typedef 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 */
110typedef 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 */
121typedef 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
134extern const ToxAvCSettings av_DefaultSettings;
135
136/**
137 * Start new A/V session. There can only be one session at the time.
138 */
139ToxAv *toxav_new(Tox *messenger, int32_t max_calls);
140
141/**
142 * Remove A/V session.
143 */
144void 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 */
150uint32_t toxav_do_interval(ToxAv *av);
151
152/**
153 * Main loop for the session. Best called right after tox_do();
154 */
155void toxav_do(ToxAv *av);
156
157/**
158 * Register callback for call state.
159 */
160void toxav_register_callstate_callback (ToxAv *av, ToxAVCallback cb, ToxAvCallbackID id, void *userdata);
161
162/**
163 * Register callback for audio data.
164 */
165void toxav_register_audio_callback (ToxAv *av, ToxAvAudioCallback cb, void *userdata);
166
167/**
168 * Register callback for video data.
169 */
170void toxav_register_video_callback (ToxAv *av, ToxAvVideoCallback cb, void *userdata);
171
172/**
173 * Call user. Use its friend_id.
174 */
175int 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 */
184int toxav_hangup(ToxAv *av, int32_t call_index);
185
186/**
187 * Answer incoming call. Pass the csettings that you will use.
188 */
189int toxav_answer(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings );
190
191/**
192 * Reject incoming call.
193 */
194int toxav_reject(ToxAv *av, int32_t call_index, const char *reason);
195
196/**
197 * Cancel outgoing request.
198 */
199int 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 */
204int 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 */
210int 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 */
216int 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 */
221int toxav_kill_transmission(ToxAv *av, int32_t call_index);
222
223/**
224 * Encode video frame.
225 */
226int 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 */
235int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, uint32_t frame_size);
236
237/**
238 * Encode audio frame.
239 */
240int 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 */
250int 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 */
256int 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 */
261int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer );
262
263/**
264 * Get current call state.
265 */
266ToxAvCallState 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 */
271int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability );
272
273/**
274 * Returns tox reference.
275 */
276Tox *toxav_get_tox (ToxAv *av);
277
278/**
279 * Returns number of active calls or -1 on error.
280 */
281int 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 */
293int 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 */
306int 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 */
322int 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 */