2016-02-16 17:56:55 +00:00
/* C-Netz audio processing
*
* ( 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-07-31 13:09:46 +00:00
# define CHAN cnetz->sender.kanal
2016-02-16 17:56:55 +00:00
# include <stdio.h>
# include <stdint.h>
# include <stdlib.h>
# include <string.h>
# include <math.h>
# include <errno.h>
2017-11-18 07:06:06 +00:00
# include "../libsample/sample.h"
2024-01-05 13:20:36 +00:00
# include "../liblogging/logging.h"
2017-11-18 07:33:07 +00:00
# include "../libmobile/call.h"
2024-01-05 13:20:36 +00:00
# include "../libmobile/get_time.h"
2016-02-16 17:56:55 +00:00
# include "cnetz.h"
# include "sysinfo.h"
# include "telegramm.h"
# include "dsp.h"
/* test function to mirror received audio from ratio back to radio */
2016-05-13 06:56:26 +00:00
//#define TEST_SCRAMBLE
/* test the audio quality after cascading two scramblers (TEST_SCRAMBLE must be defined) */
//#define TEST_UNSCRAMBLE
2016-02-16 17:56:55 +00:00
# define PI M_PI
2017-01-29 06:25:12 +00:00
# define MAX_DEVIATION 4000.0
2017-02-12 06:31:29 +00:00
# define MAX_MODULATION 3000.0
2019-12-05 07:33:08 +00:00
# define FSK_DEVIATION (2500.0 / speech_deviation) /* no emphasis */
# define MAX_DISPLAY 1.4 /* something above speech level, no emphasis */
2016-02-16 17:56:55 +00:00
# define BITRATE 5280.0 /* bits per second */
# define BLOCK_BITS 198 /* duration of one time slot including pause at beginning and end */
2016-05-13 06:56:26 +00:00
# ifdef TEST_SCRAMBLE
2024-03-10 12:45:08 +00:00
test_echo_t scrambler_test_echo = { } ;
2016-02-16 17:56:55 +00:00
scrambler_t scrambler_test_scrambler1 ;
scrambler_t scrambler_test_scrambler2 ;
# endif
2024-04-05 19:51:41 +00:00
static const char * cnetz_dsp_mode_name ( enum dsp_mode mode )
2020-06-01 19:07:49 +00:00
{
static char invalid [ 16 ] ;
switch ( mode ) {
case DSP_SCHED_NONE :
return " SCHED_NONE " ;
case DSP_MODE_OFF :
return " OFF " ;
case DSP_MODE_OGK :
return " OGK " ;
case DSP_MODE_SPK_K :
return " SPK_K " ;
case DSP_MODE_SPK_V :
return " SPK_V " ;
}
sprintf ( invalid , " invalid(%d) " , mode ) ;
return invalid ;
}
2016-02-16 17:56:55 +00:00
void dsp_init ( void )
{
2023-03-18 18:49:56 +00:00
compandor_init ( ) ;
2016-02-16 17:56:55 +00:00
}
static void dsp_init_ramp ( cnetz_t * cnetz )
{
double c ;
int i ;
2024-01-05 13:20:36 +00:00
LOGP ( DDSP , LOGL_DEBUG , " Generating smooth ramp table. \n " ) ;
2016-02-16 17:56:55 +00:00
for ( i = 0 ; i < 256 ; i + + ) {
2017-05-16 11:48:03 +00:00
/* use square-root of cosine ramp. tests showed that phones are more
2021-10-21 18:59:12 +00:00
* happy with that . ( This is not correct pulse shaping ! ) */
c = cos ( ( double ) i / 256.0 * PI ) ;
2016-02-16 17:56:55 +00:00
if ( c < 0 )
c = - sqrt ( - c ) ;
else
c = sqrt ( c ) ;
2021-10-21 18:59:12 +00:00
cnetz - > fsk_ramp_down [ i ] = c * ( double ) cnetz - > fsk_deviation ;
cnetz - > fsk_ramp_up [ i ] = - cnetz - > fsk_ramp_down [ i ] ;
2016-02-16 17:56:55 +00:00
}
}
/* Init transceiver instance. */
2019-12-05 07:33:08 +00:00
int dsp_init_sender ( cnetz_t * cnetz , int measure_speed , double clock_speed [ 2 ] , enum demod_type demod , double speech_deviation )
2016-02-16 17:56:55 +00:00
{
int rc = 0 ;
double size ;
2024-01-05 13:20:36 +00:00
LOGP_CHAN ( DDSP , LOGL_DEBUG , " Init FSK for 'Sender'. \n " ) ;
2016-02-16 17:56:55 +00:00
2017-01-29 06:25:12 +00:00
/* set modulation parameters */
2019-12-05 07:33:08 +00:00
sender_set_fm ( & cnetz - > sender , MAX_DEVIATION , MAX_MODULATION , speech_deviation , MAX_DISPLAY ) ;
2017-01-06 11:22:51 +00:00
2016-02-16 17:56:55 +00:00
if ( measure_speed ) {
cnetz - > measure_speed = measure_speed ;
cant_recover = 1 ;
}
if ( clock_speed [ 0 ] > 1000 | | clock_speed [ 0 ] < - 1000 | | clock_speed [ 1 ] > 1000 | | clock_speed [ 1 ] < - 1000 ) {
2024-01-05 13:20:36 +00:00
LOGP_CHAN ( DDSP , LOGL_ERROR , " Clock speed %.1f,%.1f ppm out of range! Please use range between +-1000 ppm! \n " , clock_speed [ 0 ] , clock_speed [ 1 ] ) ;
2016-02-16 17:56:55 +00:00
return - EINVAL ;
}
2024-01-05 13:20:36 +00:00
LOGP_CHAN ( DDSP , LOGL_INFO , " Using clock speed of %.1f ppm (RX) and %.1f ppm (TX) to correct sound card's clock. \n " , clock_speed [ 0 ] , clock_speed [ 1 ] ) ;
2016-02-16 17:56:55 +00:00
cnetz - > fsk_bitduration = ( double ) cnetz - > sender . samplerate / ( ( double ) BITRATE / ( 1.0 + clock_speed [ 1 ] / 1000000.0 ) ) ;
cnetz - > fsk_tx_bitstep = 1.0 / cnetz - > fsk_bitduration ;
2024-01-05 13:20:36 +00:00
LOGP_CHAN ( DDSP , LOGL_DEBUG , " Use %.4f samples for one bit duration @ %d. \n " , cnetz - > fsk_bitduration , cnetz - > sender . samplerate ) ;
2016-02-16 17:56:55 +00:00
size = cnetz - > fsk_bitduration * ( double ) BLOCK_BITS * 16.0 ; /* 16 blocks for distributed frames */
cnetz - > fsk_tx_buffer_size = size * 1.1 ; /* more to compensate clock speed */
2017-01-27 15:57:34 +00:00
cnetz - > fsk_tx_buffer = calloc ( sizeof ( sample_t ) , cnetz - > fsk_tx_buffer_size ) ;
2016-02-16 17:56:55 +00:00
if ( ! cnetz - > fsk_tx_buffer ) {
2024-01-05 13:20:36 +00:00
LOGP_CHAN ( DDSP , LOGL_ERROR , " No memory! \n " ) ;
2016-02-16 17:56:55 +00:00
rc = - ENOMEM ;
goto error ;
}
2021-01-01 21:11:48 +00:00
/* create deviation and ramp */
2017-01-29 06:25:12 +00:00
cnetz - > fsk_deviation = FSK_DEVIATION ;
2016-02-16 17:56:55 +00:00
dsp_init_ramp ( cnetz ) ;
2017-02-12 06:31:29 +00:00
/* init low pass filter for received signal */
2017-05-13 14:04:00 +00:00
iir_lowpass_init ( & cnetz - > lp , MAX_MODULATION , cnetz - > sender . samplerate , 2 ) ;
2017-02-12 06:31:29 +00:00
2016-02-16 17:56:55 +00:00
/* create speech buffer */
2017-05-16 11:48:03 +00:00
cnetz - > dsp_speech_buffer = calloc ( sizeof ( sample_t ) , ( int ) ( cnetz - > fsk_bitduration * 70.0 ) ) ; /* more to compensate clock speed. we just need it to fill 62 bits (60 bits, including pause bits). */
2016-02-16 17:56:55 +00:00
if ( ! cnetz - > dsp_speech_buffer ) {
2024-01-05 13:20:36 +00:00
LOGP_CHAN ( DDSP , LOGL_ERROR , " No memory! \n " ) ;
2016-02-16 17:56:55 +00:00
rc = - ENOMEM ;
goto error ;
}
/* reinit the sample rate to shrink/expand audio */
2022-07-17 12:58:14 +00:00
init_samplerate ( & cnetz - > sender . srstate , 8000.0 , ( double ) cnetz - > sender . samplerate / ( 1.1 / ( 1.0 + clock_speed [ 0 ] / 1000000.0 ) ) , 3300.0 ) ; /* 66 <-> 60 */
2016-02-16 17:56:55 +00:00
2017-05-19 17:11:59 +00:00
rc = fsk_fm_init ( & cnetz - > fsk_demod , cnetz , cnetz - > sender . samplerate , ( double ) BITRATE / ( 1.0 + clock_speed [ 0 ] / 1000000.0 ) , demod ) ;
2016-02-16 17:56:55 +00:00
if ( rc < 0 )
goto error ;
/* init scrambler for shrinked audio */
scrambler_setup ( & cnetz - > scrambler_tx , ( double ) cnetz - > sender . samplerate / 1.1 ) ;
scrambler_setup ( & cnetz - > scrambler_rx , ( double ) cnetz - > sender . samplerate / 1.1 ) ;
2016-06-20 17:37:56 +00:00
/* init compandor, according to C-Netz specs, attack and recovery time
2016-02-16 17:56:55 +00:00
* shall not exceed according to ITU G .162 */
2023-03-18 18:49:56 +00:00
setup_compandor ( & cnetz - > cstate , 8000 , 5.0 , 22.5 ) ;
2016-02-16 17:56:55 +00:00
2022-07-17 12:58:14 +00:00
/* use duration of one bit to ramp level of last frame to current frame */
cnetz - > offset_range = ceil ( cnetz - > fsk_bitduration ) ;
2016-05-13 06:56:26 +00:00
# ifdef TEST_SCRAMBLE
2024-03-10 12:45:08 +00:00
rc = test_echo_alloc ( & scrambler_test_echo , cnetz - > sender . samplerate / 20 ) ;
2016-02-16 17:56:55 +00:00
if ( rc < 0 ) {
2024-03-10 12:45:08 +00:00
LOGP_CHAN ( DDSP , LOGL_ERROR , " Failed to init echo buffer for scrambler test! \n " ) ;
2016-02-16 17:56:55 +00:00
exit ( 0 ) ;
}
scrambler_setup ( & scrambler_test_scrambler1 , cnetz - > sender . samplerate ) ;
scrambler_setup ( & scrambler_test_scrambler2 , cnetz - > sender . samplerate ) ;
# endif
2020-06-01 19:07:49 +00:00
cnetz - > sched_dsp_mode_ts = - 1 ;
2016-02-16 17:56:55 +00:00
return 0 ;
error :
dsp_cleanup_sender ( cnetz ) ;
return rc ;
}
void dsp_cleanup_sender ( cnetz_t * cnetz )
{
2024-01-05 13:20:36 +00:00
LOGP_CHAN ( DDSP , LOGL_DEBUG , " Cleanup FSK for 'Sender'. \n " ) ;
2016-02-16 17:56:55 +00:00
2017-01-06 11:18:24 +00:00
if ( cnetz - > fsk_tx_buffer ) {
2016-02-16 17:56:55 +00:00
free ( cnetz - > fsk_tx_buffer ) ;
2017-01-06 11:18:24 +00:00
cnetz - > fsk_tx_buffer = NULL ;
}
if ( cnetz - > dsp_speech_buffer ) {
2016-02-16 17:56:55 +00:00
free ( cnetz - > dsp_speech_buffer ) ;
2017-01-06 11:18:24 +00:00
cnetz - > dsp_speech_buffer = NULL ;
}
2017-01-06 13:13:14 +00:00
fsk_fm_exit ( & cnetz - > fsk_demod ) ;
2016-02-16 17:56:55 +00:00
}
/* receive sample time and calculate speed against system clock
* tx : indicates transmit stream
* result : if set the actual signal speed is used ( instead of sample rate ) */
2017-02-01 16:57:09 +00:00
void calc_clock_speed ( cnetz_t * cnetz , double samples , int tx , int result )
2016-02-16 17:56:55 +00:00
{
struct clock_speed * cs = & cnetz - > clock_speed ;
double ti ;
2017-02-01 16:57:09 +00:00
double speed_ppm_avg [ 4 ] ;
int index = ( result < < 1 ) | tx ;
2017-01-30 19:02:45 +00:00
int i ;
2016-02-16 17:56:55 +00:00
if ( ! cnetz - > measure_speed )
return ;
ti = get_time ( ) ;
2021-01-01 21:11:48 +00:00
/* skip some time to avoid false measurement due to filling of buffers */
2016-02-16 17:56:55 +00:00
if ( cs - > meas_ti = = 0.0 ) {
cs - > meas_ti = ti + 1.0 ;
return ;
}
if ( cs - > meas_ti > ti )
return ;
/* start sample counting */
2017-02-01 16:57:09 +00:00
if ( cs - > start_ti [ index ] = = 0.0 ) {
cs - > start_ti [ index ] = ti ;
cs - > spl_count [ index ] = 0.0 ;
2016-02-16 17:56:55 +00:00
return ;
}
/* add elapsed time */
2017-02-01 16:57:09 +00:00
cs - > last_ti [ index ] = ti ;
cs - > spl_count [ index ] + = samples ;
2016-02-16 17:56:55 +00:00
/* only calculate speed, if one second has elapsed */
2017-02-01 16:57:09 +00:00
if ( ti - cs - > meas_ti < = 2.0 )
2016-02-16 17:56:55 +00:00
return ;
2017-02-01 16:57:09 +00:00
cs - > meas_ti + = 2.0 ;
2016-02-16 17:56:55 +00:00
2017-02-01 16:57:09 +00:00
/* add to ring buffer */
if ( ! cs - > spl_count [ 0 ] | | ! cs - > spl_count [ 1 ] | | ! cs - > spl_count [ 2 ] | | ! cs - > spl_count [ 3 ] )
2016-02-16 17:56:55 +00:00
return ;
2017-02-01 16:57:09 +00:00
for ( index = 0 ; index < 4 ; index + + ) {
cs - > speed_ppm [ index ] [ cs - > idx [ index ] & 0xff ] = ( cs - > spl_count [ index ] / ( double ) cnetz - > sender . samplerate ) / ( cs - > last_ti [ index ] - cs - > start_ti [ index ] ) * 1000000.0 - 1000000.0 ;
cs - > idx [ index ] + + ;
if ( cs - > num [ index ] + + > 30 )
cs - > num [ index ] = 30 ;
speed_ppm_avg [ index ] = 0.0 ;
for ( i = 0 ; i < cs - > num [ index ] ; i + + )
speed_ppm_avg [ index ] + = cs - > speed_ppm [ index ] [ ( cs - > idx [ index ] - i - 1 ) & 0xff ] ;
speed_ppm_avg [ index ] / = ( double ) cs - > num [ index ] ;
2017-01-30 19:02:45 +00:00
}
2024-01-05 13:20:36 +00:00
LOGP_CHAN ( DDSP , LOGL_NOTICE , " Clock: RX=%.3f TX=%.3f; Signal: RX=%.3f TX=%.3f ppm \n " , speed_ppm_avg [ 0 ] , speed_ppm_avg [ 1 ] , speed_ppm_avg [ 2 ] , speed_ppm_avg [ 3 ] ) ;
2016-02-16 17:56:55 +00:00
}
static int fsk_nothing_encode ( cnetz_t * cnetz )
{
2017-01-27 15:57:34 +00:00
sample_t * spl ;
2017-01-29 09:30:06 +00:00
double phase , bitstep ;
2016-02-16 17:56:55 +00:00
int i , count ;
spl = cnetz - > fsk_tx_buffer ;
phase = cnetz - > fsk_tx_phase ;
bitstep = cnetz - > fsk_tx_bitstep * 256.0 ;
2017-08-19 10:27:05 +00:00
/* add 198 bits of no power (silence) */
2017-01-29 09:30:06 +00:00
for ( i = 0 ; i < 198 ; i + + ) {
do {
2017-08-19 10:27:05 +00:00
* spl + + = - 10.0 ; /* marker for power off */
2017-01-29 09:30:06 +00:00
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
2016-02-16 17:56:55 +00:00
}
/* depending on the number of samples, return the number */
count = ( ( uintptr_t ) spl - ( uintptr_t ) cnetz - > fsk_tx_buffer ) / sizeof ( * spl ) ;
cnetz - > fsk_tx_phase = phase ;
cnetz - > fsk_tx_buffer_length = count ;
return count ;
}
/* encode one data block into samples
* input : 184 data bits ( including barker code )
* output : samples
* return number of samples */
2017-08-19 10:27:05 +00:00
static int fsk_block_encode ( cnetz_t * cnetz , const char * bits , int ogk )
2016-02-16 17:56:55 +00:00
{
/* alloc samples, add 1 in case there is a rest */
2017-01-27 15:57:34 +00:00
sample_t * spl ;
2016-02-16 17:56:55 +00:00
double phase , bitstep , deviation ;
int i , count ;
char last ;
deviation = cnetz - > fsk_deviation ;
spl = cnetz - > fsk_tx_buffer ;
phase = cnetz - > fsk_tx_phase ;
bitstep = cnetz - > fsk_tx_bitstep * 256.0 ;
/* add 7 bits of pause */
for ( i = 0 ; i < 7 ; i + + ) {
do {
2017-08-19 10:27:05 +00:00
* spl + + = 0.0 ;
2016-02-16 17:56:55 +00:00
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
}
/* add 184 bits */
last = ' ' ;
for ( i = 0 ; i < 184 ; i + + ) {
switch ( last ) {
case ' ' :
if ( bits [ i ] = = ' 1 ' ) {
/* ramp up from 0 */
do {
2021-10-21 18:59:12 +00:00
* spl + + = cnetz - > fsk_ramp_up [ ( uint8_t ) phase ] / 2 + deviation / 2 ;
2016-02-16 17:56:55 +00:00
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
} else {
/* ramp down from 0 */
do {
2021-10-21 18:59:12 +00:00
* spl + + = cnetz - > fsk_ramp_down [ ( uint8_t ) phase ] / 2 - deviation / 2 ;
2016-02-16 17:56:55 +00:00
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
}
break ;
case ' 1 ' :
if ( bits [ i ] = = ' 1 ' ) {
/* stay up */
do {
* spl + + = deviation ;
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
} else {
/* ramp down */
do {
2021-10-21 18:59:12 +00:00
* spl + + = cnetz - > fsk_ramp_down [ ( uint8_t ) phase ] ;
2016-02-16 17:56:55 +00:00
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
}
break ;
case ' 0 ' :
if ( bits [ i ] = = ' 1 ' ) {
/* ramp up */
do {
2021-10-21 18:59:12 +00:00
* spl + + = cnetz - > fsk_ramp_up [ ( uint8_t ) phase ] ;
2016-02-16 17:56:55 +00:00
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
} else {
/* stay down */
do {
* spl + + = - deviation ;
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
}
break ;
}
last = bits [ i ] ;
}
/* add 7 bits of pause */
if ( last = = ' 0 ' ) {
/* ramp up to 0 */
do {
2021-10-21 18:59:12 +00:00
* spl + + = cnetz - > fsk_ramp_up [ ( uint8_t ) phase ] / 2 - deviation / 2 ;
2016-02-16 17:56:55 +00:00
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
} else {
/* ramp down to 0 */
do {
2021-10-21 18:59:12 +00:00
* spl + + = cnetz - > fsk_ramp_down [ ( uint8_t ) phase ] / 2 + deviation / 2 ;
2016-02-16 17:56:55 +00:00
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
}
for ( i = 1 ; i < 7 ; i + + ) {
2017-08-19 10:27:05 +00:00
/* turn off power for OgK */
if ( ogk ) {
do {
* spl + + = - 10.0 ; /* marker for power off */
phase + = bitstep ;
} while ( phase < 256.0 ) ;
} else {
do {
* spl + + = 0.0 ;
phase + = bitstep ;
} while ( phase < 256.0 ) ;
}
2016-02-16 17:56:55 +00:00
phase - = 256.0 ;
}
/* depending on the number of samples, return the number */
count = ( ( uintptr_t ) spl - ( uintptr_t ) cnetz - > fsk_tx_buffer ) / sizeof ( * spl ) ;
cnetz - > fsk_tx_phase = phase ;
cnetz - > fsk_tx_buffer_length = count ;
return count ;
}
/* encode one distributed data block into samples
* input : 184 data bits ( including barker code )
* output : samples
2017-05-16 11:48:03 +00:00
* if a sample contains a marker , it indicates where to insert speech block
* return number of samples
*
* the marker is placed in the middle of the 6 th bit .
* because we have a transition ( ramp ) in the middle of each bit .
* the phone will see the position of the marker as start of the 6 th bit .
2021-01-01 21:11:48 +00:00
* the marker marks the point where the speech is ramped up , so the phone
2017-05-16 11:48:03 +00:00
* will see the speech completely ramped up after the 6 th bit
*/
2016-02-16 17:56:55 +00:00
static int fsk_distributed_encode ( cnetz_t * cnetz , const char * bits )
{
/* alloc samples, add 1 in case there is a rest */
2017-01-27 15:57:34 +00:00
sample_t * spl , * marker ;
2016-02-16 17:56:55 +00:00
double phase , bitstep , deviation ;
int i , j , count ;
char last ;
deviation = cnetz - > fsk_deviation ;
spl = cnetz - > fsk_tx_buffer ;
phase = cnetz - > fsk_tx_phase ;
bitstep = cnetz - > fsk_tx_bitstep * 256.0 ;
/* add 2 * (1+4+1 + 60) bits of pause / for speech */
for ( i = 0 ; i < 2 ; i + + ) {
for ( j = 0 ; j < 6 ; j + + ) {
do {
* spl + + = 0 ;
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
}
2017-05-16 11:48:03 +00:00
marker = spl - ( int ) ( cnetz - > fsk_bitduration / 2.0 ) ; /* in the middle of the 6th bit */
2016-02-16 17:56:55 +00:00
for ( j = 0 ; j < 60 ; j + + ) {
do {
* spl + + = 0 ;
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
}
2017-05-16 11:48:03 +00:00
* marker + = 10.0 ; /* marker for inserting speech */
2016-02-16 17:56:55 +00:00
}
/* add 46 * (1+4+1 + 60) bits */
for ( i = 0 ; i < 46 ; i + + ) {
/* unmodulated bit */
do {
* spl + + = 0 ;
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
last = ' ' ;
for ( j = 0 ; j < 4 ; j + + ) {
switch ( last ) {
case ' ' :
if ( bits [ i * 4 + j ] = = ' 1 ' ) {
/* ramp up from 0 */
do {
2021-10-21 18:59:12 +00:00
* spl + + = cnetz - > fsk_ramp_up [ ( uint8_t ) phase ] / 2 + deviation / 2 ;
2016-02-16 17:56:55 +00:00
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
} else {
/* ramp down from 0 */
do {
2021-10-21 18:59:12 +00:00
* spl + + = cnetz - > fsk_ramp_down [ ( uint8_t ) phase ] / 2 - deviation / 2 ;
2016-02-16 17:56:55 +00:00
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
}
break ;
case ' 1 ' :
if ( bits [ i * 4 + j ] = = ' 1 ' ) {
/* stay up */
do {
* spl + + = deviation ;
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
} else {
/* ramp down */
do {
2021-10-21 18:59:12 +00:00
* spl + + = cnetz - > fsk_ramp_down [ ( uint8_t ) phase ] ;
2016-02-16 17:56:55 +00:00
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
}
break ;
case ' 0 ' :
if ( bits [ i * 4 + j ] = = ' 1 ' ) {
/* ramp up */
do {
2021-10-21 18:59:12 +00:00
* spl + + = cnetz - > fsk_ramp_up [ ( uint8_t ) phase ] ;
2016-02-16 17:56:55 +00:00
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
} else {
/* stay down */
do {
* spl + + = - deviation ;
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
}
break ;
}
last = bits [ i * 4 + j ] ;
}
2017-05-16 11:48:03 +00:00
/* ramp down */
2016-02-16 17:56:55 +00:00
if ( last = = ' 0 ' ) {
/* ramp up to 0 */
do {
2021-10-21 18:59:12 +00:00
* spl + + = cnetz - > fsk_ramp_up [ ( uint8_t ) phase ] / 2 - deviation / 2 ;
2016-02-16 17:56:55 +00:00
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
} else {
/* ramp down to 0 */
do {
2021-10-21 18:59:12 +00:00
* spl + + = cnetz - > fsk_ramp_down [ ( uint8_t ) phase ] / 2 + deviation / 2 ;
2016-02-16 17:56:55 +00:00
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
}
2017-05-16 11:48:03 +00:00
marker = spl - ( int ) ( cnetz - > fsk_bitduration / 2.0 ) ; /* in the middle of the 6th bit */
2016-02-16 17:56:55 +00:00
for ( j = 0 ; j < 60 ; j + + ) {
do {
* spl + + = 0 ;
phase + = bitstep ;
} while ( phase < 256.0 ) ;
phase - = 256.0 ;
}
2017-05-16 11:48:03 +00:00
* marker + = 10.0 ; /* marker for inserting speech */
2016-02-16 17:56:55 +00:00
}
/* depending on the number of samples, return the number */
count = ( ( uintptr_t ) spl - ( uintptr_t ) cnetz - > fsk_tx_buffer ) / sizeof ( * spl ) ;
cnetz - > fsk_tx_phase = phase ;
cnetz - > fsk_tx_buffer_length = count ;
return count ;
}
/* decode samples and hut for bit changes
* use deviation to find greatest slope of the signal ( bit change )
*/
2022-06-09 17:27:22 +00:00
void sender_receive ( sender_t * sender , sample_t * samples , int length , double rf_level_db )
2016-02-16 17:56:55 +00:00
{
cnetz_t * cnetz = ( cnetz_t * ) sender ;
2022-06-09 17:27:22 +00:00
cnetz - > rf_level_db = rf_level_db ;
2016-02-16 17:56:55 +00:00
/* measure rx sample speed */
calc_clock_speed ( cnetz , length , 0 , 0 ) ;
2016-05-13 06:56:26 +00:00
# ifdef TEST_SCRAMBLE
# ifdef TEST_UNSCRAMBLE
2016-02-16 17:56:55 +00:00
scrambler ( & scrambler_test_scrambler1 , samples , length ) ;
# endif
2024-03-10 12:45:08 +00:00
test_echo_store ( & scrambler_test_echo , samples , length ) ;
2016-02-16 17:56:55 +00:00
return ;
# endif
2017-02-12 06:31:29 +00:00
if ( cnetz - > dsp_mode ! = DSP_MODE_OFF ) {
2017-05-13 14:04:00 +00:00
iir_process ( & cnetz - > lp , samples , length ) ;
2019-10-26 09:40:48 +00:00
fsk_fm_demod ( & cnetz - > fsk_demod , samples , length ) ; /* process */
} else
fsk_fm_demod ( & cnetz - > fsk_demod , NULL , length ) ; /* just count bit time */
2016-02-16 17:56:55 +00:00
return ;
}
2017-05-17 18:14:37 +00:00
/* shrink audio segment from 12.5 ms to the duration of 60 bits */
static int shrink_speech ( cnetz_t * cnetz , sample_t * speech_buffer )
{
int speech_length ;
2024-03-10 12:45:08 +00:00
int16_t spl [ 100 ] ;
2017-05-17 18:14:37 +00:00
2024-03-10 12:45:08 +00:00
jitter_load_samples ( & cnetz - > sender . dejitter , ( uint8_t * ) spl , 100 , sizeof ( * spl ) , jitter_conceal_s16 , NULL ) ;
int16_to_samples_speech ( speech_buffer , spl , 100 ) ;
2017-05-17 18:14:37 +00:00
/* 1. compress dynamics */
compress_audio ( & cnetz - > cstate , speech_buffer , 100 ) ;
/* 2. upsample */
2022-07-31 05:55:14 +00:00
speech_length = samplerate_upsample_output_num ( & cnetz - > sender . srstate , 100 ) ;
samplerate_upsample ( & cnetz - > sender . srstate , speech_buffer , 100 , speech_buffer , speech_length ) ;
2017-05-17 18:14:37 +00:00
/* 3. scramble */
if ( cnetz - > scrambler )
scrambler ( & cnetz - > scrambler_tx , speech_buffer , speech_length ) ;
/* 4. pre-emphasis is done by cnetz code, not by common code */
/* pre-emphasis is only used when scrambler is off, see FTZ 171 TR 60 Clause 4 */
if ( cnetz - > pre_emphasis & & ! cnetz - > scrambler )
pre_emphasis ( & cnetz - > estate , speech_buffer , speech_length ) ;
return speech_length ;
}
2017-08-19 10:27:05 +00:00
static int fsk_telegramm ( cnetz_t * cnetz , sample_t * samples , uint8_t * power , int length )
2016-02-16 17:56:55 +00:00
{
int count = 0 , pos , copy , i , speech_length , speech_pos ;
2017-01-27 15:57:34 +00:00
sample_t * spl , * speech_buffer ;
2016-02-16 17:56:55 +00:00
const char * bits ;
speech_buffer = cnetz - > dsp_speech_buffer ;
speech_length = cnetz - > dsp_speech_length ;
speech_pos = cnetz - > dsp_speech_pos ;
again :
/* there must be length, otherwise we would skip blocks */
2016-04-25 18:20:54 +00:00
if ( count = = length )
2016-02-16 17:56:55 +00:00
return count ;
pos = cnetz - > fsk_tx_buffer_pos ;
spl = cnetz - > fsk_tx_buffer + pos ;
/* start new telegramm, so we generate one */
if ( pos = = 0 ) {
2019-10-26 09:40:48 +00:00
/* a new super frame starts */
2016-04-25 18:20:54 +00:00
if ( cnetz - > sched_ts = = 0 & & cnetz - > sched_r_m = = 0 ) {
2016-11-30 17:09:38 +00:00
/* measure actual signal speed */
2017-02-01 16:57:09 +00:00
calc_clock_speed ( cnetz , ( double ) cnetz - > sender . samplerate * 2.4 , 1 , 1 ) ;
2016-11-30 17:09:38 +00:00
/* sync TX (might not be required, if there is no error in math calculation) */
2017-01-03 11:31:59 +00:00
if ( ! cnetz - > sender . master ) { /* if no link to a master, we are master */
2016-04-25 18:20:54 +00:00
/* we are master, so we store sample count and phase */
2016-11-30 17:09:38 +00:00
cnetz - > frame_last_scount = cnetz - > fsk_tx_scount ;
2016-04-25 18:20:54 +00:00
cnetz - > frame_last_phase = cnetz - > fsk_tx_phase ;
2017-01-03 11:31:59 +00:00
} else {
2016-11-30 17:09:38 +00:00
/* we are slave, so we sync to phase */
2016-04-25 18:20:54 +00:00
cnetz_t * master = ( cnetz_t * ) cnetz - > sender . master ;
2016-11-30 17:09:38 +00:00
/* it may happen that the sample count does not match with the master,
* because one has a phase wrap before and the other after a sample .
2019-10-26 09:40:48 +00:00
* then we do it next super frame cycle */
2016-11-30 17:09:38 +00:00
if ( master - > frame_last_scount = = cnetz - > fsk_tx_scount ) {
2024-01-05 13:20:36 +00:00
LOGP ( DDSP , LOGL_DEBUG , " Sync phase of slave to master: master=%.15f, slave=%.15f, diff=%.15f \n " , master - > frame_last_phase , cnetz - > fsk_tx_phase , master - > frame_last_phase - cnetz - > fsk_tx_phase ) ;
2016-11-30 17:09:38 +00:00
cnetz - > fsk_tx_phase = master - > frame_last_phase ;
} else {
2024-01-05 13:20:36 +00:00
LOGP ( DDSP , LOGL_DEBUG , " Not sync phase of slave to master: Sample counts during frame change are different, ignoring this time! \n " ) ;
2016-04-25 18:20:54 +00:00
}
}
}
2016-02-16 17:56:55 +00:00
/* switch to speech channel */
2020-06-01 19:07:49 +00:00
if ( cnetz - > sched_dsp_mode_ts > = 0 & & cnetz - > sched_r_m = = 0 ) {
if ( cnetz - > sched_dsp_mode_ts = = cnetz - > sched_ts ) {
2016-02-16 17:56:55 +00:00
/* OgK / SpK(K) / SpK(V) */
2024-01-05 13:20:36 +00:00
LOGP_CHAN ( DDSP , LOGL_INFO , " Now switching channel mode to %s at timeslot %d \n " , cnetz_dsp_mode_name ( cnetz - > sched_dsp_mode ) , cnetz - > sched_dsp_mode_ts ) ;
2020-06-01 19:07:49 +00:00
cnetz - > sched_dsp_mode_ts = - 1 ;
2016-06-04 13:14:20 +00:00
cnetz_set_dsp_mode ( cnetz , cnetz - > sched_dsp_mode ) ;
2016-02-16 17:56:55 +00:00
}
}
switch ( cnetz - > dsp_mode ) {
case DSP_MODE_OGK :
2022-06-11 12:57:28 +00:00
if ( ( ( si . timeslots > > cnetz - > sched_ts ) & 1 ) ) {
2016-02-16 17:56:55 +00:00
if ( cnetz - > sched_r_m = = 0 ) {
2022-06-11 12:57:28 +00:00
/* if automatic polarity selection is used, toggle between two polarities (every transmitted slot) until a response is received then continue to use the time slots of that polarity */
if ( cnetz - > auto_polarity )
cnetz - > negative_polarity = ( cnetz - > sched_ts & 7 ) > > 2 ;
2019-11-24 17:26:38 +00:00
/* set last time slot, so we know to which time slot the message from mobile station belongs to */
cnetz - > sched_last_ts = cnetz - > sched_ts ;
2016-02-16 17:56:55 +00:00
bits = cnetz_encode_telegramm ( cnetz ) ;
2020-12-20 18:21:52 +00:00
if ( bits ) {
2024-01-05 13:20:36 +00:00
LOGP_CHAN ( DDSP , LOGL_DEBUG , " Transmitting 'Rufblock' at timeslot %d \n " , cnetz - > sched_ts ) ;
2020-12-20 18:21:52 +00:00
fsk_block_encode ( cnetz , bits , 1 ) ;
} else
fsk_nothing_encode ( cnetz ) ;
2016-02-16 17:56:55 +00:00
} else {
bits = cnetz_encode_telegramm ( cnetz ) ;
2020-12-20 18:21:52 +00:00
if ( bits ) {
2024-01-05 13:20:36 +00:00
LOGP_CHAN ( DDSP , LOGL_DEBUG , " Transmitting 'Meldeblock' at timeslot %d \n " , cnetz - > sched_ts ) ;
2020-12-20 18:21:52 +00:00
fsk_block_encode ( cnetz , bits , 1 ) ;
} else
fsk_nothing_encode ( cnetz ) ;
2016-02-16 17:56:55 +00:00
}
} else {
fsk_nothing_encode ( cnetz ) ;
}
break ;
case DSP_MODE_SPK_K :
bits = cnetz_encode_telegramm ( cnetz ) ;
2020-12-20 18:21:52 +00:00
if ( bits ) {
2024-01-05 13:20:36 +00:00
LOGP_CHAN ( DDSP , LOGL_DEBUG , " Transmitting 'Konzentrierte Signalisierung' at timeslot %d.%d \n " , cnetz - > sched_ts , cnetz - > sched_r_m * 5 ) ;
2020-12-20 18:21:52 +00:00
fsk_block_encode ( cnetz , bits , 0 ) ;
} else
fsk_nothing_encode ( cnetz ) ;
2016-02-16 17:56:55 +00:00
break ;
case DSP_MODE_SPK_V :
bits = cnetz_encode_telegramm ( cnetz ) ;
2020-12-20 18:21:52 +00:00
if ( bits ) {
2024-01-05 13:20:36 +00:00
LOGP_CHAN ( DDSP , LOGL_DEBUG , " Transmitting 'Verteilte Signalisierung' starting at timeslot %d \n " , cnetz - > sched_ts ) ;
2020-12-20 18:21:52 +00:00
fsk_distributed_encode ( cnetz , bits ) ;
} else
fsk_nothing_encode ( cnetz ) ;
2016-02-16 17:56:55 +00:00
break ;
2016-04-25 18:20:54 +00:00
case DSP_MODE_OFF :
2016-02-16 17:56:55 +00:00
default :
2017-08-19 10:27:05 +00:00
fsk_nothing_encode ( cnetz ) ;
2016-02-16 17:56:55 +00:00
}
if ( cnetz - > dsp_mode = = DSP_MODE_SPK_V ) {
/* count sub frame */
cnetz - > sched_ts + = 8 ;
} else {
/* count slot */
if ( cnetz - > sched_r_m = = 0 )
cnetz - > sched_r_m = 1 ;
else {
cnetz - > sched_r_m = 0 ;
cnetz - > sched_ts + + ;
}
}
if ( cnetz - > sched_ts = = 32 )
cnetz - > sched_ts = 0 ;
}
copy = cnetz - > fsk_tx_buffer_length - pos ;
2016-04-25 18:20:54 +00:00
if ( length - count < copy )
copy = length - count ;
2016-02-16 17:56:55 +00:00
for ( i = 0 ; i < copy ; i + + ) {
2017-08-19 10:27:05 +00:00
if ( * spl > 5.0 ) { /* speech marker found */
2017-05-16 11:48:03 +00:00
int begin , end , j ;
/* correct marker (not the best way) */
* spl - = 10.0 ;
begin = ( int ) cnetz - > fsk_bitduration ;
end = ( int ) ( cnetz - > fsk_bitduration * 61.0 ) ;
2017-05-17 18:14:37 +00:00
/* get audio */
speech_length = shrink_speech ( cnetz , speech_buffer + begin ) ;
/* ramp before speech */
2017-05-16 11:48:03 +00:00
for ( j = 0 ; j < begin ; j + + ) {
/* ramp up from 0 to speech level */
2021-10-21 18:59:12 +00:00
speech_buffer [ j ] = speech_buffer [ begin ] * ( cnetz - > fsk_ramp_up [ j * 256 / begin ] / cnetz - > fsk_deviation / 2.0 + 0.5 ) ;
2017-05-16 11:48:03 +00:00
}
speech_length + = begin ; /* add one bit duration before speech*/
2017-05-17 18:14:37 +00:00
/* ramp after speech */
2017-05-16 11:48:03 +00:00
while ( speech_length < end ) {
speech_buffer [ speech_length ] = speech_buffer [ speech_length - 1 ] ;
speech_length + + ;
}
speech_length = end ; /* shorten 'speech_length', if greater than 'end' */
for ( j = 0 ; j < begin ; j + + ) {
/* ramp down from speech level to 0 */
2021-10-21 18:59:12 +00:00
speech_buffer [ end + j ] = speech_buffer [ end - 1 ] * ( cnetz - > fsk_ramp_down [ j * 256 / begin ] / cnetz - > fsk_deviation / 2.0 + 0.5 ) ;
2017-05-16 11:48:03 +00:00
}
speech_length + = begin ; /* add one bit duration after speech */
2016-02-16 17:56:55 +00:00
speech_pos = 0 ;
}
2017-08-19 10:27:05 +00:00
if ( * spl < - 5.0 ) { /* power off marker found */
/* correct marker (not the best way) */
* spl + = 10.0 ;
* power = 0 ;
} else
* power = 1 ;
2017-05-16 11:48:03 +00:00
/* add speech as long as we have something left in buffer */
2016-02-16 17:56:55 +00:00
if ( speech_pos < speech_length )
2017-05-16 11:48:03 +00:00
* samples + + = * spl + speech_buffer [ speech_pos + + ] ;
2016-02-16 17:56:55 +00:00
else
* samples + + = * spl ;
spl + + ;
2017-08-19 10:27:05 +00:00
power + + ;
2016-02-16 17:56:55 +00:00
}
cnetz - > dsp_speech_length = speech_length ;
cnetz - > dsp_speech_pos = speech_pos ;
2016-11-30 17:09:38 +00:00
cnetz - > fsk_tx_scount + = copy ;
2016-02-16 17:56:55 +00:00
pos + = copy ;
count + = copy ;
if ( pos = = cnetz - > fsk_tx_buffer_length ) {
cnetz - > fsk_tx_buffer_pos = 0 ;
goto again ;
}
cnetz - > fsk_tx_buffer_pos = pos ;
return count ;
}
/* Provide stream of audio toward radio unit */
2017-08-19 10:27:05 +00:00
void sender_send ( sender_t * sender , sample_t * samples , uint8_t * power , int length )
2016-02-16 17:56:55 +00:00
{
cnetz_t * cnetz = ( cnetz_t * ) sender ;
int count ;
/* measure tx sample speed */
calc_clock_speed ( cnetz , length , 1 , 0 ) ;
2016-05-13 06:56:26 +00:00
# ifdef TEST_SCRAMBLE
2024-03-10 12:45:08 +00:00
test_echo_load ( & scrambler_test_echo , samples , length ) ;
2016-02-16 17:56:55 +00:00
scrambler ( & scrambler_test_scrambler2 , samples , length ) ;
return ;
# endif
2017-08-19 10:27:05 +00:00
count = fsk_telegramm ( cnetz , samples , power , length ) ;
2016-02-16 17:56:55 +00:00
if ( count < length ) {
printf ( " length=%d < count=%d \n " , length , count ) ;
printf ( " this shall not happen, so please fix! \n " ) ;
exit ( 0 ) ;
}
2016-04-25 18:20:54 +00:00
2016-02-16 17:56:55 +00:00
}
2016-05-13 06:56:26 +00:00
/* unshrink audio segment from the duration of 60 bits to 12.5 ms */
2017-01-27 15:57:34 +00:00
void unshrink_speech ( cnetz_t * cnetz , sample_t * speech_buffer , int count )
2016-05-13 06:56:26 +00:00
{
2017-01-27 15:57:34 +00:00
sample_t * spl ;
2016-05-13 06:56:26 +00:00
int pos , i ;
2022-07-17 12:58:14 +00:00
int range ;
double offset ;
2016-05-13 06:56:26 +00:00
2016-10-07 06:00:10 +00:00
/* check if we still have a transaction
* this might not be true , if we just released transaction , but still
* get a complete frame before we already switched back to OgK .
*/
if ( ! cnetz - > trans_list )
return ;
2022-07-17 12:58:14 +00:00
/* ramp from level of last frame to level of current frame */
range = cnetz - > offset_range ;
offset = speech_buffer [ 0 ] - cnetz - > offset_last ;
for ( i = 0 ; i < range ; i + + ) {
speech_buffer [ i ] - = offset * ( 1.0 - ( double ) i / ( double ) range ) ;
2016-05-13 06:56:26 +00:00
}
2022-07-17 12:58:14 +00:00
cnetz - > offset_last = speech_buffer [ count - 1 ] ;
2016-05-13 06:56:26 +00:00
/* 4. de-emphasis is done by cnetz code, not by common code */
/* de-emphasis is only used when scrambler is off, see FTZ 171 TR 60 Clause 4 */
2017-01-28 17:18:44 +00:00
if ( cnetz - > de_emphasis )
dc_filter ( & cnetz - > estate , speech_buffer , count ) ;
2016-05-13 06:56:26 +00:00
if ( cnetz - > de_emphasis & & ! cnetz - > scrambler )
de_emphasis ( & cnetz - > estate , speech_buffer , count ) ;
/* 3. descramble */
if ( cnetz - > scrambler )
scrambler ( & cnetz - > scrambler_rx , speech_buffer , count ) ;
/* 2. decompress time */
2017-01-27 15:57:34 +00:00
count = samplerate_downsample ( & cnetz - > sender . srstate , speech_buffer , count ) ;
2016-05-13 06:56:26 +00:00
/* 1. expand dynamics */
expand_audio ( & cnetz - > cstate , speech_buffer , count ) ;
/* to call control */
spl = cnetz - > sender . rxbuf ;
pos = cnetz - > sender . rxbuf_pos ;
for ( i = 0 ; i < count ; i + + ) {
spl [ pos + + ] = speech_buffer [ i ] ;
if ( pos = = 160 ) {
2017-10-28 05:11:40 +00:00
call_up_audio ( cnetz - > trans_list - > callref , spl , 160 ) ;
2016-05-13 06:56:26 +00:00
pos = 0 ;
}
}
cnetz - > sender . rxbuf_pos = pos ;
}
2016-06-04 13:14:20 +00:00
void cnetz_set_dsp_mode ( cnetz_t * cnetz , enum dsp_mode mode )
{
2020-06-01 19:07:49 +00:00
if ( mode ! = cnetz - > dsp_mode ) {
2024-01-05 13:20:36 +00:00
LOGP_CHAN ( DDSP , LOGL_INFO , " DSP mode %s -> %s \n " , cnetz_dsp_mode_name ( cnetz - > dsp_mode ) , cnetz_dsp_mode_name ( mode ) ) ;
2020-06-01 19:07:49 +00:00
cnetz - > dsp_mode = mode ;
}
2024-03-10 12:45:08 +00:00
if ( mode = = DSP_MODE_SPK_V & & cnetz - > dsp_mode ! = mode )
jitter_reset ( & cnetz - > sender . dejitter ) ;
2016-10-07 06:00:34 +00:00
/* we must get rid of partly received frame */
fsk_demod_reset ( & cnetz - > fsk_demod ) ;
2016-06-04 13:14:20 +00:00
}
2020-06-01 19:07:49 +00:00
void cnetz_set_sched_dsp_mode ( cnetz_t * cnetz , enum dsp_mode mode , int timeslot )
2016-06-04 13:14:20 +00:00
{
2020-12-20 18:21:52 +00:00
if ( cnetz - > sched_dsp_mode_ts < 0 & & mode = = cnetz - > dsp_mode ) {
2024-01-05 13:20:36 +00:00
LOGP_CHAN ( DDSP , LOGL_INFO , " Schedule DSP mode %s not required, we are already in that mode \n " , cnetz_dsp_mode_name ( mode ) ) ;
2020-12-20 18:21:52 +00:00
return ;
2020-06-01 19:07:49 +00:00
}
2024-01-05 13:20:36 +00:00
LOGP_CHAN ( DDSP , LOGL_INFO , " Schedule DSP mode %s -> %s at timeslot %d \n " , cnetz_dsp_mode_name ( cnetz - > dsp_mode ) , cnetz_dsp_mode_name ( mode ) , timeslot ) ;
2020-12-20 18:21:52 +00:00
cnetz - > sched_dsp_mode = mode ;
cnetz - > sched_dsp_mode_ts = timeslot ;
2016-06-04 13:14:20 +00:00
}
2024-03-10 12:45:08 +00:00
/* 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 ;
cnetz_t * cnetz ;
for ( sender = sender_head ; sender ; sender = sender - > next ) {
cnetz = ( cnetz_t * ) sender ;
if ( cnetz - > trans_list & & cnetz - > trans_list - > callref = = callref )
break ;
}
if ( ! sender )
return ;
if ( cnetz - > dsp_mode = = DSP_MODE_SPK_V ) {
jitter_frame_t * jf ;
jf = jitter_frame_alloc ( decoder , decoder_priv , payload , payload_len , marker , sequence , timestamp , ssrc ) ;
if ( jf )
jitter_save ( & cnetz - > sender . dejitter , jf ) ;
}
}
void call_down_clock ( void ) { }