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