/* Common transceiver functions * * (C) 2016 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 . */ #define CHAN sender->kanal #include #include #include #include #include #include "debug.h" #include "sender.h" sender_t *sender_head = NULL; static sender_t **sender_tailp = &sender_head; int cant_recover = 0; /* Init transceiver instance and link to list of transceivers. */ int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empfangsfrequenz, const char *audiodev, int samplerate, double rx_gain, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, int loopback, double loss_volume, enum pilot_signal pilot_signal) { sender_t *master, *slave; int rc = 0; sender->kanal = kanal; sender->sendefrequenz = sendefrequenz; sender->empfangsfrequenz = empfangsfrequenz; sender->bandwidth = 4000; /* default is overwritten by dsp.c */ sender->sample_deviation = 0.2; /* default is overwritten by dsp.c */ strncpy(sender->audiodev, audiodev, sizeof(sender->audiodev) - 1); sender->samplerate = samplerate; sender->rx_gain = rx_gain; sender->pre_emphasis = pre_emphasis; sender->de_emphasis = de_emphasis; sender->loopback = loopback; sender->loss_volume = loss_volume; #ifdef HAVE_SDR if (!strcmp(audiodev, "sdr")) pilot_signal = PILOT_SIGNAL_NONE; #endif sender->pilot_signal = pilot_signal; sender->pilotton_phaseshift = 1.0 / ((double)samplerate / 1000.0); PDEBUG_CHAN(DSENDER, DEBUG_DEBUG, "Creating 'Sender' instance\n"); /* if we find a channel that uses the same device as we do, * we will link us as slave to this master channel. then we * receive and send audio via second channel of the device * of the master channel. */ for (master = sender_head; master; master = master->next) { if (master->kanal == kanal) { PDEBUG(DSENDER, DEBUG_ERROR, "Channel %d may not be defined for multiple transceivers!\n", kanal); rc = -EIO; goto error; } if (!strcmp(master->audiodev, audiodev)) break; } if (master) { if (master->pilot_signal != PILOT_SIGNAL_NONE) { PDEBUG(DSENDER, DEBUG_ERROR, "Cannot share audio device with channel %d, because second channel is used for pilot signal!\n", master->kanal); rc = -EBUSY; goto error; } if (pilot_signal != PILOT_SIGNAL_NONE) { PDEBUG(DSENDER, DEBUG_ERROR, "Cannot share audio device with channel %d, because we need a stereo channel for pilot signal!\n", master->kanal); rc = -EBUSY; goto error; } /* link us to a master */ sender->master = master; /* link master (or last slave) to us */ for (slave = master; ; slave = slave->slave) { if (!slave->slave) break; } slave->slave = sender; } else { /* link audio device */ #ifdef HAVE_SDR if (!strcmp(audiodev, "sdr")) { if (pilot_signal != PILOT_SIGNAL_NONE) { PDEBUG(DSENDER, DEBUG_ERROR, "No pilot signal allowed with SDR, please fix!\n"); abort(); } sender->audio_open = sdr_open; sender->audio_close = sdr_close; sender->audio_read = sdr_read; sender->audio_write = sdr_write; sender->audio_get_inbuffer = sdr_get_inbuffer; } else #endif { sender->audio_open = sound_open; sender->audio_close = sound_close; sender->audio_read = sound_read; sender->audio_write = sound_write; sender->audio_get_inbuffer = sound_get_inbuffer; } } rc = init_samplerate(&sender->srstate, samplerate); if (rc < 0) { PDEBUG(DSENDER, DEBUG_ERROR, "Failed to init sample rate conversion!\n"); goto error; } rc = jitter_create(&sender->dejitter, samplerate / 5); if (rc < 0) { PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create and init audio buffer!\n"); goto error; } if (write_rx_wave) { rc = wave_create_record(&sender->wave_rx_rec, write_rx_wave, samplerate); if (rc < 0) { PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create WAVE recoding instance!\n"); goto error; } } if (write_tx_wave) { rc = wave_create_record(&sender->wave_tx_rec, write_tx_wave, samplerate); if (rc < 0) { PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create WAVE recoding instance!\n"); goto error; } } if (read_rx_wave) { rc = wave_create_playback(&sender->wave_rx_play, read_rx_wave, samplerate); if (rc < 0) { PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create WAVE playback instance!\n"); goto error; } } rc = init_emphasis(&sender->estate, samplerate, CUT_OFF_EMPHASIS_DEFAULT); if (rc < 0) goto error; *sender_tailp = sender; sender_tailp = &sender->next; display_wave_init(sender, samplerate); return 0; error: sender_destroy(sender); return rc; } int sender_open_audio(void) { sender_t *master, *inst; int channels; int i; for (master = sender_head; master; master = master->next) { /* skip audio slaves */ if (master->master) continue; /* get list of frequencies */ channels = 0; for (inst = master; inst; inst = inst->slave) { channels++; } double tx_f[channels], rx_f[channels]; for (i = 0, inst = master; inst; i++, inst = inst->slave) { tx_f[i] = inst->sendefrequenz; if (inst->loopback) rx_f[i] = inst->sendefrequenz; else rx_f[i] = inst->empfangsfrequenz; } /* open device */ master->audio = master->audio_open(master->audiodev, tx_f, rx_f, channels, master->samplerate, master->bandwidth, master->sample_deviation); if (!master->audio) { PDEBUG(DSENDER, DEBUG_ERROR, "No audio device!\n"); return -EIO; } } return 0; } /* Destroy transceiver instance and unlink from list. */ void sender_destroy(sender_t *sender) { PDEBUG_CHAN(DSENDER, DEBUG_DEBUG, "Destroying 'Sender' instance\n"); sender_tailp = &sender_head; while (*sender_tailp) { if (sender == *sender_tailp) *sender_tailp = (*sender_tailp)->next; else sender_tailp = &((*sender_tailp)->next); } if (sender->audio) { sender->audio_close(sender->audio); sender->audio = NULL; } wave_destroy_record(&sender->wave_rx_rec); wave_destroy_record(&sender->wave_tx_rec); wave_destroy_playback(&sender->wave_rx_play); jitter_destroy(&sender->dejitter); } static void gen_pilotton(sender_t *sender, int16_t *samples, int length) { double phaseshift, phase; int i; phaseshift = sender->pilotton_phaseshift; phase = sender->pilotton_phase; for (i = 0; i < length; i++) { if (phase < 0.5) *samples++ = 30000; else *samples++ = -30000; phase += phaseshift; if (phase >= 1.0) phase -= 1.0; } sender->pilotton_phase = phase; } static void gain_samples(int16_t *samples, int length, double gain) { int i; int32_t sample; for (i = 0; i < length; i++) { sample = (int32_t)((double)(*samples) * gain); if (sample > 32767) sample = 32767; else if (sample < -32768) sample = -32768; *samples++ = sample; } } /* Handle audio streaming of one transceiver. */ void process_sender_audio(sender_t *sender, int *quit, int latspl) { sender_t *inst; int rc, count; int num_chan, i; /* count instances for audio channel */ for (num_chan = 0, inst = sender; inst; num_chan++, inst = inst->slave); if (sender->pilot_signal != PILOT_SIGNAL_NONE) { if (num_chan != 1) { PDEBUG(DSENDER, DEBUG_ERROR, "Software error, please fix!\n"); abort(); } num_chan = 2; } int16_t buff[num_chan][latspl], *samples[num_chan]; for (i = 0; i < num_chan; i++) samples[i] = buff[i]; count = sender->audio_get_inbuffer(sender->audio); if (count < 0) { /* special case when the device is not yet ready to transmit packets */ if (count == -EAGAIN) { goto transmit_later; } PDEBUG(DSENDER, DEBUG_ERROR, "Failed to get samples in buffer (rc = %d)!\n", count); if (count == -EPIPE) { if (cant_recover) { cant_recover: PDEBUG(DSENDER, DEBUG_ERROR, "Cannot recover due to measurements, quitting!\n"); *quit = 1; return; } PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover!\n"); } return; } if (count < latspl) { count = latspl - count; /* loop through all channels */ for (i = 0, inst = sender; inst; i++, inst = inst->slave) { /* load TX data from audio loop or from sender instance */ if (inst->loopback == 3) jitter_load(&inst->dejitter, samples[i], count); else sender_send(inst, samples[i], count); if (inst->wave_tx_rec.fp) wave_write(&inst->wave_tx_rec, samples[i], count); /* internal loopback: loop back TX audio to RX */ if (inst->loopback == 1) { if (inst->wave_rx_rec.fp) wave_write(&inst->wave_rx_rec, samples[i], count); display_wave(inst, samples[i], count); sender_receive(inst, samples[i], count); } /* do pre emphasis towards radio, not wave_write */ if (inst->pre_emphasis) pre_emphasis(&inst->estate, samples[i], count); } switch (sender->pilot_signal) { case PILOT_SIGNAL_TONE: /* tone if pilot signal is on */ if (sender->pilot_on) gen_pilotton(sender, samples[1], count); else memset(samples[1], 0, count << 1); break; case PILOT_SIGNAL_NOTONE: /* tone if pilot signal is off */ if (!sender->pilot_on) gen_pilotton(sender, samples[1], count); else memset(samples[1], 0, count << 1); break; case PILOT_SIGNAL_POSITIVE: /* positive signal if pilot signal is on */ if (sender->pilot_on) memset(samples[1], 127, count << 1); else memset(samples[1], 128, count << 1); break; case PILOT_SIGNAL_NEGATIVE: /* negative signal if pilot signal is on */ if (sender->pilot_on) memset(samples[1], 128, count << 1); else memset(samples[1], 127, count << 1); break; case PILOT_SIGNAL_NONE: break; } rc = sender->audio_write(sender->audio, samples, count, num_chan); if (rc < 0) { PDEBUG(DSENDER, DEBUG_ERROR, "Failed to write TX data to audio device (rc = %d)\n", rc); if (rc == -EPIPE) { if (cant_recover) goto cant_recover; PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover!\n"); } return; } } transmit_later: count = sender->audio_read(sender->audio, samples, latspl, num_chan); if (count < 0) { /* special case when audio_read wants us to quit */ if (count == -EPERM) { *quit = 1; return; } PDEBUG(DSENDER, DEBUG_ERROR, "Failed to read from audio device (rc = %d)!\n", count); if (count == -EPIPE) { if (cant_recover) goto cant_recover; PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover!\n"); } return; } if (count) { /* loop through all channels */ for (i = 0, inst = sender; inst; i++, inst = inst->slave) { /* rx gain */ if (inst->rx_gain != 1.0) gain_samples(samples[i], count, inst->rx_gain); /* do de emphasis from radio (then write_wave/wave_read), receive audio, process echo test */ if (inst->de_emphasis) de_emphasis(&inst->estate, samples[i], count); if (inst->wave_rx_play.fp) wave_read(&inst->wave_rx_play, samples[i], count); if (inst->loopback != 1) { if (inst->wave_rx_rec.fp) wave_write(&inst->wave_rx_rec, samples[i], count); display_wave(inst, samples[i], count); sender_receive(inst, samples[i], count); } if (inst->loopback == 3) jitter_save(&inst->dejitter, samples[i], count); } } } void sender_pilot(sender_t *sender, int on) { sender->pilot_on = on; }