forked from cc/osmo-cc-ss5-endpoint
Preparte for Bell system; Put common code into lib
This commit is contained in:
parent
48dd37e1ae
commit
91e8521071
|
@ -42,4 +42,5 @@ src/libsample/libsample.a
|
||||||
src/libtimer/libtimer.a
|
src/libtimer/libtimer.a
|
||||||
src/libselect/libselect.a
|
src/libselect/libselect.a
|
||||||
src/libfilter/libfilter.a
|
src/libfilter/libfilter.a
|
||||||
|
src/common/libcommon.a
|
||||||
src/ss5/osmo-cc-ss5-endpoint
|
src/ss5/osmo-cc-ss5-endpoint
|
||||||
|
|
|
@ -87,6 +87,7 @@ AC_OUTPUT(
|
||||||
src/libosmocc/Makefile
|
src/libosmocc/Makefile
|
||||||
src/libg711/Makefile
|
src/libg711/Makefile
|
||||||
src/libfilter/Makefile
|
src/libfilter/Makefile
|
||||||
|
src/common/Makefile
|
||||||
src/ss5/Makefile
|
src/ss5/Makefile
|
||||||
src/Makefile
|
src/Makefile
|
||||||
Makefile)
|
Makefile)
|
||||||
|
|
|
@ -10,5 +10,6 @@ SUBDIRS = \
|
||||||
libosmocc \
|
libosmocc \
|
||||||
libg711 \
|
libg711 \
|
||||||
libfilter \
|
libfilter \
|
||||||
|
common \
|
||||||
ss5
|
ss5
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
|
||||||
|
|
||||||
|
noinst_LIBRARIES = libcommon.a
|
||||||
|
|
||||||
|
libcommon_a_SOURCES = \
|
||||||
|
mf.c \
|
||||||
|
dsp.c
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CHAN ((ss5_t *)(dsp->priv))->name
|
#define CHAN dsp->name
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include "../libdebug/debug.h"
|
#include "../libdebug/debug.h"
|
||||||
#include "ss5.h"
|
#include "dsp.h"
|
||||||
|
|
||||||
//#define DEBUG_DEMODULATOR
|
//#define DEBUG_DEMODULATOR
|
||||||
|
|
||||||
|
@ -50,16 +50,20 @@ static double tone_diff_ampl_sq[NUM_TONES];
|
||||||
#define SPLIT_DURATION 0.030
|
#define SPLIT_DURATION 0.030
|
||||||
#define MF_RECOGNITION 0.025
|
#define MF_RECOGNITION 0.025
|
||||||
|
|
||||||
int dsp_init_inst(dsp_t *dsp, void *priv, double samplerate, double sense_db)
|
int dsp_init_inst(dsp_t *dsp, void *priv, const char *name, double samplerate, int crosstalk, int comfort_noise, int delay_ms, double sense_db)
|
||||||
{
|
{
|
||||||
double tone_amplitude[NUM_TONES];
|
double tone_amplitude[NUM_TONES];
|
||||||
int t;
|
int t;
|
||||||
|
int rc;
|
||||||
|
|
||||||
PDEBUG(DDSP, DEBUG_DEBUG, "Init DSP for SS5 instance.\n");
|
PDEBUG(DDSP, DEBUG_DEBUG, "Init DSP instance.\n");
|
||||||
|
|
||||||
memset(dsp, 0, sizeof(*dsp));
|
memset(dsp, 0, sizeof(*dsp));
|
||||||
dsp->priv = priv;
|
dsp->priv = priv;
|
||||||
|
strncpy(dsp->name, name, sizeof(dsp->name - 1));
|
||||||
dsp->samplerate = samplerate;
|
dsp->samplerate = samplerate;
|
||||||
|
dsp->crosstalk = crosstalk;
|
||||||
|
dsp->comfort_noise = comfort_noise;
|
||||||
dsp->interrupt_duration = (int)(1000.0 * INTERRUPT_DURATION);
|
dsp->interrupt_duration = (int)(1000.0 * INTERRUPT_DURATION);
|
||||||
dsp->split_duration = (int)(1000.0 * SPLIT_DURATION);
|
dsp->split_duration = (int)(1000.0 * SPLIT_DURATION);
|
||||||
dsp->mf_detect_duration = (int)(1000.0 * MF_RECOGNITION);
|
dsp->mf_detect_duration = (int)(1000.0 * MF_RECOGNITION);
|
||||||
|
@ -83,22 +87,44 @@ int dsp_init_inst(dsp_t *dsp, void *priv, double samplerate, double sense_db)
|
||||||
if (!dsp->mf_mod)
|
if (!dsp->mf_mod)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* alloc delay buffer */
|
||||||
|
if (delay_ms) {
|
||||||
|
dsp->delay_length = (int)(dsp->samplerate * (double)delay_ms / 1000.0);
|
||||||
|
dsp->delay_buffer = calloc(dsp->delay_length, sizeof(*dsp->delay_buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate jitter buffer */
|
||||||
|
rc = jitter_create(&dsp->tx_dejitter, "tx", 8000, sizeof(sample_t), JITTER_DATA);
|
||||||
|
if (rc < 0)
|
||||||
|
abort();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dsp_cleanup_inst(dsp_t *dsp)
|
void dsp_cleanup_inst(dsp_t *dsp)
|
||||||
{
|
{
|
||||||
PDEBUG(DDSP, DEBUG_DEBUG, "Cleanup DSP of SS5 instance.\n");
|
PDEBUG(DDSP, DEBUG_DEBUG, "Cleanup DSP instance.\n");
|
||||||
|
|
||||||
|
/* free FM modulator */
|
||||||
if (dsp->mf_mod) {
|
if (dsp->mf_mod) {
|
||||||
mf_mod_exit(dsp->mf_mod);
|
mf_mod_exit(dsp->mf_mod);
|
||||||
dsp->mf_mod = NULL;
|
dsp->mf_mod = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* free FM demodulator */
|
||||||
if (dsp->mf_demod) {
|
if (dsp->mf_demod) {
|
||||||
mf_demod_exit(dsp->mf_demod);
|
mf_demod_exit(dsp->mf_demod);
|
||||||
dsp->mf_demod = NULL;
|
dsp->mf_demod = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* free delay buffer */
|
||||||
|
if (dsp->delay_buffer) {
|
||||||
|
free(dsp->delay_buffer);
|
||||||
|
dsp->delay_buffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free jitter buffer */
|
||||||
|
jitter_destroy(&dsp->tx_dejitter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -400,7 +426,7 @@ static void detect_tones(dsp_t *dsp, sample_t *samples, sample_t **levels_square
|
||||||
}
|
}
|
||||||
|
|
||||||
/* process audio from one link (source) to another (destination) */
|
/* process audio from one link (source) to another (destination) */
|
||||||
static void process_audio(ss5_t *ss5_a, ss5_t *ss5_b, int length)
|
static void process_audio(dsp_t *dsp_a, dsp_t *dsp_b, int length)
|
||||||
{
|
{
|
||||||
sample_t samples[2][length], s;
|
sample_t samples[2][length], s;
|
||||||
sample_t b1[length], b2[length], b3[length], b4[length], b5[length], b6[length], b7[length], b8[length];
|
sample_t b1[length], b2[length], b3[length], b4[length], b5[length], b6[length], b7[length], b8[length];
|
||||||
|
@ -411,32 +437,32 @@ static void process_audio(ss5_t *ss5_a, ss5_t *ss5_b, int length)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* get audio from jitter buffer */
|
/* get audio from jitter buffer */
|
||||||
jitter_load(&ss5_a->tx_dejitter, samples[0], length);
|
jitter_load(&dsp_a->tx_dejitter, samples[0], length);
|
||||||
jitter_load(&ss5_b->tx_dejitter, samples[1], length);
|
jitter_load(&dsp_b->tx_dejitter, samples[1], length);
|
||||||
|
|
||||||
/* optionally add comfort noise */
|
/* optionally add comfort noise */
|
||||||
if (!ss5_a->cc_callref && ss5_a->ss5_ep->comfort_noise) {
|
if (!dsp_a->cc_callref && dsp_a->comfort_noise) {
|
||||||
for (i = 0; i < length; i++)
|
for (i = 0; i < length; i++)
|
||||||
samples[0][i] += (double)((int8_t)random()) / 8000.0;
|
samples[0][i] += (double)((int8_t)random()) / 8000.0;
|
||||||
}
|
}
|
||||||
if (!ss5_b->cc_callref && ss5_b->ss5_ep->comfort_noise) {
|
if (!dsp_b->cc_callref && dsp_b->comfort_noise) {
|
||||||
for (i = 0; i < length; i++)
|
for (i = 0; i < length; i++)
|
||||||
samples[1][i] += (double)((int8_t)random()) / 8000.0;
|
samples[1][i] += (double)((int8_t)random()) / 8000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* modulate tone/digit. if no tone has to be played (or it stopped), count is less than length */
|
/* modulate tone/digit. if no tone has to be played (or it stopped), count is less than length */
|
||||||
count1 = assemble_tones(&ss5_a->dsp, mask, length);
|
count1 = assemble_tones(dsp_a, mask, length);
|
||||||
mf_mod(ss5_a->dsp.mf_mod, mask, samples[0], count1);
|
mf_mod(dsp_a->mf_mod, mask, samples[0], count1);
|
||||||
count2 = assemble_tones(&ss5_b->dsp, mask, length);
|
count2 = assemble_tones(dsp_b, mask, length);
|
||||||
mf_mod(ss5_b->dsp.mf_mod, mask, samples[1], count2);
|
mf_mod(dsp_b->mf_mod, mask, samples[1], count2);
|
||||||
|
|
||||||
/* optionally add some crosstalk */
|
/* optionally add some crosstalk */
|
||||||
if (ss5_a->ss5_ep->crosstalk) {
|
if (dsp_a->crosstalk) {
|
||||||
/* use count, since it carries number of samples with signalling */
|
/* use count, since it carries number of samples with signalling */
|
||||||
for (i = 0; i < count1; i++)
|
for (i = 0; i < count1; i++)
|
||||||
samples[1][i] += samples[0][i] / 70.0;
|
samples[1][i] += samples[0][i] / 70.0;
|
||||||
}
|
}
|
||||||
if (ss5_b->ss5_ep->crosstalk) {
|
if (dsp_b->crosstalk) {
|
||||||
/* use count, since it carries number of samples with signalling */
|
/* use count, since it carries number of samples with signalling */
|
||||||
for (i = 0; i < count2; i++)
|
for (i = 0; i < count2; i++)
|
||||||
samples[0][i] += samples[1][i] / 70.0;
|
samples[0][i] += samples[1][i] / 70.0;
|
||||||
|
@ -445,63 +471,63 @@ static void process_audio(ss5_t *ss5_a, ss5_t *ss5_b, int length)
|
||||||
/* ! here is the bridge from a to b and from b to a ! */
|
/* ! here is the bridge from a to b and from b to a ! */
|
||||||
|
|
||||||
/* optionally add one way delay */
|
/* optionally add one way delay */
|
||||||
if (ss5_b->delay_buffer) {
|
if (dsp_b->delay_buffer) {
|
||||||
for (i = 0; i < length; i++) {
|
for (i = 0; i < length; i++) {
|
||||||
s = ss5_b->delay_buffer[ss5_b->delay_index];
|
s = dsp_b->delay_buffer[dsp_b->delay_index];
|
||||||
ss5_b->delay_buffer[ss5_b->delay_index] = samples[0][i];
|
dsp_b->delay_buffer[dsp_b->delay_index] = samples[0][i];
|
||||||
if (++(ss5_b->delay_index) == ss5_b->delay_length)
|
if (++(dsp_b->delay_index) == dsp_b->delay_length)
|
||||||
ss5_b->delay_index = 0;
|
dsp_b->delay_index = 0;
|
||||||
samples[0][i] = s;
|
samples[0][i] = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ss5_a->delay_buffer) {
|
if (dsp_a->delay_buffer) {
|
||||||
for (i = 0; i < length; i++) {
|
for (i = 0; i < length; i++) {
|
||||||
s = ss5_a->delay_buffer[ss5_a->delay_index];
|
s = dsp_a->delay_buffer[dsp_a->delay_index];
|
||||||
ss5_a->delay_buffer[ss5_a->delay_index] = samples[1][i];
|
dsp_a->delay_buffer[dsp_a->delay_index] = samples[1][i];
|
||||||
if (++(ss5_a->delay_index) == ss5_a->delay_length)
|
if (++(dsp_a->delay_index) == dsp_a->delay_length)
|
||||||
ss5_a->delay_index = 0;
|
dsp_a->delay_index = 0;
|
||||||
samples[1][i] = s;
|
samples[1][i] = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* demodulate and call tone detector */
|
/* demodulate and call tone detector */
|
||||||
mf_demod(ss5_b->dsp.mf_demod, samples[0], length, levels_squared);
|
mf_demod(dsp_b->mf_demod, samples[0], length, levels_squared);
|
||||||
detect_tones(&ss5_b->dsp, samples[0], levels_squared, length, 1);
|
detect_tones(dsp_b->priv, samples[0], levels_squared, length, 1);
|
||||||
mf_demod(ss5_a->dsp.mf_demod, samples[1], length, levels_squared);
|
mf_demod(dsp_a->mf_demod, samples[1], length, levels_squared);
|
||||||
detect_tones(&ss5_a->dsp, samples[1], levels_squared, length, 0);
|
detect_tones(dsp_a->priv, samples[1], levels_squared, length, 0);
|
||||||
|
|
||||||
/* forward audio to CC if call exists */
|
/* forward audio to CC if call exists */
|
||||||
if (ss5_b->cc_callref && ss5_b->codec) {
|
if (dsp_b->cc_callref && dsp_b->codec) {
|
||||||
samples_to_int16_1mw(data, samples[0], length);
|
samples_to_int16_1mw(data, samples[0], length);
|
||||||
osmo_cc_rtp_send(ss5_b->codec, (uint8_t *)data, length * 2, 0, 1, length, ss5_b);
|
osmo_cc_rtp_send(dsp_b->codec, (uint8_t *)data, length * 2, 0, 1, length, dsp_b);
|
||||||
}
|
}
|
||||||
if (ss5_a->cc_callref && ss5_a->codec) {
|
if (dsp_a->cc_callref && dsp_a->codec) {
|
||||||
samples_to_int16_1mw(data, samples[1], length);
|
samples_to_int16_1mw(data, samples[1], length);
|
||||||
osmo_cc_rtp_send(ss5_a->codec, (uint8_t *)data, length * 2, 0, 1, length, ss5_a);
|
osmo_cc_rtp_send(dsp_a->codec, (uint8_t *)data, length * 2, 0, 1, length, dsp_a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clock is called every given number of samples (20ms) */
|
/* clock is called every given number of samples (20ms) */
|
||||||
void audio_clock(ss5_endpoint_t *ss5_ep_sunset, ss5_endpoint_t *ss5_ep_sunrise, int len)
|
void audio_clock(dsp_t *sunset_list, dsp_t *sunrise_list, int len)
|
||||||
{
|
{
|
||||||
ss5_t *ss5_a, *ss5_b;
|
dsp_t *dsp_a, *dsp_b;
|
||||||
|
|
||||||
if (!ss5_ep_sunset)
|
if (!sunset_list)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!ss5_ep_sunrise) {
|
if (!sunrise_list) {
|
||||||
/* each pair of links on the same endpoint are bridged */
|
/* each pair of links on the same endpoint are bridged */
|
||||||
for (ss5_b = ss5_ep_sunset->link_list; ss5_b; ss5_b = ss5_b->next) {
|
for (dsp_b = sunset_list; dsp_b; dsp_b = dsp_b->next) {
|
||||||
ss5_a = ss5_b;
|
dsp_a = dsp_b;
|
||||||
ss5_b = ss5_b->next;
|
dsp_b = dsp_b->next;
|
||||||
if (!ss5_b)
|
if (!dsp_b)
|
||||||
break;
|
break;
|
||||||
process_audio(ss5_a, ss5_b, len);
|
process_audio(dsp_a, dsp_b, len);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* each link on two endpoints are bridged */
|
/* each link on two endpoints are bridged */
|
||||||
for (ss5_a = ss5_ep_sunset->link_list, ss5_b = ss5_ep_sunrise->link_list; ss5_a && ss5_b; ss5_a = ss5_a->next, ss5_b = ss5_b->next) {
|
for (dsp_a = sunset_list, dsp_b = sunrise_list; dsp_a && dsp_b; dsp_a = dsp_a->next, dsp_b = dsp_b->next) {
|
||||||
process_audio(ss5_a, ss5_b, len);
|
process_audio(dsp_a, dsp_b, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -509,12 +535,12 @@ void audio_clock(ss5_endpoint_t *ss5_ep_sunset, ss5_endpoint_t *ss5_ep_sunrise,
|
||||||
/* take audio from CC and store in jitter buffer */
|
/* take audio from CC and store in jitter buffer */
|
||||||
void down_audio(struct osmo_cc_session_codec *codec, uint8_t __attribute__((unused)) marker, uint16_t sequence, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len)
|
void down_audio(struct osmo_cc_session_codec *codec, uint8_t __attribute__((unused)) marker, uint16_t sequence, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len)
|
||||||
{
|
{
|
||||||
ss5_t *ss5 = codec->media->session->priv;
|
dsp_t *dsp = codec->media->session->priv;
|
||||||
int count = len/2;
|
int count = len/2;
|
||||||
sample_t samples[count];
|
sample_t samples[count];
|
||||||
|
|
||||||
int16_to_samples_1mw(samples, (int16_t *)data, count);
|
int16_to_samples_1mw(samples, (int16_t *)data, count);
|
||||||
jitter_save(&ss5->tx_dejitter, samples, count, 1, sequence, timestamp, ssrc);
|
jitter_save(&dsp->tx_dejitter, samples, count, 1, sequence, timestamp, ssrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void encode_l16(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void __attribute__((unused)) *priv)
|
void encode_l16(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void __attribute__((unused)) *priv)
|
|
@ -1,8 +1,16 @@
|
||||||
|
|
||||||
struct ss5_endpoint;
|
#include "../libtimer/timer.h"
|
||||||
|
#include "../libselect/select.h"
|
||||||
|
#include "../libosmocc/endpoint.h"
|
||||||
|
#include "../libosmocc/helper.h"
|
||||||
|
#include "../libsample/sample.h"
|
||||||
|
#include "../libjitter/jitter.h"
|
||||||
|
#include "mf.h"
|
||||||
|
|
||||||
typedef struct dsp {
|
typedef struct dsp {
|
||||||
void *priv;
|
struct dsp *next; /* next instance (list is maintained by dsp) */
|
||||||
|
void *priv; /* back pointer to application */
|
||||||
|
char name[32]; /* name of link for debugging */
|
||||||
double samplerate;
|
double samplerate;
|
||||||
|
|
||||||
/* tone generation */
|
/* tone generation */
|
||||||
|
@ -28,15 +36,27 @@ typedef struct dsp {
|
||||||
int mf_detect_duration; /* MF tone duration in milliseconds */
|
int mf_detect_duration; /* MF tone duration in milliseconds */
|
||||||
int detect_count; /* counter for tone detection */
|
int detect_count; /* counter for tone detection */
|
||||||
char detect_tone; /* current tone detected or ' ' for no tone */
|
char detect_tone; /* current tone detected or ' ' for no tone */
|
||||||
|
|
||||||
|
/* audio processing */
|
||||||
|
jitter_t tx_dejitter; /* jitter buffer for audio from CC */
|
||||||
|
sample_t *delay_buffer; /* buffer for delaying audio */
|
||||||
|
int delay_length;
|
||||||
|
int delay_index;
|
||||||
|
int crosstalk; /* mix crosstalk from TX to RX */
|
||||||
|
int comfort_noise; /* add comfort noise before answer and after disconnect */
|
||||||
|
|
||||||
|
/* osmo-CC */
|
||||||
|
uint32_t cc_callref; /* ref to CC call */
|
||||||
|
osmo_cc_session_t *cc_session; /* audio session description */
|
||||||
|
osmo_cc_session_codec_t *codec; /* selected codec */
|
||||||
} dsp_t;
|
} dsp_t;
|
||||||
|
|
||||||
|
int dsp_init_inst(dsp_t *dsp, void *priv, const char *name, double samplerate, int crosstalk, int comfort_noise, int delay_ms, double sense_db);
|
||||||
int dsp_init_inst(dsp_t *dsp, void *priv, double samplerate, double sense_db);
|
|
||||||
void dsp_cleanup_inst(dsp_t *dsp);
|
void dsp_cleanup_inst(dsp_t *dsp);
|
||||||
void set_sig_detect_duration(dsp_t *dsp, double duration_AB, double duration_C);
|
void set_sig_detect_duration(dsp_t *dsp, double duration_AB, double duration_C);
|
||||||
void set_tone(dsp_t *dsp, char tone, double duration);
|
void set_tone(dsp_t *dsp, char tone, double duration);
|
||||||
void set_dial_string(dsp_t *dsp, const char *dial);
|
void set_dial_string(dsp_t *dsp, const char *dial);
|
||||||
void audio_clock(struct ss5_endpoint *ss5_ep_sunset, struct ss5_endpoint *ss5_ep_sunrise, int len);
|
void audio_clock(dsp_t *sunset_list, dsp_t *sunrise_list, int len);
|
||||||
void down_audio(struct osmo_cc_session_codec *codec, uint8_t marker, uint16_t sequence, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len);
|
void down_audio(struct osmo_cc_session_codec *codec, uint8_t marker, uint16_t sequence, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len);
|
||||||
void encode_l16(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
|
void encode_l16(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
|
||||||
void decode_l16(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
|
void decode_l16(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void *priv);
|
|
@ -4,14 +4,13 @@ bin_PROGRAMS = \
|
||||||
osmo-cc-ss5-endpoint
|
osmo-cc-ss5-endpoint
|
||||||
|
|
||||||
osmo_cc_ss5_endpoint_SOURCES = \
|
osmo_cc_ss5_endpoint_SOURCES = \
|
||||||
mf.c \
|
|
||||||
dsp.c \
|
|
||||||
ss5.c \
|
ss5.c \
|
||||||
display_status.c \
|
display_status.c \
|
||||||
main.c
|
main.c
|
||||||
|
|
||||||
osmo_cc_ss5_endpoint_LDADD = \
|
osmo_cc_ss5_endpoint_LDADD = \
|
||||||
$(COMMON_LA) \
|
$(COMMON_LA) \
|
||||||
|
../common/libcommon.a \
|
||||||
../libdebug/libdebug.a \
|
../libdebug/libdebug.a \
|
||||||
../liboptions/liboptions.a \
|
../liboptions/liboptions.a \
|
||||||
../libsample/libsample.a \
|
../libsample/libsample.a \
|
||||||
|
|
|
@ -234,7 +234,7 @@ static void clock_timeout(void __attribute__((unused)) *data)
|
||||||
timer_start(&clock_timer, last_time_clock - now);
|
timer_start(&clock_timer, last_time_clock - now);
|
||||||
|
|
||||||
/* call audio clock every 20ms */
|
/* call audio clock every 20ms */
|
||||||
audio_clock(ss5_ep_sunset, ss5_ep_sunrise, 160);
|
audio_clock(ss5_ep_sunset->dsp_list, ss5_ep_sunrise->dsp_list, 160);
|
||||||
|
|
||||||
/* process keyboard input */
|
/* process keyboard input */
|
||||||
c = get_char();
|
c = get_char();
|
||||||
|
@ -280,14 +280,14 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create sunset and (optionally) sunrise */
|
/* create sunset and (optionally) sunrise */
|
||||||
ss5_ep_sunset = ss5_ep_create("sunset", links, prevent_blueboxing, crosstalk, delay_ms, comfort_noise, suppress_disconnect, sense_db);
|
ss5_ep_sunset = ss5_ep_create("sunset", links, prevent_blueboxing, suppress_disconnect, crosstalk, comfort_noise, delay_ms, sense_db);
|
||||||
if (!ss5_ep_sunset)
|
if (!ss5_ep_sunset)
|
||||||
goto error;
|
goto error;
|
||||||
rc = osmo_cc_new(&ss5_ep_sunset->cc_ep, OSMO_CC_VERSION, "sunset", OSMO_CC_LOCATION_BEYOND_INTERWORKING, cc_message, NULL, ss5_ep_sunset, cc_argc_sunset, cc_argv_sunset);
|
rc = osmo_cc_new(&ss5_ep_sunset->cc_ep, OSMO_CC_VERSION, "sunset", OSMO_CC_LOCATION_BEYOND_INTERWORKING, cc_message, NULL, ss5_ep_sunset, cc_argc_sunset, cc_argv_sunset);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto error;
|
goto error;
|
||||||
if (endpoints == 2) {
|
if (endpoints == 2) {
|
||||||
ss5_ep_sunrise = ss5_ep_create("sunrise", links, prevent_blueboxing, crosstalk, delay_ms, comfort_noise, suppress_disconnect, sense_db);
|
ss5_ep_sunrise = ss5_ep_create("sunrise", links, prevent_blueboxing, suppress_disconnect, crosstalk, comfort_noise, delay_ms, sense_db);
|
||||||
if (!ss5_ep_sunrise)
|
if (!ss5_ep_sunrise)
|
||||||
goto error;
|
goto error;
|
||||||
rc = osmo_cc_new(&ss5_ep_sunrise->cc_ep, OSMO_CC_VERSION, "sunrise", OSMO_CC_LOCATION_BEYOND_INTERWORKING, cc_message, NULL, ss5_ep_sunrise, cc_argc_sunrise, cc_argv_sunrise);
|
rc = osmo_cc_new(&ss5_ep_sunrise->cc_ep, OSMO_CC_VERSION, "sunrise", OSMO_CC_LOCATION_BEYOND_INTERWORKING, cc_message, NULL, ss5_ep_sunrise, cc_argc_sunrise, cc_argv_sunrise);
|
||||||
|
|
151
src/ss5/ss5.c
151
src/ss5/ss5.c
|
@ -92,6 +92,7 @@ void refresh_status(void)
|
||||||
{
|
{
|
||||||
osmo_cc_endpoint_t *ep;
|
osmo_cc_endpoint_t *ep;
|
||||||
ss5_endpoint_t *ss5_ep;
|
ss5_endpoint_t *ss5_ep;
|
||||||
|
dsp_t *dsp;
|
||||||
ss5_t *ss5;
|
ss5_t *ss5;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -99,10 +100,12 @@ void refresh_status(void)
|
||||||
|
|
||||||
for (ep = osmo_cc_endpoint_list; ep; ep = ep->next) {
|
for (ep = osmo_cc_endpoint_list; ep; ep = ep->next) {
|
||||||
ss5_ep = ep->priv;
|
ss5_ep = ep->priv;
|
||||||
if (!ss5_ep->link_list)
|
if (!ss5_ep->dsp_list)
|
||||||
display_status_line(ep->local_name, 0, NULL, NULL, 0);
|
display_status_line(ep->local_name, 0, NULL, NULL, 0);
|
||||||
for (i = 0, ss5 = ss5_ep->link_list; ss5; i++, ss5 = ss5->next)
|
for (i = 0, dsp = ss5_ep->dsp_list; dsp; i++, dsp = dsp->next) {
|
||||||
|
ss5 = dsp->priv;
|
||||||
display_status_line(ep->local_name, i, ss5->callerid, ss5->dialing, ss5->state);
|
display_status_line(ep->local_name, i, ss5->callerid, ss5->dialing, ss5->state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
display_status_end();
|
display_status_end();
|
||||||
|
@ -125,20 +128,20 @@ void ss5_new_state(ss5_t *ss5, enum ss5_state state)
|
||||||
static void link_reset(ss5_t *ss5)
|
static void link_reset(ss5_t *ss5)
|
||||||
{
|
{
|
||||||
/* unlink callref */
|
/* unlink callref */
|
||||||
ss5->cc_callref = 0;
|
ss5->dsp.cc_callref = 0;
|
||||||
|
|
||||||
/* stop timer */
|
/* stop timer */
|
||||||
timer_stop(&ss5->timer);
|
timer_stop(&ss5->timer);
|
||||||
|
|
||||||
/* free session description */
|
/* free session description */
|
||||||
if (ss5->cc_session) {
|
if (ss5->dsp.cc_session) {
|
||||||
osmo_cc_free_session(ss5->cc_session);
|
osmo_cc_free_session(ss5->dsp.cc_session);
|
||||||
ss5->cc_session = NULL;
|
ss5->dsp.cc_session = NULL;
|
||||||
ss5->codec = NULL;
|
ss5->dsp.codec = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reset jitter buffer */
|
/* reset jitter buffer */
|
||||||
jitter_reset(&ss5->tx_dejitter);
|
jitter_reset(&ss5->dsp.tx_dejitter);
|
||||||
|
|
||||||
/* set recognition time */
|
/* set recognition time */
|
||||||
set_sig_detect_duration(&ss5->dsp, SIGN_RECOGNITION_FAST, SIGN_RECOGNITION_NORMAL);
|
set_sig_detect_duration(&ss5->dsp, SIGN_RECOGNITION_FAST, SIGN_RECOGNITION_NORMAL);
|
||||||
|
@ -153,10 +156,10 @@ static void link_reset(ss5_t *ss5)
|
||||||
|
|
||||||
static void ss5_timeout(void *data);
|
static void ss5_timeout(void *data);
|
||||||
|
|
||||||
static ss5_t *link_create(ss5_endpoint_t *ss5_ep, const char *ep_name, int linkid)
|
static ss5_t *link_create(ss5_endpoint_t *ss5_ep, const char *ep_name, int linkid, double samplerate, int crosstalk, int comfort_noise, int delay_ms, double sense_db)
|
||||||
{
|
{
|
||||||
ss5_t *ss5, **ss5_p;
|
ss5_t *ss5;
|
||||||
int rc;
|
dsp_t **dsp_p;
|
||||||
|
|
||||||
ss5 = calloc(1, sizeof(*ss5));
|
ss5 = calloc(1, sizeof(*ss5));
|
||||||
if (!ss5) {
|
if (!ss5) {
|
||||||
|
@ -165,37 +168,27 @@ static ss5_t *link_create(ss5_endpoint_t *ss5_ep, const char *ep_name, int linki
|
||||||
}
|
}
|
||||||
ss5->ss5_ep = ss5_ep;
|
ss5->ss5_ep = ss5_ep;
|
||||||
|
|
||||||
ss5_p = &ss5_ep->link_list;
|
|
||||||
while (*ss5_p)
|
|
||||||
ss5_p = &((*ss5_p)->next);
|
|
||||||
*ss5_p = ss5;
|
|
||||||
|
|
||||||
/* debug name */
|
/* debug name */
|
||||||
snprintf(ss5->name, sizeof(ss5->name) - 1, "%s/%d", ep_name, linkid);
|
snprintf(ss5->name, sizeof(ss5->name) - 1, "%s/%d", ep_name, linkid);
|
||||||
|
|
||||||
/* init dsp instance */
|
/* init dsp instance */
|
||||||
dsp_init_inst(&ss5->dsp, ss5, ss5_ep->samplerate, ss5_ep->sense_db);
|
dsp_init_inst(&ss5->dsp, ss5, ss5->name, samplerate, crosstalk, comfort_noise, delay_ms, sense_db);
|
||||||
|
|
||||||
/* init timer */
|
/* init timer */
|
||||||
timer_init(&ss5->timer, ss5_timeout, ss5);
|
timer_init(&ss5->timer, ss5_timeout, ss5);
|
||||||
|
|
||||||
/* allocate jitter buffer */
|
|
||||||
rc = jitter_create(&ss5->tx_dejitter, "tx", 8000, sizeof(sample_t), JITTER_DATA);
|
|
||||||
if (rc < 0)
|
|
||||||
abort();
|
|
||||||
|
|
||||||
/* alloc delay buffer */
|
|
||||||
if (ss5_ep->delay_ms) {
|
|
||||||
ss5->delay_length = (int)(ss5_ep->samplerate * (double)ss5_ep->delay_ms / 1000.0);
|
|
||||||
ss5->delay_buffer = calloc(ss5->delay_length, sizeof(*ss5->delay_buffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* reset instance */
|
/* reset instance */
|
||||||
link_reset(ss5);
|
link_reset(ss5);
|
||||||
|
|
||||||
/* state idle */
|
/* state idle */
|
||||||
ss5_new_state(ss5, SS5_STATE_IDLE);
|
ss5_new_state(ss5, SS5_STATE_IDLE);
|
||||||
|
|
||||||
|
/* link */
|
||||||
|
dsp_p = &ss5_ep->dsp_list;
|
||||||
|
while (*dsp_p)
|
||||||
|
dsp_p = &((*dsp_p)->next);
|
||||||
|
*dsp_p = &ss5->dsp;
|
||||||
|
|
||||||
PDEBUG_CHAN(DSS5, DEBUG_DEBUG, "created ss5 instance\n");
|
PDEBUG_CHAN(DSS5, DEBUG_DEBUG, "created ss5 instance\n");
|
||||||
|
|
||||||
return ss5;
|
return ss5;
|
||||||
|
@ -203,7 +196,16 @@ static ss5_t *link_create(ss5_endpoint_t *ss5_ep, const char *ep_name, int linki
|
||||||
|
|
||||||
static void link_destroy(ss5_t *ss5)
|
static void link_destroy(ss5_t *ss5)
|
||||||
{
|
{
|
||||||
ss5_t **ss5_p;
|
dsp_t **dsp_p;
|
||||||
|
|
||||||
|
/* detach */
|
||||||
|
dsp_p = &ss5->ss5_ep->dsp_list;
|
||||||
|
while (*dsp_p) {
|
||||||
|
if (*dsp_p == &ss5->dsp)
|
||||||
|
break;
|
||||||
|
dsp_p = &((*dsp_p)->next);
|
||||||
|
}
|
||||||
|
*dsp_p = ss5->dsp.next;
|
||||||
|
|
||||||
/* state idle */
|
/* state idle */
|
||||||
ss5_new_state(ss5, SS5_STATE_IDLE);
|
ss5_new_state(ss5, SS5_STATE_IDLE);
|
||||||
|
@ -214,33 +216,15 @@ static void link_destroy(ss5_t *ss5)
|
||||||
/* exit timer */
|
/* exit timer */
|
||||||
timer_exit(&ss5->timer);
|
timer_exit(&ss5->timer);
|
||||||
|
|
||||||
/* free jitter buffer */
|
|
||||||
jitter_destroy(&ss5->tx_dejitter);
|
|
||||||
|
|
||||||
/* free delay buffer */
|
|
||||||
if (ss5->delay_buffer) {
|
|
||||||
free(ss5->delay_buffer);
|
|
||||||
ss5->delay_buffer = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* cleanup dsp instance */
|
/* cleanup dsp instance */
|
||||||
dsp_cleanup_inst(&ss5->dsp);
|
dsp_cleanup_inst(&ss5->dsp);
|
||||||
|
|
||||||
/* detach */
|
|
||||||
ss5_p = &ss5->ss5_ep->link_list;
|
|
||||||
while (*ss5_p) {
|
|
||||||
if (*ss5_p == ss5)
|
|
||||||
break;
|
|
||||||
ss5_p = &((*ss5_p)->next);
|
|
||||||
}
|
|
||||||
*ss5_p = ss5->next;
|
|
||||||
|
|
||||||
PDEBUG_CHAN(DSS5, DEBUG_DEBUG, "destroyed ss5 instance\n");
|
PDEBUG_CHAN(DSS5, DEBUG_DEBUG, "destroyed ss5 instance\n");
|
||||||
|
|
||||||
free(ss5);
|
free(ss5);
|
||||||
}
|
}
|
||||||
|
|
||||||
ss5_endpoint_t *ss5_ep_create(const char *ep_name, int links, int prevent_blueboxing, int crosstalk, int delay_ms, int comfort_noise, int suppress_disconnect, double sense_db)
|
ss5_endpoint_t *ss5_ep_create(const char *ep_name, int links, int prevent_blueboxing, int suppress_disconnect, int crosstalk, int comfort_noise, int delay_ms, double sense_db)
|
||||||
{
|
{
|
||||||
ss5_endpoint_t *ss5_ep;
|
ss5_endpoint_t *ss5_ep;
|
||||||
int i;
|
int i;
|
||||||
|
@ -251,16 +235,11 @@ ss5_endpoint_t *ss5_ep_create(const char *ep_name, int links, int prevent_bluebo
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
ss5_ep->samplerate = 8000;
|
|
||||||
ss5_ep->prevent_blueboxing = prevent_blueboxing;
|
ss5_ep->prevent_blueboxing = prevent_blueboxing;
|
||||||
ss5_ep->crosstalk = crosstalk;
|
|
||||||
ss5_ep->delay_ms = delay_ms;
|
|
||||||
ss5_ep->comfort_noise = comfort_noise;
|
|
||||||
ss5_ep->suppress_disconnect = suppress_disconnect;
|
ss5_ep->suppress_disconnect = suppress_disconnect;
|
||||||
ss5_ep->sense_db = sense_db;
|
|
||||||
|
|
||||||
for (i = 0; i < links; i++)
|
for (i = 0; i < links; i++)
|
||||||
link_create(ss5_ep, ep_name, i + 1);
|
link_create(ss5_ep, ep_name, i + 1, 8000, crosstalk, comfort_noise, delay_ms, sense_db);
|
||||||
|
|
||||||
PDEBUG(DSS5, DEBUG_DEBUG, "SS5 endpoint instance created\n");
|
PDEBUG(DSS5, DEBUG_DEBUG, "SS5 endpoint instance created\n");
|
||||||
|
|
||||||
|
@ -270,8 +249,8 @@ ss5_endpoint_t *ss5_ep_create(const char *ep_name, int links, int prevent_bluebo
|
||||||
void ss5_ep_destroy(ss5_endpoint_t *ss5_ep)
|
void ss5_ep_destroy(ss5_endpoint_t *ss5_ep)
|
||||||
{
|
{
|
||||||
/* destroy all calls */
|
/* destroy all calls */
|
||||||
while (ss5_ep->link_list)
|
while (ss5_ep->dsp_list)
|
||||||
link_destroy(ss5_ep->link_list);
|
link_destroy(ss5_ep->dsp_list->priv);
|
||||||
|
|
||||||
free(ss5_ep);
|
free(ss5_ep);
|
||||||
|
|
||||||
|
@ -304,7 +283,7 @@ static void release_call(ss5_t *ss5, uint8_t isdn_cause)
|
||||||
/* cause */
|
/* cause */
|
||||||
osmo_cc_add_ie_cause(new_msg, OSMO_CC_LOCATION_BEYOND_INTERWORKING, isdn_cause, 0, 0);
|
osmo_cc_add_ie_cause(new_msg, OSMO_CC_LOCATION_BEYOND_INTERWORKING, isdn_cause, 0, 0);
|
||||||
/* send message to osmo-cc */
|
/* send message to osmo-cc */
|
||||||
osmo_cc_ll_msg(&ss5->ss5_ep->cc_ep, ss5->cc_callref, new_msg);
|
osmo_cc_ll_msg(&ss5->ss5_ep->cc_ep, ss5->dsp.cc_callref, new_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void disconnect_call(ss5_t *ss5, uint8_t isdn_cause)
|
static void disconnect_call(ss5_t *ss5, uint8_t isdn_cause)
|
||||||
|
@ -320,7 +299,7 @@ static void disconnect_call(ss5_t *ss5, uint8_t isdn_cause)
|
||||||
/* cause */
|
/* cause */
|
||||||
osmo_cc_add_ie_cause(new_msg, OSMO_CC_LOCATION_BEYOND_INTERWORKING, isdn_cause, 0, 0);
|
osmo_cc_add_ie_cause(new_msg, OSMO_CC_LOCATION_BEYOND_INTERWORKING, isdn_cause, 0, 0);
|
||||||
/* send message to osmo-cc */
|
/* send message to osmo-cc */
|
||||||
osmo_cc_ll_msg(&ss5->ss5_ep->cc_ep, ss5->cc_callref, new_msg);
|
osmo_cc_ll_msg(&ss5->ss5_ep->cc_ep, ss5->dsp.cc_callref, new_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void proceed_call(ss5_t *ss5, const char *sdp)
|
static void proceed_call(ss5_t *ss5, const char *sdp)
|
||||||
|
@ -334,7 +313,7 @@ static void proceed_call(ss5_t *ss5, const char *sdp)
|
||||||
/* sdp */
|
/* sdp */
|
||||||
osmo_cc_add_ie_sdp(new_msg, sdp);
|
osmo_cc_add_ie_sdp(new_msg, sdp);
|
||||||
/* send message to osmo-cc */
|
/* send message to osmo-cc */
|
||||||
osmo_cc_ll_msg(&ss5->ss5_ep->cc_ep, ss5->cc_callref, new_msg);
|
osmo_cc_ll_msg(&ss5->ss5_ep->cc_ep, ss5->dsp.cc_callref, new_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void alert_call(ss5_t *ss5)
|
static void alert_call(ss5_t *ss5)
|
||||||
|
@ -344,7 +323,7 @@ static void alert_call(ss5_t *ss5)
|
||||||
/* create osmo-cc message */
|
/* create osmo-cc message */
|
||||||
new_msg = osmo_cc_new_msg(OSMO_CC_MSG_ALERT_IND);
|
new_msg = osmo_cc_new_msg(OSMO_CC_MSG_ALERT_IND);
|
||||||
/* send message to osmo-cc */
|
/* send message to osmo-cc */
|
||||||
osmo_cc_ll_msg(&ss5->ss5_ep->cc_ep, ss5->cc_callref, new_msg);
|
osmo_cc_ll_msg(&ss5->ss5_ep->cc_ep, ss5->dsp.cc_callref, new_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void answer_call(ss5_t *ss5)
|
static void answer_call(ss5_t *ss5)
|
||||||
|
@ -354,7 +333,7 @@ static void answer_call(ss5_t *ss5)
|
||||||
/* create osmo-cc message */
|
/* create osmo-cc message */
|
||||||
new_msg = osmo_cc_new_msg(OSMO_CC_MSG_SETUP_CNF);
|
new_msg = osmo_cc_new_msg(OSMO_CC_MSG_SETUP_CNF);
|
||||||
/* send message to osmo-cc */
|
/* send message to osmo-cc */
|
||||||
osmo_cc_ll_msg(&ss5->ss5_ep->cc_ep, ss5->cc_callref, new_msg);
|
osmo_cc_ll_msg(&ss5->ss5_ep->cc_ep, ss5->dsp.cc_callref, new_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_comp_call(ss5_t *ss5)
|
static void setup_comp_call(ss5_t *ss5)
|
||||||
|
@ -364,7 +343,7 @@ static void setup_comp_call(ss5_t *ss5)
|
||||||
/* create osmo-cc message */
|
/* create osmo-cc message */
|
||||||
new_msg = osmo_cc_new_msg(OSMO_CC_MSG_SETUP_COMP_IND);
|
new_msg = osmo_cc_new_msg(OSMO_CC_MSG_SETUP_COMP_IND);
|
||||||
/* send message to osmo-cc */
|
/* send message to osmo-cc */
|
||||||
osmo_cc_ll_msg(&ss5->ss5_ep->cc_ep, ss5->cc_callref, new_msg);
|
osmo_cc_ll_msg(&ss5->ss5_ep->cc_ep, ss5->dsp.cc_callref, new_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -604,11 +583,11 @@ void receive_digit(void *priv, char digit, double dbm)
|
||||||
if (ss5->state != SS5_STATE_SEND_CLR_FWD && digit == 'C') {
|
if (ss5->state != SS5_STATE_SEND_CLR_FWD && digit == 'C') {
|
||||||
PDEBUG_CHAN(DSS5, DEBUG_INFO, "Received 'clear-forward' signal in '%s' state, sending 'release-guard' and clearing call.\n", ss5_state_names[ss5->state]);
|
PDEBUG_CHAN(DSS5, DEBUG_INFO, "Received 'clear-forward' signal in '%s' state, sending 'release-guard' and clearing call.\n", ss5_state_names[ss5->state]);
|
||||||
/* release outgoing call */
|
/* release outgoing call */
|
||||||
if (ss5->cc_callref) {
|
if (ss5->dsp.cc_callref) {
|
||||||
/* send release indication towards CC */
|
/* send release indication towards CC */
|
||||||
release_call(ss5, OSMO_CC_ISDN_CAUSE_NORM_CALL_CLEAR);
|
release_call(ss5, OSMO_CC_ISDN_CAUSE_NORM_CALL_CLEAR);
|
||||||
/* remove ref */
|
/* remove ref */
|
||||||
ss5->cc_callref = 0;
|
ss5->dsp.cc_callref = 0;
|
||||||
}
|
}
|
||||||
/* stop timer */
|
/* stop timer */
|
||||||
timer_stop(&ss5->timer);
|
timer_stop(&ss5->timer);
|
||||||
|
@ -856,8 +835,8 @@ void receive_digit(void *priv, char digit, double dbm)
|
||||||
/* called number */
|
/* called number */
|
||||||
osmo_cc_add_ie_called(msg, type, OSMO_CC_PLAN_TELEPHONY, dialing);
|
osmo_cc_add_ie_called(msg, type, OSMO_CC_PLAN_TELEPHONY, dialing);
|
||||||
/* sdp offer */
|
/* sdp offer */
|
||||||
ss5->cc_session = osmo_cc_helper_audio_offer(&ss5->ss5_ep->cc_ep.session_config, ss5, codecs, down_audio, msg, 1);
|
ss5->dsp.cc_session = osmo_cc_helper_audio_offer(&ss5->ss5_ep->cc_ep.session_config, &ss5->dsp, codecs, down_audio, msg, 1);
|
||||||
if (!ss5->cc_session) {
|
if (!ss5->dsp.cc_session) {
|
||||||
osmo_cc_free_msg(msg);
|
osmo_cc_free_msg(msg);
|
||||||
PDEBUG_CHAN(DSS5, DEBUG_NOTICE, "Failed to offer audio, sending 'clear-back'.\n");
|
PDEBUG_CHAN(DSS5, DEBUG_NOTICE, "Failed to offer audio, sending 'clear-back'.\n");
|
||||||
/* send clear-back */
|
/* send clear-back */
|
||||||
|
@ -868,9 +847,9 @@ void receive_digit(void *priv, char digit, double dbm)
|
||||||
}
|
}
|
||||||
/* create new call */
|
/* create new call */
|
||||||
osmo_cc_call_t *cc_call = osmo_cc_call_new(&ss5->ss5_ep->cc_ep);
|
osmo_cc_call_t *cc_call = osmo_cc_call_new(&ss5->ss5_ep->cc_ep);
|
||||||
ss5->cc_callref = cc_call->callref;
|
ss5->dsp.cc_callref = cc_call->callref;
|
||||||
/* send message to CC */
|
/* send message to CC */
|
||||||
osmo_cc_ll_msg(&ss5->ss5_ep->cc_ep, ss5->cc_callref, msg);
|
osmo_cc_ll_msg(&ss5->ss5_ep->cc_ep, ss5->dsp.cc_callref, msg);
|
||||||
/* change state */
|
/* change state */
|
||||||
ss5_new_state(ss5, SS5_STATE_IN_INACTIVE);
|
ss5_new_state(ss5, SS5_STATE_IN_INACTIVE);
|
||||||
break;
|
break;
|
||||||
|
@ -976,6 +955,7 @@ static void ss5_timeout(void *data)
|
||||||
void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg)
|
void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg)
|
||||||
{
|
{
|
||||||
ss5_endpoint_t *ss5_ep = ep->priv;
|
ss5_endpoint_t *ss5_ep = ep->priv;
|
||||||
|
dsp_t *dsp;
|
||||||
ss5_t *ss5;
|
ss5_t *ss5;
|
||||||
osmo_cc_msg_t *new_msg;
|
osmo_cc_msg_t *new_msg;
|
||||||
uint8_t type, plan, present, screen;
|
uint8_t type, plan, present, screen;
|
||||||
|
@ -984,12 +964,13 @@ void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg)
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* hunt for callref */
|
/* hunt for callref */
|
||||||
ss5 = ss5_ep->link_list;
|
dsp = ss5_ep->dsp_list;
|
||||||
while (ss5) {
|
while (dsp) {
|
||||||
if (ss5->cc_callref == callref)
|
if (dsp->cc_callref == callref)
|
||||||
break;
|
break;
|
||||||
ss5 = ss5->next;
|
dsp = dsp->next;
|
||||||
}
|
}
|
||||||
|
ss5 = (dsp) ? dsp->priv : NULL;
|
||||||
|
|
||||||
/* process SETUP */
|
/* process SETUP */
|
||||||
if (!ss5) {
|
if (!ss5) {
|
||||||
|
@ -998,19 +979,21 @@ void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* hunt free ss5 instance */
|
/* hunt free ss5 instance */
|
||||||
ss5 = ss5_ep->link_list;
|
dsp = ss5_ep->dsp_list;
|
||||||
while (ss5) {
|
while (dsp) {
|
||||||
|
ss5 = dsp->priv;
|
||||||
if (ss5->state == SS5_STATE_IDLE)
|
if (ss5->state == SS5_STATE_IDLE)
|
||||||
break;
|
break;
|
||||||
ss5 = ss5->next;
|
dsp = dsp->next;
|
||||||
}
|
}
|
||||||
|
ss5 = (dsp) ? dsp->priv : NULL;
|
||||||
if (!ss5) {
|
if (!ss5) {
|
||||||
PDEBUG(DSS5, DEBUG_NOTICE, "No free ss5 instance, rejecting.\n");
|
PDEBUG(DSS5, DEBUG_NOTICE, "No free ss5 instance, rejecting.\n");
|
||||||
reject_call(ss5_ep, callref, OSMO_CC_ISDN_CAUSE_NO_CIRCUIT_CHAN);
|
reject_call(ss5_ep, callref, OSMO_CC_ISDN_CAUSE_NO_CIRCUIT_CHAN);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* link with cc */
|
/* link with cc */
|
||||||
ss5->cc_callref = callref;
|
ss5->dsp.cc_callref = callref;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (msg->type) {
|
switch (msg->type) {
|
||||||
|
@ -1023,7 +1006,7 @@ void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg)
|
||||||
if (rc < 0 || !dialing[0]) {
|
if (rc < 0 || !dialing[0]) {
|
||||||
PDEBUG_CHAN(DSS5, DEBUG_NOTICE, "No number given, call is rejected!\n");
|
PDEBUG_CHAN(DSS5, DEBUG_NOTICE, "No number given, call is rejected!\n");
|
||||||
inv_nr:
|
inv_nr:
|
||||||
reject_call(ss5->ss5_ep, ss5->cc_callref, OSMO_CC_ISDN_CAUSE_INV_NR_FORMAT);
|
reject_call(ss5->ss5_ep, ss5->dsp.cc_callref, OSMO_CC_ISDN_CAUSE_INV_NR_FORMAT);
|
||||||
link_reset(ss5);
|
link_reset(ss5);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -1031,9 +1014,9 @@ void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg)
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto inv_nr;
|
goto inv_nr;
|
||||||
/* sdp accept */
|
/* sdp accept */
|
||||||
sdp = osmo_cc_helper_audio_accept(&ss5->ss5_ep->cc_ep.session_config, ss5, codecs, down_audio, msg, &ss5->cc_session, &ss5->codec, 0);
|
sdp = osmo_cc_helper_audio_accept(&ss5->ss5_ep->cc_ep.session_config, &ss5->dsp, codecs, down_audio, msg, &ss5->dsp.cc_session, &ss5->dsp.codec, 0);
|
||||||
if (!sdp) {
|
if (!sdp) {
|
||||||
reject_call(ss5->ss5_ep, ss5->cc_callref, OSMO_CC_ISDN_CAUSE_RESOURCE_UNAVAIL);
|
reject_call(ss5->ss5_ep, ss5->dsp.cc_callref, OSMO_CC_ISDN_CAUSE_RESOURCE_UNAVAIL);
|
||||||
link_reset(ss5);
|
link_reset(ss5);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -1048,7 +1031,7 @@ void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg)
|
||||||
case OSMO_CC_MSG_PROC_REQ: /* call of endpoint is proceeding */
|
case OSMO_CC_MSG_PROC_REQ: /* call of endpoint is proceeding */
|
||||||
case OSMO_CC_MSG_ALERT_REQ: /* call of endpoint is ringing */
|
case OSMO_CC_MSG_ALERT_REQ: /* call of endpoint is ringing */
|
||||||
case OSMO_CC_MSG_PROGRESS_REQ: /* progress */
|
case OSMO_CC_MSG_PROGRESS_REQ: /* progress */
|
||||||
rc = osmo_cc_helper_audio_negotiate(msg, &ss5->cc_session, &ss5->codec);
|
rc = osmo_cc_helper_audio_negotiate(msg, &ss5->dsp.cc_session, &ss5->dsp.codec);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
codec_failed:
|
codec_failed:
|
||||||
PDEBUG_CHAN(DSS5, DEBUG_NOTICE, "Releasing, because codec negotiation failed.\n");
|
PDEBUG_CHAN(DSS5, DEBUG_NOTICE, "Releasing, because codec negotiation failed.\n");
|
||||||
|
@ -1065,7 +1048,7 @@ void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg)
|
||||||
break;
|
break;
|
||||||
case OSMO_CC_MSG_SETUP_RSP: /* call of endpoint is connected */
|
case OSMO_CC_MSG_SETUP_RSP: /* call of endpoint is connected */
|
||||||
PDEBUG_CHAN(DSS5, DEBUG_INFO, "Incoming call has answered in '%s' state, sending 'answer'.\n", ss5_state_names[ss5->state]);
|
PDEBUG_CHAN(DSS5, DEBUG_INFO, "Incoming call has answered in '%s' state, sending 'answer'.\n", ss5_state_names[ss5->state]);
|
||||||
rc = osmo_cc_helper_audio_negotiate(msg, &ss5->cc_session, &ss5->codec);
|
rc = osmo_cc_helper_audio_negotiate(msg, &ss5->dsp.cc_session, &ss5->dsp.codec);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto codec_failed;
|
goto codec_failed;
|
||||||
/* connect acknowledge */
|
/* connect acknowledge */
|
||||||
|
@ -1081,7 +1064,7 @@ void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg)
|
||||||
case OSMO_CC_MSG_REJ_REQ: /* call has been rejected */
|
case OSMO_CC_MSG_REJ_REQ: /* call has been rejected */
|
||||||
case OSMO_CC_MSG_REL_REQ: /* call has been released */
|
case OSMO_CC_MSG_REL_REQ: /* call has been released */
|
||||||
case OSMO_CC_MSG_DISC_REQ: /* call has been disconnected */
|
case OSMO_CC_MSG_DISC_REQ: /* call has been disconnected */
|
||||||
rc = osmo_cc_helper_audio_negotiate(msg, &ss5->cc_session, &ss5->codec);
|
rc = osmo_cc_helper_audio_negotiate(msg, &ss5->dsp.cc_session, &ss5->dsp.codec);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto codec_failed;
|
goto codec_failed;
|
||||||
/* right state */
|
/* right state */
|
||||||
|
@ -1109,7 +1092,7 @@ void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg)
|
||||||
new_msg = osmo_cc_clone_msg(msg);
|
new_msg = osmo_cc_clone_msg(msg);
|
||||||
new_msg->type = OSMO_CC_MSG_REL_IND;
|
new_msg->type = OSMO_CC_MSG_REL_IND;
|
||||||
/* send message to osmo-cc */
|
/* send message to osmo-cc */
|
||||||
osmo_cc_ll_msg(&ss5->ss5_ep->cc_ep, ss5->cc_callref, new_msg);
|
osmo_cc_ll_msg(&ss5->ss5_ep->cc_ep, ss5->dsp.cc_callref, new_msg);
|
||||||
/* reset */
|
/* reset */
|
||||||
link_reset(ss5);
|
link_reset(ss5);
|
||||||
break;
|
break;
|
||||||
|
@ -1121,7 +1104,7 @@ void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg)
|
||||||
new_msg = osmo_cc_clone_msg(msg);
|
new_msg = osmo_cc_clone_msg(msg);
|
||||||
new_msg->type = OSMO_CC_MSG_REL_CNF;
|
new_msg->type = OSMO_CC_MSG_REL_CNF;
|
||||||
/* send message to osmo-cc */
|
/* send message to osmo-cc */
|
||||||
osmo_cc_ll_msg(&ss5->ss5_ep->cc_ep, ss5->cc_callref, new_msg);
|
osmo_cc_ll_msg(&ss5->ss5_ep->cc_ep, ss5->dsp.cc_callref, new_msg);
|
||||||
}
|
}
|
||||||
/* on reject/release we reset/unlink call */
|
/* on reject/release we reset/unlink call */
|
||||||
if (msg->type != OSMO_CC_MSG_DISC_REQ)
|
if (msg->type != OSMO_CC_MSG_DISC_REQ)
|
||||||
|
|
|
@ -1,12 +1,5 @@
|
||||||
|
|
||||||
#include "../libtimer/timer.h"
|
#include "../common/dsp.h"
|
||||||
#include "../libselect/select.h"
|
|
||||||
#include "../libosmocc/endpoint.h"
|
|
||||||
#include "../libosmocc/helper.h"
|
|
||||||
#include "../libsample/sample.h"
|
|
||||||
#include "../libjitter/jitter.h"
|
|
||||||
#include "mf.h"
|
|
||||||
#include "dsp.h"
|
|
||||||
|
|
||||||
enum ss5_state {
|
enum ss5_state {
|
||||||
SS5_STATE_NULL = 0,
|
SS5_STATE_NULL = 0,
|
||||||
|
@ -45,42 +38,29 @@ struct ss5_endpoint;
|
||||||
|
|
||||||
/* SS5 link definition */
|
/* SS5 link definition */
|
||||||
typedef struct ss5 {
|
typedef struct ss5 {
|
||||||
struct ss5 *next;
|
|
||||||
struct ss5_endpoint *ss5_ep;
|
struct ss5_endpoint *ss5_ep;
|
||||||
char name[32]; /* name of link for debugging */
|
char name[32]; /* name of link for debugging */
|
||||||
|
|
||||||
/* call states */
|
/* call states */
|
||||||
enum ss5_state state; /* state of link */
|
enum ss5_state state; /* state of link */
|
||||||
struct timer timer; /* for several timeouts */
|
struct timer timer; /* for several timeouts */
|
||||||
uint32_t cc_callref; /* ref to CC call */
|
|
||||||
osmo_cc_session_t *cc_session; /* audio session description */
|
|
||||||
osmo_cc_session_codec_t *codec; /* selected codec */
|
|
||||||
char callerid[65]; /* current caller id (outgoing only) */
|
char callerid[65]; /* current caller id (outgoing only) */
|
||||||
char dialing[33]; /* current dial string (send or receive) */
|
char dialing[33]; /* current dial string (send or receive) */
|
||||||
|
|
||||||
/* audio processing */
|
/* audio processing */
|
||||||
jitter_t tx_dejitter; /* jitter buffer for audio from CC */
|
|
||||||
dsp_t dsp; /* all dsp processing */
|
dsp_t dsp; /* all dsp processing */
|
||||||
sample_t *delay_buffer; /* buffer for delaying audio */
|
|
||||||
int delay_length;
|
|
||||||
int delay_index;
|
|
||||||
} ss5_t;
|
} ss5_t;
|
||||||
|
|
||||||
/* SS5 endpoint definition */
|
/* SS5 endpoint definition */
|
||||||
typedef struct ss5_endpoint {
|
typedef struct ss5_endpoint {
|
||||||
osmo_cc_endpoint_t cc_ep;
|
osmo_cc_endpoint_t cc_ep;
|
||||||
ss5_t *link_list;
|
dsp_t *dsp_list;
|
||||||
double samplerate;
|
|
||||||
int suppress_disconnect; /* do not forward disconnect towards CC */
|
int suppress_disconnect; /* do not forward disconnect towards CC */
|
||||||
int prevent_blueboxing; /* extend release-guard, so outgoing exchange releases */
|
int prevent_blueboxing; /* extend release-guard, so outgoing exchange releases */
|
||||||
int crosstalk; /* mix crosstalk from TX to RX */
|
|
||||||
int comfort_noise; /* add comfort noise before answer and after disconnect */
|
|
||||||
int delay_ms; /* add delay to simulate long distance lines */
|
|
||||||
double sense_db; /* increase sensitivity of decoder by this value */
|
|
||||||
} ss5_endpoint_t;
|
} ss5_endpoint_t;
|
||||||
|
|
||||||
void refresh_status(void);
|
void refresh_status(void);
|
||||||
ss5_endpoint_t *ss5_ep_create(const char *ep_name, int links, int prevent_blueboxing, int crosstalk, int delay_ms, int comfort_noise, int suppress_disconnect, double sense_db);
|
ss5_endpoint_t *ss5_ep_create(const char *ep_name, int links, int prevent_blueboxing, int suppress_disconnect, int crosstalk, int comfort_noise, int delay_ms, double sense_db);
|
||||||
void ss5_ep_destroy(ss5_endpoint_t *ss5_ep);
|
void ss5_ep_destroy(ss5_endpoint_t *ss5_ep);
|
||||||
void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg);
|
void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue