summaryrefslogtreecommitdiff
path: root/toxav/groupav.c
diff options
context:
space:
mode:
authorDmytro Vorobiov <d@dvor.me>2016-10-28 22:11:48 +0200
committerDmytro Vorobiov <d@dvor.me>2016-10-28 22:11:48 +0200
commit59d27e6d941e429cf180ce66a5154e655fc5b77a (patch)
treeb3f0b398765a668f8511432efe89e62bd65169ea /toxav/groupav.c
parentde966cdf90843819e2f7287e22ddcb5f95491b18 (diff)
toxav renaming: group.{h,c} -> groupav.{h,c}
toxav file for "group" conflicts with toxcore "group" file. While this works fine in almost all cases, Xcode on macOS is confused with that.
Diffstat (limited to 'toxav/groupav.c')
-rw-r--r--toxav/groupav.c573
1 files changed, 573 insertions, 0 deletions
diff --git a/toxav/groupav.c b/toxav/groupav.c
new file mode 100644
index 00000000..88844536
--- /dev/null
+++ b/toxav/groupav.c
@@ -0,0 +1,573 @@
1/** groupav.h
2 *
3 * Copyright (C) 2014 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#ifdef HAVE_CONFIG_H
22#include "config.h"
23#endif /* HAVE_CONFIG_H */
24
25#include "groupav.h"
26
27#include "../toxcore/logger.h"
28#include "../toxcore/util.h"
29
30#define GROUP_JBUF_SIZE 6
31#define GROUP_JBUF_DEAD_SECONDS 4
32
33typedef struct {
34 uint16_t sequnum;
35 uint16_t length;
36 uint8_t data[];
37} Group_Audio_Packet;
38
39typedef struct {
40 Group_Audio_Packet **queue;
41 uint32_t size;
42 uint32_t capacity;
43 uint16_t bottom;
44 uint16_t top;
45 uint64_t last_queued_time;
46} Group_JitterBuffer;
47
48static Group_JitterBuffer *create_queue(unsigned int capacity)
49{
50 unsigned int size = 1;
51
52 while (size <= capacity) {
53 size *= 2;
54 }
55
56 Group_JitterBuffer *q;
57
58 if (!(q = (Group_JitterBuffer *)calloc(sizeof(Group_JitterBuffer), 1))) {
59 return NULL;
60 }
61
62 if (!(q->queue = (Group_Audio_Packet **)calloc(sizeof(Group_Audio_Packet *), size))) {
63 free(q);
64 return NULL;
65 }
66
67 q->size = size;
68 q->capacity = capacity;
69 return q;
70}
71
72static void clear_queue(Group_JitterBuffer *q)
73{
74 for (; q->bottom != q->top; ++q->bottom) {
75 if (q->queue[q->bottom % q->size]) {
76 free(q->queue[q->bottom % q->size]);
77 q->queue[q->bottom % q->size] = NULL;
78 }
79 }
80}
81
82static void terminate_queue(Group_JitterBuffer *q)
83{
84 if (!q) {
85 return;
86 }
87
88 clear_queue(q);
89 free(q->queue);
90 free(q);
91}
92
93/* Return 0 if packet was queued, -1 if it wasn't.
94 */
95static int queue(Group_JitterBuffer *q, Group_Audio_Packet *pk)
96{
97 uint16_t sequnum = pk->sequnum;
98
99 unsigned int num = sequnum % q->size;
100
101 if (!is_timeout(q->last_queued_time, GROUP_JBUF_DEAD_SECONDS)) {
102 if ((uint32_t)(sequnum - q->bottom) > (1 << 15)) {
103 /* Drop old packet. */
104 return -1;
105 }
106 }
107
108 if ((uint32_t)(sequnum - q->bottom) > q->size) {
109 clear_queue(q);
110 q->bottom = sequnum - q->capacity;
111 q->queue[num] = pk;
112 q->top = sequnum + 1;
113 q->last_queued_time = unix_time();
114 return 0;
115 }
116
117 if (q->queue[num]) {
118 return -1;
119 }
120
121 q->queue[num] = pk;
122
123 if ((sequnum - q->bottom) >= (q->top - q->bottom)) {
124 q->top = sequnum + 1;
125 }
126
127 q->last_queued_time = unix_time();
128 return 0;
129}
130
131/* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */
132static Group_Audio_Packet *dequeue(Group_JitterBuffer *q, int *success)
133{
134 if (q->top == q->bottom) {
135 *success = 0;
136 return NULL;
137 }
138
139 unsigned int num = q->bottom % q->size;
140
141 if (q->queue[num]) {
142 Group_Audio_Packet *ret = q->queue[num];
143 q->queue[num] = NULL;
144 ++q->bottom;
145 *success = 1;
146 return ret;
147 }
148
149 if ((uint32_t)(q->top - q->bottom) > q->capacity) {
150 ++q->bottom;
151 *success = 2;
152 return NULL;
153 }
154
155 *success = 0;
156 return NULL;
157}
158
159typedef struct {
160 Logger *log;
161 Group_Chats *g_c;
162 OpusEncoder *audio_encoder;
163
164 unsigned int audio_channels, audio_sample_rate, audio_bitrate;
165
166 uint16_t audio_sequnum;
167
168 void (*audio_data)(Messenger *m, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples,
169 uint8_t channels, unsigned int sample_rate, void *userdata);
170 void *userdata;
171} Group_AV;
172
173typedef struct {
174 Group_JitterBuffer *buffer;
175
176 OpusDecoder *audio_decoder;
177 int decoder_channels;
178 unsigned int last_packet_samples;
179} Group_Peer_AV;
180
181static void kill_group_av(Group_AV *group_av)
182{
183 if (group_av->audio_encoder) {
184 opus_encoder_destroy(group_av->audio_encoder);
185 }
186
187 free(group_av);
188}
189
190static int recreate_encoder(Group_AV *group_av)
191{
192 if (group_av->audio_encoder) {
193 opus_encoder_destroy(group_av->audio_encoder);
194 group_av->audio_encoder = NULL;
195 }
196
197 int rc = OPUS_OK;
198 group_av->audio_encoder = opus_encoder_create(group_av->audio_sample_rate, group_av->audio_channels,
199 OPUS_APPLICATION_AUDIO, &rc);
200
201 if (rc != OPUS_OK) {
202 LOGGER_ERROR(group_av->log, "Error while starting audio encoder: %s", opus_strerror(rc));
203 group_av->audio_encoder = NULL;
204 return -1;
205 }
206
207 rc = opus_encoder_ctl(group_av->audio_encoder, OPUS_SET_BITRATE(group_av->audio_bitrate));
208
209 if (rc != OPUS_OK) {
210 LOGGER_ERROR(group_av->log, "Error while setting encoder ctl: %s", opus_strerror(rc));
211 opus_encoder_destroy(group_av->audio_encoder);
212 group_av->audio_encoder = NULL;
213 return -1;
214 }
215
216 rc = opus_encoder_ctl(group_av->audio_encoder, OPUS_SET_COMPLEXITY(10));
217
218 if (rc != OPUS_OK) {
219 LOGGER_ERROR(group_av->log, "Error while setting encoder ctl: %s", opus_strerror(rc));
220 opus_encoder_destroy(group_av->audio_encoder);
221 group_av->audio_encoder = NULL;
222 return -1;
223 }
224
225 return 0;
226}
227
228static Group_AV *new_group_av(Logger *log, Group_Chats *g_c, void (*audio_callback)(Messenger *, int, int,
229 const int16_t *,
230 unsigned int, uint8_t, unsigned int, void *), void *userdata)
231{
232 if (!g_c) {
233 return NULL;
234 }
235
236 Group_AV *group_av = (Group_AV *)calloc(1, sizeof(Group_AV));
237
238 if (!group_av) {
239 return NULL;
240 }
241
242 group_av->log = log;
243 group_av->g_c = g_c;
244
245 group_av->audio_data = audio_callback;
246 group_av->userdata = userdata;
247
248 return group_av;
249}
250
251static void group_av_peer_new(void *object, int groupnumber, int friendgroupnumber)
252{
253 Group_AV *group_av = (Group_AV *)object;
254 Group_Peer_AV *peer_av = (Group_Peer_AV *)calloc(1, sizeof(Group_Peer_AV));
255
256 if (!peer_av) {
257 return;
258 }
259
260 peer_av->buffer = create_queue(GROUP_JBUF_SIZE);
261 group_peer_set_object(group_av->g_c, groupnumber, friendgroupnumber, peer_av);
262}
263
264static void group_av_peer_delete(void *object, int groupnumber, int friendgroupnumber, void *peer_object)
265{
266 Group_Peer_AV *peer_av = (Group_Peer_AV *)peer_object;
267
268 if (!peer_av) {
269 return;
270 }
271
272 if (peer_av->audio_decoder) {
273 opus_decoder_destroy(peer_av->audio_decoder);
274 }
275
276 terminate_queue(peer_av->buffer);
277 free(peer_object);
278}
279
280static void group_av_groupchat_delete(void *object, int groupnumber)
281{
282 if (object) {
283 kill_group_av((Group_AV *)object);
284 }
285}
286
287static int decode_audio_packet(Group_AV *group_av, Group_Peer_AV *peer_av, int groupnumber, int friendgroupnumber)
288{
289 if (!group_av || !peer_av) {
290 return -1;
291 }
292
293 int success;
294 Group_Audio_Packet *pk = dequeue(peer_av->buffer, &success);
295
296 if (success == 0) {
297 return -1;
298 }
299
300 int16_t *out_audio = NULL;
301 int out_audio_samples = 0;
302
303 unsigned int sample_rate = 48000;
304
305 if (success == 1) {
306 int channels = opus_packet_get_nb_channels(pk->data);
307
308 if (channels == OPUS_INVALID_PACKET) {
309 free(pk);
310 return -1;
311 }
312
313 if (channels != 1 && channels != 2) {
314 free(pk);
315 return -1;
316 }
317
318 if (channels != peer_av->decoder_channels) {
319 if (peer_av->audio_decoder) {
320 opus_decoder_destroy(peer_av->audio_decoder);
321 peer_av->audio_decoder = NULL;
322 }
323
324 int rc;
325 peer_av->audio_decoder = opus_decoder_create(sample_rate, channels, &rc);
326
327 if (rc != OPUS_OK) {
328 LOGGER_ERROR(group_av->log, "Error while starting audio decoder: %s", opus_strerror(rc));
329 free(pk);
330 return -1;
331 }
332
333 peer_av->decoder_channels = channels;
334 }
335
336 int num_samples = opus_decoder_get_nb_samples(peer_av->audio_decoder, pk->data, pk->length);
337
338 out_audio = (int16_t *)malloc(num_samples * peer_av->decoder_channels * sizeof(int16_t));
339
340 if (!out_audio) {
341 free(pk);
342 return -1;
343 }
344
345 out_audio_samples = opus_decode(peer_av->audio_decoder, pk->data, pk->length, out_audio, num_samples, 0);
346 free(pk);
347
348 if (out_audio_samples <= 0) {
349 return -1;
350 }
351
352 peer_av->last_packet_samples = out_audio_samples;
353 } else {
354 if (!peer_av->audio_decoder) {
355 return -1;
356 }
357
358 if (!peer_av->last_packet_samples) {
359 return -1;
360 }
361
362 out_audio = (int16_t *)malloc(peer_av->last_packet_samples * peer_av->decoder_channels * sizeof(int16_t));
363
364 if (!out_audio) {
365 free(pk);
366 return -1;
367 }
368
369 out_audio_samples = opus_decode(peer_av->audio_decoder, NULL, 0, out_audio, peer_av->last_packet_samples, 1);
370
371 if (out_audio_samples <= 0) {
372 return -1;
373 }
374 }
375
376 if (out_audio) {
377
378 if (group_av->audio_data) {
379 group_av->audio_data(group_av->g_c->m, groupnumber, friendgroupnumber, out_audio, out_audio_samples,
380 peer_av->decoder_channels, sample_rate, group_av->userdata);
381 }
382
383 free(out_audio);
384 return 0;
385 }
386
387 return -1;
388}
389
390static int handle_group_audio_packet(void *object, int groupnumber, int friendgroupnumber, void *peer_object,
391 const uint8_t *packet, uint16_t length)
392{
393 if (!peer_object || !object || length <= sizeof(uint16_t)) {
394 return -1;
395 }
396
397 Group_Peer_AV *peer_av = (Group_Peer_AV *)peer_object;
398
399 Group_Audio_Packet *pk = (Group_Audio_Packet *)calloc(1, sizeof(Group_Audio_Packet) + (length - sizeof(uint16_t)));
400
401 if (!pk) {
402 return -1;
403 }
404
405 uint16_t sequnum;
406 memcpy(&sequnum, packet, sizeof(sequnum));
407 pk->sequnum = ntohs(sequnum);
408 pk->length = length - sizeof(uint16_t);
409 memcpy(pk->data, packet + sizeof(uint16_t), length - sizeof(uint16_t));
410
411 if (queue(peer_av->buffer, pk) == -1) {
412 free(pk);
413 return -1;
414 }
415
416 while (decode_audio_packet((Group_AV *)object, peer_av, groupnumber, friendgroupnumber) == 0) {
417 ;
418 }
419
420 return 0;
421}
422
423/* Convert groupchat to an A/V groupchat.
424 *
425 * return 0 on success.
426 * return -1 on failure.
427 */
428static int groupchat_enable_av(Logger *log, Group_Chats *g_c, int groupnumber, void (*audio_callback)(Messenger *, int,
429 int,
430 const int16_t *, unsigned int, uint8_t, unsigned int, void *), void *userdata)
431{
432 if (groupnumber == -1) {
433 return -1;
434 }
435
436 Group_AV *group_av = new_group_av(log, g_c, audio_callback, userdata);
437
438 if (group_av == NULL) {
439 return -1;
440 }
441
442 if (group_set_object(g_c, groupnumber, group_av) == -1
443 || callback_groupchat_peer_new(g_c, groupnumber, group_av_peer_new) == -1
444 || callback_groupchat_peer_delete(g_c, groupnumber, group_av_peer_delete) == -1
445 || callback_groupchat_delete(g_c, groupnumber, group_av_groupchat_delete) == -1) {
446 kill_group_av(group_av);
447 return -1;
448 }
449
450 group_lossy_packet_registerhandler(g_c, GROUP_AUDIO_PACKET_ID, &handle_group_audio_packet);
451 return 0;
452}
453
454/* Create a new toxav group.
455 *
456 * return group number on success.
457 * return -1 on failure.
458 */
459int add_av_groupchat(Logger *log, Group_Chats *g_c, void (*audio_callback)(Messenger *, int, int, const int16_t *,
460 unsigned int,
461 uint8_t, unsigned int, void *), void *userdata)
462{
463 int groupnumber = add_groupchat(g_c, GROUPCHAT_TYPE_AV);
464
465 if (groupnumber == -1) {
466 return -1;
467 }
468
469 if (groupchat_enable_av(log, g_c, groupnumber, audio_callback, userdata) == -1) {
470 del_groupchat(g_c, groupnumber);
471 return -1;
472 }
473
474 return groupnumber;
475}
476
477/* Join a AV group (you need to have been invited first.)
478 *
479 * returns group number on success
480 * returns -1 on failure.
481 */
482int join_av_groupchat(Logger *log, Group_Chats *g_c, int32_t friendnumber, const uint8_t *data, uint16_t length,
483 void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *),
484 void *userdata)
485{
486 int groupnumber = join_groupchat(g_c, friendnumber, GROUPCHAT_TYPE_AV, data, length);
487
488 if (groupnumber == -1) {
489 return -1;
490 }
491
492 if (groupchat_enable_av(log, g_c, groupnumber, audio_callback, userdata) == -1) {
493 del_groupchat(g_c, groupnumber);
494 return -1;
495 }
496
497 return groupnumber;
498}
499
500/* Send an encoded audio packet to the group chat.
501 *
502 * return 0 on success.
503 * return -1 on failure.
504 */
505static int send_audio_packet(Group_Chats *g_c, int groupnumber, uint8_t *packet, uint16_t length)
506{
507 if (!length) {
508 return -1;
509 }
510
511 Group_AV *group_av = (Group_AV *)group_get_object(g_c, groupnumber);
512 uint8_t data[1 + sizeof(uint16_t) + length];
513 data[0] = GROUP_AUDIO_PACKET_ID;
514
515 uint16_t sequnum = htons(group_av->audio_sequnum);
516 memcpy(data + 1, &sequnum, sizeof(sequnum));
517 memcpy(data + 1 + sizeof(sequnum), packet, length);
518
519 if (send_group_lossy_packet(g_c, groupnumber, data, sizeof(data)) == -1) {
520 return -1;
521 }
522
523 ++group_av->audio_sequnum;
524 return 0;
525}
526
527/* Send audio to the group chat.
528 *
529 * return 0 on success.
530 * return -1 on failure.
531 */
532int group_send_audio(Group_Chats *g_c, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,
533 unsigned int sample_rate)
534{
535 Group_AV *group_av = (Group_AV *)group_get_object(g_c, groupnumber);
536
537 if (!group_av) {
538 return -1;
539 }
540
541 if (channels != 1 && channels != 2) {
542 return -1;
543 }
544
545 if (sample_rate != 8000 && sample_rate != 12000 && sample_rate != 16000 && sample_rate != 24000
546 && sample_rate != 48000) {
547 return -1;
548 }
549
550 if (!group_av->audio_encoder || group_av->audio_channels != channels || group_av->audio_sample_rate != sample_rate) {
551 group_av->audio_channels = channels;
552 group_av->audio_sample_rate = sample_rate;
553
554 if (channels == 1) {
555 group_av->audio_bitrate = 32000; // TODO(mannol): add way of adjusting bitrate
556 } else {
557 group_av->audio_bitrate = 64000; // TODO(mannol): add way of adjusting bitrate
558 }
559
560 if (recreate_encoder(group_av) == -1) {
561 return -1;
562 }
563 }
564
565 uint8_t encoded[1024];
566 int32_t size = opus_encode(group_av->audio_encoder, pcm, samples, encoded, sizeof(encoded));
567
568 if (size <= 0) {
569 return -1;
570 }
571
572 return send_audio_packet(g_c, groupnumber, encoded, size);
573}