1
0
Fork 0

Preparte for Bell system; Put common code into lib

This commit is contained in:
Andreas Eversberg 2023-05-29 14:54:55 +02:00
parent 48dd37e1ae
commit 91e8521071
12 changed files with 183 additions and 164 deletions

1
.gitignore vendored
View File

@ -42,4 +42,5 @@ src/libsample/libsample.a
src/libtimer/libtimer.a
src/libselect/libselect.a
src/libfilter/libfilter.a
src/common/libcommon.a
src/ss5/osmo-cc-ss5-endpoint

View File

@ -87,6 +87,7 @@ AC_OUTPUT(
src/libosmocc/Makefile
src/libg711/Makefile
src/libfilter/Makefile
src/common/Makefile
src/ss5/Makefile
src/Makefile
Makefile)

View File

@ -10,5 +10,6 @@ SUBDIRS = \
libosmocc \
libg711 \
libfilter \
common \
ss5

8
src/common/Makefile.am Normal file
View File

@ -0,0 +1,8 @@
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
noinst_LIBRARIES = libcommon.a
libcommon_a_SOURCES = \
mf.c \
dsp.c

View File

@ -17,7 +17,7 @@
* 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 <string.h>
@ -29,7 +29,7 @@
#include <sys/types.h>
#include <arpa/inet.h>
#include "../libdebug/debug.h"
#include "ss5.h"
#include "dsp.h"
//#define DEBUG_DEMODULATOR
@ -50,16 +50,20 @@ static double tone_diff_ampl_sq[NUM_TONES];
#define SPLIT_DURATION 0.030
#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];
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));
dsp->priv = priv;
strncpy(dsp->name, name, sizeof(dsp->name - 1));
dsp->samplerate = samplerate;
dsp->crosstalk = crosstalk;
dsp->comfort_noise = comfort_noise;
dsp->interrupt_duration = (int)(1000.0 * INTERRUPT_DURATION);
dsp->split_duration = (int)(1000.0 * SPLIT_DURATION);
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)
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;
}
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) {
mf_mod_exit(dsp->mf_mod);
dsp->mf_mod = NULL;
}
/* free FM demodulator */
if (dsp->mf_demod) {
mf_demod_exit(dsp->mf_demod);
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) */
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 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;
/* get audio from jitter buffer */
jitter_load(&ss5_a->tx_dejitter, samples[0], length);
jitter_load(&ss5_b->tx_dejitter, samples[1], length);
jitter_load(&dsp_a->tx_dejitter, samples[0], length);
jitter_load(&dsp_b->tx_dejitter, samples[1], length);
/* 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++)
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++)
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 */
count1 = assemble_tones(&ss5_a->dsp, mask, length);
mf_mod(ss5_a->dsp.mf_mod, mask, samples[0], count1);
count2 = assemble_tones(&ss5_b->dsp, mask, length);
mf_mod(ss5_b->dsp.mf_mod, mask, samples[1], count2);
count1 = assemble_tones(dsp_a, mask, length);
mf_mod(dsp_a->mf_mod, mask, samples[0], count1);
count2 = assemble_tones(dsp_b, mask, length);
mf_mod(dsp_b->mf_mod, mask, samples[1], count2);
/* optionally add some crosstalk */
if (ss5_a->ss5_ep->crosstalk) {
if (dsp_a->crosstalk) {
/* use count, since it carries number of samples with signalling */
for (i = 0; i < count1; i++)
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 */
for (i = 0; i < count2; i++)
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 ! */
/* optionally add one way delay */
if (ss5_b->delay_buffer) {
if (dsp_b->delay_buffer) {
for (i = 0; i < length; i++) {
s = ss5_b->delay_buffer[ss5_b->delay_index];
ss5_b->delay_buffer[ss5_b->delay_index] = samples[0][i];
if (++(ss5_b->delay_index) == ss5_b->delay_length)
ss5_b->delay_index = 0;
s = dsp_b->delay_buffer[dsp_b->delay_index];
dsp_b->delay_buffer[dsp_b->delay_index] = samples[0][i];
if (++(dsp_b->delay_index) == dsp_b->delay_length)
dsp_b->delay_index = 0;
samples[0][i] = s;
}
}
if (ss5_a->delay_buffer) {
if (dsp_a->delay_buffer) {
for (i = 0; i < length; i++) {
s = ss5_a->delay_buffer[ss5_a->delay_index];
ss5_a->delay_buffer[ss5_a->delay_index] = samples[1][i];
if (++(ss5_a->delay_index) == ss5_a->delay_length)
ss5_a->delay_index = 0;
s = dsp_a->delay_buffer[dsp_a->delay_index];
dsp_a->delay_buffer[dsp_a->delay_index] = samples[1][i];
if (++(dsp_a->delay_index) == dsp_a->delay_length)
dsp_a->delay_index = 0;
samples[1][i] = s;
}
}
/* demodulate and call tone detector */
mf_demod(ss5_b->dsp.mf_demod, samples[0], length, levels_squared);
detect_tones(&ss5_b->dsp, samples[0], levels_squared, length, 1);
mf_demod(ss5_a->dsp.mf_demod, samples[1], length, levels_squared);
detect_tones(&ss5_a->dsp, samples[1], levels_squared, length, 0);
mf_demod(dsp_b->mf_demod, samples[0], length, levels_squared);
detect_tones(dsp_b->priv, samples[0], levels_squared, length, 1);
mf_demod(dsp_a->mf_demod, samples[1], length, levels_squared);
detect_tones(dsp_a->priv, samples[1], levels_squared, length, 0);
/* 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);
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);
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) */
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;
if (!ss5_ep_sunrise) {
if (!sunrise_list) {
/* 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) {
ss5_a = ss5_b;
ss5_b = ss5_b->next;
if (!ss5_b)
for (dsp_b = sunset_list; dsp_b; dsp_b = dsp_b->next) {
dsp_a = dsp_b;
dsp_b = dsp_b->next;
if (!dsp_b)
break;
process_audio(ss5_a, ss5_b, len);
process_audio(dsp_a, dsp_b, len);
}
} else {
/* 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) {
process_audio(ss5_a, ss5_b, len);
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(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 */
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;
sample_t samples[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)

View File

@ -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 {
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;
/* tone generation */
@ -28,15 +36,27 @@ typedef struct dsp {
int mf_detect_duration; /* MF tone duration in milliseconds */
int detect_count; /* counter for tone detection */
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;
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);
void dsp_cleanup_inst(dsp_t *dsp);
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_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 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);

View File

@ -4,14 +4,13 @@ bin_PROGRAMS = \
osmo-cc-ss5-endpoint
osmo_cc_ss5_endpoint_SOURCES = \
mf.c \
dsp.c \
ss5.c \
display_status.c \
main.c
osmo_cc_ss5_endpoint_LDADD = \
$(COMMON_LA) \
../common/libcommon.a \
../libdebug/libdebug.a \
../liboptions/liboptions.a \
../libsample/libsample.a \

View File

@ -234,7 +234,7 @@ static void clock_timeout(void __attribute__((unused)) *data)
timer_start(&clock_timer, last_time_clock - now);
/* 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 */
c = get_char();
@ -280,14 +280,14 @@ int main(int argc, char *argv[])
}
/* 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)
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);
if (rc < 0)
goto error;
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)
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);

View File

@ -92,6 +92,7 @@ void refresh_status(void)
{
osmo_cc_endpoint_t *ep;
ss5_endpoint_t *ss5_ep;
dsp_t *dsp;
ss5_t *ss5;
int i;
@ -99,10 +100,12 @@ void refresh_status(void)
for (ep = osmo_cc_endpoint_list; ep; ep = ep->next) {
ss5_ep = ep->priv;
if (!ss5_ep->link_list)
if (!ss5_ep->dsp_list)
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_end();
@ -125,20 +128,20 @@ void ss5_new_state(ss5_t *ss5, enum ss5_state state)
static void link_reset(ss5_t *ss5)
{
/* unlink callref */
ss5->cc_callref = 0;
ss5->dsp.cc_callref = 0;
/* stop timer */
timer_stop(&ss5->timer);
/* free session description */
if (ss5->cc_session) {
osmo_cc_free_session(ss5->cc_session);
ss5->cc_session = NULL;
ss5->codec = NULL;
if (ss5->dsp.cc_session) {
osmo_cc_free_session(ss5->dsp.cc_session);
ss5->dsp.cc_session = NULL;
ss5->dsp.codec = NULL;
}
/* reset jitter buffer */
jitter_reset(&ss5->tx_dejitter);
jitter_reset(&ss5->dsp.tx_dejitter);
/* set recognition time */
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 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;
int rc;
ss5_t *ss5;
dsp_t **dsp_p;
ss5 = calloc(1, sizeof(*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_p = &ss5_ep->link_list;
while (*ss5_p)
ss5_p = &((*ss5_p)->next);
*ss5_p = ss5;
/* debug name */
snprintf(ss5->name, sizeof(ss5->name) - 1, "%s/%d", ep_name, linkid);
/* 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 */
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 */
link_reset(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");
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)
{
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 */
ss5_new_state(ss5, SS5_STATE_IDLE);
@ -214,33 +216,15 @@ static void link_destroy(ss5_t *ss5)
/* exit 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 */
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");
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;
int i;
@ -251,16 +235,11 @@ ss5_endpoint_t *ss5_ep_create(const char *ep_name, int links, int prevent_bluebo
abort();
}
ss5_ep->samplerate = 8000;
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->sense_db = sense_db;
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");
@ -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)
{
/* destroy all calls */
while (ss5_ep->link_list)
link_destroy(ss5_ep->link_list);
while (ss5_ep->dsp_list)
link_destroy(ss5_ep->dsp_list->priv);
free(ss5_ep);
@ -304,7 +283,7 @@ static void release_call(ss5_t *ss5, uint8_t isdn_cause)
/* cause */
osmo_cc_add_ie_cause(new_msg, OSMO_CC_LOCATION_BEYOND_INTERWORKING, isdn_cause, 0, 0);
/* 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)
@ -320,7 +299,7 @@ static void disconnect_call(ss5_t *ss5, uint8_t isdn_cause)
/* cause */
osmo_cc_add_ie_cause(new_msg, OSMO_CC_LOCATION_BEYOND_INTERWORKING, isdn_cause, 0, 0);
/* 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)
@ -334,7 +313,7 @@ static void proceed_call(ss5_t *ss5, const char *sdp)
/* sdp */
osmo_cc_add_ie_sdp(new_msg, sdp);
/* 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)
@ -344,7 +323,7 @@ static void alert_call(ss5_t *ss5)
/* create osmo-cc message */
new_msg = osmo_cc_new_msg(OSMO_CC_MSG_ALERT_IND);
/* 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)
@ -354,7 +333,7 @@ static void answer_call(ss5_t *ss5)
/* create osmo-cc message */
new_msg = osmo_cc_new_msg(OSMO_CC_MSG_SETUP_CNF);
/* 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)
@ -364,7 +343,7 @@ static void setup_comp_call(ss5_t *ss5)
/* create osmo-cc message */
new_msg = osmo_cc_new_msg(OSMO_CC_MSG_SETUP_COMP_IND);
/* 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') {
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 */
if (ss5->cc_callref) {
if (ss5->dsp.cc_callref) {
/* send release indication towards CC */
release_call(ss5, OSMO_CC_ISDN_CAUSE_NORM_CALL_CLEAR);
/* remove ref */
ss5->cc_callref = 0;
ss5->dsp.cc_callref = 0;
}
/* stop timer */
timer_stop(&ss5->timer);
@ -856,8 +835,8 @@ void receive_digit(void *priv, char digit, double dbm)
/* called number */
osmo_cc_add_ie_called(msg, type, OSMO_CC_PLAN_TELEPHONY, dialing);
/* sdp offer */
ss5->cc_session = osmo_cc_helper_audio_offer(&ss5->ss5_ep->cc_ep.session_config, ss5, codecs, down_audio, msg, 1);
if (!ss5->cc_session) {
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->dsp.cc_session) {
osmo_cc_free_msg(msg);
PDEBUG_CHAN(DSS5, DEBUG_NOTICE, "Failed to offer audio, sending 'clear-back'.\n");
/* send clear-back */
@ -868,9 +847,9 @@ void receive_digit(void *priv, char digit, double dbm)
}
/* create new call */
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 */
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 */
ss5_new_state(ss5, SS5_STATE_IN_INACTIVE);
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)
{
ss5_endpoint_t *ss5_ep = ep->priv;
dsp_t *dsp;
ss5_t *ss5;
osmo_cc_msg_t *new_msg;
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;
/* hunt for callref */
ss5 = ss5_ep->link_list;
while (ss5) {
if (ss5->cc_callref == callref)
dsp = ss5_ep->dsp_list;
while (dsp) {
if (dsp->cc_callref == callref)
break;
ss5 = ss5->next;
dsp = dsp->next;
}
ss5 = (dsp) ? dsp->priv : NULL;
/* process SETUP */
if (!ss5) {
@ -998,19 +979,21 @@ void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg)
goto done;
}
/* hunt free ss5 instance */
ss5 = ss5_ep->link_list;
while (ss5) {
dsp = ss5_ep->dsp_list;
while (dsp) {
ss5 = dsp->priv;
if (ss5->state == SS5_STATE_IDLE)
break;
ss5 = ss5->next;
dsp = dsp->next;
}
ss5 = (dsp) ? dsp->priv : NULL;
if (!ss5) {
PDEBUG(DSS5, DEBUG_NOTICE, "No free ss5 instance, rejecting.\n");
reject_call(ss5_ep, callref, OSMO_CC_ISDN_CAUSE_NO_CIRCUIT_CHAN);
goto done;
}
/* link with cc */
ss5->cc_callref = callref;
ss5->dsp.cc_callref = callref;
}
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]) {
PDEBUG_CHAN(DSS5, DEBUG_NOTICE, "No number given, call is rejected!\n");
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);
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)
goto inv_nr;
/* 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) {
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);
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_ALERT_REQ: /* call of endpoint is ringing */
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) {
codec_failed:
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;
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]);
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)
goto codec_failed;
/* 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_REL_REQ: /* call has been released */
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)
goto codec_failed;
/* 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->type = OSMO_CC_MSG_REL_IND;
/* 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 */
link_reset(ss5);
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->type = OSMO_CC_MSG_REL_CNF;
/* 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 */
if (msg->type != OSMO_CC_MSG_DISC_REQ)

View File

@ -1,12 +1,5 @@
#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"
#include "dsp.h"
#include "../common/dsp.h"
enum ss5_state {
SS5_STATE_NULL = 0,
@ -45,42 +38,29 @@ struct ss5_endpoint;
/* SS5 link definition */
typedef struct ss5 {
struct ss5 *next;
struct ss5_endpoint *ss5_ep;
char name[32]; /* name of link for debugging */
/* call states */
enum ss5_state state; /* state of link */
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 dialing[33]; /* current dial string (send or receive) */
/* audio processing */
jitter_t tx_dejitter; /* jitter buffer for audio from CC */
dsp_t dsp; /* all dsp processing */
sample_t *delay_buffer; /* buffer for delaying audio */
int delay_length;
int delay_index;
} ss5_t;
/* SS5 endpoint definition */
typedef struct ss5_endpoint {
osmo_cc_endpoint_t cc_ep;
ss5_t *link_list;
double samplerate;
dsp_t *dsp_list;
int suppress_disconnect; /* do not forward disconnect towards CC */
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;
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 cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg);