From bb64c6b3ba80f8ef844bae59e270ca9e3b43d1fd Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Thu, 25 May 2017 09:57:22 +0200 Subject: AMPS: Add DTX support When DTX is enabled (-S dtx=2 or 3), a missing SAT tone causes the receiver to mute audio and insert a low level of comfort noise. Also the missing SAT tone will not cause the connection to be terminated. --- src/amps/amps.c | 13 ++++++++++++- src/amps/amps.h | 5 +++-- src/amps/dsp.c | 47 ++++++++++++++++++++++++++++++----------------- src/amps/main.c | 19 ++++++++++++++++--- src/amps/sysinfo.c | 4 ++-- src/amps/sysinfo.h | 2 +- src/amps/transaction.h | 1 + 7 files changed, 65 insertions(+), 26 deletions(-) (limited to 'src/amps') diff --git a/src/amps/amps.c b/src/amps/amps.c index a7a04d9..d180a4f 100644 --- a/src/amps/amps.c +++ b/src/amps/amps.c @@ -680,7 +680,10 @@ void amps_rx_sat(amps_t *amps, int tone, double quality) if (tone) { timer_stop(&trans->timer); } else { - timer_start(&trans->timer, SAT_TO2); + if (!trans->dtx) + timer_start(&trans->timer, SAT_TO2); + else + timer_stop(&trans->timer); } } @@ -769,6 +772,14 @@ reject: trans_new_state(trans, TRANS_CALL_MT_ASSIGN); trans->chan = vc->sender.kanal; } + /* if we support DTX and also the phone does, we set DTX state of transaction */ + if (amps->si.word2.dtx) { + if ((scm & 4)) { + PDEBUG(DAMPS, DEBUG_INFO, " -> Use DTX for this call\n"); + trans->dtx = 1; + } else + PDEBUG(DAMPS, DEBUG_INFO, " -> Requested DTX, but not supported by phone\n"); + } } else PDEBUG_CHAN(DAMPS, DEBUG_NOTICE, "Unsupported RECC messages: ORDER: %d ORDQ: %d MSG TYPE: %d (See Table 4 of specs.)\n", order, ordq, msg_type); } diff --git a/src/amps/amps.h b/src/amps/amps.h index 1c5ddeb..db5fa64 100644 --- a/src/amps/amps.h +++ b/src/amps/amps.h @@ -139,9 +139,10 @@ typedef struct amps { int sat_filter_pos; /* current sample position in filter_spl */ double sat_phaseshift65536[3]; /* how much the phase of sine wave changes per sample */ double sat_phase65536; /* current phase */ - int sat_detected; /* current detection state flag */ + int dtx_state; /* 1 = high (fast sat detection) */ + int sat_detected; /* current detection state flag (delayed detection) */ int sat_detect_count; /* current number of consecutive detections/losses */ - int sig_detected; /* current detection state flag */ + int sig_detected; /* current detection state flag (delayed detection) */ int sig_detect_count; /* current number of consecutive detections/losses */ double test_phaseshift65536; /* how much the phase of sine wave changes per sample */ double test_phase65536; /* current phase */ diff --git a/src/amps/dsp.c b/src/amps/dsp.c index 94ea774..ece14aa 100644 --- a/src/amps/dsp.c +++ b/src/amps/dsp.c @@ -107,17 +107,17 @@ #define SAT_DEVIATION (2000.0 / DBM0_DEVIATION) /* no emphasis */ #define MAX_DISPLAY (8000.0 / DBM0_DEVIATION) /* no emphasis */ #define BITRATE 10000 -#define SIG_TONE_CROSSINGS 2000 /* 2000 crossings are 100ms @ 10 KHz */ -#define SIG_TONE_MINBITS 950 /* minimum bit durations to detect signaling tone (1000 is perfect for 100 ms) */ -#define SIG_TONE_MAXBITS 1050 /* as above, maximum bits */ -#define SAT_DURATION 0.100 /* duration of SAT signal measurement */ -#define SAT_QUALITY 0.85 /* quality needed to detect sat */ -#define SAT_DETECT_COUNT 3 /* number of measures to detect SAT signal (specs say 250ms) */ -#define SAT_LOST_COUNT 3 /* number of measures to loose SAT signal (specs say 250ms) */ -#define SIG_DETECT_COUNT 3 /* number of measures to detect Signaling Tone */ -#define SIG_LOST_COUNT 2 /* number of measures to loose Signaling Tone */ +#define SAT_DURATION 0.05 /* duration of SAT signal measurement */ +#define SAT_QUALITY 0.85 /* quality needed to detect SAT signal */ +#define DTX_LEVEL 0.50 /* SAT level needed to mute/unmute */ +#define SIG_QUALITY 0.80 /* quality needed to detect Signaling Tone */ +#define SAT_DETECT_COUNT 5 /* number of measures to detect SAT signal (specs say 250ms) */ +#define SAT_LOST_COUNT 5 /* number of measures to loose SAT signal (specs say 250ms) */ +#define SIG_DETECT_COUNT 6 /* number of measures to detect Signaling Tone */ +#define SIG_LOST_COUNT 4 /* number of measures to loose Signaling Tone */ #define CUT_OFF_HIGHPASS 300.0 /* cut off frequency for high pass filter to remove dc level from sound card / sample */ #define BEST_QUALITY 0.68 /* Best possible RX quality */ +#define COMFORT_NOISE 0.02 /* audio level of comfort noise (relative to ISDN level) */ static sample_t ramp_up[256], ramp_down[256]; @@ -423,6 +423,18 @@ done: return count; } +/* send comfort noise */ +static void comfort_noise(sample_t *samples, int length) +{ + int i; + int16_t r; + + for (i = 0; i < length; i++) { + r = random(); + samples[i] = (double)r / 32768.0 * COMFORT_NOISE; + } +} + /* Generate audio stream with SAT signal. Keep phase for next call of function. */ static void sat_encode(amps_t *amps, sample_t *samples, int length) { @@ -716,7 +728,7 @@ static void sender_receive_frame(amps_t *amps, sample_t *samples, int length) } -/* decode signaling tone */ +/* decode SAT and signaling tone */ /* compare supervisory signal against noise floor on 5800 Hz */ static void sat_decode(amps_t *amps, sample_t *samples, int length) { @@ -737,6 +749,10 @@ static void sat_decode(amps_t *amps, sample_t *samples, int length) if (amps->sender.loopback || debuglevel == DEBUG_DEBUG) { PDEBUG_CHAN(DDSP, debuglevel, "Signaling Tone level %.2f%% quality %.0f%%\n", result[2] / FSK_DEVIATION / 0.63662 * 100.0, quality[1] * 100.0); } + if (quality[0] > SAT_QUALITY && result[0] / SAT_DEVIATION / 0.63662 > DTX_LEVEL) + amps->dtx_state = 1; + else + amps->dtx_state = 0; if (quality[0] > SAT_QUALITY) { if (amps->sat_detected == 0) { amps->sat_detect_count++; @@ -760,7 +776,7 @@ static void sat_decode(amps_t *amps, sample_t *samples, int length) } else amps->sat_detect_count = 0; } - if (quality[1] > 0.8) { + if (quality[1] > SIG_QUALITY) { if (amps->sig_detected == 0) { amps->sig_detect_count++; if (amps->sig_detect_count == SIG_DETECT_COUNT) { @@ -785,11 +801,6 @@ static void sat_decode(amps_t *amps, sample_t *samples, int length) } } -/* decode signaling/audio */ -/* Count SIG_TONE_CROSSINGS of zero crossings, then check if the elapsed bit - * time is between SIG_TONE_MINBITS and SIG_TONE_MAXBITS. If it is, the - * frequency is close to the singalling tone, so it is detected - */ static void sender_receive_audio(amps_t *amps, sample_t *samples, int length) { transaction_t *trans = amps->trans_list; @@ -813,7 +824,7 @@ static void sender_receive_audio(amps_t *amps, sample_t *samples, int length) /* receive audio, but only if call established and SAT detected */ if ((amps->dsp_mode == DSP_MODE_AUDIO_RX_AUDIO_TX || amps->dsp_mode == DSP_MODE_AUDIO_RX_FRAME_TX) - && trans && trans->callref && trans->sat_detected) { + && trans && trans->callref) { int pos, count; int i; @@ -828,6 +839,8 @@ static void sender_receive_audio(amps_t *amps, sample_t *samples, int length) for (i = 0; i < count; i++) { spl[pos++] = samples[i]; if (pos == 160) { + if (amps->dtx_state == 0) + comfort_noise(spl, 160); call_tx_audio(trans->callref, spl, 160); pos = 0; } diff --git a/src/amps/main.c b/src/amps/main.c index 6585306..e4dc243 100644 --- a/src/amps/main.c +++ b/src/amps/main.c @@ -43,7 +43,7 @@ int num_chan_type = 0; enum amps_chan_type chan_type[MAX_SENDER] = { CHAN_TYPE_CC_PC_VC }; const char *flip_polarity = ""; -int ms_power = 4, dcc = 0, scc = 0, sid = 40, regh = 1, regr = 1, pureg = 1, pdreg = 1, locaid = -1, regincr = 300, bis = 0; +int ms_power = 4, dtx = 0, dcc = 0, scc = 0, sid = 40, regh = 1, regr = 1, pureg = 1, pdreg = 1, locaid = -1, regincr = 300, bis = 0; int tolerant = 0; void print_help(const char *arg0) @@ -61,6 +61,10 @@ void print_help(const char *arg0) printf(" Give power level of the mobile station 0..7. (default = '%d')\n", ms_power); printf(" 0 = 4 W; 1 = 1.6 W; 2 = 630 mW; 3 = 250 mW;\n"); printf(" 4 = 100 mW; 5 = 40 mW; 6 = 16 mW; 7 = 6.3 mW\n"); + printf(" -D --dtx \n"); + printf(" Give DTX parameter for Discontinuous Transmission. (default = '%d')\n", dtx); + printf(" 0 = disable DTX; 1 = reserved;\n"); + printf(" 2 = 8 dB attenuation in low state; 3 = transmitter off\n"); printf(" -S --sysinfo sid= | sid=list\n"); printf(" Give system ID of cell broadcast (default = '%d')\n", sid); printf(" If it changes, phone re-registers. Use 'sid=list' to get a full list.\n"); @@ -106,12 +110,13 @@ static int handle_options(int argc, char **argv) {"channel-type", 1, 0, 'T'}, {"flip-polarity", 1, 0, 'F'}, {"ms-power", 1, 0, 'P'}, + {"dtx", 1, 0, 'D'}, {"sysinfo", 1, 0, 'S'}, {"tolerant", 0, 0, 'O'}, {0, 0, 0, 0} }; - set_options_common("T:F:P:S:O", long_options_special); + set_options_common("T:F:P:D:S:O", long_options_special); while (1) { int option_index = 0, c; @@ -154,6 +159,14 @@ static int handle_options(int argc, char **argv) ms_power = 0; skip_args += 2; break; + case 'D': + dtx = atoi(optarg); + if (dtx > 3) + dtx = 3; + if (dtx < 0) + dtx = 0; + skip_args += 2; + break; case 'S': p = strchr(optarg, '='); if (!p) { @@ -360,7 +373,7 @@ int main(int argc, char *argv[]) for (i = 0; i < num_kanal; i++) { amps_si si; - init_sysinfo(&si, ms_power, ms_power, dcc, sid >> 1, regh, regr, pureg, pdreg, locaid, regincr, bis); + init_sysinfo(&si, ms_power, ms_power, dtx, dcc, sid >> 1, regh, regr, pureg, pdreg, locaid, regincr, bis); rc = amps_create(kanal[i], chan_type[i], audiodev[i], use_sdr, samplerate, rx_gain, do_pre_emphasis, do_de_emphasis, write_rx_wave, write_tx_wave, read_rx_wave, &si, sid, scc, polarity, tolerant, loopback); if (rc < 0) { fprintf(stderr, "Failed to create \"Sender\" instance. Quitting!\n"); diff --git a/src/amps/sysinfo.c b/src/amps/sysinfo.c index 45826ce..064abbf 100644 --- a/src/amps/sysinfo.c +++ b/src/amps/sysinfo.c @@ -42,7 +42,7 @@ static struct sysinfo_acc_attempt default_acc_attempt = { 10, }; -void init_sysinfo(amps_si *si, int cmac, int vmac, int dcc, int sid1, int regh, int regr, int pureg, int pdreg, int locaid, int regincr, int bis) +void init_sysinfo(amps_si *si, int cmac, int vmac, int dtx, int dcc, int sid1, int regh, int regr, int pureg, int pdreg, int locaid, int regincr, int bis) { int i; @@ -70,7 +70,7 @@ void init_sysinfo(amps_si *si, int cmac, int vmac, int dcc, int sid1, int regh, si->word2.e = 1; si->word2.regh = regh; si->word2.regr = regr; - si->word2.dtx = 0; /* DTX seems not to work with Dynatac 8000 */ + si->word2.dtx = dtx; /* DTX seems not to work with my White Dynatac 8000 */ si->word2.n_1 = 20; si->word2.rcf = (bis) ? 0 : 1; /* must be set to ignore B/I bit */ si->word2.cpa = 1; /* must be set for combined CC+PC */ diff --git a/src/amps/sysinfo.h b/src/amps/sysinfo.h index b786add..211c128 100644 --- a/src/amps/sysinfo.h +++ b/src/amps/sysinfo.h @@ -108,7 +108,7 @@ typedef struct system_information { int count; /* count message train */ } amps_si; -void init_sysinfo(amps_si *si, int cmac, int vmac, int dcc, int sid1, int regh, int regr, int pureg, int pdreg, int locaid, int regincr, int bis); +void init_sysinfo(amps_si *si, int cmac, int vmac, int dtx, int dcc, int sid1, int regh, int regr, int pureg, int pdreg, int locaid, int regincr, int bis); void prepare_sysinfo(amps_si *si); uint64_t get_sysinfo(amps_si *si); diff --git a/src/amps/transaction.h b/src/amps/transaction.h index 5240991..79fd467 100644 --- a/src/amps/transaction.h +++ b/src/amps/transaction.h @@ -36,6 +36,7 @@ typedef struct transaction { enum amps_trans_state state; /* state of transaction */ struct timer timer; /* for varous timeouts */ int sat_detected; /* state if we detected SAT */ + int dtx; /* if set, DTX is used with this call */ } transaction_t; transaction_t *create_transaction(amps_t *amps, enum amps_trans_state trans_state, uint32_t min1, uint16_t min2, uint8_t msg_type, uint8_t ordq, uint8_t order, uint16_t chan); -- cgit v1.2.3