diff options
Diffstat (limited to 'toxav/av_test.c')
-rw-r--r-- | toxav/av_test.c | 602 |
1 files changed, 275 insertions, 327 deletions
diff --git a/toxav/av_test.c b/toxav/av_test.c index 249e0ab7..5ca53eb9 100644 --- a/toxav/av_test.c +++ b/toxav/av_test.c | |||
@@ -1,35 +1,32 @@ | |||
1 | #include "toxav.h" | 1 | #include "toxav.h" |
2 | #include "../toxcore/tox.h" | 2 | #include "../toxcore/tox.h" |
3 | 3 | ||
4 | #ifdef __APPLE__ | 4 | /* For playing audio data */ |
5 | # include <OpenAL/al.h> | 5 | #include <AL/al.h> |
6 | # include <OpenAL/alc.h> | 6 | #include <AL/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 | 7 | ||
8 | /* Processing wav's */ | ||
9 | #include <sndfile.h> | ||
10 | |||
11 | /* For reading and displaying video data */ | ||
16 | #include <opencv/cv.h> | 12 | #include <opencv/cv.h> |
17 | #include <opencv/highgui.h> | 13 | #include <opencv/highgui.h> |
18 | 14 | ||
15 | /* For converting images TODO remove */ | ||
19 | #include <vpx/vpx_image.h> | 16 | #include <vpx/vpx_image.h> |
20 | 17 | ||
18 | |||
19 | #include <sys/stat.h> | ||
21 | #include <assert.h> | 20 | #include <assert.h> |
22 | #include <stdio.h> | 21 | #include <stdio.h> |
23 | #include <stdlib.h> | 22 | #include <stdlib.h> |
24 | #include <time.h> | 23 | #include <time.h> |
25 | #include <string.h> | 24 | #include <string.h> |
26 | 25 | #include <errno.h> | |
27 | #if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) | ||
28 | #define c_sleep(x) Sleep(1*x) | ||
29 | #else | ||
30 | #include <unistd.h> | 26 | #include <unistd.h> |
27 | |||
28 | |||
31 | #define c_sleep(x) usleep(1000*x) | 29 | #define c_sleep(x) usleep(1000*x) |
32 | #endif | ||
33 | 30 | ||
34 | 31 | ||
35 | /* Enable/disable tests */ | 32 | /* Enable/disable tests */ |
@@ -39,17 +36,17 @@ | |||
39 | #define TEST_REJECT 0 | 36 | #define TEST_REJECT 0 |
40 | #define TEST_CANCEL 0 | 37 | #define TEST_CANCEL 0 |
41 | #define TEST_MUTE_UNMUTE 0 | 38 | #define TEST_MUTE_UNMUTE 0 |
42 | #define TEST_TRANSFER_A 0 | 39 | #define TEST_TRANSFER_A 1 |
43 | #define TEST_TRANSFER_V 1 | 40 | #define TEST_TRANSFER_V 0 |
44 | 41 | ||
45 | 42 | ||
46 | typedef struct { | 43 | typedef struct { |
47 | bool incoming; | 44 | bool incoming; |
48 | uint32_t state; | 45 | uint32_t state; |
49 | uint32_t output_source; | ||
50 | } CallControl; | 46 | } CallControl; |
51 | 47 | ||
52 | const char* video_test_window = "AV Test"; | 48 | const char* vdout = "AV Test"; |
49 | uint32_t adout; | ||
53 | 50 | ||
54 | const char* stringify_state(TOXAV_CALL_STATE s) | 51 | const char* stringify_state(TOXAV_CALL_STATE s) |
55 | { | 52 | { |
@@ -65,10 +62,7 @@ const char* stringify_state(TOXAV_CALL_STATE s) | |||
65 | }; | 62 | }; |
66 | 63 | ||
67 | return strings [s]; | 64 | return strings [s]; |
68 | }; | 65 | } |
69 | |||
70 | |||
71 | int device_play_frame(uint32_t source, const int16_t* PCM, size_t size); | ||
72 | 66 | ||
73 | /** | 67 | /** |
74 | * Callbacks | 68 | * Callbacks |
@@ -104,9 +98,11 @@ void t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number, | |||
104 | const uint8_t* vData = planes[VPX_PLANE_U]; | 98 | const uint8_t* vData = planes[VPX_PLANE_U]; |
105 | 99 | ||
106 | // convert from planar to packed | 100 | // convert from planar to packed |
107 | for (int y = 0; y < height; ++y) | 101 | int y = 0; |
102 | for (; y < height; ++y) | ||
108 | { | 103 | { |
109 | for (int x = 0; x < width; ++x) | 104 | int x = 0; |
105 | for (; x < width; ++x) | ||
110 | { | 106 | { |
111 | uint8_t Y = planes[VPX_PLANE_Y][x + y * bpl]; | 107 | uint8_t Y = planes[VPX_PLANE_Y][x + y * bpl]; |
112 | uint8_t U = planes[VPX_PLANE_V][x/(1 << 1) + y/(1 << 1)*cxbpl]; | 108 | uint8_t U = planes[VPX_PLANE_V][x/(1 << 1) + y/(1 << 1)*cxbpl]; |
@@ -117,7 +113,7 @@ void t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number, | |||
117 | } | 113 | } |
118 | } | 114 | } |
119 | 115 | ||
120 | cvShowImage(video_test_window, &output_img); | 116 | cvShowImage(vdout, &output_img); |
121 | free(output_img.imageData); | 117 | free(output_img.imageData); |
122 | } | 118 | } |
123 | void t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number, | 119 | void t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number, |
@@ -127,7 +123,32 @@ void t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number, | |||
127 | uint32_t sampling_rate, | 123 | uint32_t sampling_rate, |
128 | void *user_data) | 124 | void *user_data) |
129 | { | 125 | { |
130 | device_play_frame(((CallControl*)user_data)->output_source, pcm, sample_count); | 126 | uint32_t bufid; |
127 | int32_t processed, queued; | ||
128 | alGetSourcei(adout, AL_BUFFERS_PROCESSED, &processed); | ||
129 | alGetSourcei(adout, AL_BUFFERS_QUEUED, &queued); | ||
130 | |||
131 | if(processed) { | ||
132 | uint32_t bufids[processed]; | ||
133 | alSourceUnqueueBuffers(adout, processed, bufids); | ||
134 | alDeleteBuffers(processed - 1, bufids + 1); | ||
135 | bufid = bufids[0]; | ||
136 | } | ||
137 | // else if(queued < 16) | ||
138 | alGenBuffers(1, &bufid); | ||
139 | // else | ||
140 | // return; | ||
141 | |||
142 | |||
143 | alBufferData(bufid, channels == 2 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16, | ||
144 | pcm, sample_count * channels * 2, sampling_rate); | ||
145 | alSourceQueueBuffers(adout, 1, &bufid); | ||
146 | |||
147 | int32_t state; | ||
148 | alGetSourcei(adout, AL_SOURCE_STATE, &state); | ||
149 | |||
150 | if(state != AL_PLAYING) | ||
151 | alSourcePlay(adout); | ||
131 | } | 152 | } |
132 | void t_accept_friend_request_cb(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata) | 153 | void t_accept_friend_request_cb(Tox *m, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata) |
133 | { | 154 | { |
@@ -139,8 +160,20 @@ void t_accept_friend_request_cb(Tox *m, const uint8_t *public_key, const uint8_t | |||
139 | 160 | ||
140 | /** | 161 | /** |
141 | */ | 162 | */ |
142 | void prepare(Tox* Bsn, Tox* Alice, Tox* Bob) | 163 | void initialize_tox(Tox** bootstrap, ToxAV** AliceAV, CallControl* AliceCC, ToxAV** BobAV, CallControl* BobCC) |
143 | { | 164 | { |
165 | Tox* Alice; | ||
166 | Tox* Bob; | ||
167 | |||
168 | *bootstrap = tox_new(0); | ||
169 | Alice = tox_new(0); | ||
170 | Bob = tox_new(0); | ||
171 | |||
172 | assert(bootstrap && Alice && Bob); | ||
173 | |||
174 | printf("Created 3 instances of Tox\n"); | ||
175 | |||
176 | printf("Preparing network...\n"); | ||
144 | long long unsigned int cur_time = time(NULL); | 177 | long long unsigned int cur_time = time(NULL); |
145 | 178 | ||
146 | uint32_t to_compare = 974536; | 179 | uint32_t to_compare = 974536; |
@@ -154,11 +187,11 @@ void prepare(Tox* Bsn, Tox* Alice, Tox* Bob) | |||
154 | uint8_t off = 1; | 187 | uint8_t off = 1; |
155 | 188 | ||
156 | while (1) { | 189 | while (1) { |
157 | tox_do(Bsn); | 190 | tox_do(*bootstrap); |
158 | tox_do(Alice); | 191 | tox_do(Alice); |
159 | tox_do(Bob); | 192 | tox_do(Bob); |
160 | 193 | ||
161 | if (tox_isconnected(Bsn) && tox_isconnected(Alice) && tox_isconnected(Bob) && off) { | 194 | if (tox_isconnected(*bootstrap) && tox_isconnected(Alice) && tox_isconnected(Bob) && off) { |
162 | printf("Toxes are online, took %llu seconds\n", time(NULL) - cur_time); | 195 | printf("Toxes are online, took %llu seconds\n", time(NULL) - cur_time); |
163 | off = 0; | 196 | off = 0; |
164 | } | 197 | } |
@@ -169,25 +202,32 @@ void prepare(Tox* Bsn, Tox* Alice, Tox* Bob) | |||
169 | c_sleep(20); | 202 | c_sleep(20); |
170 | } | 203 | } |
171 | 204 | ||
172 | printf("All set after %llu seconds!\n", time(NULL) - cur_time); | 205 | |
173 | } | 206 | TOXAV_ERR_NEW rc; |
174 | void prepareAV(ToxAV* AliceAV, void* AliceUD, ToxAV* BobAV, void* BobUD) | 207 | *AliceAV = toxav_new(Alice, &rc); |
175 | { | 208 | assert(rc == TOXAV_ERR_NEW_OK); |
209 | |||
210 | *BobAV = toxav_new(Bob, &rc); | ||
211 | assert(rc == TOXAV_ERR_NEW_OK); | ||
212 | |||
176 | /* Alice */ | 213 | /* Alice */ |
177 | toxav_callback_call(AliceAV, t_toxav_call_cb, AliceUD); | 214 | toxav_callback_call(*AliceAV, t_toxav_call_cb, AliceCC); |
178 | toxav_callback_call_state(AliceAV, t_toxav_call_state_cb, AliceUD); | 215 | toxav_callback_call_state(*AliceAV, t_toxav_call_state_cb, AliceCC); |
179 | toxav_callback_receive_video_frame(AliceAV, t_toxav_receive_video_frame_cb, AliceUD); | 216 | toxav_callback_receive_video_frame(*AliceAV, t_toxav_receive_video_frame_cb, AliceCC); |
180 | toxav_callback_receive_audio_frame(AliceAV, t_toxav_receive_audio_frame_cb, AliceUD); | 217 | toxav_callback_receive_audio_frame(*AliceAV, t_toxav_receive_audio_frame_cb, AliceCC); |
181 | 218 | ||
182 | /* Bob */ | 219 | /* Bob */ |
183 | toxav_callback_call(BobAV, t_toxav_call_cb, BobUD); | 220 | toxav_callback_call(*BobAV, t_toxav_call_cb, BobCC); |
184 | toxav_callback_call_state(BobAV, t_toxav_call_state_cb, BobUD); | 221 | toxav_callback_call_state(*BobAV, t_toxav_call_state_cb, BobCC); |
185 | toxav_callback_receive_video_frame(BobAV, t_toxav_receive_video_frame_cb, BobUD); | 222 | toxav_callback_receive_video_frame(*BobAV, t_toxav_receive_video_frame_cb, BobCC); |
186 | toxav_callback_receive_audio_frame(BobAV, t_toxav_receive_audio_frame_cb, BobUD); | 223 | toxav_callback_receive_audio_frame(*BobAV, t_toxav_receive_audio_frame_cb, BobCC); |
224 | |||
225 | printf("Created 2 instances of ToxAV\n"); | ||
226 | printf("All set after %llu seconds!\n", time(NULL) - cur_time); | ||
187 | } | 227 | } |
188 | void iterate(Tox* Bsn, ToxAV* AliceAV, ToxAV* BobAV) | 228 | int iterate_tox(Tox* bootstrap, ToxAV* AliceAV, ToxAV* BobAV) |
189 | { | 229 | { |
190 | tox_do(Bsn); | 230 | tox_do(bootstrap); |
191 | tox_do(toxav_get_tox(AliceAV)); | 231 | tox_do(toxav_get_tox(AliceAV)); |
192 | tox_do(toxav_get_tox(BobAV)); | 232 | tox_do(toxav_get_tox(BobAV)); |
193 | 233 | ||
@@ -197,114 +237,16 @@ void iterate(Tox* Bsn, ToxAV* AliceAV, ToxAV* BobAV) | |||
197 | int mina = MIN(tox_do_interval(toxav_get_tox(AliceAV)), toxav_iteration_interval(AliceAV)); | 237 | int mina = MIN(tox_do_interval(toxav_get_tox(AliceAV)), toxav_iteration_interval(AliceAV)); |
198 | int minb = MIN(tox_do_interval(toxav_get_tox(BobAV)), toxav_iteration_interval(BobAV)); | 238 | int minb = MIN(tox_do_interval(toxav_get_tox(BobAV)), toxav_iteration_interval(BobAV)); |
199 | 239 | ||
200 | c_sleep(MIN(mina, minb)); | 240 | int rc = MIN(mina, minb); |
201 | } | 241 | c_sleep(rc); |
202 | |||
203 | int device_read_frame(ALCdevice* device, int32_t frame_dur, int16_t* PCM, size_t max_size) | ||
204 | { | ||
205 | int f_size = (8000 * frame_dur / 1000); | ||
206 | |||
207 | if (max_size < f_size) | ||
208 | return -1; | ||
209 | |||
210 | /* Don't block if not enough data */ | ||
211 | int32_t samples; | ||
212 | alcGetIntegerv(device, ALC_CAPTURE_SAMPLES, sizeof(int32_t), &samples); | ||
213 | if (samples < f_size) | ||
214 | return 0; | ||
215 | |||
216 | alcCaptureSamples(device, PCM, f_size); | ||
217 | return f_size; | ||
218 | } | ||
219 | |||
220 | int device_play_frame(uint32_t source, const int16_t* PCM, size_t size) | ||
221 | { | ||
222 | uint32_t bufid; | ||
223 | int32_t processed, queued; | ||
224 | alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed); | ||
225 | alGetSourcei(source, AL_BUFFERS_QUEUED, &queued); | ||
226 | |||
227 | if(processed) { | ||
228 | uint32_t bufids[processed]; | ||
229 | alSourceUnqueueBuffers(source, processed, bufids); | ||
230 | alDeleteBuffers(processed - 1, bufids + 1); | ||
231 | bufid = bufids[0]; | ||
232 | } | ||
233 | else if(queued < 16) | ||
234 | alGenBuffers(1, &bufid); | ||
235 | else | ||
236 | return 0; | ||
237 | 242 | ||
238 | 243 | return rc; | |
239 | alBufferData(bufid, AL_FORMAT_STEREO16, PCM, size * 2 * 2, 48000); | ||
240 | alSourceQueueBuffers(source, 1, &bufid); | ||
241 | |||
242 | int32_t state; | ||
243 | alGetSourcei(source, AL_SOURCE_STATE, &state); | ||
244 | |||
245 | if(state != AL_PLAYING) | ||
246 | alSourcePlay(source); | ||
247 | return 1; | ||
248 | } | ||
249 | |||
250 | int print_devices() | ||
251 | { | ||
252 | const char* default_input; | ||
253 | const char* default_output; | ||
254 | |||
255 | const char *device; | ||
256 | |||
257 | printf("Default input device: %s\n", alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER)); | ||
258 | printf("Default output device: %s\n", alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER)); | ||
259 | |||
260 | printf("\n"); | ||
261 | |||
262 | printf("Input devices:\n"); | ||
263 | |||
264 | int i = 0; | ||
265 | for(device = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); *device; | ||
266 | device += strlen( device ) + 1, ++i) { | ||
267 | printf("%d) %s\n", i, device); | ||
268 | } | ||
269 | |||
270 | printf("\n"); | ||
271 | printf("Output devices:\n"); | ||
272 | |||
273 | i = 0; | ||
274 | for(device = alcGetString(NULL, ALC_DEVICE_SPECIFIER); *device; | ||
275 | device += strlen( device ) + 1, ++i) { | ||
276 | printf("%d) %s\n", i, device); | ||
277 | } | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | int print_help(const char* name, int rc) | ||
283 | { | ||
284 | fprintf(stderr, "Usage: %s [-h] <in device> <out device>\n", name); | ||
285 | return rc; | ||
286 | } | ||
287 | |||
288 | long get_device_idx(const char* arg) | ||
289 | { | ||
290 | if (strcmp(arg, "-") == 0) | ||
291 | return -1; /* Default */ | ||
292 | |||
293 | char *p; | ||
294 | long res = strtol(arg, &p, 10); | ||
295 | |||
296 | if (*p) { | ||
297 | fprintf(stderr, "Invalid device!"); | ||
298 | exit(1); | ||
299 | } | ||
300 | |||
301 | return res; | ||
302 | } | 244 | } |
303 | 245 | ||
304 | int send_opencv_img(ToxAV* av, uint32_t friend_number, const IplImage* img) | 246 | int send_opencv_img(ToxAV* av, uint32_t friend_number, const IplImage* img) |
305 | { | 247 | { |
306 | /* I use vpx image coz i'm noob TODO use opencv conversion */ | 248 | /* I use vpx image coz i'm noob TODO use opencv conversion */ |
307 | vpx_image vpx_img; | 249 | vpx_image_t vpx_img; |
308 | vpx_img.w = vpx_img.h = vpx_img.d_w = vpx_img.d_h = 0; | 250 | vpx_img.w = vpx_img.h = vpx_img.d_w = vpx_img.d_h = 0; |
309 | 251 | ||
310 | const int w = img->width; | 252 | const int w = img->width; |
@@ -312,9 +254,11 @@ int send_opencv_img(ToxAV* av, uint32_t friend_number, const IplImage* img) | |||
312 | 254 | ||
313 | vpx_img_alloc(&vpx_img, VPX_IMG_FMT_VPXI420, w, h, 1); | 255 | vpx_img_alloc(&vpx_img, VPX_IMG_FMT_VPXI420, w, h, 1); |
314 | 256 | ||
315 | for (int y = 0; y < h; ++y) | 257 | int y = 0; |
258 | for (; y < h; ++y) | ||
316 | { | 259 | { |
317 | for (int x = 0; x < w; ++x) | 260 | int x = 0; |
261 | for (; x < w; ++x) | ||
318 | { | 262 | { |
319 | uint8_t b = img->imageData[(x + y * w) * 3 + 0]; | 263 | uint8_t b = img->imageData[(x + y * w) * 3 + 0]; |
320 | uint8_t g = img->imageData[(x + y * w) * 3 + 1]; | 264 | uint8_t g = img->imageData[(x + y * w) * 3 + 1]; |
@@ -341,113 +285,118 @@ int send_opencv_img(ToxAV* av, uint32_t friend_number, const IplImage* img) | |||
341 | return rc; | 285 | return rc; |
342 | } | 286 | } |
343 | 287 | ||
344 | int main (int argc, char** argv) | 288 | int print_audio_devices() |
345 | { | 289 | { |
346 | /* AV files for testing */ | 290 | const char *device; |
347 | const char* audio_in = ""; | 291 | |
348 | const char* video_in = ""; | 292 | printf("Default output device: %s\n", alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER)); |
349 | long audio_out_dev = 0; | 293 | printf("Output devices:\n"); |
350 | 294 | ||
351 | AGAIN: | 295 | int i = 0; |
352 | switch (getopt(argc, argv, "a:v:o:")) | 296 | for(device = alcGetString(NULL, ALC_DEVICE_SPECIFIER); *device; |
353 | { | 297 | device += strlen( device ) + 1, ++i) { |
354 | case 'a': | 298 | printf("%d) %s\n", i, device); |
355 | audio_in = optarg; | ||
356 | goto AGAIN; | ||
357 | break; | ||
358 | case 'v': | ||
359 | video_in = optarg; | ||
360 | goto AGAIN; | ||
361 | break; | ||
362 | case 'o': | ||
363 | char *d; | ||
364 | audio_out_dev = strtol(optarg, &d, 10); | ||
365 | if (*d) { | ||
366 | fprintf(stderr, "Invalid value for argument: 'o'"); | ||
367 | return 1; | ||
368 | } | ||
369 | goto AGAIN; | ||
370 | break; | ||
371 | case '?': | ||
372 | return 1; | ||
373 | break; | ||
374 | case -1: | ||
375 | break; | ||
376 | } | 299 | } |
377 | 300 | ||
378 | 301 | return 0; | |
302 | } | ||
303 | |||
304 | int print_help (const char* name) | ||
305 | { | ||
306 | printf("Usage: %s -[a:v:o:dh]\n" | ||
307 | "-a <path> video input file\n" | ||
308 | "-v <path> video input file\n" | ||
309 | "-o <idx> output audio device index\n" | ||
310 | "-d print output audio devices\n" | ||
311 | "-h print this help\n", name); | ||
379 | 312 | ||
380 | return 0; | 313 | return 0; |
314 | } | ||
315 | |||
316 | int main (int argc, char** argv) | ||
317 | { | ||
318 | struct stat st; | ||
381 | 319 | ||
382 | if (argc == 2) { | 320 | /* AV files for testing */ |
383 | if (strcmp(argv[1], "-d") == 0 || strcmp(argv[1], "--devices") == 0) { | 321 | const char* af_name = NULL; |
384 | return print_devices(); | 322 | const char* vf_name = NULL; |
385 | } | 323 | long audio_out_dev_idx = 0; |
386 | if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) { | 324 | |
387 | return print_help(argv[0], 0); | 325 | /* Pasre settings */ |
388 | } | 326 | CHECK_ARG: switch (getopt(argc, argv, "a:v:o:dh")) { |
389 | } | 327 | case 'a': |
390 | 328 | af_name = optarg; | |
391 | if (argc != 3) { | 329 | goto CHECK_ARG; |
392 | fprintf(stderr, "Invalid input!\n"); | 330 | case 'v': |
393 | return print_help(argv[0], 1); | 331 | vf_name = optarg; |
394 | } | 332 | goto CHECK_ARG; |
395 | 333 | case 'o': { | |
396 | int i; | 334 | char *d; |
397 | 335 | audio_out_dev_idx = strtol(optarg, &d, 10); | |
398 | const char* in_device_name = ""; | 336 | if (*d) { |
399 | const char* out_device_name = ""; | 337 | printf("Invalid value for argument: 'o'"); |
400 | 338 | exit(1); | |
401 | { | 339 | } |
402 | long dev = get_device_idx(argv[1]); | 340 | goto CHECK_ARG; |
403 | if (dev == -1) | 341 | } |
404 | in_device_name = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); | 342 | case 'd': |
405 | else | 343 | return print_audio_devices(); |
406 | { | 344 | case 'h': |
407 | const char* tmp; | 345 | return print_help(argv[0]); |
408 | i = -1; | 346 | case '?': |
409 | for(tmp = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); *tmp && i != dev; | 347 | exit(1); |
410 | tmp += strlen( tmp ) + 1, ++i) | 348 | case -1:; |
411 | in_device_name = tmp; | 349 | } |
412 | } | 350 | |
413 | 351 | { /* Check files */ | |
414 | printf("Input device: %s\n", in_device_name); | 352 | if (!af_name) { |
415 | } | 353 | printf("Required audio input file!\n"); |
416 | 354 | exit(1); | |
417 | { | 355 | } |
418 | long dev = get_device_idx(argv[1]); | 356 | |
419 | if (dev == -1) | 357 | if (!vf_name) { |
420 | out_device_name = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); | 358 | printf("Required video input file!\n"); |
421 | else | 359 | exit(1); |
422 | { | 360 | } |
423 | const char* tmp; | 361 | |
424 | i = -1; | 362 | /* Check for files */ |
425 | for(tmp = alcGetString(NULL, ALC_DEVICE_SPECIFIER); *tmp && i != dev; | 363 | if(stat(af_name, &st) != 0 || !S_ISREG(st.st_mode)) |
426 | tmp += strlen( tmp ) + 1, ++i) | 364 | { |
427 | out_device_name = tmp; | 365 | printf("%s doesn't seem to be a regular file!\n", af_name); |
428 | } | 366 | exit(1); |
429 | 367 | } | |
430 | printf("Output device: %s\n", out_device_name); | 368 | |
431 | } | 369 | if(stat(vf_name, &st) != 0 || !S_ISREG(st.st_mode)) |
432 | 370 | { | |
433 | ALCdevice* out_device; | 371 | printf("%s doesn't seem to be a regular file!\n", vf_name); |
434 | ALCcontext* out_ctx; | 372 | exit(1); |
435 | uint32_t source; | 373 | } |
436 | uint32_t buffers[5]; | 374 | } |
375 | |||
376 | ALCdevice* audio_out_device; | ||
437 | 377 | ||
438 | { /* Open output device */ | 378 | { /* Open output device */ |
439 | out_device = alcOpenDevice(out_device_name); | 379 | const char* audio_out_dev_name = NULL; |
440 | if ( !out_device ) { | 380 | |
441 | fprintf(stderr, "Failed to open playback device: %s: %d\n", out_device_name, alGetError()); | 381 | int i = 0; |
442 | return 1; | 382 | for(audio_out_dev_name = alcGetString(NULL, ALC_DEVICE_SPECIFIER); i < audio_out_dev_idx; |
383 | audio_out_dev_name += strlen( audio_out_dev_name ) + 1, ++i) | ||
384 | if (!(audio_out_dev_name + strlen( audio_out_dev_name ) + 1)) | ||
385 | break; | ||
386 | |||
387 | audio_out_device = alcOpenDevice(audio_out_dev_name); | ||
388 | if ( !audio_out_device ) { | ||
389 | printf("Failed to open playback device: %s: %d\n", audio_out_dev_name, alGetError()); | ||
390 | exit(1); | ||
443 | } | 391 | } |
444 | 392 | ||
445 | out_ctx = alcCreateContext(out_device, NULL); | 393 | ALCcontext* out_ctx = alcCreateContext(audio_out_device, NULL); |
446 | alcMakeContextCurrent(out_ctx); | 394 | alcMakeContextCurrent(out_ctx); |
447 | 395 | ||
396 | uint32_t buffers[5]; | ||
448 | alGenBuffers(5, buffers); | 397 | alGenBuffers(5, buffers); |
449 | alGenSources((uint32_t)1, &source); | 398 | alGenSources((uint32_t)1, &adout); |
450 | alSourcei(source, AL_LOOPING, AL_FALSE); | 399 | alSourcei(adout, AL_LOOPING, AL_FALSE); |
451 | 400 | ||
452 | uint16_t zeros[10000]; | 401 | uint16_t zeros[10000]; |
453 | memset(zeros, 0, 10000); | 402 | memset(zeros, 0, 10000); |
@@ -455,45 +404,31 @@ AGAIN: | |||
455 | for ( i = 0; i < 5; ++i ) | 404 | for ( i = 0; i < 5; ++i ) |
456 | alBufferData(buffers[i], AL_FORMAT_STEREO16, zeros, 10000, 48000); | 405 | alBufferData(buffers[i], AL_FORMAT_STEREO16, zeros, 10000, 48000); |
457 | 406 | ||
458 | alSourceQueueBuffers(source, 5, buffers); | 407 | alSourceQueueBuffers(adout, 5, buffers); |
459 | alSourcePlay(source); | 408 | alSourcePlay(adout); |
409 | |||
410 | printf("Using audio device: %s\n", audio_out_dev_name); | ||
460 | } | 411 | } |
461 | 412 | ||
462 | ALCdevice* in_device; | 413 | printf("Using audio file: %s\n", af_name); |
463 | 414 | printf("Using video file: %s\n", vf_name); | |
464 | { /* Open input device */ | 415 | |
465 | in_device = alcCaptureOpenDevice(in_device_name, 48000, AL_FORMAT_STEREO16, 10000); | ||
466 | if ( !in_device ) { | ||
467 | fprintf(stderr, "Failed to open capture device: %s: %d\n", in_device_name, alGetError()); | ||
468 | return 1; | ||
469 | } | ||
470 | |||
471 | alcCaptureStart(in_device); | ||
472 | } | ||
473 | 416 | ||
474 | Tox *Bsn = tox_new(0); | ||
475 | Tox *Alice = tox_new(0); | ||
476 | Tox *Bob = tox_new(0); | ||
477 | 417 | ||
478 | assert(Bsn && Alice && Bob); | ||
479 | 418 | ||
480 | prepare(Bsn, Alice, Bob); | ||
481 | 419 | ||
420 | /* START TOX NETWORK */ | ||
421 | |||
422 | Tox *bootstrap; | ||
423 | ToxAV *AliceAV; | ||
424 | ToxAV *BobAV; | ||
425 | |||
426 | CallControl AliceCC; | ||
427 | CallControl BobCC; | ||
428 | |||
429 | initialize_tox(&bootstrap, &AliceAV, &AliceCC, &BobAV, &BobCC); | ||
482 | 430 | ||
483 | ToxAV *AliceAV, *BobAV; | ||
484 | CallControl AliceCC, BobCC; | ||
485 | 431 | ||
486 | { | ||
487 | TOXAV_ERR_NEW rc; | ||
488 | AliceAV = toxav_new(Alice, &rc); | ||
489 | assert(rc == TOXAV_ERR_NEW_OK); | ||
490 | |||
491 | BobAV = toxav_new(Bob, &rc); | ||
492 | assert(rc == TOXAV_ERR_NEW_OK); | ||
493 | |||
494 | prepareAV(AliceAV, &AliceCC, BobAV, &BobCC); | ||
495 | printf("Created 2 instances of ToxAV\n"); | ||
496 | } | ||
497 | 432 | ||
498 | 433 | ||
499 | #define REGULAR_CALL_FLOW(A_BR, V_BR) \ | 434 | #define REGULAR_CALL_FLOW(A_BR, V_BR) \ |
@@ -539,7 +474,7 @@ AGAIN: | |||
539 | } \ | 474 | } \ |
540 | } \ | 475 | } \ |
541 | \ | 476 | \ |
542 | iterate(Bsn, AliceAV, BobAV); \ | 477 | iterate(bootstrap, AliceAV, BobAV); \ |
543 | } \ | 478 | } \ |
544 | printf("Success!\n");\ | 479 | printf("Success!\n");\ |
545 | } while(0) | 480 | } while(0) |
@@ -578,7 +513,7 @@ AGAIN: | |||
578 | } | 513 | } |
579 | 514 | ||
580 | while (!BobCC.incoming) | 515 | while (!BobCC.incoming) |
581 | iterate(Bsn, AliceAV, BobAV); | 516 | iterate_tox(bootstrap, AliceAV, BobAV); |
582 | 517 | ||
583 | /* Reject */ | 518 | /* Reject */ |
584 | { | 519 | { |
@@ -592,7 +527,7 @@ AGAIN: | |||
592 | } | 527 | } |
593 | 528 | ||
594 | while (AliceCC.state != TOXAV_CALL_STATE_END) | 529 | while (AliceCC.state != TOXAV_CALL_STATE_END) |
595 | iterate(Bsn, AliceAV, BobAV); | 530 | iterate_tox(bootstrap, AliceAV, BobAV); |
596 | 531 | ||
597 | printf("Success!\n"); | 532 | printf("Success!\n"); |
598 | } | 533 | } |
@@ -614,7 +549,7 @@ AGAIN: | |||
614 | } | 549 | } |
615 | 550 | ||
616 | while (!BobCC.incoming) | 551 | while (!BobCC.incoming) |
617 | iterate(Bsn, AliceAV, BobAV); | 552 | iterate_tox(bootstrap, AliceAV, BobAV); |
618 | 553 | ||
619 | /* Cancel */ | 554 | /* Cancel */ |
620 | { | 555 | { |
@@ -629,7 +564,7 @@ AGAIN: | |||
629 | 564 | ||
630 | /* Alice will not receive end state */ | 565 | /* Alice will not receive end state */ |
631 | while (BobCC.state != TOXAV_CALL_STATE_END) | 566 | while (BobCC.state != TOXAV_CALL_STATE_END) |
632 | iterate(Bsn, AliceAV, BobAV); | 567 | iterate_tox(bootstrap, AliceAV, BobAV); |
633 | 568 | ||
634 | printf("Success!\n"); | 569 | printf("Success!\n"); |
635 | } | 570 | } |
@@ -652,7 +587,7 @@ AGAIN: | |||
652 | } | 587 | } |
653 | 588 | ||
654 | while (!BobCC.incoming) | 589 | while (!BobCC.incoming) |
655 | iterate(Bsn, AliceAV, BobAV); | 590 | iterate_tox(bootstrap, AliceAV, BobAV); |
656 | 591 | ||
657 | /* At first try all stuff while in invalid state */ | 592 | /* At first try all stuff while in invalid state */ |
658 | assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL)); | 593 | assert(!toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL)); |
@@ -670,39 +605,39 @@ AGAIN: | |||
670 | } | 605 | } |
671 | } | 606 | } |
672 | 607 | ||
673 | iterate(Bsn, AliceAV, BobAV); | 608 | iterate_tox(bootstrap, AliceAV, BobAV); |
674 | 609 | ||
675 | /* Pause and Resume */ | 610 | /* Pause and Resume */ |
676 | printf("Pause and Resume\n"); | 611 | printf("Pause and Resume\n"); |
677 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL)); | 612 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_PAUSE, NULL)); |
678 | iterate(Bsn, AliceAV, BobAV); | 613 | iterate_tox(bootstrap, AliceAV, BobAV); |
679 | assert(BobCC.state == TOXAV_CALL_STATE_PAUSED); | 614 | assert(BobCC.state == TOXAV_CALL_STATE_PAUSED); |
680 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_RESUME, NULL)); | 615 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_RESUME, NULL)); |
681 | iterate(Bsn, AliceAV, BobAV); | 616 | iterate_tox(bootstrap, AliceAV, BobAV); |
682 | assert(BobCC.state & (TOXAV_CALL_STATE_SENDING_A | TOXAV_CALL_STATE_SENDING_V)); | 617 | assert(BobCC.state & (TOXAV_CALL_STATE_SENDING_A | TOXAV_CALL_STATE_SENDING_V)); |
683 | 618 | ||
684 | /* Mute/Unmute single */ | 619 | /* Mute/Unmute single */ |
685 | printf("Mute/Unmute single\n"); | 620 | printf("Mute/Unmute single\n"); |
686 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL)); | 621 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL)); |
687 | iterate(Bsn, AliceAV, BobAV); | 622 | iterate_tox(bootstrap, AliceAV, BobAV); |
688 | assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_A); | 623 | assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_A); |
689 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL)); | 624 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL)); |
690 | iterate(Bsn, AliceAV, BobAV); | 625 | iterate_tox(bootstrap, AliceAV, BobAV); |
691 | assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_A); | 626 | assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_A); |
692 | 627 | ||
693 | /* Mute/Unmute both */ | 628 | /* Mute/Unmute both */ |
694 | printf("Mute/Unmute both\n"); | 629 | printf("Mute/Unmute both\n"); |
695 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL)); | 630 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL)); |
696 | iterate(Bsn, AliceAV, BobAV); | 631 | iterate_tox(bootstrap, AliceAV, BobAV); |
697 | assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_A); | 632 | assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_A); |
698 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_VIDEO, NULL)); | 633 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_VIDEO, NULL)); |
699 | iterate(Bsn, AliceAV, BobAV); | 634 | iterate_tox(bootstrap, AliceAV, BobAV); |
700 | assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_V); | 635 | assert(BobCC.state ^ TOXAV_CALL_STATE_RECEIVING_V); |
701 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL)); | 636 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_AUDIO, NULL)); |
702 | iterate(Bsn, AliceAV, BobAV); | 637 | iterate_tox(bootstrap, AliceAV, BobAV); |
703 | assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_A); | 638 | assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_A); |
704 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_VIDEO, NULL)); | 639 | assert(toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_TOGGLE_MUTE_VIDEO, NULL)); |
705 | iterate(Bsn, AliceAV, BobAV); | 640 | iterate_tox(bootstrap, AliceAV, BobAV); |
706 | assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_V); | 641 | assert(BobCC.state & TOXAV_CALL_STATE_RECEIVING_V); |
707 | 642 | ||
708 | { | 643 | { |
@@ -715,21 +650,22 @@ AGAIN: | |||
715 | } | 650 | } |
716 | } | 651 | } |
717 | 652 | ||
718 | iterate(Bsn, AliceAV, BobAV); | 653 | iterate_tox(bootstrap, AliceAV, BobAV); |
719 | assert(BobCC.state == TOXAV_CALL_STATE_END); | 654 | assert(BobCC.state == TOXAV_CALL_STATE_END); |
720 | 655 | ||
721 | printf("Success!\n"); | 656 | printf("Success!\n"); |
722 | } | 657 | } |
723 | 658 | ||
724 | if (TEST_TRANSFER_A) { /* Audio encoding/decoding and transfer */ | 659 | if (TEST_TRANSFER_A) { /* Audio encoding/decoding and transfer */ |
660 | SNDFILE* af_handle; | ||
661 | SF_INFO af_info; | ||
662 | |||
725 | printf("\nTrying audio enc/dec...\n"); | 663 | printf("\nTrying audio enc/dec...\n"); |
726 | 664 | ||
727 | memset(&AliceCC, 0, sizeof(CallControl)); | 665 | memset(&AliceCC, 0, sizeof(CallControl)); |
728 | memset(&BobCC, 0, sizeof(CallControl)); | 666 | memset(&BobCC, 0, sizeof(CallControl)); |
729 | |||
730 | AliceCC.output_source = BobCC.output_source = source; | ||
731 | 667 | ||
732 | { | 668 | { /* Call */ |
733 | TOXAV_ERR_CALL rc; | 669 | TOXAV_ERR_CALL rc; |
734 | toxav_call(AliceAV, 0, 48, 0, &rc); | 670 | toxav_call(AliceAV, 0, 48, 0, &rc); |
735 | 671 | ||
@@ -740,11 +676,11 @@ AGAIN: | |||
740 | } | 676 | } |
741 | 677 | ||
742 | while (!BobCC.incoming) | 678 | while (!BobCC.incoming) |
743 | iterate(Bsn, AliceAV, BobAV); | 679 | iterate_tox(bootstrap, AliceAV, BobAV); |
744 | 680 | ||
745 | { | 681 | { /* Answer */ |
746 | TOXAV_ERR_ANSWER rc; | 682 | TOXAV_ERR_ANSWER rc; |
747 | toxav_answer(BobAV, 0, 48, 0, &rc); | 683 | toxav_answer(BobAV, 0, 64, 0, &rc); |
748 | 684 | ||
749 | if (rc != TOXAV_ERR_ANSWER_OK) { | 685 | if (rc != TOXAV_ERR_ANSWER_OK) { |
750 | printf("toxav_answer failed: %d\n", rc); | 686 | printf("toxav_answer failed: %d\n", rc); |
@@ -752,26 +688,44 @@ AGAIN: | |||
752 | } | 688 | } |
753 | } | 689 | } |
754 | 690 | ||
755 | iterate(Bsn, AliceAV, BobAV); | 691 | iterate_tox(bootstrap, AliceAV, BobAV); |
756 | |||
757 | int16_t PCM[10000]; | ||
758 | time_t start_time = time(NULL); | ||
759 | 692 | ||
693 | /* Open audio file */ | ||
694 | af_handle = sf_open(af_name, SFM_READ, &af_info); | ||
695 | if (af_handle == NULL) | ||
696 | { | ||
697 | printf("Failed to open the file.\n"); | ||
698 | exit(1); | ||
699 | } | ||
700 | |||
760 | /* Run for 5 seconds */ | 701 | /* Run for 5 seconds */ |
761 | while ( start_time + 10 > time(NULL) ) { | 702 | |
762 | int frame_size = device_read_frame(in_device, 20, PCM, sizeof(PCM)); | 703 | uint32_t frame_duration = 10; |
763 | if (frame_size > 0) { | 704 | int16_t PCM[10000]; |
764 | TOXAV_ERR_SEND_FRAME rc; | 705 | |
765 | if (toxav_send_audio_frame(AliceAV, 0, PCM, frame_size, 2, 8000, &rc) == false) { | 706 | time_t start_time = time(NULL); |
766 | printf("Error sending frame of size %d: %d\n", frame_size, rc); | 707 | time_t expected_time = af_info.frames / af_info.samplerate + 2; |
767 | exit (1); | 708 | |
768 | } | 709 | while ( start_time + expected_time > time(NULL) ) { |
769 | } | 710 | int frame_size = (af_info.samplerate * frame_duration / 1000); |
770 | 711 | ||
771 | iterate(Bsn, AliceAV, BobAV); | 712 | int64_t count = sf_read_short(af_handle, PCM, frame_size); |
713 | if (count > 0) { | ||
714 | TOXAV_ERR_SEND_FRAME rc; | ||
715 | if (toxav_send_audio_frame(AliceAV, 0, PCM, count, af_info.channels, af_info.samplerate, &rc) == false) { | ||
716 | printf("Error sending frame of size %ld: %d\n", count, rc); | ||
717 | exit(1); | ||
718 | } | ||
719 | } | ||
720 | |||
721 | iterate_tox(bootstrap, AliceAV, BobAV); | ||
772 | } | 722 | } |
723 | |||
724 | printf("Played file in: %lu\n", time(NULL) - start_time); | ||
725 | |||
726 | sf_close(af_handle); | ||
773 | 727 | ||
774 | { | 728 | { /* Hangup */ |
775 | TOXAV_ERR_CALL_CONTROL rc; | 729 | TOXAV_ERR_CALL_CONTROL rc; |
776 | toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc); | 730 | toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc); |
777 | 731 | ||
@@ -781,24 +735,19 @@ AGAIN: | |||
781 | } | 735 | } |
782 | } | 736 | } |
783 | 737 | ||
784 | iterate(Bsn, AliceAV, BobAV); | 738 | iterate_tox(bootstrap, AliceAV, BobAV); |
785 | assert(BobCC.state == TOXAV_CALL_STATE_END); | 739 | assert(BobCC.state == TOXAV_CALL_STATE_END); |
786 | 740 | ||
787 | printf("Success!"); | 741 | printf("Success!"); |
788 | } | 742 | } |
789 | 743 | ||
790 | if (TEST_TRANSFER_V) { | 744 | if (TEST_TRANSFER_V) { |
791 | if (strlen(video_in) == 0) { | 745 | cvNamedWindow(vdout, CV_WINDOW_AUTOSIZE); |
792 | printf("Skipping video test...\n"); | ||
793 | goto CONTINUE; | ||
794 | } | ||
795 | 746 | ||
796 | cvNamedWindow(video_test_window, CV_WINDOW_AUTOSIZE); | 747 | CvCapture* capture = cvCreateFileCapture(vf_name); |
797 | |||
798 | CvCapture* capture = cvCreateFileCapture(video_in); | ||
799 | if (!capture) { | 748 | if (!capture) { |
800 | printf("No file named: %s\n", video_in); | 749 | printf("Failed to open video file: %s\n", vf_name); |
801 | return 1; | 750 | exit(1); |
802 | } | 751 | } |
803 | 752 | ||
804 | IplImage* frame; | 753 | IplImage* frame; |
@@ -812,21 +761,20 @@ AGAIN: | |||
812 | } | 761 | } |
813 | 762 | ||
814 | cvReleaseCapture(&capture); | 763 | cvReleaseCapture(&capture); |
815 | cvDestroyWindow(video_test_window); | 764 | cvDestroyWindow(vdout); |
816 | |||
817 | CONTINUE:; | ||
818 | } | 765 | } |
819 | 766 | ||
820 | 767 | ||
768 | Tox* Alice = toxav_get_tox(AliceAV); | ||
769 | Tox* Bob = toxav_get_tox(BobAV); | ||
821 | toxav_kill(BobAV); | 770 | toxav_kill(BobAV); |
822 | toxav_kill(AliceAV); | 771 | toxav_kill(AliceAV); |
823 | tox_kill(Bob); | 772 | tox_kill(Bob); |
824 | tox_kill(Alice); | 773 | tox_kill(Alice); |
825 | tox_kill(Bsn); | 774 | tox_kill(bootstrap); |
826 | 775 | ||
827 | printf("\nTest successful!\n"); | 776 | printf("\nTest successful!\n"); |
828 | 777 | ||
829 | alcCloseDevice(out_device); | 778 | alcCloseDevice(audio_out_device); |
830 | alcCaptureCloseDevice(in_device); | ||
831 | return 0; | 779 | return 0; |
832 | } | 780 | } |