From 8c0225b27f10448bbb327a517db3c67edd49f766 Mon Sep 17 00:00:00 2001 From: irungentoo Date: Tue, 11 Nov 2014 14:39:25 -0500 Subject: [PATCH] 2 channel audio can now be sent to groupchats. Some cleanups and added comments. --- toxav/group.c | 77 ++++++++++++++++++++++++++++++++++++--------------- toxav/toxav.c | 12 ++++++++ toxav/toxav.h | 14 ++++++++++ 3 files changed, 80 insertions(+), 23 deletions(-) diff --git a/toxav/group.c b/toxav/group.c index 317217dc..4a26aa96 100644 --- a/toxav/group.c +++ b/toxav/group.c @@ -158,35 +158,37 @@ typedef struct { static void kill_group_av(Group_AV *group_av) { - opus_encoder_destroy(group_av->audio_encoder); + if (group_av->audio_encoder) { + opus_encoder_destroy(group_av->audio_encoder); + } + free(group_av); } -static Group_AV *new_group_av(Group_Chats *g_c, unsigned int audio_channels, unsigned int audio_sample_rate, - unsigned int audio_bitrate, void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int, uint8_t, - unsigned int, void *), void *userdata) +static int recreate_encoder(Group_AV *group_av) { - if (!g_c) - return NULL; - - Group_AV *group_av = calloc(1, sizeof(Group_AV)); + if (group_av->audio_encoder) { + opus_encoder_destroy(group_av->audio_encoder); + group_av->audio_encoder = NULL; + } int rc = OPUS_OK; - group_av->audio_encoder = opus_encoder_create(audio_sample_rate, audio_channels, OPUS_APPLICATION_AUDIO, &rc); + group_av->audio_encoder = opus_encoder_create(group_av->audio_sample_rate, group_av->audio_channels, + OPUS_APPLICATION_AUDIO, &rc); if ( rc != OPUS_OK ) { LOGGER_ERROR("Error while starting audio encoder: %s", opus_strerror(rc)); - free(group_av); - return NULL; + group_av->audio_encoder = NULL; + return -1; } - rc = opus_encoder_ctl(group_av->audio_encoder, OPUS_SET_BITRATE(audio_bitrate)); + rc = opus_encoder_ctl(group_av->audio_encoder, OPUS_SET_BITRATE(group_av->audio_bitrate)); if ( rc != OPUS_OK ) { LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc)); opus_encoder_destroy(group_av->audio_encoder); - free(group_av); - return NULL; + group_av->audio_encoder = NULL; + return -1; } rc = opus_encoder_ctl(group_av->audio_encoder, OPUS_SET_COMPLEXITY(10)); @@ -194,17 +196,29 @@ static Group_AV *new_group_av(Group_Chats *g_c, unsigned int audio_channels, uns if ( rc != OPUS_OK ) { LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(rc)); opus_encoder_destroy(group_av->audio_encoder); - free(group_av); - return NULL; + group_av->audio_encoder = NULL; + return -1; } - group_av->audio_channels = audio_channels; - group_av->audio_sample_rate = audio_sample_rate; - group_av->audio_bitrate = audio_bitrate; + return 0; +} + +static Group_AV *new_group_av(Group_Chats *g_c, void (*audio_callback)(Messenger *, int, int, const int16_t *, + unsigned int, uint8_t, unsigned int, void *), void *userdata) +{ + if (!g_c) + return NULL; + + Group_AV *group_av = calloc(1, sizeof(Group_AV)); + + if (!group_av) + return NULL; + group_av->g_c = g_c; group_av->audio_data = audio_callback; group_av->userdata = userdata; + return group_av; } @@ -248,6 +262,8 @@ static int decode_audio_packet(Group_AV *group_av, Group_Peer_AV *peer_av, int g int16_t *out_audio = NULL; unsigned int out_audio_samples = 0; + unsigned int sample_rate = 48000; + if (success == 1) { int channels = opus_packet_get_nb_channels(pk->data); @@ -268,7 +284,7 @@ static int decode_audio_packet(Group_AV *group_av, Group_Peer_AV *peer_av, int g } int rc; - peer_av->audio_decoder = opus_decoder_create(group_av->audio_sample_rate, channels, &rc); + peer_av->audio_decoder = opus_decoder_create(sample_rate, channels, &rc); if ( rc != OPUS_OK ) { LOGGER_ERROR("Error while starting audio decoder: %s", opus_strerror(rc)); @@ -320,7 +336,7 @@ static int decode_audio_packet(Group_AV *group_av, Group_Peer_AV *peer_av, int g if (group_av->audio_data) group_av->audio_data(group_av->g_c->m, groupnumber, friendgroupnumber, out_audio, out_audio_samples, - peer_av->decoder_channels, group_av->audio_sample_rate, group_av->userdata); + peer_av->decoder_channels, sample_rate, group_av->userdata); free(out_audio); return 0; @@ -371,7 +387,7 @@ static int groupchat_enable_av(Group_Chats *g_c, int groupnumber, void (*audio_c if (groupnumber == -1) return -1; - Group_AV *group_av = new_group_av(g_c, 1, 48000, 64000, audio_callback, userdata); //TODO: Use variables instead. + Group_AV *group_av = new_group_av(g_c, audio_callback, userdata); if (group_av == NULL) return -1; @@ -465,12 +481,27 @@ static int send_audio_packet(Group_Chats *g_c, int groupnumber, uint8_t *packet, int group_send_audio(Group_Chats *g_c, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate) { - //TODO use channels and sample_rate arguments. Group_AV *group_av = group_get_object(g_c, groupnumber); if (!group_av) return -1; + if (channels != 1 && channels != 2) + return -1; + + //TODO: allow different sample rates + if (sample_rate != 48000) + return -1; + + if (!group_av->audio_encoder || group_av->audio_channels != channels || group_av->audio_sample_rate != sample_rate) { + group_av->audio_channels = channels; + group_av->audio_sample_rate = sample_rate; + group_av->audio_bitrate = 64000; //TODO: add way of adjusting bitrate + + if (recreate_encoder(group_av) == -1) + return -1; + } + uint8_t encoded[1024]; int32_t size = opus_encode(group_av->audio_encoder, pcm, samples, encoded, sizeof(encoded)); diff --git a/toxav/toxav.c b/toxav/toxav.c index dd148130..24e42572 100644 --- a/toxav/toxav.c +++ b/toxav/toxav.c @@ -1160,6 +1160,8 @@ end: * * Audio data callback format: * audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata) + * + * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). */ int toxav_add_av_groupchat(Tox *tox, void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *), void *userdata) @@ -1175,6 +1177,8 @@ int toxav_add_av_groupchat(Tox *tox, void (*audio_callback)(Messenger *, int, in * * Audio data callback format (same as the one for toxav_add_av_groupchat()): * audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata) + * + * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). */ int toxav_join_av_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length, void (*audio_callback)(Messenger *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *), @@ -1188,6 +1192,14 @@ int toxav_join_av_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, * * return 0 on success. * return -1 on failure. + * + * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). + * + * Valid number of samples are ((sample rate) * (audio length (Valid ones are: 2.5, 5, 10, 20, 40 or 60 ms)) / 1000) + * Valid number of channels are 1 or 2. + * Valid sample rates are 8000, 12000, 16000, 24000, or 48000. + * + * Recommended values are: samples = 960, channels = 1, sample_rate = 48000 */ int toxav_group_send_audio(Tox *tox, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate) diff --git a/toxav/toxav.h b/toxav/toxav.h index 29aa12c5..77afda81 100644 --- a/toxav/toxav.h +++ b/toxav/toxav.h @@ -390,6 +390,8 @@ int toxav_has_activity ( ToxAv *av, int32_t call_index, int16_t *PCM, uint16_t f * * Audio data callback format: * audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata) + * + * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). */ int toxav_add_av_groupchat(Tox *tox, void (*audio_callback)(Tox *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *), void *userdata); @@ -401,6 +403,8 @@ int toxav_add_av_groupchat(Tox *tox, void (*audio_callback)(Tox *, int, int, con * * Audio data callback format (same as the one for toxav_add_av_groupchat()): * audio_callback(Tox *tox, int groupnumber, int peernumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate, void *userdata) + * + * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). */ int toxav_join_av_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, uint16_t length, void (*audio_callback)(Tox *, int, int, const int16_t *, unsigned int, uint8_t, unsigned int, void *), void *userdata); @@ -409,6 +413,16 @@ int toxav_join_av_groupchat(Tox *tox, int32_t friendnumber, const uint8_t *data, * * return 0 on success. * return -1 on failure. + * + * Note that total size of pcm in bytes is equal to (samples * channels * sizeof(int16_t)). + * + * Valid number of samples are ((sample rate) * (audio length (Valid ones are: 2.5, 5, 10, 20, 40 or 60 ms)) / 1000) + * Valid number of channels are 1 or 2. + * Valid sample rates are 8000, 12000, 16000, 24000, or 48000. + * + * Recommended values are: samples = 960, channels = 1, sample_rate = 48000 + * + * TODO: currently the only supported sample rate is 48000. */ int toxav_group_send_audio(Tox *tox, int groupnumber, const int16_t *pcm, unsigned int samples, uint8_t channels, unsigned int sample_rate);