diff options
author | mannol <eniz_vukovic@hotmail.com> | 2015-02-14 23:37:52 +0100 |
---|---|---|
committer | mannol <eniz_vukovic@hotmail.com> | 2015-02-14 23:37:52 +0100 |
commit | aad857527cd63b5f79786df0c1aab50f4de87774 (patch) | |
tree | c94463c21fe2d73b1ec514b223a5e0166e1e8693 /toxav/toxav_new_1.c | |
parent | 39680f31d0121cef2358507fcea84cacad69893a (diff) |
Control part of new api already kind of works
Diffstat (limited to 'toxav/toxav_new_1.c')
-rw-r--r-- | toxav/toxav_new_1.c | 689 |
1 files changed, 689 insertions, 0 deletions
diff --git a/toxav/toxav_new_1.c b/toxav/toxav_new_1.c new file mode 100644 index 00000000..ee7f49a6 --- /dev/null +++ b/toxav/toxav_new_1.c | |||
@@ -0,0 +1,689 @@ | |||
1 | /** toxav.c | ||
2 | * | ||
3 | * Copyright (C) 2013 Tox project All Rights Reserved. | ||
4 | * | ||
5 | * This file is part of Tox. | ||
6 | * | ||
7 | * Tox is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation, either version 3 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * Tox is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifdef HAVE_CONFIG_H | ||
23 | #include "config.h" | ||
24 | #endif /* HAVE_CONFIG_H */ | ||
25 | |||
26 | #define __TOX_DEFINED__ | ||
27 | typedef struct Messenger Tox; | ||
28 | |||
29 | #define _GNU_SOURCE /* implicit declaration warning */ | ||
30 | |||
31 | #include "codec.h" | ||
32 | #include "msi.h" | ||
33 | #include "group.h" | ||
34 | |||
35 | #include "../toxcore/logger.h" | ||
36 | #include "../toxcore/util.h" | ||
37 | |||
38 | #include <assert.h> | ||
39 | #include <stdlib.h> | ||
40 | #include <string.h> | ||
41 | |||
42 | /* Assume 24 fps*/ | ||
43 | #define MAX_ENCODE_TIME_US ((1000 / 24) * 1000) | ||
44 | |||
45 | /* true if invalid call index */ | ||
46 | #define CALL_INVALID_INDEX(idx, max) (idx < 0 || idx >= max) | ||
47 | |||
48 | const ToxAvCSettings av_DefaultSettings = { | ||
49 | av_TypeAudio, | ||
50 | |||
51 | 500, | ||
52 | 1280, | ||
53 | 720, | ||
54 | |||
55 | 32000, | ||
56 | 20, | ||
57 | 48000, | ||
58 | 1 | ||
59 | }; | ||
60 | |||
61 | static const uint32_t jbuf_capacity = 6; | ||
62 | static const uint8_t audio_index = 0, video_index = 1; | ||
63 | |||
64 | typedef struct _ToxAvCall { | ||
65 | pthread_mutex_t mutex_control[1]; | ||
66 | pthread_mutex_t mutex_encoding_audio[1]; | ||
67 | pthread_mutex_t mutex_encoding_video[1]; | ||
68 | pthread_mutex_t mutex_do[1]; | ||
69 | RTPSession *crtps[2]; /** Audio is first and video is second */ | ||
70 | CSSession *cs; | ||
71 | _Bool active; | ||
72 | } ToxAvCall; | ||
73 | |||
74 | struct _ToxAv { | ||
75 | Messenger *messenger; | ||
76 | MSISession *msi_session; /** Main msi session */ | ||
77 | ToxAvCall *calls; /** Per-call params */ | ||
78 | uint32_t max_calls; | ||
79 | |||
80 | PAIR(ToxAvAudioCallback, void *) acb; | ||
81 | PAIR(ToxAvVideoCallback, void *) vcb; | ||
82 | |||
83 | /* Decode time measure */ | ||
84 | int32_t dectmsscount; /** Measure count */ | ||
85 | int32_t dectmsstotal; /** Last cycle total */ | ||
86 | int32_t avgdectms; /** Average decoding time in ms */ | ||
87 | }; | ||
88 | |||
89 | static const MSICSettings *msicsettings_cast (const ToxAvCSettings *from) | ||
90 | { | ||
91 | assert(sizeof(MSICSettings) == sizeof(ToxAvCSettings)); | ||
92 | return (const MSICSettings *) from; | ||
93 | } | ||
94 | |||
95 | static const ToxAvCSettings *toxavcsettings_cast (const MSICSettings *from) | ||
96 | { | ||
97 | assert(sizeof(MSICSettings) == sizeof(ToxAvCSettings)); | ||
98 | return (const ToxAvCSettings *) from; | ||
99 | |||
100 | } | ||
101 | |||
102 | ToxAv *toxav_new( Tox *messenger, int32_t max_calls) | ||
103 | { | ||
104 | ToxAv *av = calloc ( sizeof(ToxAv), 1); | ||
105 | |||
106 | if (av == NULL) { | ||
107 | LOGGER_WARNING("Allocation failed!"); | ||
108 | return NULL; | ||
109 | } | ||
110 | |||
111 | av->messenger = (Messenger *)messenger; | ||
112 | av->msi_session = msi_new(av->messenger, max_calls); | ||
113 | av->msi_session->agent_handler = av; | ||
114 | av->calls = calloc(sizeof(ToxAvCall), max_calls); | ||
115 | av->max_calls = max_calls; | ||
116 | |||
117 | unsigned int i; | ||
118 | |||
119 | for (i = 0; i < max_calls; ++i) { | ||
120 | if (create_recursive_mutex(av->calls[i].mutex_control) != 0 ) { | ||
121 | LOGGER_WARNING("Failed to init call(%u) mutex!", i); | ||
122 | msi_kill(av->msi_session); | ||
123 | |||
124 | free(av->calls); | ||
125 | free(av); | ||
126 | return NULL; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | return av; | ||
131 | } | ||
132 | |||
133 | void toxav_kill ( ToxAv *av ) | ||
134 | { | ||
135 | uint32_t i; | ||
136 | |||
137 | for (i = 0; i < av->max_calls; i ++) { | ||
138 | if ( av->calls[i].crtps[audio_index] ) | ||
139 | rtp_kill(av->calls[i].crtps[audio_index], av->msi_session->messenger_handle); | ||
140 | |||
141 | |||
142 | if ( av->calls[i].crtps[video_index] ) | ||
143 | rtp_kill(av->calls[i].crtps[video_index], av->msi_session->messenger_handle); | ||
144 | |||
145 | if ( av->calls[i].cs ) | ||
146 | cs_kill(av->calls[i].cs); | ||
147 | |||
148 | pthread_mutex_destroy(av->calls[i].mutex_control); | ||
149 | } | ||
150 | |||
151 | msi_kill(av->msi_session); | ||
152 | |||
153 | free(av->calls); | ||
154 | free(av); | ||
155 | } | ||
156 | |||
157 | uint32_t toxav_do_interval(ToxAv *av) | ||
158 | { | ||
159 | int i = 0; | ||
160 | uint32_t rc = 200 + av->avgdectms; /* Return 200 if no call is active */ | ||
161 | |||
162 | for (; i < av->max_calls; i ++) { | ||
163 | pthread_mutex_lock(av->calls[i].mutex_control); | ||
164 | |||
165 | if (av->calls[i].active) { | ||
166 | /* This should work. Video payload will always come in greater intervals */ | ||
167 | rc = MIN(av->calls[i].cs->audio_decoder_frame_duration, rc); | ||
168 | } | ||
169 | |||
170 | pthread_mutex_unlock(av->calls[i].mutex_control); | ||
171 | } | ||
172 | |||
173 | return rc < av->avgdectms ? 0 : rc - av->avgdectms; | ||
174 | } | ||
175 | |||
176 | void toxav_do(ToxAv *av) | ||
177 | { | ||
178 | msi_do(av->msi_session); | ||
179 | |||
180 | uint64_t start = current_time_monotonic(); | ||
181 | |||
182 | uint32_t i = 0; | ||
183 | |||
184 | for (; i < av->max_calls; i ++) { | ||
185 | pthread_mutex_lock(av->calls[i].mutex_control); | ||
186 | |||
187 | if (av->calls[i].active) { | ||
188 | pthread_mutex_lock(av->calls[i].mutex_do); | ||
189 | pthread_mutex_unlock(av->calls[i].mutex_control); | ||
190 | cs_do(av->calls[i].cs); | ||
191 | pthread_mutex_unlock(av->calls[i].mutex_do); | ||
192 | } else { | ||
193 | pthread_mutex_unlock(av->calls[i].mutex_control); | ||
194 | } | ||
195 | } | ||
196 | |||
197 | uint64_t end = current_time_monotonic(); | ||
198 | |||
199 | /* TODO maybe use variable for sizes */ | ||
200 | av->dectmsstotal += end - start; | ||
201 | |||
202 | if (++av->dectmsscount == 3) { | ||
203 | av->avgdectms = av->dectmsstotal / 3 + 2 /* NOTE Magic Offset */; | ||
204 | av->dectmsscount = 0; | ||
205 | av->dectmsstotal = 0; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | void toxav_register_callstate_callback ( ToxAv *av, ToxAVCallback cb, ToxAvCallbackID id, void *userdata ) | ||
210 | { | ||
211 | msi_register_callback(av->msi_session, (MSICallbackType)cb, (MSICallbackID) id, userdata); | ||
212 | } | ||
213 | |||
214 | void toxav_register_audio_callback(ToxAv *av, ToxAvAudioCallback cb, void *userdata) | ||
215 | { | ||
216 | av->acb.first = cb; | ||
217 | av->acb.second = userdata; | ||
218 | } | ||
219 | |||
220 | void toxav_register_video_callback(ToxAv *av, ToxAvVideoCallback cb, void *userdata) | ||
221 | { | ||
222 | av->vcb.first = cb; | ||
223 | av->vcb.second = userdata; | ||
224 | } | ||
225 | |||
226 | int toxav_call (ToxAv *av, | ||
227 | int32_t *call_index, | ||
228 | int user, | ||
229 | const ToxAvCSettings *csettings, | ||
230 | int ringing_seconds ) | ||
231 | { | ||
232 | return msi_invite(av->msi_session, call_index, msicsettings_cast(csettings), ringing_seconds * 1000, user); | ||
233 | } | ||
234 | |||
235 | int toxav_hangup ( ToxAv *av, int32_t call_index ) | ||
236 | { | ||
237 | return msi_hangup(av->msi_session, call_index); | ||
238 | } | ||
239 | |||
240 | int toxav_answer ( ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings ) | ||
241 | { | ||
242 | return msi_answer(av->msi_session, call_index, msicsettings_cast(csettings)); | ||
243 | } | ||
244 | |||
245 | int toxav_reject ( ToxAv *av, int32_t call_index, const char *reason ) | ||
246 | { | ||
247 | return msi_reject(av->msi_session, call_index, reason); | ||
248 | } | ||
249 | |||
250 | int toxav_cancel ( ToxAv *av, int32_t call_index, int peer_id, const char *reason ) | ||
251 | { | ||
252 | return msi_cancel(av->msi_session, call_index, peer_id, reason); | ||
253 | } | ||
254 | |||
255 | int toxav_change_settings(ToxAv *av, int32_t call_index, const ToxAvCSettings *csettings) | ||
256 | { | ||
257 | return msi_change_csettings(av->msi_session, call_index, msicsettings_cast(csettings)); | ||
258 | } | ||
259 | |||
260 | int toxav_stop_call ( ToxAv *av, int32_t call_index ) | ||
261 | { | ||
262 | return msi_stopcall(av->msi_session, call_index); | ||
263 | } | ||
264 | |||
265 | int toxav_prepare_transmission ( ToxAv *av, int32_t call_index, int support_video ) | ||
266 | { | ||
267 | if ( !av->msi_session || CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) || | ||
268 | !av->msi_session->calls[call_index] || !av->msi_session->calls[call_index]->csettings_peer) { | ||
269 | LOGGER_ERROR("Error while starting RTP session: invalid call!\n"); | ||
270 | return av_ErrorNoCall; | ||
271 | } | ||
272 | |||
273 | ToxAvCall *call = &av->calls[call_index]; | ||
274 | |||
275 | pthread_mutex_lock(call->mutex_control); | ||
276 | |||
277 | if (call->active) { | ||
278 | pthread_mutex_unlock(call->mutex_control); | ||
279 | LOGGER_ERROR("Error while starting RTP session: call already active!\n"); | ||
280 | return av_ErrorAlreadyInCallWithPeer; | ||
281 | } | ||
282 | |||
283 | if (pthread_mutex_init(call->mutex_encoding_audio, NULL) != 0 | ||
284 | || pthread_mutex_init(call->mutex_encoding_video, NULL) != 0 || pthread_mutex_init(call->mutex_do, NULL) != 0) { | ||
285 | pthread_mutex_unlock(call->mutex_control); | ||
286 | LOGGER_ERROR("Error while starting RTP session: mutex initializing failed!\n"); | ||
287 | return av_ErrorUnknown; | ||
288 | } | ||
289 | |||
290 | const ToxAvCSettings *c_peer = toxavcsettings_cast | ||
291 | (&av->msi_session->calls[call_index]->csettings_peer[0]); | ||
292 | const ToxAvCSettings *c_self = toxavcsettings_cast | ||
293 | (&av->msi_session->calls[call_index]->csettings_local); | ||
294 | |||
295 | LOGGER_DEBUG( | ||
296 | "Type: %u(s) %u(p)\n" | ||
297 | "Video bitrate: %u(s) %u(p)\n" | ||
298 | "Video height: %u(s) %u(p)\n" | ||
299 | "Video width: %u(s) %u(p)\n" | ||
300 | "Audio bitrate: %u(s) %u(p)\n" | ||
301 | "Audio framedur: %u(s) %u(p)\n" | ||
302 | "Audio sample rate: %u(s) %u(p)\n" | ||
303 | "Audio channels: %u(s) %u(p)\n", | ||
304 | c_self->call_type, c_peer->call_type, | ||
305 | c_self->video_bitrate, c_peer->video_bitrate, | ||
306 | c_self->max_video_height, c_peer->max_video_height, | ||
307 | c_self->max_video_width, c_peer->max_video_width, | ||
308 | c_self->audio_bitrate, c_peer->audio_bitrate, | ||
309 | c_self->audio_frame_duration, c_peer->audio_frame_duration, | ||
310 | c_self->audio_sample_rate, c_peer->audio_sample_rate, | ||
311 | c_self->audio_channels, c_peer->audio_channels ); | ||
312 | |||
313 | if ( !(call->cs = cs_new(c_self, c_peer, jbuf_capacity, support_video)) ) { | ||
314 | LOGGER_ERROR("Error while starting Codec State!\n"); | ||
315 | pthread_mutex_unlock(call->mutex_control); | ||
316 | return av_ErrorInitializingCodecs; | ||
317 | } | ||
318 | |||
319 | call->cs->agent = av; | ||
320 | call->cs->call_idx = call_index; | ||
321 | |||
322 | call->cs->acb.first = av->acb.first; | ||
323 | call->cs->acb.second = av->acb.second; | ||
324 | |||
325 | call->cs->vcb.first = av->vcb.first; | ||
326 | call->cs->vcb.second = av->vcb.second; | ||
327 | |||
328 | |||
329 | call->crtps[audio_index] = | ||
330 | rtp_new(msi_TypeAudio, av->messenger, av->msi_session->calls[call_index]->peers[0]); | ||
331 | |||
332 | if ( !call->crtps[audio_index] ) { | ||
333 | LOGGER_ERROR("Error while starting audio RTP session!\n"); | ||
334 | goto error; | ||
335 | } | ||
336 | |||
337 | call->crtps[audio_index]->cs = call->cs; | ||
338 | |||
339 | if ( support_video ) { | ||
340 | call->crtps[video_index] = | ||
341 | rtp_new(msi_TypeVideo, av->messenger, av->msi_session->calls[call_index]->peers[0]); | ||
342 | |||
343 | if ( !call->crtps[video_index] ) { | ||
344 | LOGGER_ERROR("Error while starting video RTP session!\n"); | ||
345 | goto error; | ||
346 | } | ||
347 | |||
348 | call->crtps[video_index]->cs = call->cs; | ||
349 | } | ||
350 | |||
351 | call->active = 1; | ||
352 | pthread_mutex_unlock(call->mutex_control); | ||
353 | return av_ErrorNone; | ||
354 | error: | ||
355 | rtp_kill(call->crtps[audio_index], av->messenger); | ||
356 | call->crtps[audio_index] = NULL; | ||
357 | rtp_kill(call->crtps[video_index], av->messenger); | ||
358 | call->crtps[video_index] = NULL; | ||
359 | cs_kill(call->cs); | ||
360 | call->cs = NULL; | ||
361 | call->active = 0; | ||
362 | pthread_mutex_destroy(call->mutex_encoding_audio); | ||
363 | pthread_mutex_destroy(call->mutex_encoding_video); | ||
364 | pthread_mutex_destroy(call->mutex_do); | ||
365 | |||
366 | pthread_mutex_unlock(call->mutex_control); | ||
367 | return av_ErrorCreatingRtpSessions; | ||
368 | } | ||
369 | |||
370 | int toxav_kill_transmission ( ToxAv *av, int32_t call_index ) | ||
371 | { | ||
372 | if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) { | ||
373 | LOGGER_WARNING("Invalid call index: %d", call_index); | ||
374 | return av_ErrorNoCall; | ||
375 | } | ||
376 | |||
377 | ToxAvCall *call = &av->calls[call_index]; | ||
378 | |||
379 | pthread_mutex_lock(call->mutex_control); | ||
380 | |||
381 | if (!call->active) { | ||
382 | pthread_mutex_unlock(call->mutex_control); | ||
383 | LOGGER_WARNING("Action on inactive call: %d", call_index); | ||
384 | return av_ErrorInvalidState; | ||
385 | } | ||
386 | |||
387 | call->active = 0; | ||
388 | |||
389 | pthread_mutex_lock(call->mutex_encoding_audio); | ||
390 | pthread_mutex_unlock(call->mutex_encoding_audio); | ||
391 | pthread_mutex_lock(call->mutex_encoding_video); | ||
392 | pthread_mutex_unlock(call->mutex_encoding_video); | ||
393 | pthread_mutex_lock(call->mutex_do); | ||
394 | pthread_mutex_unlock(call->mutex_do); | ||
395 | |||
396 | rtp_kill(call->crtps[audio_index], av->messenger); | ||
397 | call->crtps[audio_index] = NULL; | ||
398 | rtp_kill(call->crtps[video_index], av->messenger); | ||
399 | call->crtps[video_index] = NULL; | ||
400 | cs_kill(call->cs); | ||
401 | call->cs = NULL; | ||
402 | |||
403 | pthread_mutex_destroy(call->mutex_encoding_audio); | ||
404 | pthread_mutex_destroy(call->mutex_encoding_video); | ||
405 | pthread_mutex_destroy(call->mutex_do); | ||
406 | |||
407 | pthread_mutex_unlock(call->mutex_control); | ||
408 | |||
409 | return av_ErrorNone; | ||
410 | } | ||
411 | |||
412 | static int toxav_send_rtp_payload(ToxAv *av, | ||
413 | ToxAvCall *call, | ||
414 | ToxAvCallType type, | ||
415 | const uint8_t *payload, | ||
416 | unsigned int length) | ||
417 | { | ||
418 | if (call->crtps[type - av_TypeAudio]) { | ||
419 | |||
420 | /* Audio */ | ||
421 | if (type == av_TypeAudio) | ||
422 | return rtp_send_msg(call->crtps[audio_index], av->messenger, payload, length); | ||
423 | |||
424 | /* Video */ | ||
425 | int parts = cs_split_video_payload(call->cs, payload, length); | ||
426 | |||
427 | if (parts < 0) return parts; | ||
428 | |||
429 | uint16_t part_size; | ||
430 | const uint8_t *iter; | ||
431 | |||
432 | int i; | ||
433 | |||
434 | for (i = 0; i < parts; i++) { | ||
435 | iter = cs_iterate_split_video_frame(call->cs, &part_size); | ||
436 | |||
437 | if (rtp_send_msg(call->crtps[video_index], av->messenger, iter, part_size) < 0) | ||
438 | return av_ErrorSendingPayload; | ||
439 | } | ||
440 | |||
441 | return av_ErrorNone; | ||
442 | |||
443 | } else return av_ErrorNoRtpSession; | ||
444 | } | ||
445 | |||
446 | int toxav_prepare_video_frame ( ToxAv *av, int32_t call_index, uint8_t *dest, int dest_max, vpx_image_t *input) | ||
447 | { | ||
448 | if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) { | ||
449 | LOGGER_WARNING("Invalid call index: %d", call_index); | ||
450 | return av_ErrorNoCall; | ||
451 | } | ||
452 | |||
453 | |||
454 | ToxAvCall *call = &av->calls[call_index]; | ||
455 | pthread_mutex_lock(call->mutex_control); | ||
456 | |||
457 | if (!call->active) { | ||
458 | pthread_mutex_unlock(call->mutex_control); | ||
459 | LOGGER_WARNING("Action on inactive call: %d", call_index); | ||
460 | return av_ErrorInvalidState; | ||
461 | } | ||
462 | |||
463 | if (cs_set_sending_video_resolution(call->cs, input->d_w, input->d_h) < 0) { | ||
464 | pthread_mutex_unlock(call->mutex_control); | ||
465 | return av_ErrorSettingVideoResolution; | ||
466 | } | ||
467 | |||
468 | pthread_mutex_lock(call->mutex_encoding_video); | ||
469 | pthread_mutex_unlock(call->mutex_control); | ||
470 | |||
471 | int rc = vpx_codec_encode(call->cs->v_encoder, input, call->cs->frame_counter, 1, 0, MAX_ENCODE_TIME_US); | ||
472 | |||
473 | if ( rc != VPX_CODEC_OK) { | ||
474 | LOGGER_ERROR("Could not encode video frame: %s\n", vpx_codec_err_to_string(rc)); | ||
475 | pthread_mutex_unlock(call->mutex_encoding_video); | ||
476 | return av_ErrorEncodingVideo; | ||
477 | } | ||
478 | |||
479 | ++call->cs->frame_counter; | ||
480 | |||
481 | vpx_codec_iter_t iter = NULL; | ||
482 | const vpx_codec_cx_pkt_t *pkt; | ||
483 | int copied = 0; | ||
484 | |||
485 | while ( (pkt = vpx_codec_get_cx_data(call->cs->v_encoder, &iter)) ) { | ||
486 | if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { | ||
487 | if ( copied + pkt->data.frame.sz > dest_max ) { | ||
488 | pthread_mutex_unlock(call->mutex_encoding_video); | ||
489 | return av_ErrorPacketTooLarge; | ||
490 | } | ||
491 | |||
492 | memcpy(dest + copied, pkt->data.frame.buf, pkt->data.frame.sz); | ||
493 | copied += pkt->data.frame.sz; | ||
494 | } | ||
495 | } | ||
496 | |||
497 | pthread_mutex_unlock(call->mutex_encoding_video); | ||
498 | return copied; | ||
499 | } | ||
500 | |||
501 | int toxav_send_video ( ToxAv *av, int32_t call_index, const uint8_t *frame, unsigned int frame_size) | ||
502 | { | ||
503 | |||
504 | if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) { | ||
505 | LOGGER_WARNING("Invalid call index: %d", call_index); | ||
506 | return av_ErrorNoCall; | ||
507 | } | ||
508 | |||
509 | ToxAvCall *call = &av->calls[call_index]; | ||
510 | pthread_mutex_lock(call->mutex_control); | ||
511 | |||
512 | |||
513 | if (!call->active) { | ||
514 | pthread_mutex_unlock(call->mutex_control); | ||
515 | LOGGER_WARNING("Action on inactive call: %d", call_index); | ||
516 | return av_ErrorInvalidState; | ||
517 | } | ||
518 | |||
519 | int rc = toxav_send_rtp_payload(av, call, av_TypeVideo, frame, frame_size); | ||
520 | pthread_mutex_unlock(call->mutex_control); | ||
521 | |||
522 | return rc; | ||
523 | } | ||
524 | |||
525 | int toxav_prepare_audio_frame ( ToxAv *av, | ||
526 | int32_t call_index, | ||
527 | uint8_t *dest, | ||
528 | int dest_max, | ||
529 | const int16_t *frame, | ||
530 | int frame_size) | ||
531 | { | ||
532 | if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) { | ||
533 | LOGGER_WARNING("Action on nonexisting call: %d", call_index); | ||
534 | return av_ErrorNoCall; | ||
535 | } | ||
536 | |||
537 | ToxAvCall *call = &av->calls[call_index]; | ||
538 | pthread_mutex_lock(call->mutex_control); | ||
539 | |||
540 | if (!call->active) { | ||
541 | pthread_mutex_unlock(call->mutex_control); | ||
542 | LOGGER_WARNING("Action on inactive call: %d", call_index); | ||
543 | return av_ErrorInvalidState; | ||
544 | } | ||
545 | |||
546 | pthread_mutex_lock(call->mutex_encoding_audio); | ||
547 | pthread_mutex_unlock(call->mutex_control); | ||
548 | int32_t rc = opus_encode(call->cs->audio_encoder, frame, frame_size, dest, dest_max); | ||
549 | pthread_mutex_unlock(call->mutex_encoding_audio); | ||
550 | |||
551 | if (rc < 0) { | ||
552 | LOGGER_ERROR("Failed to encode payload: %s\n", opus_strerror(rc)); | ||
553 | return av_ErrorEncodingAudio; | ||
554 | } | ||
555 | |||
556 | return rc; | ||
557 | } | ||
558 | |||
559 | int toxav_send_audio ( ToxAv *av, int32_t call_index, const uint8_t *data, unsigned int size) | ||
560 | { | ||
561 | if (CALL_INVALID_INDEX(call_index, av->msi_session->max_calls)) { | ||
562 | LOGGER_WARNING("Action on nonexisting call: %d", call_index); | ||
563 | return av_ErrorNoCall; | ||
564 | } | ||
565 | |||
566 | ToxAvCall *call = &av->calls[call_index]; | ||
567 | pthread_mutex_lock(call->mutex_control); | ||
568 | |||
569 | |||
570 | if (!call->active) { | ||
571 | pthread_mutex_unlock(call->mutex_control); | ||
572 | LOGGER_WARNING("Action on inactive call: %d", call_index); | ||
573 | return av_ErrorInvalidState; | ||
574 | } | ||
575 | |||
576 | int rc = toxav_send_rtp_payload(av, call, av_TypeAudio, data, size); | ||
577 | pthread_mutex_unlock(call->mutex_control); | ||
578 | return rc; | ||
579 | } | ||
580 | |||
581 | int toxav_get_peer_csettings ( ToxAv *av, int32_t call_index, int peer, ToxAvCSettings *dest ) | ||
582 | { | ||
583 | if ( peer < 0 || CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) || | ||
584 | !av->msi_session->calls[call_index] || av->msi_session->calls[call_index]->peer_count <= peer ) | ||
585 | return av_ErrorNoCall; | ||
586 | |||
587 | *dest = *toxavcsettings_cast(&av->msi_session->calls[call_index]->csettings_peer[peer]); | ||
588 | return av_ErrorNone; | ||
589 | } | ||
590 | |||
591 | int toxav_get_peer_id ( ToxAv *av, int32_t call_index, int peer ) | ||
592 | { | ||
593 | if ( peer < 0 || CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) || !av->msi_session->calls[call_index] | ||
594 | || av->msi_session->calls[call_index]->peer_count <= peer ) | ||
595 | return av_ErrorNoCall; | ||
596 | |||
597 | return av->msi_session->calls[call_index]->peers[peer]; | ||
598 | } | ||
599 | |||
600 | ToxAvCallState toxav_get_call_state(ToxAv *av, int32_t call_index) | ||
601 | { | ||
602 | if ( CALL_INVALID_INDEX(call_index, av->msi_session->max_calls) || !av->msi_session->calls[call_index] ) | ||
603 | return av_CallNonExistent; | ||
604 | |||
605 | return av->msi_session->calls[call_index]->state; | ||
606 | |||
607 | } | ||
608 | |||
609 | int toxav_capability_supported ( ToxAv *av, int32_t call_index, ToxAvCapabilities capability ) | ||
610 | { | ||
611 | } | ||
612 | |||
613 | Tox *toxav_get_tox(ToxAv *av) | ||
614 | { | ||
615 | return (Tox *)av->messenger; | ||
616 | } | ||
617 | |||
618 | int toxav_get_active_count(ToxAv *av) | ||
619 | { | ||
620 | if (!av) return -1; | ||
621 | |||
622 | int rc = 0, i = 0; | ||
623 | |||
624 | for (; i < av->max_calls; i++) { | ||
625 | pthread_mutex_lock(av->calls[i].mutex_control); | ||
626 | |||
627 | if (av->calls[i].active) rc++; | ||
628 | |||
629 | pthread_mutex_unlock(av->calls[i].mutex_control); | ||
630 | } | ||
631 | |||
632 | return rc; | ||
633 | } | ||
634 | |||
635 | /* Create a new toxav group. | ||
636 | * | ||
637 | * return group number on success. | ||
638 | * return -1 on failure. | ||
639 | * | ||
640 | * Audio data callback format: | ||
641 | * audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata) | ||
642 | * | ||
643 | * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). | ||
644 | */ | ||
645 | int toxav_add_av_groupchat(Tox *tox, void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int, | ||
646 | uint8_t, unsigned int, void *), void *userdata) | ||
647 | { | ||
648 | Messenger *m = tox; | ||
649 | return add_av_groupchat(m->group_chat_object, audio_callback, userdata); | ||
650 | } | ||
651 | |||
652 | /* Join a AV group (you need to have been invited first.) | ||
653 | * | ||
654 | * returns group number on success | ||
655 | * returns -1 on failure. | ||
656 | * | ||
657 | * Audio data callback format (same as the one for toxav_add_av_groupchat()): | ||
658 | * audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata) | ||
659 | * | ||
660 | * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). | ||
661 | */ | ||
662 | int toxav_join_av_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length, | ||
663 | void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *), | ||
664 | void *userdata) | ||
665 | { | ||
666 | Messenger *m = tox; | ||
667 | return join_av_groupchat(m->group_chat_object, friendnumber, data, length, audio_callback, userdata); | ||
668 | } | ||
669 | |||
670 | /* Send audio to the group chat. | ||
671 | * | ||
672 | * return 0 on success. | ||
673 | * return -1 on failure. | ||
674 | * | ||
675 | * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). | ||
676 | * | ||
677 | * Valid number of samples are ((sample rate) * (audio length (Valid ones are: 2.5, 5, 10, 20, 40 or 60 ms)) / 1000) | ||
678 | * Valid number of channels are 1 or 2. | ||
679 | * Valid sample rates are 8000, 12000, 16000, 24000, or 48000. | ||
680 | * | ||
681 | * Recommended values are: samples = 960, channels = 1, sample_rate = 48000 | ||
682 | */ | ||
683 | int toxav_group_send_audio(Tox *tox, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels, | ||
684 | unsigned int sample_rate) | ||
685 | { | ||
686 | Messenger *m = tox; | ||
687 | return group_send_audio(m->group_chat_object, groupnumber, pcm, samples, channels, sample_rate); | ||
688 | } | ||
689 | |||