summaryrefslogtreecommitdiff
path: root/toxav/av_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxav/av_test.c')
-rw-r--r--toxav/av_test.c632
1 files changed, 632 insertions, 0 deletions
diff --git a/toxav/av_test.c b/toxav/av_test.c
new file mode 100644
index 00000000..01484249
--- /dev/null
+++ b/toxav/av_test.c
@@ -0,0 +1,632 @@
1#include "toxav.h"
2#include "../toxcore/tox.h"
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
16#include <assert.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <time.h>
20#include <string.h>
21
22#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
23#define c_sleep(x) Sleep(1*x)
24#else
25#include <unistd.h>
26#define c_sleep(x) usleep(1000*x)
27#endif
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
39typedef struct {
40 bool incoming;
41 uint32_t state;
42} CallControl;
43
44const char* stringify_state(TOXAV_CALL_STATE s)
45{
46 static const char* strings[] =
47 {
48 "NOT SENDING",
49 "SENDING AUDIO",
50 "SENDING VIDEO",
51 "SENDING AUDIO AND VIDEO",
52 "PAUSED",
53 "END",
54 "ERROR"
55 };
56
57 return strings [s];
58};
59
60
61/**
62 * Callbacks
63 */
64void t_toxav_call_cb(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled, void *user_data)
65{
66 printf("Handling CALL callback\n");
67 ((CallControl*)user_data)->incoming = true;
68}
69void t_toxav_call_state_cb(ToxAV *av, uint32_t friend_number, uint32_t state, void *user_data)
70{
71 printf("Handling CALL STATE callback: %d\n", state);
72
73 ((CallControl*)user_data)->state = state;
74}
75void t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
76 uint16_t width, uint16_t height,
77 uint8_t const *planes[], int32_t const stride[],
78 void *user_data)
79{
80 printf("Handling VIDEO FRAME callback\n");
81}
82void t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
83 int16_t const *pcm,
84 size_t sample_count,
85 uint8_t channels,
86 uint32_t sampling_rate,
87 void *user_data)
88{
89 printf("Handling AUDIO FRAME callback\n");
90}
91void t_accept_friend_request_cb(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata)
92{
93 if (length == 7 && memcmp("gentoo", data, 7) == 0) {
94 tox_add_friend_norequest(m, public_key);
95 }
96}
97
98
99/**
100 */
101void prepare(Tox* Bsn, Tox* Alice, Tox* Bob)
102{
103 long long unsigned int cur_time = time(NULL);
104
105 uint32_t to_compare = 974536;
106 uint8_t address[TOX_FRIEND_ADDRESS_SIZE];
107
108 tox_callback_friend_request(Alice, t_accept_friend_request_cb, &to_compare);
109 tox_get_address(Alice, address);
110
111 assert(tox_add_friend(Bob, address, (uint8_t *)"gentoo", 7) >= 0);
112
113 uint8_t off = 1;
114
115 while (1) {
116 tox_do(Bsn);
117 tox_do(Alice);
118 tox_do(Bob);
119
120 if (tox_isconnected(Bsn) && tox_isconnected(Alice) && tox_isconnected(Bob) && off) {
121 printf("Toxes are online, took %llu seconds\n", time(NULL) - cur_time);
122 off = 0;
123 }
124
125 if (tox_get_friend_connection_status(Alice, 0) == 1 && tox_get_friend_connection_status(Bob, 0) == 1)
126 break;
127
128 c_sleep(20);
129 }
130
131 printf("All set after %llu seconds!\n", time(NULL) - cur_time);
132}
133void prepareAV(ToxAV* AliceAV, void* AliceUD, ToxAV* BobAV, void* BobUD)
134{
135 /* Alice */
136 toxav_callback_call(AliceAV, t_toxav_call_cb, AliceUD);
137 toxav_callback_call_state(AliceAV, t_toxav_call_state_cb, AliceUD);
138 toxav_callback_receive_video_frame(AliceAV, t_toxav_receive_video_frame_cb, AliceUD);
139 toxav_callback_receive_audio_frame(AliceAV, t_toxav_receive_audio_frame_cb, AliceUD);
140
141 /* Bob */
142 toxav_callback_call(BobAV, t_toxav_call_cb, BobUD);
143 toxav_callback_call_state(BobAV, t_toxav_call_state_cb, BobUD);
144 toxav_callback_receive_video_frame(BobAV, t_toxav_receive_video_frame_cb, BobUD);
145 toxav_callback_receive_audio_frame(BobAV, t_toxav_receive_audio_frame_cb, BobUD);
146}
147void iterate(Tox* Bsn, ToxAV* AliceAV, ToxAV* BobAV)
148{
149 tox_do(Bsn);
150 tox_do(toxav_get_tox(AliceAV));
151 tox_do(toxav_get_tox(BobAV));
152
153 toxav_iteration(AliceAV);
154 toxav_iteration(BobAV);
155
156 c_sleep(20);
157}
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}
259
260int main (int argc, char** argv)
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
354 Tox *Bsn = tox_new(0);
355 Tox *Alice = tox_new(0);
356 Tox *Bob = tox_new(0);
357
358 assert(Bsn && Alice && Bob);
359
360 prepare(Bsn, Alice, Bob);
361
362
363 ToxAV *AliceAV, *BobAV;
364 CallControl AliceCC, BobCC;
365
366 {
367 TOXAV_ERR_NEW rc;
368 AliceAV = toxav_new(Alice, &rc);
369 assert(rc == TOXAV_ERR_NEW_OK);
370
371 BobAV = toxav_new(Bob, &rc);
372 assert(rc == TOXAV_ERR_NEW_OK);
373
374 prepareAV(AliceAV, &AliceCC, BobAV, &BobCC);
375 printf("Created 2 instances of ToxAV\n");
376 }
377
378
379#define REGULAR_CALL_FLOW(A_BR, V_BR) \
380 do { \
381 memset(&AliceCC, 0, sizeof(CallControl)); \
382 memset(&BobCC, 0, sizeof(CallControl)); \
383 \
384 TOXAV_ERR_CALL rc; \
385 toxav_call(AliceAV, 0, A_BR, V_BR, &rc); \
386 \
387 if (rc != TOXAV_ERR_CALL_OK) { \
388 printf("toxav_call failed: %d\n", rc); \
389 exit(1); \
390 } \
391 \
392 \
393 long long unsigned int start_time = time(NULL); \
394 \
395 \
396 while (BobCC.state != TOXAV_CALL_STATE_END) { \
397 \
398 if (BobCC.incoming) { \
399 TOXAV_ERR_ANSWER rc; \
400 toxav_answer(BobAV, 0, A_BR, V_BR, &rc); \
401 \
402 if (rc != TOXAV_ERR_ANSWER_OK) { \
403 printf("toxav_answer failed: %d\n", rc); \
404 exit(1); \
405 } \
406 BobCC.incoming = false; \
407 } else { \
408 /* TODO rtp */ \
409 \
410 if (time(NULL) - start_time == 5) { \
411 \
412 TOXAV_ERR_CALL_CONTROL rc; \
413 toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc); \
414 \
415 if (rc != TOXAV_ERR_CALL_CONTROL_OK) { \
416 printf("toxav_call_control failed: %d\n", rc); \
417 exit(1); \
418 } \
419 } \
420 } \
421 \
422 iterate(Bsn, AliceAV, BobAV); \
423 } \
424 printf("Success!\n");\
425 } while(0)
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
442#undef REGULAR_CALL_FLOW
443
444 if (TEST_REJECT) { /* Alice calls; Bob rejects */
445 printf("\nTrying reject flow...\n");
446
447 memset(&AliceCC, 0, sizeof(CallControl));
448 memset(&BobCC, 0, sizeof(CallControl));
449
450 {
451 TOXAV_ERR_CALL rc;
452 toxav_call(AliceAV, 0, 48, 0, &rc);
453
454 if (rc != TOXAV_ERR_CALL_OK) {
455 printf("toxav_call failed: %d\n", rc);
456 exit(1);
457 }
458 }
459
460 while (!BobCC.incoming)
461 iterate(Bsn, AliceAV, BobAV);
462
463 /* Reject */
464 {
465 TOXAV_ERR_CALL_CONTROL rc;
466 toxav_call_control(BobAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
467
468 if (rc != TOXAV_ERR_CALL_CONTROL_OK) {
469 printf("toxav_call_control failed: %d\n", rc);
470 exit(1);
471 }
472 }
473
474 while (AliceCC.state != TOXAV_CALL_STATE_END)
475 iterate(Bsn, AliceAV, BobAV);
476
477 printf("Success!\n");
478 }
479
480 if (TEST_CANCEL) { /* Alice calls; Alice cancels while ringing */
481 printf("\nTrying cancel (while ringing) flow...\n");
482
483 memset(&AliceCC, 0, sizeof(CallControl));
484 memset(&BobCC, 0, sizeof(CallControl));
485
486 {
487 TOXAV_ERR_CALL rc;
488 toxav_call(AliceAV, 0, 48, 0, &rc);
489
490 if (rc != TOXAV_ERR_CALL_OK) {
491 printf("toxav_call failed: %d\n", rc);
492 exit(1);
493 }
494 }
495
496 while (!BobCC.incoming)
497 iterate(Bsn, AliceAV, BobAV);
498
499 /* Cancel */
500 {
501 TOXAV_ERR_CALL_CONTROL rc;
502 toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
503
504 if (rc != TOXAV_ERR_CALL_CONTROL_OK) {
505 printf("toxav_call_control failed: %d\n", rc);
506 exit(1);
507 }
508 }
509
510 /* Alice will not receive end state */
511 while (BobCC.state != TOXAV_CALL_STATE_END)
512 iterate(Bsn, AliceAV, BobAV);
513
514 printf("Success!\n");
515 }
516
517 if (TEST_MUTE_UNMUTE) { /* Check Mute-Unmute etc */
518 printf("\nTrying mute functionality...\n");
519
520 memset(&AliceCC, 0, sizeof(CallControl));
521 memset(&BobCC, 0, sizeof(CallControl));
522
523 /* Assume sending audio and video */
524 {
525 TOXAV_ERR_CALL rc;
526 toxav_call(AliceAV, 0, 48, 1000, &rc);
527
528 if (rc != TOXAV_ERR_CALL_OK) {
529 printf("toxav_call failed: %d\n", rc);
530 exit(1);
531 }
532 }
533
534 while (!BobCC.incoming)
535 iterate(Bsn, AliceAV, BobAV);
536
537 /* At first try all stuff while in invalid state */
538 assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL));
539 assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_RESUME, NULL));
540 assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL));
541 assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_VIDEO, NULL));
542
543 {
544 TOXAV_ERR_ANSWER rc;
545 toxav_answer(BobAV, 0, 48, 4000, &rc);
546
547 if (rc != TOXAV_ERR_ANSWER_OK) {
548 printf("toxav_answer failed: %d\n", rc);
549 exit(1);
550 }
551 }
552
553 iterate(Bsn, AliceAV, BobAV);
554
555 /* Pause and Resume */
556 printf("Pause and Resume\n");
557 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL));
558 iterate(Bsn, AliceAV, BobAV);
559 assert(BobCC.state == TOXAV_CALL_STATE_PAUSED);
560 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_RESUME, NULL));
561 iterate(Bsn, AliceAV, BobAV);
562 assert(BobCC.state & (TOXAV_CALL_STATE_SENDING_A | TOXAV_CALL_STATE_SENDING_V));
563
564 /* Mute/Unmute single */
565 printf("Mute/Unmute single\n");
566 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL));
567 iterate(Bsn, AliceAV, BobAV);
568 assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_A);
569 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL));
570 iterate(Bsn, AliceAV, BobAV);
571 assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_A);
572
573 /* Mute/Unmute both */
574 printf("Mute/Unmute both\n");
575 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL));
576 iterate(Bsn, AliceAV, BobAV);
577 assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_A);
578 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_VIDEO, NULL));
579 iterate(Bsn, AliceAV, BobAV);
580 assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_V);
581 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL));
582 iterate(Bsn, AliceAV, BobAV);
583 assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_A);
584 assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_VIDEO, NULL));
585 iterate(Bsn, AliceAV, BobAV);
586 assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_V);
587
588 {
589 TOXAV_ERR_CALL_CONTROL rc;
590 toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc);
591
592 if (rc != TOXAV_ERR_CALL_CONTROL_OK) {
593 printf("toxav_call_control failed: %d\n", rc);
594 exit(1);
595 }
596 }
597
598 iterate(Bsn, AliceAV, BobAV);
599 assert(BobCC.state == TOXAV_CALL_STATE_END);
600
601 printf("Success!\n");
602 }
603
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
621 toxav_kill(BobAV);
622 toxav_kill(AliceAV);
623 tox_kill(Bob);
624 tox_kill(Alice);
625 tox_kill(Bsn);
626
627 printf("\nTest successful!\n");
628
629 alcCloseDevice(out_device);
630 alcCaptureCloseDevice(in_device);
631 return 0;
632} \ No newline at end of file