summaryrefslogtreecommitdiff
path: root/toxav/group.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxav/group.c')
-rw-r--r--toxav/group.c182
1 files changed, 173 insertions, 9 deletions
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}