summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--testing/nTox.c12
-rw-r--r--toxav/group.c182
-rw-r--r--toxav/group.h21
-rw-r--r--toxav/toxav.c42
-rw-r--r--toxav/toxav.h25
5 files changed, 269 insertions, 13 deletions
diff --git a/testing/nTox.c b/testing/nTox.c
index b33b1fd3..329191d7 100644
--- a/testing/nTox.c
+++ b/testing/nTox.c
@@ -1001,11 +1001,17 @@ void print_help(char *prog_name)
1001 puts(" -f keyfile [Optional] Specify a keyfile to read from and write to."); 1001 puts(" -f keyfile [Optional] Specify a keyfile to read from and write to.");
1002} 1002}
1003 1003
1004void print_invite(Tox *m, int friendnumber, const uint8_t *data, uint16_t length, void *userdata) 1004void print_invite(Tox *m, int friendnumber, uint8_t type, const uint8_t *data, uint16_t length, void *userdata)
1005{ 1005{
1006 char msg[256]; 1006 char msg[256];
1007 sprintf(msg, "[i] received group chat invite from: %u, auto accepting and joining. group number: %u", friendnumber, 1007
1008 tox_join_groupchat(m, friendnumber, data, length)); 1008 if (type == TOX_GROUPCHAT_TYPE_TEXT) {
1009 sprintf(msg, "[i] received group chat invite from: %u, auto accepting and joining. group number: %u", friendnumber,
1010 tox_join_groupchat(m, friendnumber, data, length));
1011 } else {
1012 sprintf(msg, "[i] Group chat invite received of type %u that could not be accepted by ntox.", type);
1013 }
1014
1009 new_lines(msg); 1015 new_lines(msg);
1010} 1016}
1011 1017
diff --git a/toxav/group.c b/toxav/group.c
index f5707aa6..a899239c 100644
--- a/toxav/group.c
+++ b/toxav/group.c
@@ -135,19 +135,25 @@ static Group_Audio_Packet *dequeue(Group_JitterBuffer *q, int *success)
135 return NULL; 135 return NULL;
136} 136}
137 137
138
139typedef struct { 138typedef struct {
139 Group_Chats *g_c;
140 OpusEncoder *audio_encoder; 140 OpusEncoder *audio_encoder;
141 141
142 unsigned int audio_channels, audio_sample_rate, audio_bitrate; 142 unsigned int audio_channels, audio_sample_rate, audio_bitrate;
143 143
144 uint16_t audio_sequnum; 144 uint16_t audio_sequnum;
145
146 void (*audio_data)(Messenger *m, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples,
147 uint8_t channels, unsigned int sample_rate, void *userdata);
148 void *userdata;
145} Group_AV; 149} Group_AV;
146 150
147typedef struct { 151typedef struct {
148 Group_JitterBuffer *buffer; 152 Group_JitterBuffer *buffer;
149 153
150 OpusDecoder *audio_decoder; 154 OpusDecoder *audio_decoder;
155 int decoder_channels;
156 unsigned int last_packet_samples;
151} Group_Peer_AV; 157} Group_Peer_AV;
152 158
153static void kill_group_av(Group_AV *group_av) 159static void kill_group_av(Group_AV *group_av)
@@ -156,8 +162,13 @@ static void kill_group_av(Group_AV *group_av)
156 free(group_av); 162 free(group_av);
157} 163}
158 164
159static Group_AV *new_group_av(unsigned int audio_channels, unsigned int audio_sample_rate, unsigned int audio_bitrate) 165static Group_AV *new_group_av(Group_Chats *g_c, unsigned int audio_channels, unsigned int audio_sample_rate,
166 unsigned int audio_bitrate, void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int, uint8_t,
167 unsigned int, void *), void *userdata)
160{ 168{
169 if (!g_c)
170 return NULL;
171
161 Group_AV *group_av = calloc(1, sizeof(Group_AV)); 172 Group_AV *group_av = calloc(1, sizeof(Group_AV));
162 173
163 int rc = OPUS_OK; 174 int rc = OPUS_OK;
@@ -190,6 +201,10 @@ static Group_AV *new_group_av(unsigned int audio_channels, unsigned int audio_sa
190 group_av->audio_channels = audio_channels; 201 group_av->audio_channels = audio_channels;
191 group_av->audio_sample_rate = audio_sample_rate; 202 group_av->audio_sample_rate = audio_sample_rate;
192 group_av->audio_bitrate = audio_bitrate; 203 group_av->audio_bitrate = audio_bitrate;
204 group_av->g_c = g_c;
205
206 group_av->audio_data = audio_callback;
207 group_av->userdata = userdata;
193 return 0; 208 return 0;
194} 209}
195 210
@@ -217,6 +232,100 @@ static void group_av_peer_delete(void *object, int groupnumber, int friendgroupn
217 free(peer_object); 232 free(peer_object);
218} 233}
219 234
235static int decode_audio_packet(Group_AV *group_av, Group_Peer_AV *peer_av, int groupnumber, int friendgroupnumber)
236{
237 if (!group_av || !peer_av)
238 return -1;
239
240 int success;
241 Group_Audio_Packet *pk = dequeue(peer_av->buffer, &success);
242
243 if (success == 0)
244 return -1;
245
246 int16_t *out_audio = NULL;
247 unsigned int out_audio_samples = 0;
248
249 if (success == 1) {
250 int channels = opus_packet_get_nb_channels(pk->data);
251
252 if (channels == OPUS_INVALID_PACKET) {
253 free(pk);
254 return -1;
255 }
256
257 if (channels != 1 && channels != 2) {
258 free(pk);
259 return -1;
260 }
261
262 if (channels != peer_av->decoder_channels) {
263 if (peer_av->audio_decoder) {
264 opus_decoder_destroy(peer_av->audio_decoder);
265 peer_av->audio_decoder = NULL;
266 }
267
268 int rc;
269 peer_av->audio_decoder = opus_decoder_create(group_av->audio_sample_rate, channels, &rc);
270
271 if ( rc != OPUS_OK ) {
272 LOGGER_ERROR("Error while starting audio decoder: %s", opus_strerror(rc));
273 free(pk);
274 return -1;
275 }
276
277 peer_av->decoder_channels = channels;
278 }
279
280 int num_samples = opus_decoder_get_nb_samples(peer_av->audio_decoder, pk->data, pk->length);
281
282 out_audio = malloc(num_samples * peer_av->decoder_channels * sizeof(int16_t));
283
284 if (!out_audio) {
285 free(pk);
286 return -1;
287 }
288
289 out_audio_samples = opus_decode(peer_av->audio_decoder, pk->data, pk->length, out_audio, num_samples, 0);
290 free(pk);
291
292 if (out_audio_samples <= 0)
293 return -1;
294
295 peer_av->last_packet_samples = out_audio_samples;
296 } else {
297 if (!peer_av->audio_decoder)
298 return -1;
299
300 if (!peer_av->last_packet_samples)
301 return -1;
302
303 out_audio = malloc(peer_av->last_packet_samples * peer_av->decoder_channels * sizeof(int16_t));
304
305 if (!out_audio) {
306 free(pk);
307 return -1;
308 }
309
310 out_audio_samples = opus_decode(peer_av->audio_decoder, NULL, 0, out_audio, peer_av->last_packet_samples, 1);
311
312 if (out_audio_samples <= 0)
313 return -1;
314
315 }
316
317 if (out_audio) {
318 //TODO callback
319 /*
320 if (group_av->audio_data)
321 audio_data(
322 */
323 return 0;
324 }
325
326 return -1;
327}
328
220static int handle_group_audio_packet(void *object, int groupnumber, int friendgroupnumber, void *peer_object, 329static int handle_group_audio_packet(void *object, int groupnumber, int friendgroupnumber, void *peer_object,
221 const uint8_t *packet, uint16_t length) 330 const uint8_t *packet, uint16_t length)
222{ 331{
@@ -244,13 +353,21 @@ static int handle_group_audio_packet(void *object, int groupnumber, int friendgr
244 return 0; 353 return 0;
245} 354}
246 355
247static int groupchat_enable_av(Group_Chats *g_c, int groupnumber) 356/* Convert groupchat to an A/V groupchat.
357 *
358 * return 0 on success.
359 * return -1 on failure.
360 */
361static int groupchat_enable_av(Group_Chats *g_c, int groupnumber, void (*audio_callback)(Messenger *, int, int,
362 const int16_t *, unsigned int, uint8_t, unsigned int, void *), void *userdata)
248{ 363{
249 Group_AV *group_av = new_group_av(1, 48000, 64000); //TODO: Use variables instead. 364 if (groupnumber == -1)
365 return -1;
250 366
251 if (group_av == NULL) { 367 Group_AV *group_av = new_group_av(g_c, 1, 48000, 64000, audio_callback, userdata); //TODO: Use variables instead.
368
369 if (group_av == NULL)
252 return -1; 370 return -1;
253 }
254 371
255 if (group_set_object(g_c, groupnumber, group_av) == -1 372 if (group_set_object(g_c, groupnumber, group_av) == -1
256 || callback_groupchat_peer_new(g_c, groupnumber, group_av_peer_new) == -1 373 || callback_groupchat_peer_new(g_c, groupnumber, group_av_peer_new) == -1
@@ -268,15 +385,39 @@ static int groupchat_enable_av(Group_Chats *g_c, int groupnumber)
268 * return group number on success. 385 * return group number on success.
269 * return -1 on failure. 386 * return -1 on failure.
270 */ 387 */
271int add_av_groupchat(Group_Chats *g_c) 388int add_av_groupchat(Group_Chats *g_c, void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int,
389 uint8_t, unsigned int, void *), void *userdata)
272{ 390{
273 int groupnumber = add_groupchat(g_c); 391 int groupnumber = add_groupchat(g_c, GROUPCHAT_TYPE_AV);
274 392
275 if (groupnumber == -1) { 393 if (groupnumber == -1) {
276 return -1; 394 return -1;
277 } 395 }
278 396
279 if (groupchat_enable_av(g_c, groupnumber) == -1) { 397 if (groupchat_enable_av(g_c, groupnumber, audio_callback, userdata) == -1) {
398 del_groupchat(g_c, groupnumber);
399 return -1;
400 }
401
402 return groupnumber;
403}
404
405/* Join a AV group (you need to have been invited first.)
406 *
407 * returns group number on success
408 * returns -1 on failure.
409 */
410int join_av_groupchat(Group_Chats *g_c, int32_t friendnumber, const uint8_t *data, uint16_t length,
411 void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *),
412 void *userdata)
413{
414 int groupnumber = join_groupchat(g_c, friendnumber, GROUPCHAT_TYPE_AV, data, length);
415
416 if (groupnumber == -1) {
417 return -1;
418 }
419
420 if (groupchat_enable_av(g_c, groupnumber, audio_callback, userdata) == -1) {
280 del_groupchat(g_c, groupnumber); 421 del_groupchat(g_c, groupnumber);
281 return -1; 422 return -1;
282 } 423 }
@@ -308,3 +449,26 @@ static int send_audio_packet(Group_Chats *g_c, int groupnumber, uint8_t *packet,
308 ++group_av->audio_sequnum; 449 ++group_av->audio_sequnum;
309 return 0; 450 return 0;
310} 451}
452
453/* Send audio to the group chat.
454 *
455 * return 0 on success.
456 * return -1 on failure.
457 */
458int group_send_audio(Group_Chats *g_c, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,
459 unsigned int sample_rate)
460{
461 //TODO use channels and sample_rate arguments.
462 Group_AV *group_av = group_get_object(g_c, groupnumber);
463
464 if (!group_av)
465 return -1;
466
467 uint8_t encoded[1024];
468 int32_t size = opus_encode(group_av->audio_encoder, pcm, samples, encoded, sizeof(encoded));
469
470 if (size <= 0)
471 return -1;
472
473 return send_audio_packet(g_c, groupnumber, encoded, size);
474}
diff --git a/toxav/group.h b/toxav/group.h
index 1427fe18..3355a447 100644
--- a/toxav/group.h
+++ b/toxav/group.h
@@ -30,5 +30,24 @@
30 * return group number on success. 30 * return group number on success.
31 * return -1 on failure. 31 * return -1 on failure.
32 */ 32 */
33int add_av_groupchat(Group_Chats *g_c); 33int add_av_groupchat(Group_Chats *g_c, void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int,
34 uint8_t, unsigned int, void *), void *userdata);
35
36/* Join a AV group (you need to have been invited first.)
37 *
38 * returns group number on success
39 * returns -1 on failure.
40 */
41int join_av_groupchat(Group_Chats *g_c, int32_t friendnumber, const uint8_t *data, uint16_t length,
42 void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *),
43 void *userdata);
44
45
46/* Send audio to the group chat.
47 *
48 * return 0 on success.
49 * return -1 on failure.
50 */
51int group_send_audio(Group_Chats *g_c, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,
52 unsigned int sample_rate);
34 53
diff --git a/toxav/toxav.c b/toxav/toxav.c
index 8549bc05..76e40e89 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -23,6 +23,8 @@
23#include "config.h" 23#include "config.h"
24#endif /* HAVE_CONFIG_H */ 24#endif /* HAVE_CONFIG_H */
25 25
26#define __TOX_DEFINED__
27typedef struct Messenger Tox;
26 28
27#define _GNU_SOURCE /* implicit declaration warning */ 29#define _GNU_SOURCE /* implicit declaration warning */
28 30
@@ -30,6 +32,7 @@
30#include "codec.h" 32#include "codec.h"
31#include "msi.h" 33#include "msi.h"
32#include "toxav.h" 34#include "toxav.h"
35#include "group.h"
33 36
34#include "../toxcore/logger.h" 37#include "../toxcore/logger.h"
35 38
@@ -1148,3 +1151,42 @@ end:
1148 rtp_free_msg(NULL, _msg); 1151 rtp_free_msg(NULL, _msg);
1149 } 1152 }
1150} 1153}
1154
1155
1156/* Create a new toxav group.
1157 *
1158 * return group number on success.
1159 * return -1 on failure.
1160 */
1161int toxav_add_av_groupchat(Tox *tox, void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int,
1162 uint8_t, unsigned int, void *), void *userdata)
1163{
1164 Messenger *m = tox;
1165 return add_av_groupchat(m->group_chat_object, audio_callback, userdata);
1166}
1167
1168/* Join a AV group (you need to have been invited first.)
1169 *
1170 * returns group number on success
1171 * returns -1 on failure.
1172 */
1173int toxav_join_av_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length,
1174 void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *),
1175 void *userdata)
1176{
1177 Messenger *m = tox;
1178 return join_av_groupchat(m->group_chat_object, friendnumber, data, length, audio_callback, userdata);
1179}
1180
1181/* Send audio to the group chat.
1182 *
1183 * return 0 on success.
1184 * return -1 on failure.
1185 */
1186int toxav_group_send_audio(Tox *tox, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,
1187 unsigned int sample_rate)
1188{
1189 Messenger *m = tox;
1190 return group_send_audio(m->group_chat_object, groupnumber, pcm, samples, channels, sample_rate);
1191}
1192
diff --git a/toxav/toxav.h b/toxav/toxav.h
index 34c8be5d..db261fd8 100644
--- a/toxav/toxav.h
+++ b/toxav/toxav.h
@@ -382,6 +382,31 @@ Tox *toxav_get_tox(ToxAv *av);
382 382
383int toxav_has_activity ( ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t frame_size, float ref_energy ); 383int toxav_has_activity ( ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t frame_size, float ref_energy );
384 384
385
386/* Create a new toxav group.
387 *
388 * return group number on success.
389 * return -1 on failure.
390 */
391int toxav_add_av_groupchat(Tox *tox, void (*audio_callback)(Tox *, int, int, const int16_t *, unsigned int, uint8_t,
392 unsigned int, void *), void *userdata);
393
394/* Join a AV group (you need to have been invited first.)
395 *
396 * returns group number on success
397 * returns -1 on failure.
398 */
399int toxav_join_av_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length,
400 void (*audio_callback)(Tox *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *), void *userdata);
401
402/* Send audio to the group chat.
403 *
404 * return 0 on success.
405 * return -1 on failure.
406 */
407int toxav_group_send_audio(Tox *tox, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels,
408 unsigned int sample_rate);
409
385#ifdef __cplusplus 410#ifdef __cplusplus
386} 411}
387#endif 412#endif