diff options
Diffstat (limited to 'src/fuenf/dsp.c')
-rw-r--r-- | src/fuenf/dsp.c | 677 |
1 files changed, 677 insertions, 0 deletions
diff --git a/src/fuenf/dsp.c b/src/fuenf/dsp.c new file mode 100644 index 0000000..9adf167 --- /dev/null +++ b/src/fuenf/dsp.c @@ -0,0 +1,677 @@ +/* selective call signal processing + * + * (C) 2019 by Andreas Eversberg <jolly@eversberg.eu> + * 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 <http://www.gnu.org/licenses/>. + */ + +#define CHAN fuenf->sender.kanal + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <math.h> +#include "../libsample/sample.h" +#include "../liblogging/logging.h" +#include "../libmobile/call.h" +#include "fuenf.h" +#include "dsp.h" + +#define MAX_DISPLAY 1.4 /* something above speech level, no emphasis */ +#define MAX_MODULATION 3000.0 /* maximum bandwidth of audio signal */ + +/* TX and RX parameters */ +#define TONE_LEVEL 0.5 /* because we have two tones, also applies to digits */ + +/* TX parameters */ +#define TX_LEN_PREAMBLE 0.600 /* duration of preamble */ +#define TX_LEN_PAUSE 0.600 /* duration of pause */ +#define TX_LEN_POSTAMBLE 0.070 /* duration of postamble */ +#define TX_LEN_DIGIT 0.070 /* duration of paging tone */ +#define TX_NUM_KANAL 10 /* number of 'Kanalbelegungston' */ +#define TX_LEN_KANAL 0.250 /* duration of 'Kanalbelegungston' */ +#define TX_LEN_KANAL_PAUSE 0.250 /* pause after 'Kanalbelegungston' */ +#define TX_LEN_SIGNAL 5.0 /* double tone signal length */ + +/* RX parameters */ +#define RX_MIN_LEVEL 0.1 /* level relative to TONE_LEVEL, below is silence (-20 dB) */ +#define RX_MIN_PREAMBLE 800 /* duration of silence before detecting first digit (in samples) */ +#define RX_DIGIT_FILTER 100.0 /* frequency to allow change of tones ( 100 Hz = 5 ms ) */ +#define RX_TOL_DIGIT_FREQ 0.045 /* maximum frequency error factor allowd to detect a tone (+- 4.5%) */ +#define RX_LEN_DIGIT_TH 80 /* time to wait for digit being stable ( 10 ms ) */ +#define RX_LEN_DIGIT_MIN 400 /* minimum length in seconds allowed for a digit (- 20 ms in samples) */ +#define RX_LEN_DIGIT_MAX 720 /* minimum length in seconds allowed for a digit (+ 20 ms in samples) */ +#define RX_LEN_TONE_MIN 16000 /* minimum length in seconds to detect double tone (2 seconds in samples) */ +#define RX_WAIT_TONE_MAX 48000 /* maximum time to wait for double tone (6 seconds in samples) */ +#define RX_TOL_TONE_FREQ 5.0 /* use +-5 Hz for bandwidth, to make things simpler. (-7.4 dB @ +-5 Hz) */ + +static double digit_freq[DSP_NUM_DIGITS] = { + 1060.0, + 1160.0, + 1270.0, + 1400.0, + 1530.0, + 1670.0, + 1830.0, + 2000.0, + 2200.0, + 2400.0, + 2600.0, /* repeat digit */ +}; +#define DIGIT_FREQ_MIN 1080.0 +#define DIGIT_FREQ_MAX 2600.0 + +#define REPEAT_DIGIT 10 + +/* these are the frequencies of tones to be detected */ +static double tone_freq[DSP_NUM_TONES] = { + 675.0, + 825.0, + 1240.0, + 1860.0, +}; + +#define DSP_NUM_SIGNALS 6 +static struct signals { + enum fuenf_funktion funktion; + int tone1, tone2; +} signals[DSP_NUM_SIGNALS] = { + { FUENF_FUNKTION_FEUER, 0, 2 }, + { FUENF_FUNKTION_PROBE, 0, 3 }, + { FUENF_FUNKTION_WARNUNG, 0, 1 }, + { FUENF_FUNKTION_ABC, 2, 3 }, + { FUENF_FUNKTION_ENTWARNUNG, 1, 3 }, + { FUENF_FUNKTION_KATASTROPHE, 1, 2 }, +}; + +/* Init transceiver instance. */ +int dsp_init_sender(fuenf_t *fuenf, int samplerate, double max_deviation, double signal_deviation) +{ + int i; + int rc; + sample_t *spl; + int len; + + LOGP_CHAN(DDSP, LOGL_DEBUG, "Init DSP for transceiver.\n"); + + /* set modulation parameters */ + sender_set_fm(&fuenf->sender, max_deviation, MAX_MODULATION, signal_deviation, MAX_DISPLAY); + + fuenf->sample_duration = 1.0 / (double)samplerate; + + /* init digit demodulator */ + rc = fm_demod_init(&fuenf->rx_digit_demod, 8000, (DIGIT_FREQ_MIN + DIGIT_FREQ_MAX) / 2.0, DIGIT_FREQ_MAX - DIGIT_FREQ_MIN); + if (rc) + goto error; + + /* use fourth order (2 iter) filter, since it is as fast as second order (1 iter) filter */ + iir_lowpass_init(&fuenf->rx_digit_lp, RX_DIGIT_FILTER, 8000, 2); + + /* init signal tone filters */ + for (i = 0; i < DSP_NUM_TONES; i++) + audio_goertzel_init(&fuenf->rx_tone_goertzel[i], tone_freq[i], 8000); + + /* allocate buffer */ + len = (int)(8000.0 * (1.0 / RX_TOL_TONE_FREQ) + 0.5); + spl = calloc(1, len * sizeof(*spl)); + if (!spl) { + LOGP(DDSP, LOGL_ERROR, "No memory!\n"); + goto error; + } + fuenf->rx_tone_filter_spl = spl; + fuenf->rx_tone_filter_size = len; + + /* display values */ + fuenf->dmp_digit_level = display_measurements_add(&fuenf->sender.dispmeas, "Digit Level", "%.0f %%", DISPLAY_MEAS_LAST, DISPLAY_MEAS_LEFT, 0.0, 150.0, 100.0); + for (i = 0; i < DSP_NUM_TONES; i++) { + char name[64]; + sprintf(name, "%.0f Hz Level", tone_freq[i]); + fuenf->dmp_tone_levels[i] = display_measurements_add(&fuenf->sender.dispmeas, name, "%.0f %%", DISPLAY_MEAS_LAST, DISPLAY_MEAS_LEFT, 0.0, 150.0, 100.0); + } + + return 0; + +error: + dsp_cleanup_sender(fuenf); + + return -rc; +} + +/* Cleanup transceiver instance. */ +void dsp_cleanup_sender(fuenf_t *fuenf) +{ + LOGP_CHAN(DDSP, LOGL_DEBUG, "Cleanup DSP for transceiver.\n"); + + /* free tone buffers */ + if (fuenf->rx_tone_filter_spl) + free(fuenf->rx_tone_filter_spl); +} + +//#define DEBUG_CODER + +/* receive digits and decode */ +static void digit_decode(fuenf_t *fuenf, sample_t *samples, int length) +{ + sample_t frequency[length], f, a; + sample_t I[length], Q[length]; + int i, d; + int change, change_count; + + /* tone demodulation */ + fm_demodulate_real(&fuenf->rx_digit_demod, frequency, length, samples, I, Q); + + /* reduce bandwidth of tone detector */ + iir_process(&fuenf->rx_digit_lp, frequency, length); + + /* detect tone */ + for (i = 0; i < length; i++) { + /* get frequency */ + f = frequency[i] + (DIGIT_FREQ_MIN + DIGIT_FREQ_MAX) / 2.0; + + /* get amplitude (a is a sqaure of the amplitude for faster math) */ + a = (I[i] * I[i] + Q[i] * Q[i]) * 2.0 * 2.0 / TONE_LEVEL / TONE_LEVEL; + +#ifdef DEBUG_CODER + if (i == 0) printf("%s %.5f ", debug_amplitude(frequency[i] / (DIGIT_FREQ_MAX - DIGIT_FREQ_MIN) * 2.0), f); + if (i == 0) printf("%s %.5f ", debug_amplitude(sqrt(a)), sqrt(a)); +#endif + /* get digit that matches the frequency tolerance */ + for (d = 0; d < DSP_NUM_DIGITS; d++) { + if (f >= digit_freq[d] * (1.0 - RX_TOL_DIGIT_FREQ) && f <= digit_freq[d] * (1.0 + RX_TOL_DIGIT_FREQ)) + break; + } + + /* digit lound enough ? */ + if (a >= RX_MIN_LEVEL * RX_MIN_LEVEL && d < DSP_NUM_DIGITS) { +#ifdef DEBUG_CODER + if (i == 0 && d < DSP_NUM_DIGITS) printf("digit=%d (%d == no digit detected)", d, DSP_NUM_DIGITS); +#endif + } else + d = -1; +#ifdef DEBUG_CODER + sffd + if (i == 0) printf("\n"); +#endif + + /* correct amplitude at cutoff frequency digit '1' and 'repeat'.*/ + if (d == 0 || d == DSP_NUM_DIGITS - 1) + a = a * 2; /* actually 1.414 at cutoff, but a is a square, so we can use 2 */ + + /* count how long this digit sustains, also report if it has changed and when */ + if (d != fuenf->rx_digit_last) { + change = 1; + change_count = fuenf->rx_digit_count; + fuenf->rx_digit_last = d; + fuenf->rx_digit_count = 0; + } else + change = 0; + fuenf->rx_digit_count++; + + /* state machine to detect sequence of 5 tones */ + switch (fuenf->rx_state) { + case RX_STATE_RESET: + /* wait for silence */ + if (d >= 0) + break; + /* check if we have enought silence */ + if (fuenf->rx_digit_count == RX_MIN_PREAMBLE) { + LOGP_CHAN(DDSP, LOGL_DEBUG, "Detected silence, waiting for digits.\n"); + fuenf->rx_state = RX_STATE_IDLE; + break; + } + break; + case RX_STATE_IDLE: + /* wait for digit */ + if (d < 0) + break; + LOGP_CHAN(DDSP, LOGL_DEBUG, "We have some tone, start receiving digits.\n"); + fuenf->rx_callsign_count = 0; + fuenf->rx_callsign[fuenf->rx_callsign_count] = d; + fuenf->rx_state = RX_STATE_DIGIT; + break; + case RX_STATE_DIGIT: + /* wait for change */ + if (!change) { + if (fuenf->rx_digit_count == RX_LEN_DIGIT_TH) { + if (d < 0) { + LOGP_CHAN(DDSP, LOGL_DEBUG, "Not enough digits received, waiting for next transmission.\n"); + fuenf->rx_function = 0; + fuenf->rx_function_count = 0; + fuenf->rx_state = RX_STATE_RESET; + break; + } + LOGP_CHAN(DDSP, LOGL_DEBUG, "Detected digit #%d (amplitude = %.0f%%)\n", d + 1, sqrt(a) * 100.0); + display_measurements_update(fuenf->dmp_digit_level, sqrt(a) * 100.0, 0.0); + break; + } + if (fuenf->rx_digit_count == RX_LEN_DIGIT_MAX) { + LOGP_CHAN(DDSP, LOGL_DEBUG, "Detected digit too long, waiting for next transmission.\n"); + fuenf->rx_state = RX_STATE_RESET; + break; + } + break; + } + /* if digit did not become stable (changed) during threshold */ + if (change_count < RX_LEN_DIGIT_TH) { + /* store detected digit and wait for this one to become stable */ + fuenf->rx_callsign[fuenf->rx_callsign_count] = d; + break; + } + /* if counter (when changed) was too low */ + if (change_count < RX_LEN_DIGIT_MIN) { + LOGP_CHAN(DDSP, LOGL_DEBUG, "Detected digit too short, waiting for next transmission.\n"); + fuenf->rx_state = RX_STATE_RESET; + break; + } + /* increment digit and store detected digit */ + fuenf->rx_callsign_count++; + fuenf->rx_callsign[fuenf->rx_callsign_count] = d; + /* if 5 tones are received, decode */ + if (fuenf->rx_callsign_count == 5) { + for (i = 0; i < 5; i++) { + if (fuenf->rx_callsign[i] == REPEAT_DIGIT) { + if (i == 0) { + LOGP_CHAN(DDSP, LOGL_DEBUG, "First digit is a repeat digit, this is not allowed, waiting for next transmission.\n"); + fuenf->rx_state = RX_STATE_RESET; + break; + } + fuenf->rx_callsign[i] = fuenf->rx_callsign[i - 1]; + } else + if (fuenf->rx_callsign[i] == 9) + fuenf->rx_callsign[i] = '0'; + else + fuenf->rx_callsign[i] = '1' + fuenf->rx_callsign[i]; + } + fuenf->rx_callsign[i] = '\0'; + if (i < 5) + break; + LOGP_CHAN(DDSP, LOGL_DEBUG, "Complete call sign '%s' received, waiting for signal tone(s).\n", fuenf->rx_callsign); + fuenf_rx_callsign(fuenf, fuenf->rx_callsign); + fuenf->rx_function_count = 0; /* must reset, so we can detect timeout */ + fuenf->rx_state = RX_STATE_WAIT_SIGNAL; + break; + } + break; + default: + /* tones are not decoded here */ + break; + } + } +} + +/* receive tones and decode */ +static void tone_decode(fuenf_t *fuenf, sample_t *samples, int length) +{ + double levels[DSP_NUM_TONES]; + int tone1 = -1, tone2 = -1; + enum fuenf_funktion funktion = 0; + int i; + + /* filter tones */ + audio_goertzel(fuenf->rx_tone_goertzel, samples, length, 0, levels, DSP_NUM_TONES); + for (i = 0; i < DSP_NUM_TONES; i++) + fuenf->rx_tone_levels[i] = levels[i] / TONE_LEVEL; + + /* find two frequencies */ + for (i = 0; i < DSP_NUM_TONES; i++) { + if (fuenf->rx_tone_levels[i] < RX_MIN_LEVEL) + continue; + /* accpet only two ones */ + if (tone1 < 0) + tone1 = i; + else if (tone2 < 0) + tone2 = i; + else { + /* abort, if more than two tones */ + tone1 = -1; + tone2 = -1; + break; + } + } + + /* if exactly two tones */ + if (tone2 >= 0) { + /* select function from signal */ + for (i = 0; i < DSP_NUM_SIGNALS; i++) { + if (tone1 == signals[i].tone1 + && tone2 == signals[i].tone2) { + funktion = signals[i].funktion; + break; + } + } + } + + fuenf->rx_function_count += length; + + /* state machine to detect two tones */ + switch (fuenf->rx_state) { + case RX_STATE_WAIT_SIGNAL: + /* wait for signal */ + if (!funktion) { + if (fuenf->rx_function_count >= RX_WAIT_TONE_MAX) { + LOGP_CHAN(DDSP, LOGL_DEBUG, "There is no double tone, waiting for next transmission.\n"); + fuenf->rx_state = RX_STATE_RESET; + break; + } + break; + } + /* store signal */ + fuenf->rx_function = funktion; + fuenf->rx_function_count = 0; + fuenf->rx_state = RX_STATE_SIGNAL; + break; + case RX_STATE_SIGNAL: + /* if signal ceases too early */ + if (funktion != fuenf->rx_function) { + LOGP_CHAN(DDSP, LOGL_DEBUG, "Signal tones ceased to early, waiting for next transmission.\n"); + fuenf->rx_state = RX_STATE_RESET; + break; + } + if (fuenf->rx_function_count >= RX_LEN_TONE_MIN) { + LOGP_CHAN(DDSP, LOGL_DEBUG, "Detected tones %.0f+%.0f Hz (amplitude = %.0f%%+%.0f%%)\n", tone_freq[tone1], tone_freq[tone2], fuenf->rx_tone_levels[tone1] * 100.0, fuenf->rx_tone_levels[tone2] * 100.0); + LOGP_CHAN(DDSP, LOGL_DEBUG, "Signal tones detected, done, waiting for next transmission.\n"); + fuenf_rx_function(fuenf, fuenf->rx_function); + fuenf->rx_state = RX_STATE_RESET; + break; + } + break; + default: + /* digits are not decoded here */ + break; + } +} + +/* Process received audio stream from radio unit. */ +void sender_receive(sender_t *sender, sample_t *samples, int length, double __attribute__((unused)) rf_level_db) +{ + fuenf_t *fuenf = (fuenf_t *) sender; + + if (fuenf->rx) { + sample_t down[length]; + int count, i; + + /* downsample */ + memcpy(down, samples, sizeof(down)); // copy, so audio will not be corrupted at loopback + count = samplerate_downsample(&fuenf->sender.srstate, down, length); + + /* decode digit */ + digit_decode(fuenf, down, count); + + /* decode tone */ + for (i = 0; i < count; i++) { + /* fill buffer and decode when full */ + fuenf->rx_tone_filter_spl[fuenf->rx_tone_filter_pos] = down[i]; + if (++fuenf->rx_tone_filter_pos == fuenf->rx_tone_filter_size) { + tone_decode(fuenf, fuenf->rx_tone_filter_spl, fuenf->rx_tone_filter_size); + fuenf->rx_tone_filter_pos = 0; + } + } + /* display levels */ + for (i = 0; i < DSP_NUM_TONES; i++) + display_measurements_update(fuenf->dmp_tone_levels[i], fuenf->rx_tone_levels[i] * 100.0, 0.0); + } +} + +/* set sequence to send */ +int dsp_setup(fuenf_t *fuenf, const char *rufzeichen, enum fuenf_funktion funktion) +{ + tone_seq_t *seq = fuenf->tx_seq; + int index = 0, tone_index; + int i; + + fuenf->tx_seq_length = 0; + + if (strlen(rufzeichen) != 5) { + LOGP_CHAN(DDSP, LOGL_ERROR, "Given call sign has invalid length.\n"); + return -EINVAL; + } + + LOGP_CHAN(DDSP, LOGL_DEBUG, "Generating sequence for call sign '%s' and function code '%d'.\n", rufzeichen, funktion); + + /* add preamble */ + seq[index].phasestep1 = 0; + seq[index].phasestep2 = 0; + seq[index].duration = TX_LEN_PREAMBLE; + index++; + + /* add tones */ + tone_index = index; + for (i = 0; rufzeichen[i]; i++) { + if (rufzeichen[i] < '0' || rufzeichen[i] > '9') { + LOGP_CHAN(DDSP, LOGL_ERROR, "Given call sign has invalid digit '%c'.\n", rufzeichen[i]); + return -EINVAL; + } + if (rufzeichen[i] == '0') + seq[index].phasestep1 = 2.0 * M_PI * digit_freq[9] * fuenf->sample_duration; + else + seq[index].phasestep1 = 2.0 * M_PI * digit_freq[rufzeichen[i] - '1'] * fuenf->sample_duration; + /* use repeat digit, if two subsequent digits are the same */ + if (i > 0 && seq[index - 1].phasestep1 == seq[index].phasestep1) { + seq[index].phasestep1 = 2.0 * M_PI * digit_freq[REPEAT_DIGIT] * fuenf->sample_duration; + LOGP_CHAN(DDSP, LOGL_DEBUG, " -> Adding digit '%c' as tone with %.0f Hz.\n", rufzeichen[i], digit_freq[REPEAT_DIGIT]); + } else + LOGP_CHAN(DDSP, LOGL_DEBUG, " -> Adding digit '%c' as tone with %.0f Hz.\n", rufzeichen[i], digit_freq[rufzeichen[i] - '0']); + seq[index].phasestep2 = 0; + seq[index].duration = TX_LEN_DIGIT; + index++; + } + + if (funktion != FUENF_FUNKTION_TURBO) { + /* add pause */ + seq[index].phasestep1 = 0; + seq[index].phasestep2 = 0; + seq[index].duration = TX_LEN_PAUSE; + index++; + + /* add tones (again) */ + for (i = 0; rufzeichen[i]; i++) { + seq[index].phasestep1 = seq[tone_index + i].phasestep1; + seq[index].phasestep2 = 0; + seq[index].duration = TX_LEN_DIGIT; + index++; + } + + /* add (second) pause */ + seq[index].phasestep1 = 0; + seq[index].phasestep2 = 0; + seq[index].duration = TX_LEN_PAUSE; + index++; + } + +#ifndef DEBUG_CODER + if (funktion == FUENF_FUNKTION_RUF) { + LOGP_CHAN(DDSP, LOGL_DEBUG, " -> Adding call signal of %.0f Hz.\n", digit_freq[REPEAT_DIGIT]); + for (i = 0; i < TX_NUM_KANAL; i++) { + /* add tone (double volume) */ + seq[index].phasestep1 = 2.0 * M_PI * digit_freq[REPEAT_DIGIT] * fuenf->sample_duration; + seq[index].phasestep2 = 2.0 * M_PI * digit_freq[REPEAT_DIGIT] * fuenf->sample_duration; + seq[index].duration = TX_LEN_KANAL; + index++; + + /* add pause after tone */ + if (i < TX_NUM_KANAL - 1) { + seq[index].phasestep1 = 0; + seq[index].phasestep2 = 0; + seq[index].duration = TX_LEN_KANAL_PAUSE; + index++; + } + } + + /* add postamble */ + seq[index].phasestep1 = 0; + seq[index].phasestep2 = 0; + seq[index].duration = TX_LEN_POSTAMBLE; + index++; + } else + if (funktion != FUENF_FUNKTION_TURBO) { + /* add signal */ + for (i = 0; i < DSP_NUM_SIGNALS; i++) { + if (signals[i].funktion == funktion) + break; + } + LOGP_CHAN(DDSP, LOGL_DEBUG, " -> Adding call signal of %.0f Hz and %.0f Hz.\n", tone_freq[signals[i].tone1], tone_freq[signals[i].tone2]); + seq[index].phasestep1 = 2.0 * M_PI * tone_freq[signals[i].tone1] * fuenf->sample_duration; + seq[index].phasestep2 = 2.0 * M_PI * tone_freq[signals[i].tone2] * fuenf->sample_duration; + seq[index].duration = TX_LEN_SIGNAL; + index++; + } +#endif + + /* check array overflow, if it did not already crashed before */ + if (index > (int)(sizeof(fuenf->tx_seq) / sizeof(fuenf->tx_seq[0]))) { + LOGP_CHAN(DDSP, LOGL_ERROR, "Array size of tx_seq too small, please fix!\n"); + abort(); + } + + fuenf->tx_funktion = funktion; + fuenf->tx_seq_length = index; + fuenf->tx_seq_index = 0; + fuenf->tx_count = 0.0; + + return index; +} + +/* transmit call tone or pause, return 0, if no sequence */ +static int encode(fuenf_t *fuenf, sample_t *samples, int length) +{ + tone_seq_t *seq; + int count = 0; + double value; + + /* no sequence */ + if (!fuenf->tx_seq_length) + return 0; + + seq = &fuenf->tx_seq[fuenf->tx_seq_index]; + + /* generate wave */ + while (count < length && fuenf->tx_count < seq->duration) { + value = 0; + /* reset phase when not sending sine wave */ + if (seq->phasestep1) { + value += sin(fuenf->tx_phase1); + fuenf->tx_phase1 += seq->phasestep1; + } else + fuenf->tx_phase1 = 0.0; + if (seq->phasestep2) { + value += sin(fuenf->tx_phase2); + fuenf->tx_phase2 += seq->phasestep2; + } else + fuenf->tx_phase2 = 0.0; + fuenf->tx_count += fuenf->sample_duration; + *samples++ = value * TONE_LEVEL; + count++; + } + + /* transition to next segment */ + if (fuenf->tx_count >= seq->duration) { + fuenf->tx_count -= seq->duration; + if (++fuenf->tx_seq_index == fuenf->tx_seq_length) { + fuenf->tx_seq_length = 0; + fuenf_tx_done(fuenf); + } + + } + + return count; +} + +/* Provide stream of audio toward radio unit */ +void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length) +{ + fuenf_t *fuenf = (fuenf_t *) sender; + sample_t *orig_samples = samples; + int orig_length = length; + int count, input_num; + sample_t *spl; + int pos; + int i; + + /* speak through */ + if (fuenf->state == FUENF_STATE_DURCHSAGE && fuenf->callref) { + memset(power, 1, length); + input_num = samplerate_upsample_input_num(&sender->srstate, length); + { + int16_t spl[input_num]; + jitter_load_samples(&sender->dejitter, (uint8_t *)spl, input_num, sizeof(*spl), jitter_conceal_s16, NULL); + int16_to_samples_speech(samples, spl, input_num); + } + samplerate_upsample(&sender->srstate, samples, input_num, samples, length); + } else { + /* send if something has to be sent. else turn transmitter off */ + while ((count = encode(fuenf, samples, length))) { + memset(power, 1, count); + samples += count; + power += count; + length -= count; + } + if (length) { + memset(samples, 0, sizeof(samples) * length); + memset(power, 0, length); + } + } + + /* Also forward audio to network (call process). */ + if (fuenf->callref) { + sample_t copy_samples[orig_length]; +// should we always echo back what we talk through??? +#if 0 + if (fuenf->state == FUENF_STATE_DURCHSAGE) + memset(copy_samples, 0, sizeof(copy_samples)); + else +#endif + memcpy(copy_samples, orig_samples, sizeof(copy_samples)); + count = samplerate_downsample(&fuenf->sender.srstate, copy_samples, orig_length); + spl = fuenf->sender.rxbuf; + pos = fuenf->sender.rxbuf_pos; + for (i = 0; i < count; i++) { + spl[pos++] = copy_samples[i]; + if (pos == 160) { + call_up_audio(fuenf->callref, spl, 160); + pos = 0; + } + } + fuenf->sender.rxbuf_pos = pos; + } else + fuenf->sender.rxbuf_pos = 0; + +} + +/* Receive audio from call instance. */ +void call_down_audio(void *decoder, void *decoder_priv, int callref, uint16_t sequence, uint8_t marker, uint32_t timestamp, uint32_t ssrc, uint8_t *payload, int payload_len) +{ + sender_t *sender; + fuenf_t *fuenf; + + for (sender = sender_head; sender; sender = sender->next) { + fuenf = (fuenf_t *) sender; + if (fuenf->callref == callref) + break; + } + if (!sender) + return; + + if (fuenf->state == FUENF_STATE_DURCHSAGE) { + jitter_frame_t *jf; + jf = jitter_frame_alloc(decoder, decoder_priv, payload, payload_len, marker, sequence, timestamp, ssrc); + if (jf) + jitter_save(&fuenf->sender.dejitter, jf); + } +} + +void call_down_clock(void) {} + |