2016-03-01 17:40:38 +00:00
/* Common transceiver functions
*
* ( C ) 2016 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/>.
*/
2016-06-05 09:35:16 +00:00
/* Uncomment this for writing TX as wave (For debug purpose) */
//#define WAVE_WRITE_TX
2016-07-31 13:09:46 +00:00
# define CHAN sender->kanal
2016-03-01 17:40:38 +00:00
# include <stdio.h>
# include <stdint.h>
# include <stdlib.h>
# include <errno.h>
# include <string.h>
# include "debug.h"
# include "sender.h"
sender_t * sender_head = NULL ;
static sender_t * * sender_tailp = & sender_head ;
2016-02-16 17:56:55 +00:00
int cant_recover = 0 ;
2016-03-01 17:40:38 +00:00
/* Init transceiver instance and link to list of transceivers. */
2016-05-06 05:00:27 +00:00
int sender_create ( sender_t * sender , int kanal , const char * sounddev , int samplerate , int cross_channels , double rx_gain , int pre_emphasis , int de_emphasis , const char * write_wave , const char * read_wave , int loopback , double loss_volume , int use_pilot_signal )
2016-03-01 17:40:38 +00:00
{
2016-04-25 18:20:54 +00:00
sender_t * master ;
2016-03-01 17:40:38 +00:00
int rc = 0 ;
2016-07-31 13:09:46 +00:00
sender - > kanal = kanal ;
strncpy ( sender - > sounddev , sounddev , sizeof ( sender - > sounddev ) - 1 ) ;
sender - > samplerate = samplerate ;
sender - > cross_channels = cross_channels ;
sender - > rx_gain = rx_gain ;
sender - > pre_emphasis = pre_emphasis ;
sender - > de_emphasis = de_emphasis ;
sender - > loopback = loopback ;
sender - > loss_volume = loss_volume ;
sender - > use_pilot_signal = use_pilot_signal ;
sender - > pilotton_phaseshift = 1.0 / ( ( double ) samplerate / 1000.0 ) ;
PDEBUG_CHAN ( DSENDER , DEBUG_DEBUG , " Creating 'Sender' instance \n " ) ;
2016-03-01 17:40:38 +00:00
2016-04-25 18:20:54 +00:00
/* 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 - > sounddev , sounddev ) )
break ;
}
if ( master ) {
if ( master - > slave ) {
PDEBUG ( DSENDER , DEBUG_ERROR , " Sound device '%s' cannot be used for channel %d. It is already shared by channel %d and %d! \n " , sounddev , kanal , master - > kanal , master - > slave - > kanal ) ;
rc = - EBUSY ;
goto error ;
}
if ( ! sound_is_stereo_capture ( master - > sound ) | | ! sound_is_stereo_playback ( master - > sound ) ) {
PDEBUG ( DSENDER , DEBUG_ERROR , " Sound device '%s' cannot be used for more than one channel, because one direction is mono! \n " , sounddev ) ;
rc = - EBUSY ;
goto error ;
}
if ( master - > use_pilot_signal > = 0 ) {
PDEBUG ( DSENDER , DEBUG_ERROR , " Cannot share sound device with channel %d, because second channel is used for pilot signal! \n " , master - > kanal ) ;
rc = - EBUSY ;
goto error ;
}
if ( use_pilot_signal > = 0 ) {
PDEBUG ( DSENDER , DEBUG_ERROR , " Cannot share sound 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 */
master - > slave = sender ;
sender - > master = master ;
} else {
/* open own device */
sender - > sound = sound_open ( sounddev , samplerate ) ;
if ( ! sender - > sound ) {
PDEBUG ( DSENDER , DEBUG_ERROR , " No sound device! \n " ) ;
rc = - EIO ;
goto error ;
}
}
2016-03-01 17:40:38 +00:00
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 - > audio , samplerate / 5 ) ;
if ( rc < 0 ) {
PDEBUG ( DSENDER , DEBUG_ERROR , " Failed to create and init audio buffer! \n " ) ;
goto error ;
}
2016-03-25 12:58:16 +00:00
if ( write_wave ) {
rc = wave_create_record ( & sender - > wave_rec , write_wave , samplerate ) ;
if ( rc < 0 ) {
PDEBUG ( DSENDER , DEBUG_ERROR , " Failed to create WAVE recoding instance! \n " ) ;
goto error ;
}
}
if ( read_wave ) {
rc = wave_create_playback ( & sender - > wave_play , read_wave , samplerate ) ;
if ( rc < 0 ) {
PDEBUG ( DSENDER , DEBUG_ERROR , " Failed to create WAVE playback instance! \n " ) ;
goto error ;
}
}
2016-04-23 16:50:11 +00:00
rc = init_emphasis ( & sender - > estate , samplerate ) ;
if ( rc < 0 )
goto error ;
2016-03-01 17:40:38 +00:00
* sender_tailp = sender ;
sender_tailp = & sender - > next ;
2016-06-17 05:28:45 +00:00
if ( sender = = sender_head )
display_wave_init ( sender , samplerate ) ;
2016-03-01 17:40:38 +00:00
return 0 ;
error :
sender_destroy ( sender ) ;
return rc ;
}
/* Destroy transceiver instance and unlink from list. */
void sender_destroy ( sender_t * sender )
{
2016-07-31 13:09:46 +00:00
PDEBUG_CHAN ( DSENDER , DEBUG_DEBUG , " Destroying 'Sender' instance \n " ) ;
2016-03-01 17:40:38 +00:00
sender_tailp = & sender_head ;
while ( * sender_tailp ) {
if ( sender = = * sender_tailp )
2016-04-25 18:20:54 +00:00
* sender_tailp = ( * sender_tailp ) - > next ;
else
sender_tailp = & ( ( * sender_tailp ) - > next ) ;
2016-03-01 17:40:38 +00:00
}
2016-04-25 18:20:54 +00:00
if ( sender - > slave )
sender - > slave - > master = NULL ;
if ( sender - > master )
sender - > master - > slave = NULL ;
2016-03-01 17:40:38 +00:00
if ( sender - > sound )
sound_close ( sender - > sound ) ;
2016-03-25 12:58:16 +00:00
wave_destroy_record ( & sender - > wave_rec ) ;
wave_destroy_playback ( & sender - > wave_play ) ;
2016-03-01 17:40:38 +00:00
jitter_destroy ( & sender - > audio ) ;
}
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 ;
}
2016-05-06 05:00:27 +00:00
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 ;
}
}
2016-03-01 17:40:38 +00:00
/* Handle audio streaming of one transceiver. */
2016-06-17 05:28:45 +00:00
void process_sender_audio ( sender_t * sender , int * quit , int latspl )
2016-03-01 17:40:38 +00:00
{
2016-04-25 18:20:54 +00:00
sender_t * slave = sender - > slave ;
int16_t samples [ latspl ] , pilot [ latspl ] , slave_samples [ latspl ] ;
2016-03-01 17:40:38 +00:00
int rc , count ;
count = sound_get_inbuffer ( sender - > sound ) ;
if ( count < 0 ) {
PDEBUG ( DSENDER , DEBUG_ERROR , " Failed to get samples in buffer (rc = %d)! \n " , count ) ;
2016-02-16 17:56:55 +00:00
if ( count = = - EPIPE ) {
if ( cant_recover ) {
cant_recover :
PDEBUG ( DSENDER , DEBUG_ERROR , " Cannot recover due to measurements, quitting! \n " ) ;
* quit = 1 ;
return ;
}
2016-03-01 17:40:38 +00:00
PDEBUG ( DSENDER , DEBUG_ERROR , " Trying to recover! \n " ) ;
2016-02-16 17:56:55 +00:00
}
2016-03-01 17:40:38 +00:00
return ;
}
if ( count < latspl ) {
count = latspl - count ;
2016-04-25 18:20:54 +00:00
/* load TX data from audio loop or from sender instance */
2016-03-01 17:40:38 +00:00
if ( sender - > loopback = = 3 )
jitter_load ( & sender - > audio , samples , count ) ;
else
sender_send ( sender , samples , count ) ;
2016-06-05 09:35:16 +00:00
# ifdef WAVE_WRITE_TX
if ( sender - > wave_rec . fp )
wave_write ( & sender - > wave_rec , samples , count ) ;
# endif
2016-04-25 18:20:54 +00:00
/* internal loopback: loop back TX audio to RX */
if ( sender - > loopback = = 1 ) {
2016-06-05 09:35:16 +00:00
# ifndef WAVE_WRITE_TX
2016-04-25 18:20:54 +00:00
if ( sender - > wave_rec . fp )
wave_write ( & sender - > wave_rec , samples , count ) ;
2016-06-17 05:28:45 +00:00
if ( sender = = sender_head )
display_wave ( sender , samples , count ) ;
2016-04-25 18:20:54 +00:00
sender_receive ( sender , samples , count ) ;
2016-06-05 09:35:16 +00:00
# endif
2016-04-25 18:20:54 +00:00
}
/* do pre emphasis towards radio, not wave_write */
2016-04-23 16:50:11 +00:00
if ( sender - > pre_emphasis )
pre_emphasis ( & sender - > estate , samples , count ) ;
2016-04-25 18:20:54 +00:00
/* do above for audio slave, if set */
if ( slave ) {
if ( slave - > loopback = = 3 )
jitter_load ( & slave - > audio , slave_samples , count ) ;
else
sender_send ( slave , slave_samples , count ) ;
2016-06-05 09:35:16 +00:00
# ifdef WAVE_WRITE_TX
if ( sender - > wave_rec . fp )
wave_write ( & slave - > wave_rec , slave_samples , count ) ;
# endif
2016-04-25 18:20:54 +00:00
/* internal loopback, if audio slave is set */
if ( slave & & slave - > loopback = = 1 ) {
2016-06-05 09:35:16 +00:00
# ifndef WAVE_WRITE_TX
2016-04-25 18:20:54 +00:00
if ( slave - > wave_rec . fp )
wave_write ( & slave - > wave_rec , slave_samples , count ) ;
2016-06-05 09:35:16 +00:00
# endif
2016-04-25 18:20:54 +00:00
sender_receive ( slave , slave_samples , count ) ;
}
/* do pre emphasis towards radio, not wave_write */
if ( slave - > pre_emphasis )
pre_emphasis ( & slave - > estate , slave_samples , count ) ;
}
2016-03-01 17:40:38 +00:00
switch ( sender - > use_pilot_signal ) {
case 2 :
/* tone if pilot signal is on */
if ( sender - > pilot_on )
gen_pilotton ( sender , pilot , count ) ;
else
memset ( pilot , 0 , count < < 1 ) ;
2016-04-25 18:20:54 +00:00
if ( ! sender - > cross_channels )
rc = sound_write ( sender - > sound , samples , pilot , count ) ;
else
rc = sound_write ( sender - > sound , pilot , samples , count ) ;
2016-03-01 17:40:38 +00:00
break ;
case 1 :
/* positive signal if pilot signal is on */
if ( sender - > pilot_on )
memset ( pilot , 127 , count < < 1 ) ;
else
memset ( pilot , 128 , count < < 1 ) ;
2016-04-25 18:20:54 +00:00
if ( ! sender - > cross_channels )
rc = sound_write ( sender - > sound , samples , pilot , count ) ;
else
rc = sound_write ( sender - > sound , pilot , samples , count ) ;
2016-03-01 17:40:38 +00:00
break ;
case 0 :
/* negative signal if pilot signal is on */
if ( sender - > pilot_on )
memset ( pilot , 128 , count < < 1 ) ;
else
memset ( pilot , 127 , count < < 1 ) ;
2016-04-25 18:20:54 +00:00
if ( ! sender - > cross_channels )
rc = sound_write ( sender - > sound , samples , pilot , count ) ;
else
rc = sound_write ( sender - > sound , pilot , samples , count ) ;
2016-03-01 17:40:38 +00:00
break ;
default :
2016-04-25 18:20:54 +00:00
/* if audio slave is set, write audio of both sender instances */
if ( slave ) {
if ( ! sender - > cross_channels )
rc = sound_write ( sender - > sound , samples , slave_samples , count ) ;
else
rc = sound_write ( sender - > sound , slave_samples , samples , count ) ;
} else {
/* use pilot tone buffer for silence */
memset ( pilot , 0 , count < < 1 ) ;
if ( ! sender - > cross_channels )
rc = sound_write ( sender - > sound , samples , pilot , count ) ;
else
rc = sound_write ( sender - > sound , pilot , samples , count ) ;
}
2016-03-01 17:40:38 +00:00
}
if ( rc < 0 ) {
PDEBUG ( DSENDER , DEBUG_ERROR , " Failed to write TX data to sound device (rc = %d) \n " , rc ) ;
2016-02-16 17:56:55 +00:00
if ( rc = = - EPIPE ) {
if ( cant_recover )
goto cant_recover ;
2016-03-01 17:40:38 +00:00
PDEBUG ( DSENDER , DEBUG_ERROR , " Trying to recover! \n " ) ;
2016-02-16 17:56:55 +00:00
}
2016-03-01 17:40:38 +00:00
return ;
}
}
2016-04-25 18:20:54 +00:00
if ( ! sender - > cross_channels )
count = sound_read ( sender - > sound , samples , slave_samples , latspl ) ;
else
count = sound_read ( sender - > sound , slave_samples , samples , latspl ) ;
2016-03-01 17:40:38 +00:00
//printf("count=%d time= %.4f\n", count, (double)count * 1000 / sender->samplerate);
if ( count < 0 ) {
PDEBUG ( DSENDER , DEBUG_ERROR , " Failed to read from sound device (rc = %d)! \n " , count ) ;
2016-02-16 17:56:55 +00:00
if ( count = = - EPIPE ) {
if ( cant_recover )
goto cant_recover ;
2016-03-01 17:40:38 +00:00
PDEBUG ( DSENDER , DEBUG_ERROR , " Trying to recover! \n " ) ;
2016-02-16 17:56:55 +00:00
}
2016-03-01 17:40:38 +00:00
return ;
}
if ( count ) {
2016-05-06 05:00:27 +00:00
/* rx gain */
if ( sender - > rx_gain ! = 1.0 )
gain_samples ( samples , count , sender - > rx_gain ) ;
2016-04-25 18:20:54 +00:00
/* do de emphasis from radio (then write_wave/wave_read), receive audio, process echo test */
2016-04-23 16:50:11 +00:00
if ( sender - > de_emphasis )
de_emphasis ( & sender - > estate , samples , count ) ;
2016-03-25 12:58:16 +00:00
if ( sender - > wave_play . fp )
wave_read ( & sender - > wave_play , samples , count ) ;
if ( sender - > loopback ! = 1 ) {
2016-06-05 09:35:16 +00:00
# ifndef WAVE_WRITE_TX
2016-03-25 12:58:16 +00:00
if ( sender - > wave_rec . fp )
wave_write ( & sender - > wave_rec , samples , count ) ;
2016-06-05 09:35:16 +00:00
# endif
2016-06-17 05:28:45 +00:00
if ( sender = = sender_head )
display_wave ( sender , samples , count ) ;
2016-03-01 17:40:38 +00:00
sender_receive ( sender , samples , count ) ;
2016-03-25 12:58:16 +00:00
}
2016-04-25 18:20:54 +00:00
if ( sender - > loopback = = 3 )
2016-03-01 17:40:38 +00:00
jitter_save ( & sender - > audio , samples , count ) ;
2016-04-25 18:20:54 +00:00
/* do above for audio slave, if set */
if ( slave ) {
2016-05-06 05:00:27 +00:00
if ( sender - > rx_gain ! = 1.0 )
gain_samples ( slave_samples , count , slave - > rx_gain ) ;
2016-04-25 18:20:54 +00:00
if ( slave - > de_emphasis )
de_emphasis ( & slave - > estate , slave_samples , count ) ;
if ( slave - > wave_play . fp )
wave_read ( & slave - > wave_play , slave_samples , count ) ;
if ( slave - > loopback ! = 1 ) {
2016-06-05 09:35:16 +00:00
# ifndef WAVE_WRITE_TX
2016-04-25 18:20:54 +00:00
if ( slave - > wave_rec . fp )
wave_write ( & slave - > wave_rec , slave_samples , count ) ;
2016-06-05 09:35:16 +00:00
# endif
2016-04-25 18:20:54 +00:00
sender_receive ( slave , slave_samples , count ) ;
}
if ( slave - > loopback = = 3 )
jitter_save ( & slave - > audio , slave_samples , count ) ;
2016-03-01 17:40:38 +00:00
}
}
}