/* audio handling * * (C) 2020 by Andreas Eversberg * All Rights Reserved * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* * Audio flow diagram: * * This diagrams shows the audio processing. The function for each processing * segment is given by the names ending with "()". * * ORIGINATOR * * receive_originator() * | /|\ * | | * \|/ | * +-------+ +-------+ * |int to | |samples| * |samples| |to int | * +-------+ +-------+ * | /|\ * +------+ | | * | |/ | | * | DTMF |---| | * | |\ | | * +------+ | | * \|/ | * +-------+ +-------+ * | TX- | | RX- | * | GAIN | | GAIN | * +-------+ +-------+ * | /|\ * | | * | | * +------+ | | +------+ * | TX- |/ | | \| RX- | * | |---| |---| | * |JITTER|\ | | /|JITTER| * +------+ | | +------+ * | | * +------+ | | * | WAVE | | | * | |_ | | * | PLAY | \ | | * +------+ \| | * | | * \|/ send_originator() *----------------------------------- * send_terminator() /|\ * | | +------+ * | |\ | WAVE | * | | \_| | call_clock() * | | | PLAY | * \|/ | +------+ * +-------+ +-------+ * |samples| |int to | * |to int | |samples| * +-------+ +-------+ * | /|\ * | | * \|/ | * receive_terminator() * * TERMINATOR * * In recording mode: * Data is stored into jitter buffer of each endpoint. * The clock triggers dejittering of TX and RX data and writes it to wave file. * * In playback mode: * The clock triggers read from wave file and forwards it to the originator. * */ #include #include #include #include #include #include #include #include #include "../libdebug/debug.h" #include "call.h" #include "audio.h" #define db2level(db) pow(10, (double)db / 20.0) static void gain_samples(sample_t *samples, int length, double gain) { double level = db2level(gain); int i; for (i = 0; i < length; i++) *samples++ *= level; } static void send_terminator(call_relation_t *relation, sample_t *samples, int len) { int16_t spl[len]; /* convert samples to int16 */ samples_to_int16(spl, samples, len); /* encode and send via RTP */ osmo_cc_rtp_send(relation->codec, (uint8_t *)spl, len * sizeof(*spl), 1, len); } void receive_originator(struct osmo_cc_session_codec *codec, uint16_t __attribute__((unused)) sequence_number, uint32_t __attribute__((unused)) timestamp, uint8_t *data, int len) { call_relation_t *relation = codec->media->session->priv; len = len / 2; sample_t samples[len]; if (codec->decoder == decode_te) { struct telephone_event *te = (struct telephone_event *)data; telephone_event(relation, te); return; } /* convert int16 to samples */ int16_to_samples(samples, (int16_t *)data, len); /* dtmf decoding */ if (relation->dtmf_dec_enable) dtmf_decode(&relation->dtmf_dec, samples, len); /* adjust gain */ if (relation->call->tx_gain) gain_samples(samples, len, relation->call->tx_gain); /* store to originator jitter buffer */ jitter_save(&relation->orig_dejitter, samples, len); /* forward to terminators */ for (relation = relation->next; relation; relation = relation->next) { if (relation->cc_session && relation->codec && !relation->play.fp) send_terminator(relation, samples, len); } } static void send_originator(call_relation_t *relation, sample_t *samples, int len) { int16_t spl[len]; /* store to terminator jitter buffer */ jitter_save(&relation->term_dejitter, samples, len); if (relation->call->rx_gain) gain_samples(samples, len, relation->call->rx_gain); samples_to_int16(spl, samples, len); osmo_cc_rtp_send(relation->codec, (uint8_t *)spl, len * sizeof(*spl), 1, len); } void receive_terminator(struct osmo_cc_session_codec *codec, uint16_t __attribute__((unused)) sequence_number, uint32_t __attribute__((unused)) timestamp, uint8_t *data, int len) { call_relation_t *relation = codec->media->session->priv; len = len / 2; sample_t samples[len]; if (codec->decoder == decode_te) { PDEBUG(DROUTER, DEBUG_NOTICE, "Ignoring received telephony-events from terminator.\n"); return; } int16_to_samples(samples, (int16_t *)data, len); /* forward to originator, if not a forking call */ if (!relation->call->forking) { relation = relation->call->relation_list; if (relation->cc_session && relation->codec && !relation->play.fp) send_originator(relation, samples, len); } } void call_media_handle(void) { call_t *call; call_relation_t *relation; for (call = call_list; call; call = call->next) { for (relation = call->relation_list; relation; relation = relation->next) { if (relation->cc_session) osmo_cc_session_handle(relation->cc_session); } } } void call_clock(int len) { call_t *call; call_relation_t *relation; sample_t buffer[len], buffer2[len], *samples[2]; int i; int rc; for (call = call_list; call; call = call->next) { relation = call->relation_list; if (!relation->cc_session || !relation->codec) continue; /* play */ if (relation->play.fp) { int got = 0; read_again: samples[0] = buffer + got; samples[1] = buffer2 + got; rc = wave_read(&relation->play, samples, len - got); got += rc; /* we have a short read (hit the end) or nothing to play left (hit the end without short read) */ if (!relation->play.left) { wave_destroy_playback(&relation->play); if (relation->play_loop) { int samplerate = 0, channels = 0; int rc; rc = wave_create_playback(&relation->play, relation->play_filename, &samplerate, &channels, relation->play_deviation); if (rc >= 0) goto read_again; } else { /* notify routing about finished playback */ if (call->routing.routing) routing_send(&call->routing, "wave-finished"); } } /* in case wie do not get all samples filled, append silence */ while (got < len) buffer[got++] = 0; /* convert stereo to mono */ if (relation->play.channels == 2) { for (i = 0; i < len; i++) buffer[i] += buffer2[i]; } /* forward audio */ if (relation == call->relation_list) send_originator(relation, buffer, len); else send_terminator(relation, buffer, len); } /* record * NOTE: jitter buffer is recorded at send_originator() or send_terminator, so it already includes wave playback */ if (relation->rec.fp) { samples[0] = buffer; samples[1] = buffer2; jitter_load(&relation->orig_dejitter, samples[0], len); if (!call->forking && relation->next) jitter_load(&relation->term_dejitter, samples[1], len); else memset(samples[1], 0, len * sizeof(sample_t)); wave_write(&relation->rec, samples, len); } } } void encode_l16(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len) { uint16_t *src = (uint16_t *)src_data, *dst; int len = src_len / 2, i; dst = malloc(len * 2); if (!dst) return; for (i = 0; i < len; i++) dst[i] = htons(src[i]); *dst_data = (uint8_t *)dst; *dst_len = len * 2; } void decode_l16(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len) { uint16_t *src = (uint16_t *)src_data, *dst; int len = src_len / 2, i; dst = malloc(len * 2); if (!dst) return; for (i = 0; i < len; i++) dst[i] = ntohs(src[i]); *dst_data = (uint8_t *)dst; *dst_len = len * 2; } void encode_te(uint8_t __attribute__((unused)) *src_data, int __attribute__((unused)) src_len, uint8_t **dst_data, int *dst_len) { /* FIXME: TBD... */ *dst_data = NULL; *dst_len = 0; } void decode_te(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len) { uint8_t *src = src_data; struct telephone_event *te; if (src_len < 4) return; te = calloc(1, sizeof(*te)); if (!te) return; te->event = src[0]; te->e = src[1] >> 7; te->r = (src[1] >> 6) & 0x1; te->volume = src[1] & 0x3f; te->duration = (src[2] << 16) | src[3]; *dst_data = (uint8_t *)te; *dst_len = sizeof(*te); }