Compare commits

...

5 Commits

Author SHA1 Message Date
Andreas Eversberg 49c2600165 Change low pass filter to second order with one iteration 2023-11-08 22:12:20 +01:00
Andreas Eversberg d0c08f4f7d Add R1 system 2023-11-08 22:11:49 +01:00
Andreas Eversberg 2483f1c2b1 Move more common code; make it usable for SS5 and R1 2023-11-08 22:11:43 +01:00
Andreas Eversberg 91e8521071 Preparte for Bell system; Put common code into lib 2023-06-11 10:32:45 +02:00
Andreas Eversberg 48dd37e1ae Update libs 2023-06-11 10:32:42 +02:00
37 changed files with 2625 additions and 984 deletions

2
.gitignore vendored
View File

@ -42,4 +42,6 @@ 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
src/r1/osmo-cc-r1-endpoint

View File

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

View File

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

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

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

345
src/common/common.c Normal file
View File

@ -0,0 +1,345 @@
/* common process
*
* (C) 2020 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/>.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <sys/types.h>
#include "../libdebug/debug.h"
#include "../libtimer/timer.h"
#include "../libselect/select.h"
#include "../libosmocc/endpoint.h"
#include "../libosmocc/helper.h"
#include "common.h"
/*
* generate messages towards CC
*/
void reject_call(osmo_cc_endpoint_t *cc_ep, uint32_t callref, uint8_t isdn_cause)
{
osmo_cc_msg_t *new_msg;
/* create osmo-cc message */
new_msg = osmo_cc_new_msg(OSMO_CC_MSG_REJ_IND);
/* 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(cc_ep, callref, new_msg);
}
void release_call(osmo_cc_endpoint_t *cc_ep, uint32_t callref, uint8_t isdn_cause)
{
osmo_cc_msg_t *new_msg;
/* create osmo-cc message */
new_msg = osmo_cc_new_msg(OSMO_CC_MSG_REL_IND);
/* 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(cc_ep, callref, new_msg);
}
void disconnect_call(osmo_cc_endpoint_t *cc_ep, uint32_t callref, uint8_t isdn_cause)
{
osmo_cc_msg_t *new_msg;
/* create osmo-cc message */
new_msg = osmo_cc_new_msg(OSMO_CC_MSG_DISC_IND);
/* progress */
osmo_cc_add_ie_progress(new_msg, OSMO_CC_CODING_ITU_T, OSMO_CC_LOCATION_BEYOND_INTERWORKING, OSMO_CC_PROGRESS_INBAND_INFO_AVAILABLE);
/* 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(cc_ep, callref, new_msg);
}
void proceed_call(osmo_cc_endpoint_t *cc_ep, uint32_t callref, const char *sdp)
{
osmo_cc_msg_t *new_msg;
/* create osmo-cc message */
new_msg = osmo_cc_new_msg(OSMO_CC_MSG_PROC_IND);
/* progress */
osmo_cc_add_ie_progress(new_msg, OSMO_CC_CODING_ITU_T, OSMO_CC_LOCATION_BEYOND_INTERWORKING, OSMO_CC_PROGRESS_INBAND_INFO_AVAILABLE);
/* sdp */
osmo_cc_add_ie_sdp(new_msg, sdp);
/* send message to osmo-cc */
osmo_cc_ll_msg(cc_ep, callref, new_msg);
}
void alert_call(osmo_cc_endpoint_t *cc_ep, uint32_t callref)
{
osmo_cc_msg_t *new_msg;
/* create osmo-cc message */
new_msg = osmo_cc_new_msg(OSMO_CC_MSG_ALERT_IND);
/* send message to osmo-cc */
osmo_cc_ll_msg(cc_ep, callref, new_msg);
}
void answer_call(osmo_cc_endpoint_t *cc_ep, uint32_t callref)
{
osmo_cc_msg_t *new_msg;
/* create osmo-cc message */
new_msg = osmo_cc_new_msg(OSMO_CC_MSG_SETUP_CNF);
/* send message to osmo-cc */
osmo_cc_ll_msg(cc_ep, callref, new_msg);
}
void setup_comp_call(osmo_cc_endpoint_t *cc_ep, uint32_t callref)
{
osmo_cc_msg_t *new_msg;
/* 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(cc_ep, callref, new_msg);
}
/*
* dial string generation and parsing
*/
static char *prefix_1_digit[] = { "1", "7", NULL };
static char *prefix_2_digit[] = {
"20", "27", "28", "30", "31", "32", "33", "34", "36", "39", "40", "41",
"43", "44", "45", "46", "47", "48", "49", "51", "52", "53", "54", "55",
"56", "57", "58", "60", "61", "62", "63", "64", "65", "66", "81", "82",
"83", "84", "86", "89", "90", "91", "92", "93", "94", "95", "98",
NULL };
/* use number and number type to generate an SS5 dial string
* the digits are checked if they can be dialed
* if the number is already in SS5 format, only digits are checked
*/
int generate_dial_string(uint8_t type, const char *dialing, char *string, int string_size)
{
int full_string_given = 0;
int i, ii;
if ((int)strlen(dialing) + 4 > string_size) {
PDEBUG(DSS5, DEBUG_NOTICE, "Dial string is too long for our digit register, call is rejected!\n");
return -EINVAL;
}
/* check for correct digits */
for (i = 0, ii = strlen(dialing); i < ii; i++) {
/* string may start with 'a' or 'b', but then 'c' must be the last digit */
if (dialing[i] == 'a' || dialing[i] == 'b') {
full_string_given = 1;
if (dialing[ii - 1] != 'c') {
PDEBUG(DSS5, DEBUG_NOTICE, "Number starts with 'a' (KP1) or 'b' (KP2) but missing 'c' (ST) at the end, call is rejected!\n");
return -EINVAL;
}
/* remove check of last digit 'c' */
--ii;
continue;
}
/* string must only consist of numerical digits and '*' (code 11) and '#' (code 12) */
if (!strchr("0123456789*#", dialing[i])) {
PDEBUG(DSS5, DEBUG_NOTICE, "Number has invalid digits, call is rejected!\n");
return -EINVAL;
}
}
/* if full string with 'a'/'b' and 'c' is given, we have complete dial string */
if (full_string_given) {
strcpy(string, dialing);
return 0;
}
/* if number is not of international type, create national dial string */
if (type != OSMO_CC_TYPE_INTERNATIONAL) {
// make GCC happy
strcpy(string, "a0");
strcat(string, dialing);
strcat(string, "c");
return 0;
}
/* check international prefix with length of 1 digit */
if ((int)strlen(dialing) < 1) {
PDEBUG(DSS5, DEBUG_NOTICE, "International number too short to get country code from, call is rejected!\n");
return -EINVAL;
}
for (i = 0; prefix_1_digit[i]; i++) {
if (prefix_1_digit[i][0] == dialing[0])
break;
}
/* if number is of international type, create international dial string */
if (prefix_1_digit[i]) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-overflow"
sprintf(string, "b%c0%sc", dialing[0], dialing + 1);
#pragma GCC diagnostic pop
return 0;
}
/* check international prefix with length of 2 digits */
if ((int)strlen(dialing) < 2) {
PDEBUG(DSS5, DEBUG_NOTICE, "International number too short to get country code from, call is rejected!\n");
return -EINVAL;
}
for (i = 0; prefix_2_digit[i]; i++) {
if (prefix_2_digit[i][0] == dialing[0]
&& prefix_2_digit[i][1] == dialing[1])
break;
}
/* if number is of international type, create international dial string */
if (prefix_2_digit[i]) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-overflow"
sprintf(string, "b%c%c0%sc", dialing[0], dialing[1], dialing + 2);
#pragma GCC diagnostic pop
return 0;
}
/* check international prefix with length of 3 digits */
if ((int)strlen(dialing) < 3) {
PDEBUG(DSS5, DEBUG_NOTICE, "International number too short to get country code from, call is rejected!\n");
return -EINVAL;
}
/* if number is of international type, create international dial string */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-overflow"
sprintf(string, "b%c%c%c0%sc", dialing[0], dialing[1], dialing[2], dialing + 3);
#pragma GCC diagnostic pop
return 0;
}
/* parse received SS5 dial string and convert it into a national or international number */
int parse_dial_string(uint8_t *type, char *dialing, int dialing_size, const char *string)
{
char kp_digit;
const char *prefix;
int length;
int i;
/* remove start and stop digits, set string after start digit and set length to digits between start and stop */
if (string[0] != 'a' && string[0] != 'b') {
PDEBUG(DSS5, DEBUG_NOTICE, "Received digits do not start with 'a' (KP1) nor 'b' (KP2), call is rejected!\n");
return -EINVAL;
}
length = strlen(string) - 1;
if (string[length] != 'c') {
PDEBUG(DSS5, DEBUG_NOTICE, "Received digits do end with 'c' (ST), call is rejected!\n");
return -EINVAL;
}
kp_digit = *string++;
length--;
if (length > dialing_size - 1) {
PDEBUG(DSS5, DEBUG_NOTICE, "Received dial string is too long, call is rejected!\n");
return -EINVAL;
}
if (!length) {
PDEBUG(DSS5, DEBUG_NOTICE, "Nothing dialed between KP and ST, call is rejected!\n");
return -EINVAL;
}
/* received local or national call */
if (kp_digit == 'a') {
/* remove discriminaing digit */
if (string[0] == '0') {
string++;
length--;
*type = OSMO_CC_TYPE_NATIONAL;
} else
*type = OSMO_CC_TYPE_UNKNOWN;
strncpy(dialing, string, length);
dialing[length] = '\0';
return 0;
}
/* check international prefix with length of 1 digit */
if (length < 2) {
PDEBUG(DSS5, DEBUG_NOTICE, "International number too short to get country code from, call is rejected!\n");
return -EINVAL;
}
for (i = 0; prefix_1_digit[i]; i++) {
if (prefix_1_digit[i][0] == string[0])
break;
}
/* if number is of international type, create international dial string */
if (prefix_1_digit[i]) {
prefix = string;
string += 1;
length -= 1;
/* remove discriminaing digit */
string++;
--length;
*type = OSMO_CC_TYPE_INTERNATIONAL;
dialing[0] = prefix[0];
strncpy(dialing + 1, string, length);
dialing[1 + length] = '\0';
return 0;
}
/* check international prefix with length of 2 digits */
if (length < 3) {
PDEBUG(DSS5, DEBUG_NOTICE, "International number too short to get country code from, call is rejected!\n");
return -EINVAL;
}
for (i = 0; prefix_2_digit[i]; i++) {
if (prefix_2_digit[i][0] == string[0]
&& prefix_2_digit[i][1] == string[1])
break;
}
/* if number is of international type, create international dial string */
if (prefix_2_digit[i]) {
prefix = string;
string += 2;
length -= 2;
/* remove discriminaing digit */
string++;
--length;
*type = OSMO_CC_TYPE_INTERNATIONAL;
dialing[0] = prefix[0];
dialing[1] = prefix[1];
strncpy(dialing + 2, string, length);
dialing[2 + length] = '\0';
return 0;
}
/* check international prefix with length of 3 digits */
if (length < 4) {
PDEBUG(DSS5, DEBUG_NOTICE, "International number too short to get country code from, call is rejected!\n");
return -EINVAL;
}
/* if number is of international type, create international dial string */
prefix = string;
string += 3;
length -= 3;
/* remove discriminaing digit */
string++;
--length;
*type = OSMO_CC_TYPE_INTERNATIONAL;
dialing[0] = prefix[0];
dialing[1] = prefix[1];
dialing[2] = prefix[2];
strncpy(dialing + 3, string, length);
dialing[3 + length] = '\0';
return 0;
}

11
src/common/common.h Normal file
View File

@ -0,0 +1,11 @@
void reject_call(osmo_cc_endpoint_t *cc_ep, uint32_t callref, uint8_t isdn_cause);
void release_call(osmo_cc_endpoint_t *cc_ep, uint32_t callref, uint8_t isdn_cause);
void disconnect_call(osmo_cc_endpoint_t *cc_ep, uint32_t callref, uint8_t isdn_cause);
void proceed_call(osmo_cc_endpoint_t *cc_ep, uint32_t callref, const char *sdp);
void alert_call(osmo_cc_endpoint_t *cc_ep, uint32_t callref);
void answer_call(osmo_cc_endpoint_t *cc_ep, uint32_t callref);
void setup_comp_call(osmo_cc_endpoint_t *cc_ep, uint32_t callref);
int generate_dial_string(uint8_t type, const char *dialing, char *string, int string_size);
int parse_dial_string(uint8_t *type, char *dialing, int dialing_size, const char *string);

View File

@ -4,6 +4,6 @@
void display_status_on(int on);
void display_status_start(void);
void display_status_line(const char *if_name, int link_count, const char *from_id, const char *to_id, enum ss5_state state);
void display_status_line(const char *if_name, int link_count, const char *from_id, const char *to_id, const char *state_name);
void display_status_end(void);

View File

@ -22,7 +22,6 @@
#include <string.h>
#include <sys/types.h>
#include "../libdebug/debug.h"
#include "ss5.h"
#include "display.h"
static int status_on = 0;
@ -97,7 +96,7 @@ void display_status_start(void)
line_count = 1;
}
void display_status_line(const char *if_name, int link_count, const char *from_id, const char *to_id, enum ss5_state state)
void display_status_line(const char *if_name, int link_count, const char *from_id, const char *to_id, const char *state_name)
{
char line[MAX_DISPLAY_WIDTH + 4096];
char color[MAX_DISPLAY_WIDTH + 4096];
@ -136,8 +135,8 @@ void display_status_line(const char *if_name, int link_count, const char *from_i
index += 4 + from_len + 2 + 4 + to_len;
line[index] = '\0';
strcpy(line + index, ss5_state_names[state]);
memset(color + index, 7, strlen(ss5_state_names[state]));
strcpy(line + index, state_name);
memset(color + index, 7, strlen(state_name));
}
/* store line without CR, but not more than MAX_DISPLAY_WIDTH - 1 */

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,8 @@
#include <sys/types.h>
#include <arpa/inet.h>
#include "../libdebug/debug.h"
#include "ss5.h"
#include "dsp.h"
#include "sit.h"
//#define DEBUG_DEMODULATOR
@ -37,8 +38,9 @@
#define db2level(db) pow(10, (double)(db) / 20.0)
#define level2db(level) (20 * log10(level))
/* SS5 defines -9 dB (tx), -16 dB (min) for SF, R1 defines -8/-20 dB (tx), -27 dB (min) for SF */
static double tone_dbm[NUM_TONES] = { -7, -7, -7, -7, -7, -7, -9, -9 };
static double tone_freq[NUM_TONES] = { 700, 900, 1100, 1300, 1500, 1700, 2400, 2600 };
static double tone_freq[NUM_TONES] = { 700, 900, 1100, 1300, 1500, 1700, 2600, 2400 };
static double tone_width[NUM_TONES] = { 25, 25, 25, 25, 25, 25, 25, 25 };
static double tone_min_dbm[NUM_TONES] = { -14, -14, -14, -14, -14, -14, -16, -16 };
@ -46,23 +48,36 @@ static double tone_min_ampl_sq[NUM_TONES];
static double tone_diff_db[NUM_TONES] = { 4, 4, 4, 4, 4, 4, 5, 5 };
static double tone_diff_ampl_sq[NUM_TONES];
#define INTERRUPT_DURATION 0.015
#define SPLIT_DURATION 0.030
#define MF_RECOGNITION 0.025
void dsp_set_sf(double sf_db, double sf_min_db)
{
tone_dbm[6] = sf_db;
tone_dbm[7] = sf_db;
tone_min_dbm[6] = sf_min_db;
tone_min_dbm[7] = sf_min_db;
}
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 interrupt_recognition, double split_recognition, double mf_recognition, double kp_digit_duration, double other_digit_duration, double digit_pause, double pulse_pause, double notch, int ss5)
{
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->interrupt_duration = (int)(1000.0 * INTERRUPT_DURATION);
dsp->split_duration = (int)(1000.0 * SPLIT_DURATION);
dsp->mf_detect_duration = (int)(1000.0 * MF_RECOGNITION);
dsp->crosstalk = crosstalk;
dsp->comfort_noise = comfort_noise;
// NO interrupt recognition, because the filter itself has a slow response
// dsp->interrupt_recognition = (int)(1000.0 * interrupt_recognition);
dsp->split_recognition = (int)(1000.0 * split_recognition);
dsp->mf_recognition = (int)(1000.0 * mf_recognition);
dsp->kp_digit_duration = kp_digit_duration;
dsp->other_digit_duration = other_digit_duration;
dsp->digit_pause = digit_pause;
dsp->pulse_pause = pulse_pause;
dsp->ms_per_sample = 1000.0 / samplerate;
dsp->detect_tone = ' ';
@ -79,26 +94,54 @@ int dsp_init_inst(dsp_t *dsp, void *priv, double samplerate, double sense_db)
return -EINVAL;
/* init MF demodulator */
dsp->mf_demod = mf_demod_init(samplerate, NUM_TONES, tone_freq, tone_width);
dsp->mf_demod = mf_demod_init(samplerate, NUM_TONES - (!ss5), tone_freq, tone_width);
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();
/* notch filter */
if (notch) {
dsp->notch = 1;
iir_notch_init(&dsp->notch_filter, notch, (int)dsp->samplerate, 1, 4);
}
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);
}
/*
@ -124,17 +167,13 @@ static struct dsp_digits {
{ 'a', 0x04 + 0x20 }, /* KP1 */
{ 'b', 0x08 + 0x20 }, /* KP2 */
{ 'c', 0x10 + 0x20 }, /* ST */
{ 'A', 0x40 }, /* 2400 answer, acknowledge */
{ 'B', 0x80 }, /* 2600 busy */
{ 'B', 0x40 }, /* 2600 busy */
{ 'A', 0x80 }, /* 2400 answer, acknowledge */
{ 'C', 0x40 + 0x80 }, /* 2600+2400 clear forward */
{ ' ', 0 }, /* silence */
{ 0 , 0 },
};
#define KP_DIGIT_DURATION 0.100
#define OTHER_DIGIT_DURATION 0.055
#define DIGIT_PAUSE 0.055
/* set signaling tone duration threshold */
void set_sig_detect_duration(dsp_t *dsp, double duration_AB, double duration_C)
{
@ -144,7 +183,7 @@ void set_sig_detect_duration(dsp_t *dsp, double duration_AB, double duration_C)
}
/* set given tone with duration (ms) or continuously (0) */
void set_tone(dsp_t *dsp, char tone, double duration)
int set_tone(dsp_t *dsp, char tone, double duration)
{
int i;
@ -152,7 +191,7 @@ void set_tone(dsp_t *dsp, char tone, double duration)
if (!tone) {
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Remove tone\n");
return;
return 0;
}
for (i = 0; dsp_digits[i].tone; i++) {
@ -160,12 +199,48 @@ void set_tone(dsp_t *dsp, char tone, double duration)
dsp->tone_mask = dsp_digits[i].mask;
dsp->tone = tone;
dsp->tone_duration = (int)(dsp->samplerate * duration);
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Set tone=\'%c\' duration=%.0fms (mask = 0x%02x)\n", dsp->tone, 1000.0 * duration, dsp->tone_mask);
return;
if (duration)
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Set tone=\'%c\' duration=%.0fms (mask = 0x%02x)\n", dsp->tone, 1000.0 * duration, dsp->tone_mask);
else
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Set tone=\'%c\' duration=continuous (mask = 0x%02x)\n", dsp->tone, dsp->tone_mask);
return 0;
}
}
PDEBUG_CHAN(DDSP, DEBUG_ERROR, "Tone '%c' does not exist.\n", tone);
return -EINVAL;
}
void set_tone_transparent(dsp_t *dsp, int transparent)
{
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Set tones %stransparent.\n", (!transparent) ? "non-" : "");
dsp->tone_transparent = transparent;
}
void set_sit(dsp_t *dsp, int on)
{
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Turn sit %s.\n", (on) ? "on" : "off");
dsp->sit_on = on;
dsp->sit_count = 0;
}
static int digit_to_pulses(char digit)
{
if (digit >= '1' && digit <= '9')
return digit - '0';
if (digit == '0')
return 10;
if (digit == '*')
return 11;
if (digit == '#')
return 12;
return 0;
}
#define SF_PULSE_BREAK 0.060
#define SF_PULSE_MAKE 0.040
/* get next tone from dial string, if any */
static void get_tone_from_dial_string(dsp_t *dsp)
{
@ -174,6 +249,7 @@ static void get_tone_from_dial_string(dsp_t *dsp)
dsp->tone = 0;
next_digit:
if (dsp->dial_index == dsp->dial_length) {
dsp->dial_length = 0;
dialing_complete(dsp->priv);
@ -181,33 +257,73 @@ static void get_tone_from_dial_string(dsp_t *dsp)
}
/* get alternating tone/pause from dial string */
if (!dsp->digit_pause) {
/* digit on */
tone = dsp->dial_string[dsp->dial_index++];
dsp->digit_pause = 1;
if (tone == 'a' || tone == 'b')
duration = KP_DIGIT_DURATION;
else
duration = OTHER_DIGIT_DURATION;
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Send digit \'%c\' from dial string\n", tone);
if (!dsp->digit_on) {
/* start digit */
if (!dsp->pulsedialing) {
/* MF digit on */
tone = dsp->dial_string[dsp->dial_index++];
if (tone == 'a' || tone == 'b')
duration = dsp->kp_digit_duration;
else
duration = dsp->other_digit_duration;
dsp->digit_on = 1;
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Send digit \'%c\' from dial string\n", tone);
} else {
/* SF pulse */
dsp->pulse_num = digit_to_pulses(dsp->dial_string[dsp->dial_index++]);
if (dsp->pulse_num == 0) {
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Skipping digit \'%c\' from dial string that cannot be puled\n", dsp->dial_string[dsp->dial_index]);
goto next_digit;
}
/* pulse on */
tone = 'B';
dsp->pulse_on = 1;
duration = SF_PULSE_BREAK;
dsp->digit_on = 1;
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Send digit \'%c\' from dial string as pulses\n", dsp->dial_string[dsp->dial_index]);
}
} else {
/* digit pause */
tone = ' ';
dsp->digit_pause = 0;
duration = DIGIT_PAUSE;
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Send pause after digit from dial string\n");
/* ongoing digit */
if (dsp->pulse_num) {
if (dsp->pulse_on) {
/* pulse off */
tone = ' ';
dsp->pulse_on = 0;
duration = SF_PULSE_MAKE;
if (++dsp->pulse_count == dsp->pulse_num) {
dsp->pulse_count = 0;
dsp->digit_on = 0;
duration = dsp->pulse_pause;
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Send pause after pulsing digits from dial string\n");
}
} else {
/* pulse on */
tone = 'B';
dsp->pulse_on = 1;
duration = SF_PULSE_BREAK;
}
} else {
/* digit pause */
tone = ' ';
dsp->digit_on = 0;
duration = dsp->digit_pause;
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Send pause after digit from dial string\n");
}
}
set_tone(dsp, tone, duration);
}
/* set given dial string */
void set_dial_string(dsp_t *dsp, const char *dial)
void set_dial_string(dsp_t *dsp, const char *dial, int pulsedialing)
{
dsp->digit_pause = 0;
dsp->digit_on = 0;
strncpy(dsp->dial_string, dial, sizeof(dsp->dial_string) - 1);
dsp->dial_index = 0;
dsp->dial_length = strlen(dsp->dial_string);
dsp->pulse_on = 0;
dsp->pulse_count = 0;
dsp->pulsedialing = pulsedialing;
}
/* determine which tones to be modulated, get next tone, if elapsed */
@ -241,7 +357,7 @@ static int assemble_tones(dsp_t *dsp, uint32_t *mask, int length)
/* detection array for one frequency */
static char decode_one[8] =
{ ' ', ' ', ' ', ' ', ' ', ' ', 'A', 'B' }; /* A = 2400, B = 2600 */
{ ' ', ' ', ' ', ' ', ' ', ' ', 'B', 'A' }; /* A = 2400, B = 2600 */
/* detection matrix for two frequencies */
static char decode_two[8][8] =
@ -256,28 +372,36 @@ static char decode_two[8][8] =
{ ' ', ' ', ' ', ' ', ' ', ' ', 'C', ' ' }
};
#define NONE_MIN_LEVEL_SQUARED
/* determine which tone is played */
static void detect_tones(dsp_t *dsp, sample_t *samples, sample_t **levels_squared, int length, int incoming)
{
int f1, f2;
double f1_level_squared, f2_level_squared;
char tone;
int s, t;
int s, t, l;
for (s = 0; s < length; s++) {
/* mute if split duration reached */
if (dsp->split_duration && dsp->split_count == dsp->split_duration)
samples[s] = 0.0;
/* only perform tone detection every millisecond */
dsp->detect_interval += dsp->ms_per_sample;
if (dsp->detect_interval < 1.0)
/* only perform tone detection/muting every millisecond */
dsp->ms_interval += dsp->ms_per_sample;
dsp->ms_count++;
if (dsp->ms_interval < 1.0)
continue;
dsp->detect_interval -= 1.0;
if (incoming) {
/* mute/notch if split duration reached (this is the chunk, see below for the rest) */
if (dsp->split_recognition && dsp->split_count == dsp->split_recognition) {
/* l is the number of samples required to mute for this interval of one milliseconds */
l = (dsp->ms_count < s + 1) ? dsp->ms_count : s + 1;
if (dsp->notch)
iir_process(&dsp->notch_filter, samples + s + 1 - l, l);
else
memset(samples + s + 1 - l, 0, l * sizeof(*samples));
}
dsp->ms_interval -= 1.0;
dsp->ms_count = 0;
#ifdef DEBUG_DEMODULATOR
if (incoming) {
for (t = 0; t < dsp->mf_demod->tones; t++) {
char level[20];
int db;
@ -289,8 +413,8 @@ static void detect_tones(dsp_t *dsp, sample_t *samples, sample_t **levels_square
printf("%s|", level);
}
printf("\n");
#endif
}
#endif
/* find the tone which is the loudest */
f1 = -1;
@ -318,7 +442,10 @@ static void detect_tones(dsp_t *dsp, sample_t *samples, sample_t **levels_square
if (f2 >= 0 && f2_level_squared < tone_min_ampl_sq[f2])
f2 = -1;
// printf("%s f1=%.0f (%.1f dBm) f2=%.0f (%.1f dBm)\n", CHAN, (f1 >= 0) ? tone_freq[f1] : 0, level2db(sqrt(f1_level_squared)), (f2 >= 0) ? tone_freq[f2] : 0, level2db(sqrt(f2_level_squared)));
#ifdef DEBUG_DEMODULATOR
if (incoming)
printf("%s f1=%.0f (%.1f dBm) f2=%.0f (%.1f dBm)\n", CHAN, (f1 >= 0) ? tone_freq[f1] : 0, level2db(sqrt(f1_level_squared)), (f2 >= 0) ? tone_freq[f2] : 0, level2db(sqrt(f2_level_squared)));
#endif
/* check if no, one or two tones are detected */
if (f1 < 0)
tone = ' ';
@ -330,25 +457,34 @@ static void detect_tones(dsp_t *dsp, sample_t *samples, sample_t **levels_square
else
tone = decode_two[f1][f2];
}
//printf("tone=%c\n", tone);
/* process interrupt counting, keep tone until interrupt counter expires */
if (dsp->detect_tone != ' ' && tone != dsp->detect_tone) {
if (dsp->interrupt_count < dsp->interrupt_duration) {
dsp->interrupt_count++;
tone = dsp->detect_tone;
if (dsp->interrupt_recognition) {
if (dsp->detect_tone != ' ' && tone != dsp->detect_tone) {
#ifdef DEBUG_DEMODULATOR
if (!dsp->interrupt_count) if (incoming)
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "interruption detected s=%d old='%c' new='%c'\n", s, dsp->detect_tone, tone);
#endif
if (dsp->interrupt_count < dsp->interrupt_recognition) {
dsp->interrupt_count++;
tone = dsp->detect_tone;
}
} else {
#ifdef DEBUG_DEMODULATOR
if (dsp->interrupt_count) if (incoming)
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "interruption ceased at count %d s=%d old='%c' new='%c'\n", dsp->interrupt_count, s, dsp->detect_tone, tone);
#endif
dsp->interrupt_count = 0;
}
} else
dsp->interrupt_count = 0;
}
/* split audio, after minimum duration of detecting a tone */
if (tone >= 'A' && tone <= 'C') {
if (dsp->split_count < dsp->split_duration)
if (dsp->split_count < dsp->split_recognition)
dsp->split_count++;
} else
dsp->split_count = 0;
/* some change in tone */
if (dsp->detect_tone != tone) {
if (dsp->detect_count == 0)
@ -360,10 +496,14 @@ static void detect_tones(dsp_t *dsp, sample_t *samples, sample_t **levels_square
if (dsp->detect_count < dsp->sig_detect_duration_AB)
dsp->detect_count++;
else {
#ifdef DEBUG_DEMODULATOR
if (incoming)
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "Tone stable '%c' (%.1f dBm)\n", tone, level2db(sqrt(f1_level_squared)));
#endif
/* sign tone detected */
dsp->detect_count = 0;
dsp->detect_tone = tone;
receive_digit(dsp->priv, tone, level2db(sqrt(f1_level_squared)));
receive_signal(dsp->priv, tone, level2db(sqrt(f1_level_squared)));
}
break;
case 'C':
@ -374,33 +514,45 @@ static void detect_tones(dsp_t *dsp, sample_t *samples, sample_t **levels_square
/* sign tone detected */
dsp->detect_count = 0;
dsp->detect_tone = tone;
receive_digit(dsp->priv, tone, level2db(sqrt(f1_level_squared)));
receive_signal(dsp->priv, tone, level2db(sqrt(f1_level_squared)));
}
break;
case ' ':
/* tone appears or ceases */
/* tone ceases, there is no counting here, since interrupt counting does the job for us */
dsp->detect_count = 0;
dsp->detect_tone = tone;
receive_digit(dsp->priv, tone, 0.0);
if (incoming)
PDEBUG_CHAN(DDSP, DEBUG_DEBUG, "cease\n");
receive_signal(dsp->priv, tone, 0.0);
break;
default:
/* tone appears, wait some time */
if (dsp->detect_count < dsp->mf_detect_duration)
if (dsp->detect_count < dsp->mf_recognition)
dsp->detect_count++;
else {
/* sign tone detected */
dsp->detect_count = 0;
dsp->detect_tone = tone;
receive_digit(dsp->priv, tone, level2db(sqrt(f1_level_squared)));
receive_signal(dsp->priv, tone, level2db(sqrt(f1_level_squared)));
}
}
} else
dsp->detect_count = 0;
}
/* mute/notch if split duration reached (this is the rest, see above for each chunk) */
if (dsp->split_recognition && dsp->split_count == dsp->split_recognition) {
/* l is the number of samples that are left */
l = (dsp->ms_count < s) ? dsp->ms_count : s;
if (dsp->notch)
iir_process(&dsp->notch_filter, samples + s - l, l);
else
memset(samples + s - l, 0, l * sizeof(*samples));
}
}
/* 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,97 +563,103 @@ 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) {
/* optionally add (-36 dBm) 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;
samples[0][i] += (double)((int8_t)random()) / 16384.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;
samples[1][i] += (double)((int8_t)random()) / 16385.0;
}
/* send SIT, if on */
if (dsp_a->sit_on)
dsp_a->sit_count = sit_play(samples[0], dsp_a->sit_count, length);
if (dsp_b->sit_on)
dsp_b->sit_count = sit_play(samples[1], dsp_b->sit_count, 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);
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);
/* optionally add some crosstalk */
if (ss5_a->ss5_ep->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) {
/* use count, since it carries number of samples with signalling */
for (i = 0; i < count2; i++)
samples[0][i] += samples[1][i] / 70.0;
}
count1 = assemble_tones(dsp_a, mask, length);
mf_mod(dsp_a->mf_mod, mask, samples[0], count1, dsp_a->tone_transparent);
count2 = assemble_tones(dsp_b, mask, length);
mf_mod(dsp_b->mf_mod, mask, samples[1], count2, dsp_b->tone_transparent);
/* ! 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, samples[0], levels_squared, length, 1);
mf_demod(dsp_a->mf_demod, samples[1], length, levels_squared);
detect_tones(dsp_a, samples[1], levels_squared, length, 0);
/* optionally add some 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 (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;
}
/* 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 +667,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)

82
src/common/dsp.h Normal file
View File

@ -0,0 +1,82 @@
#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 {
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 */
mf_mod_t *mf_mod; /* MF modulator */
char tone; /* current digit playing or 0 */
int tone_transparent; /* mix tone with audio */
uint32_t tone_mask; /* bit-mask of which MF tones to play */
int tone_duration; /* counter of samples for length of tone */
char dial_string[33]; /* stores digits when dialing number sequence */
int dial_length; /* length of dial string, or 0 */
int dial_index; /* current position at dial string */
int digit_on; /* flag that states if digit is currently playing */
double kp_digit_duration; /* duration of kp digit */
double other_digit_duration; /* duration of other digits */
double digit_pause; /* interdigit pause between */
int pulsedialing; /* using pulses to dial */
int pulse_on; /* flag that states if pulse is currently on */
int pulse_num; /* number of pulses to send */
int pulse_count; /* counter for pulses in one digit */
double pulse_pause; /* interdigit pause between pulse digits */
int sit_on, sit_count; /* sit tone generator */
/* tone detection */
mf_demod_t *mf_demod; /* MF demodulator */
double ms_per_sample; /* how many milliseconds between two samples */
double ms_interval; /* counts milliseconds */
int ms_count; /* counts samples within millisecond interval */
int interrupt_recognition; /* number of milliseconds until interruption is detected */
int interrupt_count; /* counter for interrupt condition */
int split_recognition; /* number of milliseconds until split (mute) condition meats */
int split_count; /* counter for split condition */
int sig_detect_duration_AB; /* signaling tone duration in milliseconds (TONE A/B) */
int sig_detect_duration_C; /* signaling tone duration in milliseconds (TONE C) */
int mf_recognition; /* 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 */
int notch;
iir_filter_t notch_filter; /* remove 2600 Hz */
/* 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;
void dsp_set_sf(double sf_db, double sf_min_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 interrupt_recognition, double split_recognition, double mf_recognition, double kp_digit_duration, double other_digit_duration, double digit_pause, double pulse_pause, double notch, int ss5);
void dsp_cleanup_inst(dsp_t *dsp);
void set_sig_detect_duration(dsp_t *dsp, double duration_AB, double duration_C);
int set_tone(dsp_t *dsp, char tone, double duration);
void set_tone_transparent(dsp_t *dsp, int transparent);
void set_sit(dsp_t *dsp, int on);
void set_dial_string(dsp_t *dsp, const char *dial, int pulsedialing);
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);
void receive_signal(void *priv, char digit, double dbm);
void dialing_complete(void *priv);

View File

@ -100,13 +100,14 @@ void mf_mod_exit(mf_mod_t *mod)
free(mod);
}
void mf_mod(mf_mod_t *mod, uint32_t *mask, sample_t *samples, int length)
void mf_mod(mf_mod_t *mod, uint32_t *mask, sample_t *samples, int length, int transparent)
{
int t, s;
double phase;
for (s = 0; s < length; s++) {
samples[s] = 0;
if (!transparent)
samples[s] = 0;
for (t = 0; t < mod->tones; t++) {
/* continue phase even on muted tones */
phase = (mod->tone[t].phase += mod->tone[t].rot);
@ -149,9 +150,9 @@ mf_demod_t *mf_demod_init(double samplerate, int tones, double *freq, double *wi
else
demod->tone[t].rot = 2 * M_PI * -freq[t] / samplerate;
/* use fourth order (2 iter) filter, since it is as fast as second order (1 iter) filter */
iir_lowpass_init(&demod->tone[t].lp[0], width[t], samplerate, 2);
iir_lowpass_init(&demod->tone[t].lp[1], width[t], samplerate, 2);
/* use second order (1 iter) filter. */
iir_lowpass_init(&demod->tone[t].lp[0], width[t], samplerate, 1);
iir_lowpass_init(&demod->tone[t].lp[1], width[t], samplerate, 1);
}
return demod;

View File

@ -27,7 +27,7 @@ int mf_init(int _fast_math);
void mf_exit(void);
mf_mod_t *mf_mod_init(double samplerate, int tones, double *freq, double *amplitude);
void mf_mod_exit(mf_mod_t *mod);
void mf_mod(mf_mod_t *mod, uint32_t *mask, sample_t *samples, int length);
void mf_mod(mf_mod_t *mod, uint32_t *mask, sample_t *samples, int length, int transparent);
mf_demod_t *mf_demod_init(double samplerate, int tones, double *freq, double *width);
void mf_demod_exit(mf_demod_t *demod);
void mf_demod(mf_demod_t *demod, sample_t *samples, int length, sample_t **levels_squared);

53
src/common/sit.c Normal file
View File

@ -0,0 +1,53 @@
#include <stdlib.h>
#include <math.h>
#include "../libsample/sample.h"
#include "sit.h"
#define db2level(db) pow(10, (double)(db) / 20.0)
#define SIT_F1 950.0
#define SIT_F2 1400.0
#define SIT_F3 1800.0
#define SIT_LEVEL -24.0 /* -24 dBm */
#define SIT_DURATION 0.330 /* tone duration */
#define SIT_PAUSE 1.0 /* tone pause */
static sample_t *sit_samples;
static int sit_length = 0;
void init_sit(int samplerate)
{
int length, i;
double level = db2level(SIT_LEVEL);
length = (int)((SIT_DURATION * 3 + SIT_PAUSE) * (double)samplerate);
sit_samples = calloc(length, sizeof(*sit_samples));
if (!sit_samples)
abort();
sit_length = length;
length = (int)(SIT_DURATION * (double)samplerate);
for (i = 0; i < length; i++)
sit_samples[i] = sin(2.0 * M_PI * SIT_F1 * (double)i / (double)samplerate) * level;
for (; i < length * 2; i++)
sit_samples[i] = sin(2.0 * M_PI * SIT_F2 * (double)i / (double)samplerate) * level;
for (; i < length * 3; i++)
sit_samples[i] = sin(2.0 * M_PI * SIT_F3 * (double)i / (double)samplerate) * level;
}
void exit_sit(void)
{
free(sit_samples);
sit_length = 0;
}
int sit_play(sample_t *samples, int count, int length)
{
while (length--) {
*samples++ = sit_samples[count];
if (++count == sit_length)
count = 0;
}
return count;
}

5
src/common/sit.h Normal file
View File

@ -0,0 +1,5 @@
void init_sit(int samplerate);
void exit_sit(void);
int sit_play(sample_t *samples, int count, int length);

View File

@ -86,6 +86,7 @@ struct debug_cat {
{ "router", "\033[1;35m" },
{ "stderr", "\033[1;37m" },
{ "ss5", "\033[1;34m" },
{ "r1", "\033[1;34m" },
{ "isdn", "\033[1;35m" },
{ "misdn", "\033[0;34m" },
{ "dss1", "\033[1;34m" },

View File

@ -48,15 +48,16 @@
#define DROUTER 41
#define DSTDERR 42
#define DSS5 43
#define DISDN 44
#define DMISDN 45
#define DDSS1 46
#define DSIP 47
#define DTEL 48
#define DUK0 49
#define DPH 50
#define DDCF77 51
#define DJITTER 52
#define DR1 44
#define DISDN 45
#define DMISDN 46
#define DDSS1 47
#define DSIP 48
#define DTEL 49
#define DUK0 50
#define DPH 51
#define DDCF77 52
#define DJITTER 53
//NOTE: increment mask array, if 127 is exceeded
void lock_debug(void);

View File

@ -88,13 +88,12 @@ void iir_bandpass_init(iir_filter_t *filter, double frequency, int samplerate, i
filter->b2 = (1 - K / Q + K * K) * norm;
}
void iir_notch_init(iir_filter_t *filter, double frequency, int samplerate, int iterations)
void iir_notch_init(iir_filter_t *filter, double frequency, int samplerate, int iterations, double Q)
{
double Fc, Q, K, norm;
double Fc, K, norm;
memset(filter, 0, sizeof(*filter));
filter->iter = iterations;
Q = pow(sqrt(0.5), 1.0 / (double)iterations); /* 0.7071 @ 1 iteration */
Fc = frequency / (double)samplerate;
K = tan(PI * Fc);
norm = 1 / (1 + K / Q + K * K);

View File

@ -10,7 +10,7 @@ typedef struct iir_filter {
void iir_lowpass_init(iir_filter_t *filter, double frequency, int samplerate, int iterations);
void iir_highpass_init(iir_filter_t *filter, double frequency, int samplerate, int iterations);
void iir_bandpass_init(iir_filter_t *filter, double frequency, int samplerate, int iterations);
void iir_notch_init(iir_filter_t *filter, double frequency, int samplerate, int iterations);
void iir_notch_init(iir_filter_t *filter, double frequency, int samplerate, int iterations, double Q);
void iir_process(iir_filter_t *filter, sample_t *samples, int length);
void iir_process_baseband(iir_filter_t *filter, float *baseband, int length);

View File

@ -36,11 +36,11 @@ static osmo_cc_call_t *call_new(osmo_cc_endpoint_t *ep, uint32_t callref)
call = calloc(1, sizeof(*call));
if (!call) {
PDEBUG(DCC, DEBUG_ERROR, "No memory for call process instance.\n");
LOGP(DCC, LOGL_ERROR, "No memory for call process instance.\n");
abort();
}
PDEBUG(DCC, DEBUG_DEBUG, "Creating new call with callref %u.\n", callref);
LOGP(DCC, LOGL_DEBUG, "Creating new call with callref %u.\n", callref);
call->ep = ep;
call->callref = callref;
@ -59,7 +59,7 @@ static void call_delete(osmo_cc_call_t *call)
{
osmo_cc_call_t **cp;
PDEBUG(DCC, DEBUG_DEBUG, "Destroying call with callref %u.\n", call->callref);
LOGP(DCC, LOGL_DEBUG, "Destroying call with callref %u.\n", call->callref);
/* detach from call process list */
cp = &call->ep->call_list;
@ -105,7 +105,7 @@ static const char *state_names[] = {
static void new_call_state(osmo_cc_call_t *call, enum osmo_cc_state new_state)
{
PDEBUG(DCC, DEBUG_DEBUG, "Changing call state with callref %u from %s to %s.\n", call->callref, state_names[call->state], state_names[new_state]);
LOGP(DCC, LOGL_DEBUG, "Changing call state with callref %u from %s to %s.\n", call->callref, state_names[call->state], state_names[new_state]);
call->state = new_state;
}
@ -160,12 +160,12 @@ static int split_address(const char *address, const char **host_p, uint16_t *por
*host_p = osmo_cc_host_of_address(address);
if (!(*host_p)) {
PDEBUG(DCC, DEBUG_ERROR, "Host IP in given address '%s' is invalid.\n", address);
LOGP(DCC, LOGL_ERROR, "Host IP in given address '%s' is invalid.\n", address);
return -EINVAL;
}
portstring = osmo_cc_port_of_address(address);
if (!portstring) {
PDEBUG(DCC, DEBUG_ERROR, "Port number in given address '%s' is not specified or invalid.\n", address);
LOGP(DCC, LOGL_ERROR, "Port number in given address '%s' is not specified or invalid.\n", address);
return -EINVAL;
}
*port_p = atoi(portstring);
@ -220,7 +220,7 @@ static void forward_to_ul(osmo_cc_call_t *call, osmo_cc_msg_t *msg)
if (address && msg->type == OSMO_CC_MSG_SETUP_IND) {
rc = split_address(address, &host, &port);
if (rc < 0) {
PDEBUG(DCC, DEBUG_ERROR, "Given remote peer's address '%s' in setup message is invalid, rejecting call.\n", address);
LOGP(DCC, LOGL_ERROR, "Given remote peer's address '%s' in setup message is invalid, rejecting call.\n", address);
reject:
/* reject, due to error */
osmo_cc_free_msg(msg);
@ -229,21 +229,21 @@ reject:
call_delete(call);
return;
}
PDEBUG(DCC, DEBUG_DEBUG, "Using host IP '%s' and port '%d' from setup message.\n", host, port);
LOGP(DCC, LOGL_DEBUG, "Using host IP '%s' and port '%d' from setup message.\n", host, port);
}
/* for attach message, use remote peer */
if (msg->type == OSMO_CC_MSG_ATTACH_IND) {
host = call->ep->remote_host;
port = call->ep->remote_port;
PDEBUG(DCC, DEBUG_DEBUG, "Using host IP '%s' and port '%d' from remote address for attach message.\n", host, port);
LOGP(DCC, LOGL_DEBUG, "Using host IP '%s' and port '%d' from remote address for attach message.\n", host, port);
}
/* if there is no remote peer in the setup message, use remote peer */
if (!address && msg->type == OSMO_CC_MSG_SETUP_IND && call->ep->remote_host) {
host = call->ep->remote_host;
port = call->ep->remote_port;
PDEBUG(DCC, DEBUG_DEBUG, "Using host IP '%s' and port '%d' from remote address for setup message.\n", host, port);
LOGP(DCC, LOGL_DEBUG, "Using host IP '%s' and port '%d' from remote address for setup message.\n", host, port);
}
/* if there is no remote peer set, try to use the interface name */
@ -257,16 +257,16 @@ reject:
/* check for incoming attachment */
att = osmo_cc_get_attached_interface(call->ep, interface);
if (!att && !interface[0]) {
PDEBUG(DCC, DEBUG_ERROR, "No remote peer attached, rejecting call.\n");
LOGP(DCC, LOGL_ERROR, "No remote peer attached, rejecting call.\n");
goto reject;
}
if (!att) {
PDEBUG(DCC, DEBUG_ERROR, "No remote peer attached for given interface '%s', rejecting call.\n", interface);
LOGP(DCC, LOGL_ERROR, "No remote peer attached for given interface '%s', rejecting call.\n", interface);
goto reject;
}
host = att->attached_host;
port = att->attached_port;
PDEBUG(DCC, DEBUG_DEBUG, "Using host IP '%s' and port '%d' from attached peer for setup message.\n", host, port);
LOGP(DCC, LOGL_DEBUG, "Using host IP '%s' and port '%d' from attached peer for setup message.\n", host, port);
}
/* add local interface name to setup message */
@ -285,7 +285,7 @@ void send_attach_ind(void *data)
osmo_cc_call_t *call;
osmo_cc_msg_t *msg;
PDEBUG(DCC, DEBUG_DEBUG, "Trying to attach to remote peer \"%s\".\n", ep->remote_host);
LOGP(DCC, LOGL_DEBUG, "Trying to attach to remote peer \"%s\".\n", ep->remote_host);
/* create new call for attachment */
call = osmo_cc_call_new(ep);
@ -306,7 +306,7 @@ void send_attach_ind(void *data)
void attach_rsp(osmo_cc_call_t *call, osmo_cc_msg_t *msg)
{
PDEBUG(DCC, DEBUG_INFO, "Attached to remote peer \"%s\".\n", call->ep->remote_address);
LOGP(DCC, LOGL_INFO, "Attached to remote peer \"%s\".\n", call->ep->remote_address);
/* set state */
new_call_state(call, OSMO_CC_STATE_ATTACH_OUT);
@ -321,11 +321,11 @@ void attach_rel(osmo_cc_call_t *call, osmo_cc_msg_t *msg)
if (call->state == OSMO_CC_STATE_ATTACH_SENT
|| call->state == OSMO_CC_STATE_ATTACH_OUT) {
timer_start(&call->ep->attach_timer, OSMO_CC_ATTACH_TIMER);
PDEBUG(DCC, DEBUG_INFO, "Attachment to remote peer \"%s\" failed, retrying.\n", call->ep->remote_address);
LOGP(DCC, LOGL_INFO, "Attachment to remote peer \"%s\" failed, retrying.\n", call->ep->remote_address);
}
if (call->attached_name)
PDEBUG(DCC, DEBUG_INFO, "Peer with remote interface \"%s\" detached from us.\n", call->attached_name);
LOGP(DCC, LOGL_INFO, "Peer with remote interface \"%s\" detached from us.\n", call->attached_name);
/* change state */
new_call_state(call, OSMO_CC_STATE_IDLE);
@ -356,12 +356,12 @@ void attach_req(osmo_cc_call_t *call, osmo_cc_msg_t *msg)
if (rc < 0)
address[0] = '\0';
if (!address[0]) {
PDEBUG(DCC, DEBUG_ERROR, "Attachment request from remote peer has no remote address set, rejecting.\n");
LOGP(DCC, LOGL_ERROR, "Attachment request from remote peer has no remote address set, rejecting.\n");
rel:
/* change to REL_REQ */
msg->type = OSMO_CC_MSG_REL_IND;
PDEBUG(DCC, DEBUG_INFO, "Changing message to %s.\n", osmo_cc_msg_value2name(msg->type));
LOGP(DCC, LOGL_INFO, "Changing message to %s.\n", osmo_cc_msg_value2name(msg->type));
/* message to socket */
forward_to_ul(call, msg);
@ -373,7 +373,7 @@ rel:
}
rc = split_address(address, &host, &port);
if (rc < 0) {
PDEBUG(DCC, DEBUG_ERROR, "Given remote peer's address '%s' in attach message is invalid, rejecting call.\n", address);
LOGP(DCC, LOGL_ERROR, "Given remote peer's address '%s' in attach message is invalid, rejecting call.\n", address);
goto rel;
}
free((char *)call->attached_host);
@ -388,11 +388,11 @@ rel:
call->attached_name = strdup(interface);
}
PDEBUG(DCC, DEBUG_INFO, "Remote peer with socket address '%s' and port '%d' and interface '%s' attached to us.\n", call->attached_host, call->attached_port, call->attached_name);
LOGP(DCC, LOGL_INFO, "Remote peer with socket address '%s' and port '%d' and interface '%s' attached to us.\n", call->attached_host, call->attached_port, call->attached_name);
/* changing to confirm message */
msg->type = OSMO_CC_MSG_ATTACH_CNF;
PDEBUG(DCC, DEBUG_INFO, "Changing message to %s.\n", osmo_cc_msg_value2name(msg->type));
LOGP(DCC, LOGL_INFO, "Changing message to %s.\n", osmo_cc_msg_value2name(msg->type));
/* message to socket */
forward_to_ul(call, msg);
@ -667,7 +667,7 @@ static void disc_collision_ind(osmo_cc_call_t *call, osmo_cc_msg_t *msg)
/* change to REL_REQ */
msg->type = OSMO_CC_MSG_REL_REQ;
PDEBUG(DCC, DEBUG_INFO, "Changing message to %s.\n", osmo_cc_msg_value2name(msg->type));
LOGP(DCC, LOGL_INFO, "Changing message to %s.\n", osmo_cc_msg_value2name(msg->type));
/* to lower layer */
forward_to_ll(call, msg);
@ -688,7 +688,7 @@ static void disc_collision_req(osmo_cc_call_t *call, osmo_cc_msg_t *msg)
if (call->lower_layer_released) {
/* change to REL_REQ */
msg->type = OSMO_CC_MSG_REL_IND;
PDEBUG(DCC, DEBUG_INFO, "Changing message to %s.\n", osmo_cc_msg_value2name(msg->type));
LOGP(DCC, LOGL_INFO, "Changing message to %s.\n", osmo_cc_msg_value2name(msg->type));
/* to upper layer */
forward_to_ul(call, msg);
@ -726,7 +726,7 @@ static void rej_ind_disc(osmo_cc_call_t *call, osmo_cc_msg_t *msg)
/* change to REL_IND */
msg->type = OSMO_CC_MSG_REL_IND;
PDEBUG(DCC, DEBUG_INFO, "Changing message to %s.\n", osmo_cc_msg_value2name(msg->type));
LOGP(DCC, LOGL_INFO, "Changing message to %s.\n", osmo_cc_msg_value2name(msg->type));
/* to upper layer */
forward_to_ul(call, msg);
@ -742,7 +742,7 @@ static void rej_req_disc(osmo_cc_call_t *call, osmo_cc_msg_t *msg)
/* change to REL_REQ */
msg->type = OSMO_CC_MSG_REL_REQ;
PDEBUG(DCC, DEBUG_INFO, "Changing message to %s.\n", osmo_cc_msg_value2name(msg->type));
LOGP(DCC, LOGL_INFO, "Changing message to %s.\n", osmo_cc_msg_value2name(msg->type));
/* to lower layer */
forward_to_ll(call, msg);
@ -771,7 +771,7 @@ static void rel_ind_other(osmo_cc_call_t *call, osmo_cc_msg_t *msg)
/* change to DISC_IND */
msg->type = OSMO_CC_MSG_DISC_IND;
PDEBUG(DCC, DEBUG_INFO, "Changing message to %s.\n", osmo_cc_msg_value2name(msg->type));
LOGP(DCC, LOGL_INFO, "Changing message to %s.\n", osmo_cc_msg_value2name(msg->type));
call->lower_layer_released = 1;
/* to upper layer */
@ -798,7 +798,7 @@ static void rel_req_other(osmo_cc_call_t *call, osmo_cc_msg_t *msg)
/* change to DISC_REQ */
msg->type = OSMO_CC_MSG_DISC_REQ;
PDEBUG(DCC, DEBUG_INFO, "Changing message to %s.\n", osmo_cc_msg_value2name(msg->type));
LOGP(DCC, LOGL_INFO, "Changing message to %s.\n", osmo_cc_msg_value2name(msg->type));
call->upper_layer_released = 1;
/* to lower layer */
@ -955,16 +955,16 @@ static void handle_msg(osmo_cc_call_t *call, osmo_cc_msg_t *msg)
&& ((1 << call->state) & statemachine_list[i].states))
break;
if (i == STATEMACHINE_LEN) {
PDEBUG(DCC, DEBUG_INFO, "Message %s unhandled at state %s (callref %d)\n",
LOGP(DCC, LOGL_INFO, "Message %s unhandled at state %s (callref %d)\n",
osmo_cc_msg_value2name(msg->type), state_names[call->state], call->callref);
osmo_cc_free_msg(msg);
return;
}
PDEBUG(DCC, DEBUG_INFO, "Handle message %s at state %s (callref %d)\n",
LOGP(DCC, LOGL_INFO, "Handle message %s at state %s (callref %d)\n",
osmo_cc_msg_value2name(msg->type), state_names[call->state], call->callref);
if (debuglevel <= DEBUG_INFO)
osmo_cc_debug_ie(msg, DEBUG_INFO);
if (debuglevel <= LOGL_INFO)
osmo_cc_debug_ie(msg, LOGL_INFO);
statemachine_list[i].action(call, msg);
}
@ -1041,7 +1041,7 @@ void osmo_cc_ll_msg(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg
osmo_cc_call_t *call;
if (!(msg->type & 1)) {
PDEBUG(DCC, DEBUG_ERROR, "Received message from lower layer that is not an _IND nor _CNF, please fix!\n");
LOGP(DCC, LOGL_ERROR, "Received message from lower layer that is not an _IND nor _CNF, please fix!\n");
osmo_cc_free_msg(msg);
return;
}
@ -1064,7 +1064,7 @@ void osmo_cc_ul_msg(void *priv, uint32_t callref, osmo_cc_msg_t *msg)
osmo_cc_call_t *call;
if ((msg->type & 1)) {
PDEBUG(DCC, DEBUG_ERROR, "Received message from socket that is not an _REQ nor _RSP, please fix!\n");
LOGP(DCC, LOGL_ERROR, "Received message from socket that is not an _REQ nor _RSP, please fix!\n");
osmo_cc_free_msg(msg);
return;
}
@ -1125,7 +1125,7 @@ static int osmo_cc_set_name(osmo_cc_endpoint_t *ep, const char *text)
text++;
}
} else {
PDEBUG(DCC, DEBUG_ERROR, "Invalid name definition '%s'\n", text);
LOGP(DCC, LOGL_ERROR, "Invalid name definition '%s'\n", text);
return -EINVAL;
}
@ -1188,12 +1188,12 @@ static int osmo_cc_set_address(osmo_cc_endpoint_t *ep, const char *text)
text++;
}
if (!strcasecmp(text, "auto")) {
PDEBUG(DCC, DEBUG_DEBUG, "setting automatic remote peer selection\n");
LOGP(DCC, LOGL_DEBUG, "setting automatic remote peer selection\n");
ep->remote_auto = 1;
return 0;
}
if (!strcasecmp(text, "none")) {
PDEBUG(DCC, DEBUG_DEBUG, "disable automatic remote peer selection\n");
LOGP(DCC, LOGL_DEBUG, "disable automatic remote peer selection\n");
ep->remote_auto = 0;
return 0;
}
@ -1202,7 +1202,7 @@ static int osmo_cc_set_address(osmo_cc_endpoint_t *ep, const char *text)
host_p = &ep->remote_host;
port_p = &ep->remote_port;
} else {
PDEBUG(DCC, DEBUG_ERROR, "Invalid local or remote address definition '%s'\n", text);
LOGP(DCC, LOGL_ERROR, "Invalid local or remote address definition '%s'\n", text);
return -EINVAL;
}
@ -1227,7 +1227,7 @@ static int osmo_cc_set_address(osmo_cc_endpoint_t *ep, const char *text)
enum osmo_cc_session_addrtype addrtype;
addrtype = osmo_cc_address_type(*host_p);
if (addrtype == osmo_cc_session_addrtype_unknown) {
PDEBUG(DCC, DEBUG_ERROR, "Given local address '%s' is invalid.\n", *host_p);
LOGP(DCC, LOGL_ERROR, "Given local address '%s' is invalid.\n", *host_p);
return -EINVAL;
}
osmo_cc_set_local_peer(&ep->session_config, osmo_cc_session_nettype_inet, addrtype, *host_p);
@ -1261,7 +1261,7 @@ static int osmo_cc_set_rtp(osmo_cc_endpoint_t *ep, const char *text)
text += 9;
ports = 1;
} else {
PDEBUG(DCC, DEBUG_ERROR, "Invalid RTP definition '%s'\n", text);
LOGP(DCC, LOGL_ERROR, "Invalid RTP definition '%s'\n", text);
return -EINVAL;
}
@ -1276,7 +1276,7 @@ static int osmo_cc_set_rtp(osmo_cc_endpoint_t *ep, const char *text)
enum osmo_cc_session_addrtype addrtype;
addrtype = osmo_cc_address_type(text);
if (addrtype == osmo_cc_session_addrtype_unknown) {
PDEBUG(DCC, DEBUG_ERROR, "Given RTP address '%s' is invalid.\n", text);
LOGP(DCC, LOGL_ERROR, "Given RTP address '%s' is invalid.\n", text);
return -EINVAL;
}
osmo_cc_set_local_peer(&ep->session_config, osmo_cc_session_nettype_inet, addrtype, text);
@ -1289,7 +1289,7 @@ static int osmo_cc_set_rtp(osmo_cc_endpoint_t *ep, const char *text)
/* from port */
while (*text > ' ') {
if (*text < '0' || *text > '9') {
PDEBUG(DCC, DEBUG_ERROR, "Given 'from' port in '%s' is invalid.\n", text);
LOGP(DCC, LOGL_ERROR, "Given 'from' port in '%s' is invalid.\n", text);
return -EINVAL;
}
from = from * 10 + *text - '0';
@ -1306,7 +1306,7 @@ static int osmo_cc_set_rtp(osmo_cc_endpoint_t *ep, const char *text)
/* to port */
while (*text > ' ') {
if (*text < '0' || *text > '9') {
PDEBUG(DCC, DEBUG_ERROR, "Given 'to' port in '%s' is invalid.\n", text);
LOGP(DCC, LOGL_ERROR, "Given 'to' port in '%s' is invalid.\n", text);
return -EINVAL;
}
to = to * 10 + *text - '0';
@ -1335,10 +1335,10 @@ int osmo_cc_new(osmo_cc_endpoint_t *ep, const char *version, const char *name, u
int rc;
int i;
PDEBUG(DCC, DEBUG_DEBUG, "Creating new endpoint instance.\n");
LOGP(DCC, LOGL_DEBUG, "Creating new endpoint instance.\n");
if (!!strcmp(version, OSMO_CC_VERSION)) {
PDEBUG(DCC, DEBUG_ERROR, "Application was compiled for different Osmo-CC version.\n");
LOGP(DCC, LOGL_ERROR, "Application was compiled for different Osmo-CC version.\n");
return OSMO_CC_RC_VERSION_MISMATCH;
}
@ -1392,7 +1392,7 @@ int osmo_cc_new(osmo_cc_endpoint_t *ep, const char *version, const char *name, u
return rc;
}
} else {
PDEBUG(DCC, DEBUG_ERROR, "Unknown osmo-cc argument \"%s\"\n", argv[i]);
LOGP(DCC, LOGL_ERROR, "Unknown osmo-cc argument \"%s\"\n", argv[i]);
return -EINVAL;
}
}
@ -1408,7 +1408,7 @@ int osmo_cc_new(osmo_cc_endpoint_t *ep, const char *version, const char *name, u
port = ep->local_port;
if (!host) {
host = "127.0.0.1";
PDEBUG(DCC, DEBUG_DEBUG, "No local peer set, using default \"%s\"\n", host);
LOGP(DCC, LOGL_DEBUG, "No local peer set, using default \"%s\"\n", host);
}
rc = osmo_cc_open_socket(&ep->os, host, port, ep, osmo_cc_ul_msg, serving_location);
if (rc < 0) {
@ -1430,12 +1430,12 @@ int osmo_cc_new(osmo_cc_endpoint_t *ep, const char *version, const char *name, u
if (ep->remote_auto) {
free((char *)ep->remote_host);
ep->remote_host = strdup(ep->local_host);
PDEBUG(DCC, DEBUG_DEBUG, "Remote peer set to auto, using local peer's host \"%s\" for remote peer.\n", ep->remote_host);
LOGP(DCC, LOGL_DEBUG, "Remote peer set to auto, using local peer's host \"%s\" for remote peer.\n", ep->remote_host);
if (rc == OSMO_CC_DEFAULT_PORT)
ep->remote_port = OSMO_CC_DEFAULT_PORT + 1;
else
ep->remote_port = OSMO_CC_DEFAULT_PORT;
PDEBUG(DCC, DEBUG_DEBUG, " -> Using remote port %d.\n", ep->remote_port);
LOGP(DCC, LOGL_DEBUG, " -> Using remote port %d.\n", ep->remote_port);
/* create address string */
free((char *)ep->remote_address);
addrtype = osmo_cc_address_type(ep->remote_host);
@ -1460,7 +1460,7 @@ void osmo_cc_delete(osmo_cc_endpoint_t *ep)
{
osmo_cc_endpoint_t **epp;
PDEBUG(DCC, DEBUG_DEBUG, "Destroying endpoint instance.\n");
LOGP(DCC, LOGL_DEBUG, "Destroying endpoint instance.\n");
/* detach from list >*/
epp = &osmo_cc_endpoint_list;
@ -1536,7 +1536,7 @@ const char *osmo_cc_host_of_address(const char *address)
char *p;
if (strlen(address) >= sizeof(host)) {
PDEBUG(DCC, DEBUG_ERROR, "String way too long!\n");
LOGP(DCC, LOGL_ERROR, "String way too long!\n");
return NULL;
}

View File

@ -63,24 +63,24 @@ const char *osmo_cc_helper_audio_accept(osmo_cc_session_config_t *conf, void *pr
int i, selected_codec_i, telephone_event_i;
if (*session_p) {
PDEBUG(DCC, DEBUG_ERROR, "Session already set, please fix!\n");
LOGP(DCC, LOGL_ERROR, "Session already set, please fix!\n");
abort();
}
if (*codec_p) {
PDEBUG(DCC, DEBUG_ERROR, "Codec already set, please fix!\n");
LOGP(DCC, LOGL_ERROR, "Codec already set, please fix!\n");
abort();
}
/* SDP IE */
rc = osmo_cc_get_ie_sdp(msg, 0, offer_sdp, sizeof(offer_sdp));
if (rc < 0) {
PDEBUG(DCC, DEBUG_ERROR, "There is no SDP included in setup request.\n");
LOGP(DCC, LOGL_ERROR, "There is no SDP included in setup request.\n");
return NULL;
}
*session_p = osmo_cc_session_receive_offer(conf, priv, offer_sdp);
if (!*session_p) {
PDEBUG(DCC, DEBUG_ERROR, "Failed to parse SDP.\n");
LOGP(DCC, LOGL_ERROR, "Failed to parse SDP.\n");
return NULL;
}
@ -124,7 +124,7 @@ const char *osmo_cc_helper_audio_accept(osmo_cc_session_config_t *conf, void *pr
break;
}
if (!selected_codec) {
PDEBUG(DCC, DEBUG_ERROR, "No codec found in setup message that we support.\n");
LOGP(DCC, LOGL_ERROR, "No codec found in setup message that we support.\n");
osmo_cc_free_session(*session_p);
*session_p = NULL;
return NULL;
@ -154,7 +154,7 @@ int osmo_cc_helper_audio_negotiate(osmo_cc_msg_t *msg, osmo_cc_session_t **sessi
int rc;
if (!(*session_p)) {
PDEBUG(DCC, DEBUG_ERROR, "Session not set, please fix!\n");
LOGP(DCC, LOGL_ERROR, "Session not set, please fix!\n");
abort();
}
@ -185,7 +185,7 @@ int osmo_cc_helper_audio_negotiate(osmo_cc_msg_t *msg, osmo_cc_session_t **sessi
}
}
if (!(*codec_p)) {
PDEBUG(DCC, DEBUG_ERROR, "No codec found in setup reply message that we support.\n");
LOGP(DCC, LOGL_ERROR, "No codec found in setup reply message that we support.\n");
return -EIO;
}

View File

@ -338,6 +338,7 @@ static const char *osmo_cc_network_name[OSMO_CC_NETWORK_NUM] = {
[OSMO_CC_NETWORK_DECT_NONE] = "decs",
[OSMO_CC_NETWORK_BLUETOOTH_NONE] = "bluetooth",
[OSMO_CC_NETWORK_SS5_NONE] = "ss5",
[OSMO_CC_NETWORK_R1_NONE] = "r1",
[OSMO_CC_NETWORK_ANETZ_NONE] = "anetz",
[OSMO_CC_NETWORK_BNETZ_MUENZ] = "bnetz",
[OSMO_CC_NETWORK_CNETZ_NONE] = "cnetz",
@ -374,7 +375,7 @@ osmo_cc_msg_t *osmo_cc_new_msg(uint8_t msg_type)
/* allocate message */
msg = calloc(1, sizeof(*msg) + 65535);
if (!msg) {
PDEBUG(DCC, DEBUG_ERROR, "No memory\n");
LOGP(DCC, LOGL_ERROR, "No memory\n");
abort();
}
/* set message type and zero length */
@ -453,14 +454,14 @@ void osmo_cc_debug_ie(osmo_cc_msg_t *msg, int level)
ie = (osmo_cc_ie_t *)p;
/* check for minimum IE length */
if (msg_len < sizeof(*ie)) {
PDEBUG(DCC, level, "****** Rest of message is too short for an IE: value=%s\n", debug_hex(p, msg_len));
LOGP(DCC, level, "****** Rest of message is too short for an IE: value=%s\n", debug_hex(p, msg_len));
return;
}
/* get actual IE length */
len = ntohs(ie->length_networkorder);
/* check if IE length does not exceed message */
if (msg_len < sizeof(*ie) + len) {
PDEBUG(DCC, level, "****** IE: type=0x%02x length=%d would exceed the rest length of message (%d bytes left)\n", ie->type, len, msg_len - (int)sizeof(*ie));
LOGP(DCC, level, "****** IE: type=0x%02x length=%d would exceed the rest length of message (%d bytes left)\n", ie->type, len, msg_len - (int)sizeof(*ie));
return;
}
switch (ie->type) {
@ -468,109 +469,109 @@ void osmo_cc_debug_ie(osmo_cc_msg_t *msg, int level)
rc = osmo_cc_get_ie_called(msg, ie_repeat[ie->type], &type, &plan, string, sizeof(string));
if (rc < 0)
break;
PDEBUG(DCC, level, " %s type=%d(%s) plan=%d(%s) number='%s'\n", osmo_cc_ie_value2name(ie->type), type, osmo_cc_type_value2name(type), plan, osmo_cc_plan_value2name(plan), string);
LOGP(DCC, level, " %s type=%d(%s) plan=%d(%s) number='%s'\n", osmo_cc_ie_value2name(ie->type), type, osmo_cc_type_value2name(type), plan, osmo_cc_plan_value2name(plan), string);
break;
case OSMO_CC_IE_CALLED_SUB:
rc = osmo_cc_get_ie_called_sub(msg, ie_repeat[ie->type], &type, string, sizeof(string));
if (rc < 0)
break;
PDEBUG(DCC, level, " %s type=%d(%s) number='%s'\n", osmo_cc_ie_value2name(ie->type), type, osmo_cc_type_value2name(type), string);
LOGP(DCC, level, " %s type=%d(%s) number='%s'\n", osmo_cc_ie_value2name(ie->type), type, osmo_cc_type_value2name(type), string);
break;
case OSMO_CC_IE_CALLED_NAME:
rc = osmo_cc_get_ie_called_name(msg, ie_repeat[ie->type], string, sizeof(string));
if (rc < 0)
break;
PDEBUG(DCC, level, " %s name='%s'\n", osmo_cc_ie_value2name(ie->type), string);
LOGP(DCC, level, " %s name='%s'\n", osmo_cc_ie_value2name(ie->type), string);
break;
case OSMO_CC_IE_CALLED_INTERFACE:
rc = osmo_cc_get_ie_called_interface(msg, ie_repeat[ie->type], string, sizeof(string));
if (rc < 0)
break;
PDEBUG(DCC, level, " %s name='%s'\n", osmo_cc_ie_value2name(ie->type), string);
LOGP(DCC, level, " %s name='%s'\n", osmo_cc_ie_value2name(ie->type), string);
break;
case OSMO_CC_IE_COMPLETE:
rc = osmo_cc_get_ie_complete(msg, ie_repeat[ie->type]);
if (rc < 0)
break;
PDEBUG(DCC, level, " %s\n", osmo_cc_ie_value2name(ie->type));
LOGP(DCC, level, " %s\n", osmo_cc_ie_value2name(ie->type));
break;
case OSMO_CC_IE_CALLING:
rc = osmo_cc_get_ie_calling(msg, ie_repeat[ie->type], &type, &plan, &present, &screen, string, sizeof(string));
if (rc < 0)
break;
PDEBUG(DCC, level, " %s type=%d(%s) plan=%d(%s), presentation=%d(%s), screening=%d(%s), number='%s'\n", osmo_cc_ie_value2name(ie->type), type, osmo_cc_type_value2name(type), plan, osmo_cc_plan_value2name(plan), present, osmo_cc_present_value2name(present), screen, osmo_cc_screen_value2name(screen), string);
LOGP(DCC, level, " %s type=%d(%s) plan=%d(%s), presentation=%d(%s), screening=%d(%s), number='%s'\n", osmo_cc_ie_value2name(ie->type), type, osmo_cc_type_value2name(type), plan, osmo_cc_plan_value2name(plan), present, osmo_cc_present_value2name(present), screen, osmo_cc_screen_value2name(screen), string);
break;
case OSMO_CC_IE_CALLING_SUB:
rc = osmo_cc_get_ie_calling_sub(msg, ie_repeat[ie->type], &type, string, sizeof(string));
if (rc < 0)
break;
PDEBUG(DCC, level, " %s type=%d(%s) number='%s'\n", osmo_cc_ie_value2name(ie->type), type, osmo_cc_type_value2name(type), string);
LOGP(DCC, level, " %s type=%d(%s) number='%s'\n", osmo_cc_ie_value2name(ie->type), type, osmo_cc_type_value2name(type), string);
break;
case OSMO_CC_IE_CALLING_NAME:
rc = osmo_cc_get_ie_calling_name(msg, ie_repeat[ie->type], string, sizeof(string));
if (rc < 0)
break;
PDEBUG(DCC, level, " %s name='%s'\n", osmo_cc_ie_value2name(ie->type), string);
LOGP(DCC, level, " %s name='%s'\n", osmo_cc_ie_value2name(ie->type), string);
break;
case OSMO_CC_IE_CALLING_INTERFACE:
rc = osmo_cc_get_ie_calling_interface(msg, ie_repeat[ie->type], string, sizeof(string));
if (rc < 0)
break;
PDEBUG(DCC, level, " %s name='%s'\n", osmo_cc_ie_value2name(ie->type), string);
LOGP(DCC, level, " %s name='%s'\n", osmo_cc_ie_value2name(ie->type), string);
break;
case OSMO_CC_IE_CALLING_NETWORK:
rc = osmo_cc_get_ie_calling_network(msg, ie_repeat[ie->type], &type, string, sizeof(string));
if (rc < 0)
break;
PDEBUG(DCC, level, " %s type=%d(%s) id='%s'\n", osmo_cc_ie_value2name(ie->type), type, osmo_cc_network_value2name(type), string);
LOGP(DCC, level, " %s type=%d(%s) id='%s'\n", osmo_cc_ie_value2name(ie->type), type, osmo_cc_network_value2name(type), string);
break;
case OSMO_CC_IE_BEARER:
rc = osmo_cc_get_ie_bearer(msg, ie_repeat[ie->type], &coding, &capability, &mode);
if (rc < 0)
break;
PDEBUG(DCC, level, " %s coding=%d(%s) capability=%d(%s) mode=%d(%s)\n", osmo_cc_ie_value2name(ie->type), coding, osmo_cc_coding_value2name(coding), capability, osmo_cc_capability_value2name(capability), mode, osmo_cc_mode_value2name(mode));
LOGP(DCC, level, " %s coding=%d(%s) capability=%d(%s) mode=%d(%s)\n", osmo_cc_ie_value2name(ie->type), coding, osmo_cc_coding_value2name(coding), capability, osmo_cc_capability_value2name(capability), mode, osmo_cc_mode_value2name(mode));
break;
case OSMO_CC_IE_REDIR:
rc = osmo_cc_get_ie_redir(msg, ie_repeat[ie->type], &type, &plan, &present, &screen, &reason, string, sizeof(string));
if (rc < 0)
break;
PDEBUG(DCC, level, " %s type=%d(%s) plan=%d(%s) presentation=%d(%s) screening=%d(%s) reason=%d(%s) number='%s'\n", osmo_cc_ie_value2name(ie->type), type, osmo_cc_type_value2name(type), plan, osmo_cc_plan_value2name(plan), present, osmo_cc_present_value2name(present), screen, osmo_cc_screen_value2name(screen), reason, osmo_cc_redir_reason_value2name(reason), string);
LOGP(DCC, level, " %s type=%d(%s) plan=%d(%s) presentation=%d(%s) screening=%d(%s) reason=%d(%s) number='%s'\n", osmo_cc_ie_value2name(ie->type), type, osmo_cc_type_value2name(type), plan, osmo_cc_plan_value2name(plan), present, osmo_cc_present_value2name(present), screen, osmo_cc_screen_value2name(screen), reason, osmo_cc_redir_reason_value2name(reason), string);
break;
case OSMO_CC_IE_DTMF:
rc = osmo_cc_get_ie_dtmf(msg, ie_repeat[ie->type], &duration_ms, &pause_ms, &dtmf_mode, string, sizeof(string));
if (rc < 0)
break;
PDEBUG(DCC, level, " %s duration=%dms pause=%dms mode=%d(%s)\n", osmo_cc_ie_value2name(ie->type), duration_ms, pause_ms, dtmf_mode, osmo_cc_dtmf_mode_value2name(dtmf_mode));
LOGP(DCC, level, " %s duration=%dms pause=%dms mode=%d(%s)\n", osmo_cc_ie_value2name(ie->type), duration_ms, pause_ms, dtmf_mode, osmo_cc_dtmf_mode_value2name(dtmf_mode));
break;
case OSMO_CC_IE_KEYPAD:
rc = osmo_cc_get_ie_keypad(msg, ie_repeat[ie->type], string, sizeof(string));
if (rc < 0)
break;
PDEBUG(DCC, level, " %s digits='%s'\n", osmo_cc_ie_value2name(ie->type), string);
LOGP(DCC, level, " %s digits='%s'\n", osmo_cc_ie_value2name(ie->type), string);
break;
case OSMO_CC_IE_PROGRESS:
rc = osmo_cc_get_ie_progress(msg, ie_repeat[ie->type], &coding, &location, &progress);
if (rc < 0)
break;
PDEBUG(DCC, level, " %s coding=%d(%s) location=%d(%s) progress=%d(%s)\n", osmo_cc_ie_value2name(ie->type), coding, osmo_cc_coding_value2name(coding), location, osmo_cc_location_value2name(location), progress, osmo_cc_progress_value2name(progress));
LOGP(DCC, level, " %s coding=%d(%s) location=%d(%s) progress=%d(%s)\n", osmo_cc_ie_value2name(ie->type), coding, osmo_cc_coding_value2name(coding), location, osmo_cc_location_value2name(location), progress, osmo_cc_progress_value2name(progress));
break;
case OSMO_CC_IE_NOTIFY:
rc = osmo_cc_get_ie_notify(msg, ie_repeat[ie->type], &notify);
if (rc < 0)
break;
PDEBUG(DCC, level, " %s indicator=%d(%s)\n", osmo_cc_ie_value2name(ie->type), notify, osmo_cc_notify_value2name(notify));
LOGP(DCC, level, " %s indicator=%d(%s)\n", osmo_cc_ie_value2name(ie->type), notify, osmo_cc_notify_value2name(notify));
break;
case OSMO_CC_IE_CAUSE:
rc = osmo_cc_get_ie_cause(msg, ie_repeat[ie->type], &location, &isdn_cause, &sip_cause, &socket_cause);
if (rc < 0)
break;
PDEBUG(DCC, level, " %s location=%d(%s) isdn_cause=%d(%s) sip_cause=%d socket_cause=%d(%s)\n", osmo_cc_ie_value2name(ie->type), location, osmo_cc_location_value2name(location), isdn_cause, osmo_cc_isdn_cause_value2name(isdn_cause), sip_cause, socket_cause, osmo_cc_socket_cause_value2name(socket_cause));
LOGP(DCC, level, " %s location=%d(%s) isdn_cause=%d(%s) sip_cause=%d socket_cause=%d(%s)\n", osmo_cc_ie_value2name(ie->type), location, osmo_cc_location_value2name(location), isdn_cause, osmo_cc_isdn_cause_value2name(isdn_cause), sip_cause, socket_cause, osmo_cc_socket_cause_value2name(socket_cause));
break;
case OSMO_CC_IE_DISPLAY:
rc = osmo_cc_get_ie_display(msg, ie_repeat[ie->type], string, sizeof(string));
if (rc < 0)
break;
PDEBUG(DCC, level, " %s info='%s'\n", osmo_cc_ie_value2name(ie->type), string);
LOGP(DCC, level, " %s info='%s'\n", osmo_cc_ie_value2name(ie->type), string);
break;
case OSMO_CC_IE_SDP:
rc = osmo_cc_get_ie_sdp(msg, ie_repeat[ie->type], string, sizeof(string));
@ -582,22 +583,22 @@ void osmo_cc_debug_ie(osmo_cc_msg_t *msg, int level)
if (string[i] == '\n')
string[i] = 'n';
}
PDEBUG(DCC, level, " %s payload=%s\n", osmo_cc_ie_value2name(ie->type), string);
LOGP(DCC, level, " %s payload=%s\n", osmo_cc_ie_value2name(ie->type), string);
break;
case OSMO_CC_IE_SOCKET_ADDRESS:
rc = osmo_cc_get_ie_socket_address(msg, ie_repeat[ie->type], string, sizeof(string));
if (rc < 0)
break;
PDEBUG(DCC, level, " %s address='%s'\n", osmo_cc_ie_value2name(ie->type), string);
LOGP(DCC, level, " %s address='%s'\n", osmo_cc_ie_value2name(ie->type), string);
break;
case OSMO_CC_IE_PRIVATE:
rc = osmo_cc_get_ie_private(msg, ie_repeat[ie->type], &unique, (uint8_t *)string, sizeof(string));
if (rc < 0)
break;
PDEBUG(DCC, level, " %s unique=%u=0x%08x private=%s\n", osmo_cc_ie_value2name(ie->type), unique, unique, debug_hex((uint8_t *)string, rc));
LOGP(DCC, level, " %s unique=%u=0x%08x private=%s\n", osmo_cc_ie_value2name(ie->type), unique, unique, debug_hex((uint8_t *)string, rc));
break;
default:
PDEBUG(DCC, level, " %s type=0x%02x length=%d value=%s\n", osmo_cc_ie_value2name(ie->type), ie->type, len, debug_hex(ie->data, len));
LOGP(DCC, level, " %s type=0x%02x length=%d value=%s\n", osmo_cc_ie_value2name(ie->type), ie->type, len, debug_hex(ie->data, len));
}
ie_repeat[ie->type]++;
p += sizeof(*ie) + len;
@ -625,16 +626,16 @@ int osmo_cc_get_ie_struct(osmo_cc_msg_t *msg, uint8_t ie_type, int ie_repeat, in
ie = (osmo_cc_ie_t *)p;
/* check for minimum IE length */
if (msg_len < sizeof(*ie)) {
PDEBUG(DCC, DEBUG_ERROR, "MSG short read\n");
osmo_cc_debug_ie(msg, DEBUG_ERROR);
LOGP(DCC, LOGL_ERROR, "MSG short read\n");
osmo_cc_debug_ie(msg, LOGL_ERROR);
return -EINVAL;
}
/* get actual IE length */
len = ntohs(ie->length_networkorder);
/* check if IE length does not exceed message */
if (msg_len < sizeof(*ie) + len) {
PDEBUG(DCC, DEBUG_ERROR, "MSG short read\n");
osmo_cc_debug_ie(msg, DEBUG_ERROR);
LOGP(DCC, LOGL_ERROR, "MSG short read\n");
osmo_cc_debug_ie(msg, LOGL_ERROR);
return -EINVAL;
}
/* check if IE matches the one that is searched for */
@ -652,7 +653,7 @@ int osmo_cc_get_ie_struct(osmo_cc_msg_t *msg, uint8_t ie_type, int ie_repeat, in
}
/* return IE and indicate how many bytes we have more than the given length*/
if (ntohs(ie->length_networkorder) < ie_len) {
PDEBUG(DCC, DEBUG_ERROR, "IE 0x%02d has length of %d, but we expect it to have at least %d!\n", ie_type, ntohs(ie->length_networkorder), ie_len);
LOGP(DCC, LOGL_ERROR, "IE 0x%02d has length of %d, but we expect it to have at least %d!\n", ie_type, ntohs(ie->length_networkorder), ie_len);
return -EINVAL;
}
*ie_struct = ie;
@ -728,7 +729,7 @@ void *osmo_cc_add_ie(osmo_cc_msg_t *msg, uint8_t ie_type, int ie_len)
msg_len = ntohs(msg->length_networkorder);
new_msg_len = msg_len + sizeof(*ie) + ie_len;
if (new_msg_len > 65535) {
PDEBUG(DCC, DEBUG_ERROR, "MSG overflow\n");
LOGP(DCC, LOGL_ERROR, "MSG overflow\n");
return NULL;
}
msg->length_networkorder = htons(new_msg_len);

View File

@ -310,6 +310,7 @@ int osmo_cc_socket_cause_name2value(const char *name);
#define OSMO_CC_NETWORK_DECT_NONE 0x08
#define OSMO_CC_NETWORK_BLUETOOTH_NONE 0x09
#define OSMO_CC_NETWORK_SS5_NONE 0x0a
#define OSMO_CC_NETWORK_R1_NONE 0x0b
#define OSMO_CC_NETWORK_ANETZ_NONE 0x80
#define OSMO_CC_NETWORK_BNETZ_MUENZ 0x81 /* id starts with 'M' */
#define OSMO_CC_NETWORK_CNETZ_NONE 0x82

View File

@ -24,7 +24,6 @@
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "../libdebug/debug.h"
#include "../libtimer/timer.h"
@ -53,7 +52,7 @@ struct rtp_x_hdr {
uint16_t length;
} __attribute__((packed));
static int rtp_receive(int sock, uint8_t **payload_p, int *payload_len_p, uint8_t *marker_p, uint8_t *pt_p, uint16_t *sequence_p, uint32_t *timestamp_p, uint32_t *ssrc_p)
static int rtp_receive(struct sockaddr_storage *sa, socklen_t *slen, int sock, uint8_t **payload_p, int *payload_len_p, uint8_t *marker_p, uint8_t *pt_p, uint16_t *sequence_p, uint32_t *timestamp_p, uint32_t *ssrc_p)
{
static uint8_t data[2048];
int len;
@ -64,15 +63,15 @@ static int rtp_receive(int sock, uint8_t **payload_p, int *payload_len_p, uint8_
int payload_len;
int x_len;
len = read(sock, data, sizeof(data));
len = recvfrom(sock, data, sizeof(data), 0, (struct sockaddr *)sa, slen);
if (len < 0) {
if (errno == EAGAIN)
return -EAGAIN;
PDEBUG(DCC, DEBUG_DEBUG, "Read errno = %d (%s)\n", errno, strerror(errno));
LOGP(DCC, LOGL_DEBUG, "Read errno = %d (%s)\n", errno, strerror(errno));
return -EIO;
}
if (len < 12) {
PDEBUG(DCC, DEBUG_NOTICE, "Received RTP frame too short (len = %d).\n", len);
LOGP(DCC, LOGL_NOTICE, "Received RTP frame too short (len = %d).\n", len);
return -EINVAL;
}
@ -87,20 +86,20 @@ static int rtp_receive(int sock, uint8_t **payload_p, int *payload_len_p, uint8_
*ssrc_p = ntohl(rtph->ssrc);
if (version != RTP_VERSION) {
PDEBUG(DCC, DEBUG_NOTICE, "Received RTP version %d not supported.\n", version);
LOGP(DCC, LOGL_NOTICE, "Received RTP version %d not supported.\n", version);
return -EINVAL;
}
payload = data + sizeof(*rtph) + (csrc_count << 2);
payload_len = len - sizeof(*rtph) - (csrc_count << 2);
if (payload_len < 0) {
PDEBUG(DCC, DEBUG_NOTICE, "Received RTP frame too short (len = %d, csrc count = %d).\n", len, csrc_count);
LOGP(DCC, LOGL_NOTICE, "Received RTP frame too short (len = %d, csrc count = %d).\n", len, csrc_count);
return -EINVAL;
}
if (extension) {
if (payload_len < (int)sizeof(*rtpxh)) {
PDEBUG(DCC, DEBUG_NOTICE, "Received RTP frame too short for extension header.\n");
LOGP(DCC, LOGL_NOTICE, "Received RTP frame too short for extension header.\n");
return -EINVAL;
}
rtpxh = (struct rtp_x_hdr *)payload;
@ -108,19 +107,19 @@ static int rtp_receive(int sock, uint8_t **payload_p, int *payload_len_p, uint8_
payload += x_len;
payload_len -= x_len;
if (payload_len < (int)sizeof(*rtpxh)) {
PDEBUG(DCC, DEBUG_NOTICE, "Received RTP frame too short, extension header exceeds frame length.\n");
LOGP(DCC, LOGL_NOTICE, "Received RTP frame too short, extension header exceeds frame length.\n");
return -EINVAL;
}
}
if (padding) {
if (payload_len < 1) {
PDEBUG(DCC, DEBUG_NOTICE, "Received RTP frame too short for padding length.\n");
LOGP(DCC, LOGL_NOTICE, "Received RTP frame too short for padding length.\n");
return -EINVAL;
}
payload_len -= payload[payload_len - 1];
if (payload_len < 0) {
PDEBUG(DCC, DEBUG_NOTICE, "Received RTP frame padding is greater than payload.\n");
LOGP(DCC, LOGL_NOTICE, "Received RTP frame padding is greater than payload.\n");
return -EINVAL;
}
}
@ -133,23 +132,23 @@ static int rtp_receive(int sock, uint8_t **payload_p, int *payload_len_p, uint8_
return 0;
}
static int rtcp_receive(int sock)
static int rtcp_receive(struct sockaddr_storage *sa, socklen_t *slen, int sock)
{
static uint8_t data[2048];
int len;
len = read(sock, data, sizeof(data));
len = recvfrom(sock, data, sizeof(data), 0, (struct sockaddr *)sa, slen);
if (len < 0) {
if (errno == EAGAIN)
return -EAGAIN;
PDEBUG(DCC, DEBUG_DEBUG, "Read errno = %d (%s)\n", errno, strerror(errno));
LOGP(DCC, LOGL_DEBUG, "Read errno = %d (%s)\n", errno, strerror(errno));
return -EIO;
}
return 0;
}
static void rtp_send(int sock, uint8_t *payload, int payload_len, uint8_t marker, uint8_t pt, uint16_t sequence, uint32_t timestamp, uint32_t ssrc)
static void rtp_send(struct sockaddr_storage *sa, socklen_t slen, int sock, uint8_t *payload, int payload_len, uint8_t marker, uint8_t pt, uint16_t sequence, uint32_t timestamp, uint32_t ssrc)
{
struct rtp_hdr *rtph;
char data[sizeof(*rtph) + payload_len];
@ -164,14 +163,14 @@ static void rtp_send(int sock, uint8_t *payload, int payload_len, uint8_t marker
rtph->ssrc = htonl(ssrc);
len += payload_len;
if (len > (int)sizeof(data)) {
PDEBUG(DCC, DEBUG_NOTICE, "Buffer overflow, please fix!.\n");
LOGP(DCC, LOGL_NOTICE, "Buffer overflow, please fix!.\n");
abort();
}
memcpy(data + sizeof(*rtph), payload, payload_len);
rc = write(sock, data, len);
rc = sendto(sock, data, len, 0, (struct sockaddr *)sa, slen);
if (rc < 0)
PDEBUG(DCC, DEBUG_DEBUG, "Write errno = %d (%s)\n", errno, strerror(errno));
LOGP(DCC, LOGL_DEBUG, "sendto errno = %d (%s)\n", errno, strerror(errno));
}
static int rtp_listen_cb(struct osmo_fd *ofd, unsigned int when);
@ -186,7 +185,7 @@ int osmo_cc_rtp_open(osmo_cc_session_media_t *media)
int domain = 0; // make GCC happy
uint16_t start_port;
struct sockaddr_storage sa;
int slen = 0; // make GCC happy
socklen_t slen = 0; // make GCC happy
struct sockaddr_in6 *sa6;
struct sockaddr_in *sa4;
uint16_t *sport;
@ -206,7 +205,7 @@ int osmo_cc_rtp_open(osmo_cc_session_media_t *media)
rc = inet_pton(AF_INET, media->connection_data_local.address, &sa4->sin_addr);
if (rc < 1) {
pton_error:
PDEBUG(DCC, DEBUG_NOTICE, "Cannot bind to address '%s'.\n", media->connection_data_local.address);
LOGP(DCC, LOGL_NOTICE, "Cannot bind to address '%s'.\n", media->connection_data_local.address);
return -EINVAL;
}
sport = &sa4->sin_port;
@ -224,7 +223,7 @@ pton_error:
slen = sizeof(*sa6);
break;
case osmo_cc_session_addrtype_unknown:
PDEBUG(DCC, DEBUG_NOTICE, "Unsupported address type '%s'.\n", media->connection_data_local.addrtype_name);
LOGP(DCC, LOGL_NOTICE, "Unsupported address type '%s'.\n", media->connection_data_local.addrtype_name);
return -EINVAL;
}
@ -237,7 +236,7 @@ pton_error:
rc = socket(domain, SOCK_DGRAM, IPPROTO_UDP);
if (rc < 0) {
socket_error:
PDEBUG(DCC, DEBUG_ERROR, "Cannot create socket (domain=%d, errno=%d(%s))\n", domain, errno, strerror(errno));
LOGP(DCC, LOGL_ERROR, "Cannot create socket (domain=%d, errno=%d(%s))\n", domain, errno, strerror(errno));
osmo_cc_rtp_close(media);
return -EIO;
}
@ -263,7 +262,7 @@ bind_error:
osmo_cc_rtp_close(media);
conf->rtp_port_next = (conf->rtp_port_next + 2 > conf->rtp_port_to) ? conf->rtp_port_from : conf->rtp_port_next + 2;
if (conf->rtp_port_next == start_port) {
PDEBUG(DCC, DEBUG_ERROR, "Cannot bind socket (errno=%d(%s))\n", errno, strerror(errno));
LOGP(DCC, LOGL_ERROR, "Cannot bind socket (errno=%d(%s))\n", errno, strerror(errno));
return -EIO;
}
continue;
@ -284,7 +283,7 @@ bind_error:
break;
}
PDEBUG(DCC, DEBUG_DEBUG, "Opening media port %d\n", media->description.port_local);
LOGP(DCC, LOGL_DEBUG, "Opening media port %d\n", media->description.port_local);
return 0;
}
@ -294,56 +293,51 @@ bind_error:
*/
int osmo_cc_rtp_connect(osmo_cc_session_media_t *media)
{
struct sockaddr_storage sa;
int slen = 0; // make GCC happy
struct sockaddr_in6 *sa6;
struct sockaddr_in *sa4;
uint16_t *sport;
int rc;
PDEBUG(DCC, DEBUG_DEBUG, "Connecting media port %d->%d\n", media->description.port_local, media->description.port_remote);
LOGP(DCC, LOGL_DEBUG, "Connecting media port %d->%d (remote %s)\n", media->description.port_local, media->description.port_remote, media->connection_data_remote.address);
switch (media->connection_data_remote.addrtype) {
case osmo_cc_session_addrtype_ipv4:
memset(&sa, 0, sizeof(sa));
sa4 = (struct sockaddr_in *)&sa;
memset(&media->rtp_sa, 0, sizeof(media->rtp_sa));
sa4 = (struct sockaddr_in *)&media->rtp_sa;
sa4->sin_family = AF_INET;
rc = inet_pton(AF_INET, media->connection_data_remote.address, &sa4->sin_addr);
if (rc < 1) {
pton_error:
PDEBUG(DCC, DEBUG_NOTICE, "Cannot connect to address '%s'.\n", media->connection_data_remote.address);
LOGP(DCC, LOGL_NOTICE, "Cannot connect to address '%s'.\n", media->connection_data_remote.address);
return -EINVAL;
}
sport = &sa4->sin_port;
slen = sizeof(*sa4);
media->rtp_sport = &sa4->sin_port;
media->rtp_slen = sizeof(*sa4);
memcpy(&media->rtcp_sa, &media->rtp_sa, sizeof(*sa4));
sa4 = (struct sockaddr_in *)&media->rtcp_sa;
media->rtcp_sport = &sa4->sin_port;
media->rtcp_slen = sizeof(*sa4);
break;
case osmo_cc_session_addrtype_ipv6:
memset(&sa, 0, sizeof(sa));
sa6 = (struct sockaddr_in6 *)&sa;
memset(&media->rtp_sa, 0, sizeof(media->rtp_sa));
sa6 = (struct sockaddr_in6 *)&media->rtp_sa;
sa6->sin6_family = AF_INET6;
rc = inet_pton(AF_INET6, media->connection_data_remote.address, &sa6->sin6_addr);
if (rc < 1)
goto pton_error;
sport = &sa6->sin6_port;
slen = sizeof(*sa6);
media->rtp_sport = &sa6->sin6_port;
media->rtp_slen = sizeof(*sa6);
memcpy(&media->rtcp_sa, &media->rtp_sa, sizeof(*sa6));
sa6 = (struct sockaddr_in6 *)&media->rtcp_sa;
media->rtcp_sport = &sa6->sin6_port;
media->rtcp_slen = sizeof(*sa6);
break;
case osmo_cc_session_addrtype_unknown:
PDEBUG(DCC, DEBUG_NOTICE, "Unsupported address type '%s'.\n", media->connection_data_local.addrtype_name);
LOGP(DCC, LOGL_NOTICE, "Unsupported address type '%s'.\n", media->connection_data_local.addrtype_name);
return -EINVAL;
}
*sport = htons(media->description.port_remote);
rc = connect(media->rtp_ofd.fd, (struct sockaddr *)&sa, slen);
if (rc < 0) {
connect_error:
PDEBUG(DCC, DEBUG_NOTICE, "Cannot connect to address '%s'.\n", media->connection_data_remote.address);
osmo_cc_rtp_close(media);
return -EIO;
}
*sport = htons(media->description.port_remote + 1);
rc = connect(media->rtcp_ofd.fd, (struct sockaddr *)&sa, slen);
if (rc < 0)
goto connect_error;
*media->rtp_sport = htons(media->description.port_remote);
*media->rtcp_sport = htons(media->description.port_remote + 1);
return 0;
}
@ -364,7 +358,7 @@ void osmo_cc_rtp_send(osmo_cc_session_codec_t *codec, uint8_t *data, int len, ui
payload_len = len;
}
rtp_send(codec->media->rtp_ofd.fd, payload, payload_len, marker, codec->payload_type_remote, codec->media->tx_sequence, codec->media->tx_timestamp, codec->media->tx_ssrc);
rtp_send(&codec->media->rtp_sa, codec->media->rtp_slen, codec->media->rtp_ofd.fd, payload, payload_len, marker, codec->payload_type_remote, codec->media->tx_sequence, codec->media->tx_timestamp, codec->media->tx_ssrc);
codec->media->tx_sequence += inc_sequence;
codec->media->tx_timestamp += inc_timestamp;
@ -372,6 +366,44 @@ void osmo_cc_rtp_send(osmo_cc_session_codec_t *codec, uint8_t *data, int len, ui
free(payload);
}
static void check_port_translation(struct sockaddr_storage *sa, struct sockaddr_storage *media_sa, const char *what)
{
struct sockaddr_in6 *sa6, *sa6_2;
struct sockaddr_in *sa4, *sa4_2;
int from = 0, to = 0;
if (sa->ss_family != media_sa->ss_family)
return;
switch (sa->ss_family) {
case AF_INET:
sa4 = (struct sockaddr_in *)sa;
sa4_2 = (struct sockaddr_in *)media_sa;
if (sa4->sin_port != sa4_2->sin_port) {
if (!!memcmp(&sa4->sin_addr, &sa4_2->sin_addr, sizeof(struct in_addr)))
break;
from = ntohs(sa4_2->sin_port);
to = ntohs(sa4->sin_port);
sa4_2->sin_port = sa4->sin_port;
}
break;
case AF_INET6:
sa6 = (struct sockaddr_in6 *)sa;
sa6_2 = (struct sockaddr_in6 *)media_sa;
if (sa6->sin6_port != sa6_2->sin6_port) {
if (!!memcmp(&sa6->sin6_addr, &sa6_2->sin6_addr, sizeof(struct in6_addr)))
break;
from = ntohs(sa6_2->sin6_port);
to = ntohs(sa6->sin6_port);
sa6_2->sin6_port = sa6->sin6_port;
}
break;
}
if (from)
LOGP(DCC, LOGL_NOTICE, "Remote sends with different %s port, changing from %d to %d!\n", what, from, to);
}
static int rtp_listen_cb(struct osmo_fd *ofd, unsigned int when)
{
osmo_cc_session_media_t *media = ofd->data;
@ -383,11 +415,14 @@ static int rtp_listen_cb(struct osmo_fd *ofd, unsigned int when)
osmo_cc_session_codec_t *codec;
uint8_t *data;
int len;
struct sockaddr_storage sa;
socklen_t slen = sizeof(sa); // must be initialized and will be overwritten
if (when & OSMO_FD_READ) {
rc = rtp_receive(media->rtp_ofd.fd, &payload, &payload_len, &marker, &payload_type, &media->rx_sequence, &media->rx_timestamp, &media->rx_ssrc);
rc = rtp_receive(&sa, &slen, media->rtp_ofd.fd, &payload, &payload_len, &marker, &payload_type, &media->rx_sequence, &media->rx_timestamp, &media->rx_ssrc);
if (rc < 0)
return rc;
check_port_translation(&sa, &media->rtp_sa, "RTP");
/* search for codec */
for (codec = media->codec_list; codec; codec = codec->next) {
@ -395,7 +430,7 @@ static int rtp_listen_cb(struct osmo_fd *ofd, unsigned int when)
break;
}
if (!codec) {
PDEBUG(DCC, DEBUG_NOTICE, "Received RTP frame for unknown codec (payload_type = %d).\n", payload_type);
LOGP(DCC, LOGL_NOTICE, "Received RTP frame for unknown codec (payload_type = %d).\n", payload_type);
return 0;
}
@ -420,11 +455,14 @@ static int rtcp_listen_cb(struct osmo_fd *ofd, unsigned int when)
{
osmo_cc_session_media_t *media = ofd->data;
int rc;
struct sockaddr_storage sa;
socklen_t slen = sizeof(sa); // must be initialized and will be overwritten
if (when & OSMO_FD_READ) {
rc = rtcp_receive(media->rtp_ofd.fd);
rc = rtcp_receive(&sa, &slen, media->rtcp_ofd.fd);
if (rc < 0)
return rc;
check_port_translation(&sa, &media->rtcp_sa, "RTCP");
}
return 0;

View File

@ -153,7 +153,7 @@ int osmo_cc_add_screen(osmo_cc_endpoint_t *ep, const char *text)
text += 17;
list_p = &ep->screen_called_out;
} else {
PDEBUG(DCC, DEBUG_ERROR, "Invalid screening definition \"%s\". It must start with 'screen-calling-in' or 'screen-called-in' or 'screen-calling-out' or 'screen-called-out'\n", text);
LOGP(DCC, LOGL_ERROR, "Invalid screening definition \"%s\". It must start with 'screen-calling-in' or 'screen-called-in' or 'screen-calling-out' or 'screen-called-out'\n", text);
return -EINVAL;
}
@ -172,7 +172,7 @@ next_from:
token = osmo_cc_strtok_quotes(&text);
if (!token) {
free(list);
PDEBUG(DCC, DEBUG_ERROR, "Missing 'from' string in screening definition \"%s\". If the string shall be empty, use double quotes. (\'\' or \"\")\n", text);
LOGP(DCC, LOGL_ERROR, "Missing 'from' string in screening definition \"%s\". If the string shall be empty, use double quotes. (\'\' or \"\")\n", text);
return -EINVAL;
}
if (!strcasecmp(token, "unknown")) {
@ -209,8 +209,8 @@ next_from:
if (no_present) {
no_present_error:
free(list);
PDEBUG(DCC, DEBUG_ERROR, "Error in screening definition '%s'.\n", text);
PDEBUG(DCC, DEBUG_ERROR, "Keyword '%s' not allowed in screen entry for called number\n", token);
LOGP(DCC, LOGL_ERROR, "Error in screening definition '%s'.\n", text);
LOGP(DCC, LOGL_ERROR, "Keyword '%s' not allowed in screen entry for called number\n", token);
return -EINVAL;
}
list->has_from_present = 1;
@ -232,8 +232,8 @@ no_present_error:
if (token[i] == '*') {
if (star_used) {
free(list);
PDEBUG(DCC, DEBUG_ERROR, "Error in screening definition '%s'.\n", text);
PDEBUG(DCC, DEBUG_ERROR, "The '*' may be used only once.\n");
LOGP(DCC, LOGL_ERROR, "Error in screening definition '%s'.\n", text);
LOGP(DCC, LOGL_ERROR, "The '*' may be used only once.\n");
return -EINVAL;
}
list->from[j] = SCREEN_STAR;
@ -251,8 +251,8 @@ next_to:
token = osmo_cc_strtok_quotes(&text);
if (!token) {
free(list);
PDEBUG(DCC, DEBUG_ERROR, "Error in screening definition '%s'.\n", text);
PDEBUG(DCC, DEBUG_ERROR, "Missing screening result. If the string shall be empty, use double quotes. (\'\' or \"\")\n");
LOGP(DCC, LOGL_ERROR, "Error in screening definition '%s'.\n", text);
LOGP(DCC, LOGL_ERROR, "Missing screening result. If the string shall be empty, use double quotes. (\'\' or \"\")\n");
return -EINVAL;
}
if (!strcasecmp(token, "unknown")) {
@ -304,8 +304,8 @@ next_to:
if (token[i] == '*') {
if (star_used) {
free(list);
PDEBUG(DCC, DEBUG_ERROR, "Error in screening definition '%s'.\n", text);
PDEBUG(DCC, DEBUG_ERROR, "The '*' may be used only once.\n");
LOGP(DCC, LOGL_ERROR, "Error in screening definition '%s'.\n", text);
LOGP(DCC, LOGL_ERROR, "The '*' may be used only once.\n");
return -EINVAL;
}
list->to[j] = SCREEN_STAR;
@ -314,14 +314,14 @@ next_to:
if (token[i] == '@') {
if (!calling_in) {
free(list);
PDEBUG(DCC, DEBUG_ERROR, "Error in screening definition '%s'.\n", text);
PDEBUG(DCC, DEBUG_ERROR, "The '@' may be used only for incoming calls from interface.\n");
LOGP(DCC, LOGL_ERROR, "Error in screening definition '%s'.\n", text);
LOGP(DCC, LOGL_ERROR, "The '@' may be used only for incoming calls from interface.\n");
return -EINVAL;
}
if (at_used) {
free(list);
PDEBUG(DCC, DEBUG_ERROR, "Error in screening definition '%s'.\n", text);
PDEBUG(DCC, DEBUG_ERROR, "The '@' may be used only once.\n");
LOGP(DCC, LOGL_ERROR, "Error in screening definition '%s'.\n", text);
LOGP(DCC, LOGL_ERROR, "The '@' may be used only once.\n");
return -EINVAL;
}
list->to[j] = SCREEN_AT;
@ -338,8 +338,8 @@ next_to:
token = osmo_cc_strtok_quotes(&text);
if (token) {
free(list);
PDEBUG(DCC, DEBUG_ERROR, "Error in screening definition '%s'.\n", text);
PDEBUG(DCC, DEBUG_ERROR, "Got garbage behind screening result.\n");
LOGP(DCC, LOGL_ERROR, "Error in screening definition '%s'.\n", text);
LOGP(DCC, LOGL_ERROR, "Got garbage behind screening result.\n");
return -EINVAL;
}
@ -392,76 +392,76 @@ static int osmo_cc_screen(const char *what, osmo_cc_screen_list_t *list, uint8_t
const char *suffix;
int i, j, rule;
PDEBUG(DCC, DEBUG_INFO, "Screening %s '%s':\n", what, id_from);
LOGP(DCC, LOGL_INFO, "Screening %s '%s':\n", what, id_from);
switch (*type) {
case OSMO_CC_TYPE_UNKNOWN:
PDEBUG(DCC, DEBUG_INFO, " -> type = unknown\n");
LOGP(DCC, LOGL_INFO, " -> type = unknown\n");
break;
case OSMO_CC_TYPE_INTERNATIONAL:
PDEBUG(DCC, DEBUG_INFO, " -> type = international\n");
LOGP(DCC, LOGL_INFO, " -> type = international\n");
break;
case OSMO_CC_TYPE_NATIONAL:
PDEBUG(DCC, DEBUG_INFO, " -> type = national\n");
LOGP(DCC, LOGL_INFO, " -> type = national\n");
break;
case OSMO_CC_TYPE_NETWORK:
PDEBUG(DCC, DEBUG_INFO, " -> type = network\n");
LOGP(DCC, LOGL_INFO, " -> type = network\n");
break;
case OSMO_CC_TYPE_SUBSCRIBER:
PDEBUG(DCC, DEBUG_INFO, " -> type = subscriber\n");
LOGP(DCC, LOGL_INFO, " -> type = subscriber\n");
break;
case OSMO_CC_TYPE_ABBREVIATED:
PDEBUG(DCC, DEBUG_INFO, " -> type = abbreviated\n");
LOGP(DCC, LOGL_INFO, " -> type = abbreviated\n");
break;
}
if (present) switch (*present) {
case OSMO_CC_PRESENT_ALLOWED:
PDEBUG(DCC, DEBUG_INFO, " -> present = allowed\n");
LOGP(DCC, LOGL_INFO, " -> present = allowed\n");
break;
case OSMO_CC_PRESENT_RESTRICTED:
PDEBUG(DCC, DEBUG_INFO, " -> present = restricted\n");
LOGP(DCC, LOGL_INFO, " -> present = restricted\n");
break;
}
rule = 0;
while (list) {
rule++;
PDEBUG(DCC, DEBUG_INFO, "Comparing with rule #%d: '%s':\n", rule, print_rule_string(list->from));
LOGP(DCC, LOGL_INFO, "Comparing with rule #%d: '%s':\n", rule, print_rule_string(list->from));
if (list->has_from_type) switch (list->from_type) {
case OSMO_CC_TYPE_UNKNOWN:
PDEBUG(DCC, DEBUG_INFO, " -> type = unknown\n");
LOGP(DCC, LOGL_INFO, " -> type = unknown\n");
break;
case OSMO_CC_TYPE_INTERNATIONAL:
PDEBUG(DCC, DEBUG_INFO, " -> type = international\n");
LOGP(DCC, LOGL_INFO, " -> type = international\n");
break;
case OSMO_CC_TYPE_NATIONAL:
PDEBUG(DCC, DEBUG_INFO, " -> type = national\n");
LOGP(DCC, LOGL_INFO, " -> type = national\n");
break;
case OSMO_CC_TYPE_NETWORK:
PDEBUG(DCC, DEBUG_INFO, " -> type = network\n");
LOGP(DCC, LOGL_INFO, " -> type = network\n");
break;
case OSMO_CC_TYPE_SUBSCRIBER:
PDEBUG(DCC, DEBUG_INFO, " -> type = subscriber\n");
LOGP(DCC, LOGL_INFO, " -> type = subscriber\n");
break;
case OSMO_CC_TYPE_ABBREVIATED:
PDEBUG(DCC, DEBUG_INFO, " -> type = abbreviated\n");
LOGP(DCC, LOGL_INFO, " -> type = abbreviated\n");
break;
}
if (list->has_from_present) switch (list->from_present) {
case OSMO_CC_PRESENT_ALLOWED:
PDEBUG(DCC, DEBUG_INFO, " -> present = allowed\n");
LOGP(DCC, LOGL_INFO, " -> present = allowed\n");
break;
case OSMO_CC_PRESENT_RESTRICTED:
PDEBUG(DCC, DEBUG_INFO, " -> present = restricted\n");
LOGP(DCC, LOGL_INFO, " -> present = restricted\n");
break;
}
suffix = NULL;
/* attributes do not match */
if (list->has_from_type && list->from_type != *type) {
PDEBUG(DCC, DEBUG_INFO, "Rule does not match, because 'type' is different.\n");
LOGP(DCC, LOGL_INFO, "Rule does not match, because 'type' is different.\n");
continue;
}
if (present && list->has_from_present && list->from_present != *present) {
PDEBUG(DCC, DEBUG_INFO, "Rule does not match, because 'present' is different.\n");
LOGP(DCC, LOGL_INFO, "Rule does not match, because 'present' is different.\n");
continue;
}
for (i = 0; list->from[i] && id_from[i]; i++) {
@ -485,7 +485,7 @@ static int osmo_cc_screen(const char *what, osmo_cc_screen_list_t *list, uint8_t
/* if all digits have matched */
if (list->from[i] == '\0' && id_from[i] == '\0')
break;
PDEBUG(DCC, DEBUG_INFO, "Rule does not match, because %s is different.\n", what);
LOGP(DCC, LOGL_INFO, "Rule does not match, because %s is different.\n", what);
list = list->next;
}
@ -522,37 +522,37 @@ static int osmo_cc_screen(const char *what, osmo_cc_screen_list_t *list, uint8_t
}
id_to[j] = '\0';
PDEBUG(DCC, DEBUG_INFO, "Rule matches, changing %s to '%s'.\n", what, print_rule_string(id_to));
LOGP(DCC, LOGL_INFO, "Rule matches, changing %s to '%s'.\n", what, print_rule_string(id_to));
if (list->has_to_type) switch (list->to_type) {
case OSMO_CC_TYPE_UNKNOWN:
PDEBUG(DCC, DEBUG_INFO, " -> type = unknown\n");
LOGP(DCC, LOGL_INFO, " -> type = unknown\n");
break;
case OSMO_CC_TYPE_INTERNATIONAL:
PDEBUG(DCC, DEBUG_INFO, " -> type = international\n");
LOGP(DCC, LOGL_INFO, " -> type = international\n");
break;
case OSMO_CC_TYPE_NATIONAL:
PDEBUG(DCC, DEBUG_INFO, " -> type = national\n");
LOGP(DCC, LOGL_INFO, " -> type = national\n");
break;
case OSMO_CC_TYPE_NETWORK:
PDEBUG(DCC, DEBUG_INFO, " -> type = network\n");
LOGP(DCC, LOGL_INFO, " -> type = network\n");
break;
case OSMO_CC_TYPE_SUBSCRIBER:
PDEBUG(DCC, DEBUG_INFO, " -> type = subscriber\n");
LOGP(DCC, LOGL_INFO, " -> type = subscriber\n");
break;
case OSMO_CC_TYPE_ABBREVIATED:
PDEBUG(DCC, DEBUG_INFO, " -> type = abbreviated\n");
LOGP(DCC, LOGL_INFO, " -> type = abbreviated\n");
break;
}
if (list->has_to_present) switch (list->to_present) {
case OSMO_CC_PRESENT_ALLOWED:
PDEBUG(DCC, DEBUG_INFO, " -> present = allowed\n");
LOGP(DCC, LOGL_INFO, " -> present = allowed\n");
break;
case OSMO_CC_PRESENT_RESTRICTED:
PDEBUG(DCC, DEBUG_INFO, " -> present = restricted\n");
LOGP(DCC, LOGL_INFO, " -> present = restricted\n");
break;
}
if (routing_p && *routing_p)
PDEBUG(DCC, DEBUG_INFO, " -> remote = %s\n", *routing_p);
LOGP(DCC, LOGL_INFO, " -> remote = %s\n", *routing_p);
return 0;
}

View File

@ -136,7 +136,7 @@ char *osmo_cc_session_gensdp(osmo_cc_session_t *session)
/* check for overflow and return */
if (strlen(sdp) == sizeof(sdp) - 1) {
PDEBUG(DCC, DEBUG_ERROR, "Fatal error: Allocated SDP buffer with %d bytes is too small, please fix!\n", (int)sizeof(sdp));
LOGP(DCC, LOGL_ERROR, "Fatal error: Allocated SDP buffer with %d bytes is too small, please fix!\n", (int)sizeof(sdp));
return NULL;
}
return sdp;
@ -286,21 +286,21 @@ struct osmo_cc_session *osmo_cc_session_parsesdp(osmo_cc_session_config_t *conf,
continue;
if (line[1] != '=') {
PDEBUG(DCC, DEBUG_NOTICE, "SDP line %d = '%s' is garbage, expecting '=' as second character.\n", line_no, line);
LOGP(DCC, LOGL_NOTICE, "SDP line %d = '%s' is garbage, expecting '=' as second character.\n", line_no, line);
continue;
}
switch(line[0]) {
case 'v':
PDEBUG(DCC, DEBUG_DEBUG, " -> Version: %s\n", next_word);
LOGP(DCC, LOGL_DEBUG, " -> Version: %s\n", next_word);
if (atoi(next_word) != 0) {
PDEBUG(DCC, DEBUG_NOTICE, "SDP line %d = '%s' describes unsupported version.\n", line_no, line);
LOGP(DCC, LOGL_NOTICE, "SDP line %d = '%s' describes unsupported version.\n", line_no, line);
osmo_cc_free_session(session);
return NULL;
}
break;
case 'o':
PDEBUG(DCC, DEBUG_DEBUG, " -> Originator: %s\n", next_word);
LOGP(DCC, LOGL_DEBUG, " -> Originator: %s\n", next_word);
/* Originator */
word = wordsep(&next_word);
if (!word)
@ -335,12 +335,12 @@ struct osmo_cc_session *osmo_cc_session_parsesdp(osmo_cc_session_config_t *conf,
break;
case 's':
/* Session Name */
PDEBUG(DCC, DEBUG_DEBUG, " -> Session Name: %s\n", next_word);
LOGP(DCC, LOGL_DEBUG, " -> Session Name: %s\n", next_word);
free((char *)session->name); // if already set
session->name = strdup(next_word);
break;
case 'c': /* Connection Data */
PDEBUG(DCC, DEBUG_DEBUG, " -> Connection Data: %s\n", next_word);
LOGP(DCC, LOGL_DEBUG, " -> Connection Data: %s\n", next_word);
if (media)
cd = &media->connection_data_remote;
else
@ -351,7 +351,7 @@ struct osmo_cc_session *osmo_cc_session_parsesdp(osmo_cc_session_config_t *conf,
if (!strcmp(word, "IN"))
cd->nettype = osmo_cc_session_nettype_inet;
else {
PDEBUG(DCC, DEBUG_NOTICE, "Unsupported network type '%s' in SDP line %d = '%s'\n", word, line_no, line);
LOGP(DCC, LOGL_NOTICE, "Unsupported network type '%s' in SDP line %d = '%s'\n", word, line_no, line);
break;
}
/* address type */
@ -359,13 +359,13 @@ struct osmo_cc_session *osmo_cc_session_parsesdp(osmo_cc_session_config_t *conf,
break;
if (!strcmp(word, "IP4")) {
cd->addrtype = osmo_cc_session_addrtype_ipv4;
PDEBUG(DCC, DEBUG_DEBUG, " -> Address Type = IPv4\n");
LOGP(DCC, LOGL_DEBUG, " -> Address Type = IPv4\n");
} else
if (!strcmp(word, "IP6")) {
cd->addrtype = osmo_cc_session_addrtype_ipv6;
PDEBUG(DCC, DEBUG_DEBUG, " -> Address Type = IPv6\n");
LOGP(DCC, LOGL_DEBUG, " -> Address Type = IPv6\n");
} else {
PDEBUG(DCC, DEBUG_NOTICE, "Unsupported address type '%s' in SDP line %d = '%s'\n", word, line_no, line);
LOGP(DCC, LOGL_NOTICE, "Unsupported address type '%s' in SDP line %d = '%s'\n", word, line_no, line);
break;
}
/* connection address */
@ -375,10 +375,10 @@ struct osmo_cc_session *osmo_cc_session_parsesdp(osmo_cc_session_config_t *conf,
*p++ = '\0';
free((char *)cd->address); // in case of multiple lines of 'c'
cd->address = strdup(word);
PDEBUG(DCC, DEBUG_DEBUG, " -> Address = %s\n", word);
LOGP(DCC, LOGL_DEBUG, " -> Address = %s\n", word);
break;
case 'm': /* Media Description */
PDEBUG(DCC, DEBUG_DEBUG, " -> Media Description: %s\n", next_word);
LOGP(DCC, LOGL_DEBUG, " -> Media Description: %s\n", next_word);
/* add media description */
media = osmo_cc_add_media(session, 0, 0, NULL, 0, 0, 0, csend, creceive, NULL, 0);
/* copy common connection data from common connection, if exists */
@ -395,7 +395,7 @@ struct osmo_cc_session *osmo_cc_session_parsesdp(osmo_cc_session_config_t *conf,
else {
media->description.type = osmo_cc_session_media_type_unknown;
media->description.type_name = strdup(word);
PDEBUG(DCC, DEBUG_DEBUG, "Unsupported media type in SDP line %d = '%s'\n", line_no, line);
LOGP(DCC, LOGL_DEBUG, "Unsupported media type in SDP line %d = '%s'\n", line_no, line);
}
/* port */
if (!(word = wordsep(&next_word)))
@ -409,7 +409,7 @@ struct osmo_cc_session *osmo_cc_session_parsesdp(osmo_cc_session_config_t *conf,
else {
media->description.proto = osmo_cc_session_media_proto_unknown;
media->description.proto_name = strdup(word);
PDEBUG(DCC, DEBUG_NOTICE, "Unsupported protocol type in SDP line %d = '%s'\n", line_no, line);
LOGP(DCC, LOGL_NOTICE, "Unsupported protocol type in SDP line %d = '%s'\n", line_no, line);
break;
}
/* create codec description for each codec and link */
@ -419,17 +419,17 @@ struct osmo_cc_session *osmo_cc_session_parsesdp(osmo_cc_session_config_t *conf,
/* fmt */
codec->payload_type_remote = atoi(word);
complete_codec_by_fmt(codec->payload_type_remote, &codec->payload_name, &codec->payload_rate, &codec->payload_channels);
PDEBUG(DCC, DEBUG_DEBUG, " -> payload type = %d\n", codec->payload_type_remote);
LOGP(DCC, LOGL_DEBUG, " -> payload type = %d\n", codec->payload_type_remote);
if (codec->payload_name)
PDEBUG(DCC, DEBUG_DEBUG, " -> payload name = %s\n", codec->payload_name);
LOGP(DCC, LOGL_DEBUG, " -> payload name = %s\n", codec->payload_name);
if (codec->payload_rate)
PDEBUG(DCC, DEBUG_DEBUG, " -> payload rate = %d\n", codec->payload_rate);
LOGP(DCC, LOGL_DEBUG, " -> payload rate = %d\n", codec->payload_rate);
if (codec->payload_channels)
PDEBUG(DCC, DEBUG_DEBUG, " -> payload channels = %d\n", codec->payload_channels);
LOGP(DCC, LOGL_DEBUG, " -> payload channels = %d\n", codec->payload_channels);
}
break;
case 'a':
PDEBUG(DCC, DEBUG_DEBUG, " -> Attribute: %s\n", next_word);
LOGP(DCC, LOGL_DEBUG, " -> Attribute: %s\n", next_word);
word = wordsep(&next_word);
if (!strcmp(word, "sendrecv")) {
if (media) {
@ -472,7 +472,7 @@ struct osmo_cc_session *osmo_cc_session_parsesdp(osmo_cc_session_config_t *conf,
break;
} else
if (!media) {
PDEBUG(DCC, DEBUG_NOTICE, "Attribute without previously defined media in SDP line %d = '%s'\n", line_no, line);
LOGP(DCC, LOGL_NOTICE, "Attribute without previously defined media in SDP line %d = '%s'\n", line_no, line);
break;
}
if (!strncmp(word, "rtpmap:", 7)) {
@ -482,23 +482,23 @@ struct osmo_cc_session *osmo_cc_session_parsesdp(osmo_cc_session_config_t *conf,
break;
}
if (!codec) {
PDEBUG(DCC, DEBUG_NOTICE, "Attribute without previously defined codec in SDP line %d = '%s'\n", line_no, line);
LOGP(DCC, LOGL_NOTICE, "Attribute without previously defined codec in SDP line %d = '%s'\n", line_no, line);
break;
}
PDEBUG(DCC, DEBUG_DEBUG, " -> (rtpmap) payload type = %d\n", codec->payload_type_remote);
LOGP(DCC, LOGL_DEBUG, " -> (rtpmap) payload type = %d\n", codec->payload_type_remote);
if (!(word = wordsep(&next_word)))
goto rtpmap_done;
if ((p = strchr(word, '/')))
*p++ = '\0';
free((char *)codec->payload_name); // in case it is already set above
codec->payload_name = strdup(word);
PDEBUG(DCC, DEBUG_DEBUG, " -> (rtpmap) payload name = %s\n", codec->payload_name);
LOGP(DCC, LOGL_DEBUG, " -> (rtpmap) payload name = %s\n", codec->payload_name);
if (!(word = p))
goto rtpmap_done;
if ((p = strchr(word, '/')))
*p++ = '\0';
codec->payload_rate = atoi(word);
PDEBUG(DCC, DEBUG_DEBUG, " -> (rtpmap) payload rate = %d\n", codec->payload_rate);
LOGP(DCC, LOGL_DEBUG, " -> (rtpmap) payload rate = %d\n", codec->payload_rate);
if (!(word = p)) {
/* if no channel is given and no default was specified, we must set 1 channel */
if (!codec->payload_channels)
@ -506,10 +506,10 @@ struct osmo_cc_session *osmo_cc_session_parsesdp(osmo_cc_session_config_t *conf,
goto rtpmap_done;
}
codec->payload_channels = atoi(word);
PDEBUG(DCC, DEBUG_DEBUG, " -> (rtpmap) payload channels = %d\n", codec->payload_channels);
LOGP(DCC, LOGL_DEBUG, " -> (rtpmap) payload channels = %d\n", codec->payload_channels);
rtpmap_done:
if (!codec->payload_name || !codec->payload_rate || !codec->payload_channels) {
PDEBUG(DCC, DEBUG_NOTICE, "Broken 'rtpmap' definition in SDP line %d = '%s' Skipping codec!\n", line_no, line);
LOGP(DCC, LOGL_NOTICE, "Broken 'rtpmap' definition in SDP line %d = '%s' Skipping codec!\n", line_no, line);
osmo_cc_free_codec(codec);
}
}
@ -519,7 +519,7 @@ struct osmo_cc_session *osmo_cc_session_parsesdp(osmo_cc_session_config_t *conf,
/* if something is incomplete, abort here */
if (osmo_cc_session_check(session, 1)) {
PDEBUG(DCC, DEBUG_NOTICE, "Parsing SDP failed.\n");
LOGP(DCC, LOGL_NOTICE, "Parsing SDP failed.\n");
osmo_cc_free_session(session);
return NULL;
}
@ -537,7 +537,7 @@ void osmo_cc_debug_sdp(const char *_sdp)
for (i = 0; *sdp > 0 && *sdp >= 32 && i < (int)sizeof(text) - 1; i++)
text[i] = *sdp++;
text[i] = '\0';
PDEBUG(DCC, DEBUG_DEBUG, " | %s\n", text);
LOGP(DCC, LOGL_DEBUG, " | %s\n", text);
while (*sdp > 0 && *sdp < 32)
sdp++;
}

View File

@ -43,11 +43,11 @@ osmo_cc_session_t *osmo_cc_new_session(osmo_cc_session_config_t *conf, void *pri
{
osmo_cc_session_t *session;
if (debug) PDEBUG(DCC, DEBUG_DEBUG, "Creating session structure.\n");
if (debug) LOGP(DCC, LOGL_DEBUG, "Creating session structure.\n");
session = calloc(1, sizeof(*session));
if (!session) {
PDEBUG(DCC, DEBUG_ERROR, "No mem!\n");
LOGP(DCC, LOGL_ERROR, "No mem!\n");
abort();
}
session->config = conf;
@ -56,7 +56,7 @@ osmo_cc_session_t *osmo_cc_new_session(osmo_cc_session_config_t *conf, void *pri
int i;
for (i = 0; username[i]; i++) {
if ((uint8_t)username[i] < 33) {
PDEBUG(DCC, DEBUG_ERROR, "Fatal error: SDP's originator (username) uses invalid characters, please fix!\n");
LOGP(DCC, LOGL_ERROR, "Fatal error: SDP's originator (username) uses invalid characters, please fix!\n");
abort();
}
}
@ -64,7 +64,7 @@ osmo_cc_session_t *osmo_cc_new_session(osmo_cc_session_config_t *conf, void *pri
}
if (!username)
session->origin_local.username = strdup("-");
if (debug) PDEBUG(DCC, DEBUG_DEBUG, " -> user name = %s\n", session->origin_local.username);
if (debug) LOGP(DCC, LOGL_DEBUG, " -> user name = %s\n", session->origin_local.username);
if (sess_id)
session->origin_local.sess_id = strdup(sess_id);
if (sess_version)
@ -80,35 +80,35 @@ osmo_cc_session_t *osmo_cc_new_session(osmo_cc_session_config_t *conf, void *pri
if (!sess_version)
session->origin_local.sess_version = strdup(ntp_timestamp);
}
if (debug) PDEBUG(DCC, DEBUG_DEBUG, " -> session ID = %s\n", session->origin_local.sess_id);
if (debug) PDEBUG(DCC, DEBUG_DEBUG, " -> session version = %s\n", session->origin_local.sess_version);
if (debug) LOGP(DCC, LOGL_DEBUG, " -> session ID = %s\n", session->origin_local.sess_id);
if (debug) LOGP(DCC, LOGL_DEBUG, " -> session version = %s\n", session->origin_local.sess_version);
if (nettype)
session->origin_local.nettype = strdup(osmo_cc_session_nettype2string(nettype));
else
session->origin_local.nettype = strdup(osmo_cc_session_nettype2string(conf->default_nettype));
if (debug) PDEBUG(DCC, DEBUG_DEBUG, " -> network type = %s\n", session->origin_local.nettype);
if (debug) LOGP(DCC, LOGL_DEBUG, " -> network type = %s\n", session->origin_local.nettype);
if (addrtype)
session->origin_local.addrtype = strdup(osmo_cc_session_addrtype2string(addrtype));
else
session->origin_local.addrtype = strdup(osmo_cc_session_addrtype2string(conf->default_addrtype));
if (debug) PDEBUG(DCC, DEBUG_DEBUG, " -> address type = %s\n", session->origin_local.addrtype);
if (debug) LOGP(DCC, LOGL_DEBUG, " -> address type = %s\n", session->origin_local.addrtype);
if (unicast_address)
session->origin_local.unicast_address = strdup(unicast_address);
else
session->origin_local.unicast_address = strdup(conf->default_unicast_address);
if (debug) PDEBUG(DCC, DEBUG_DEBUG, " -> unicast address = %s\n", session->origin_local.unicast_address);
if (debug) LOGP(DCC, LOGL_DEBUG, " -> unicast address = %s\n", session->origin_local.unicast_address);
if (session_name)
session->name = strdup(session_name);
if (!session_name)
session->name = strdup("-");
if (debug) PDEBUG(DCC, DEBUG_DEBUG, " -> session name = %s\n", session->name);
if (debug) LOGP(DCC, LOGL_DEBUG, " -> session name = %s\n", session->name);
return session;
}
void osmo_cc_free_session(osmo_cc_session_t *session)
{
PDEBUG(DCC, DEBUG_DEBUG, "Free session structure.\n");
LOGP(DCC, LOGL_DEBUG, "Free session structure.\n");
free((char *)session->origin_local.username);
free((char *)session->origin_local.sess_id);
@ -135,7 +135,7 @@ osmo_cc_session_media_t *osmo_cc_add_media(osmo_cc_session_t *session, enum osmo
media = calloc(1, sizeof(*media));
if (!media) {
PDEBUG(DCC, DEBUG_ERROR, "No mem!\n");
LOGP(DCC, LOGL_ERROR, "No mem!\n");
abort();
}
media->session = session;
@ -164,14 +164,14 @@ osmo_cc_session_media_t *osmo_cc_add_media(osmo_cc_session_t *session, enum osmo
mediap = &((*mediap)->next);
*mediap = media;
if (debug) PDEBUG(DCC, DEBUG_DEBUG, "Adding session media.\n");
if (debug) PDEBUG(DCC, DEBUG_DEBUG, " -> network type = %s\n", osmo_cc_session_nettype2string(media->connection_data_local.nettype));
if (debug) PDEBUG(DCC, DEBUG_DEBUG, " -> address type = %s\n", osmo_cc_session_addrtype2string(media->connection_data_local.addrtype));
if (debug) PDEBUG(DCC, DEBUG_DEBUG, " -> address = %s\n", media->connection_data_local.address);
if (debug) PDEBUG(DCC, DEBUG_DEBUG, " -> media type = %s\n", osmo_cc_session_media_type2string(media->description.type));
if (debug) PDEBUG(DCC, DEBUG_DEBUG, " -> media port = %d\n", media->description.port_local);
if (debug) PDEBUG(DCC, DEBUG_DEBUG, " -> media proto = %s\n", osmo_cc_session_media_proto2string(media->description.proto));
if (debug) PDEBUG(DCC, DEBUG_DEBUG, "Opening and binding media port %d\n", media->description.port_local);
if (debug) LOGP(DCC, LOGL_DEBUG, "Adding session media.\n");
if (debug) LOGP(DCC, LOGL_DEBUG, " -> network type = %s\n", osmo_cc_session_nettype2string(media->connection_data_local.nettype));
if (debug) LOGP(DCC, LOGL_DEBUG, " -> address type = %s\n", osmo_cc_session_addrtype2string(media->connection_data_local.addrtype));
if (debug) LOGP(DCC, LOGL_DEBUG, " -> address = %s\n", media->connection_data_local.address);
if (debug) LOGP(DCC, LOGL_DEBUG, " -> media type = %s\n", osmo_cc_session_media_type2string(media->description.type));
if (debug) LOGP(DCC, LOGL_DEBUG, " -> media port = %d\n", media->description.port_local);
if (debug) LOGP(DCC, LOGL_DEBUG, " -> media proto = %s\n", osmo_cc_session_media_proto2string(media->description.proto));
if (debug) LOGP(DCC, LOGL_DEBUG, "Opening and binding media port %d\n", media->description.port_local);
return media;
}
@ -180,7 +180,7 @@ void osmo_cc_free_media(osmo_cc_session_media_t *media)
{
osmo_cc_session_media_t **mediap;
PDEBUG(DCC, DEBUG_DEBUG, "Free session media.\n");
LOGP(DCC, LOGL_DEBUG, "Free session media.\n");
osmo_cc_rtp_close(media);
free((char *)media->connection_data_local.nettype_name);
@ -205,7 +205,7 @@ osmo_cc_session_codec_t *osmo_cc_add_codec(osmo_cc_session_media_t *media, const
codec = calloc(1, sizeof(*codec));
if (!codec) {
PDEBUG(DCC, DEBUG_ERROR, "No mem!\n");
LOGP(DCC, LOGL_ERROR, "No mem!\n");
abort();
}
codec->media = media;
@ -232,11 +232,11 @@ osmo_cc_session_codec_t *osmo_cc_add_codec(osmo_cc_session_media_t *media, const
codecp = &((*codecp)->next);
*codecp = codec;
if (debug) PDEBUG(DCC, DEBUG_DEBUG, "Adding session codec.\n");
if (debug) PDEBUG(DCC, DEBUG_DEBUG, " -> payload type = %d\n", codec->payload_type_local);
if (debug) PDEBUG(DCC, DEBUG_DEBUG, " -> payload name = %s\n", codec->payload_name);
if (debug) PDEBUG(DCC, DEBUG_DEBUG, " -> payload rate = %d\n", codec->payload_rate);
if (debug) PDEBUG(DCC, DEBUG_DEBUG, " -> payload channels = %d\n", codec->payload_channels);
if (debug) LOGP(DCC, LOGL_DEBUG, "Adding session codec.\n");
if (debug) LOGP(DCC, LOGL_DEBUG, " -> payload type = %d\n", codec->payload_type_local);
if (debug) LOGP(DCC, LOGL_DEBUG, " -> payload name = %s\n", codec->payload_name);
if (debug) LOGP(DCC, LOGL_DEBUG, " -> payload rate = %d\n", codec->payload_rate);
if (debug) LOGP(DCC, LOGL_DEBUG, " -> payload channels = %d\n", codec->payload_channels);
return codec;
}
@ -245,7 +245,7 @@ void osmo_cc_free_codec(osmo_cc_session_codec_t *codec)
{
osmo_cc_session_codec_t **codecp;
PDEBUG(DCC, DEBUG_DEBUG, "Free session codec.\n");
LOGP(DCC, LOGL_DEBUG, "Free session codec.\n");
free((char *)codec->payload_name);
codecp = &codec->media->codec_list;
@ -274,15 +274,15 @@ int osmo_cc_session_check(osmo_cc_session_t *session, int remote)
|| !orig->nettype
|| !orig->addrtype
|| !orig->unicast_address) {
PDEBUG(DCC, DEBUG_NOTICE, "Missing data in session origin\n");
LOGP(DCC, LOGL_NOTICE, "Missing data in session origin\n");
return -EINVAL;
}
if (!session->name) {
PDEBUG(DCC, DEBUG_NOTICE, "Missing data in session origin\n");
LOGP(DCC, LOGL_NOTICE, "Missing data in session origin\n");
return -EINVAL;
}
if (!session->media_list) {
PDEBUG(DCC, DEBUG_NOTICE, "Missing media session\n");
LOGP(DCC, LOGL_NOTICE, "Missing media session\n");
return -EINVAL;
}
i = 0;
@ -293,39 +293,39 @@ int osmo_cc_session_check(osmo_cc_session_t *session, int remote)
else
cd = &media->connection_data_local;
if (!cd->nettype && !cd->nettype_name) {
PDEBUG(DCC, DEBUG_NOTICE, "Session with media #%d is missing connection network type\n", i);
LOGP(DCC, LOGL_NOTICE, "Session with media #%d is missing connection network type\n", i);
return -EINVAL;
}
if (!cd->addrtype && !cd->addrtype_name) {
PDEBUG(DCC, DEBUG_NOTICE, "Session with media #%d is missing connection address type\n", i);
LOGP(DCC, LOGL_NOTICE, "Session with media #%d is missing connection address type\n", i);
return -EINVAL;
}
if (!cd->address) {
PDEBUG(DCC, DEBUG_NOTICE, "Session with media #%d is missing connection address\n", i);
LOGP(DCC, LOGL_NOTICE, "Session with media #%d is missing connection address\n", i);
return -EINVAL;
}
md = &media->description;
if (!md->type && !md->type_name) {
PDEBUG(DCC, DEBUG_NOTICE, "Session with media #%d is missing media type\n", i);
LOGP(DCC, LOGL_NOTICE, "Session with media #%d is missing media type\n", i);
return -EINVAL;
}
if (!md->proto && !md->proto_name) {
PDEBUG(DCC, DEBUG_NOTICE, "Session with media #%d is missing protocol\n", i);
LOGP(DCC, LOGL_NOTICE, "Session with media #%d is missing protocol\n", i);
return -EINVAL;
}
j = 0;
osmo_cc_session_for_each_codec(media->codec_list, codec) {
j++;
if (!codec->payload_name) {
PDEBUG(DCC, DEBUG_NOTICE, "Session with media #%d, codec #%d is missing name\n", i, j);
LOGP(DCC, LOGL_NOTICE, "Session with media #%d, codec #%d is missing name\n", i, j);
return -EINVAL;
}
if (!codec->payload_rate) {
PDEBUG(DCC, DEBUG_NOTICE, "Session with media #%d, codec #%d is missing rate\n", i, j);
LOGP(DCC, LOGL_NOTICE, "Session with media #%d, codec #%d is missing rate\n", i, j);
return -EINVAL;
}
if (!codec->payload_channels) {
PDEBUG(DCC, DEBUG_NOTICE, "Session with media #%d, codec #%d is missing channel count\n", i, j);
LOGP(DCC, LOGL_NOTICE, "Session with media #%d, codec #%d is missing channel count\n", i, j);
return -EINVAL;
}
}
@ -340,11 +340,11 @@ const char *osmo_cc_session_send_offer(osmo_cc_session_t *session)
const char *sdp;
int rc;
PDEBUG(DCC, DEBUG_DEBUG, "Generating session offer and opening RTP stream.\n");
LOGP(DCC, LOGL_DEBUG, "Generating session offer and opening RTP stream.\n");
rc = osmo_cc_session_check(session, 0);
if (rc < 0) {
PDEBUG(DCC, DEBUG_ERROR, "Please fix!\n");
LOGP(DCC, LOGL_ERROR, "Please fix!\n");
abort();
}
@ -359,7 +359,7 @@ osmo_cc_session_t *osmo_cc_session_receive_offer(osmo_cc_session_config_t *conf,
osmo_cc_session_t *session;
int rc;
PDEBUG(DCC, DEBUG_DEBUG, "Parsing session offer.\n");
LOGP(DCC, LOGL_DEBUG, "Parsing session offer.\n");
osmo_cc_debug_sdp(sdp);
session = osmo_cc_session_parsesdp(conf, priv, sdp);
@ -397,10 +397,10 @@ void osmo_cc_session_accept_media(osmo_cc_session_media_t *media, enum osmo_cc_s
media->receive = receive;
media->receiver = receiver;
PDEBUG(DCC, DEBUG_DEBUG, "Accepting session media.\n");
PDEBUG(DCC, DEBUG_DEBUG, " -> network type = %s\n", osmo_cc_session_nettype2string(media->connection_data_local.nettype));
PDEBUG(DCC, DEBUG_DEBUG, " -> address type = %s\n", osmo_cc_session_addrtype2string(media->connection_data_local.addrtype));
PDEBUG(DCC, DEBUG_DEBUG, " -> address = %s\n", media->connection_data_local.address);
LOGP(DCC, LOGL_DEBUG, "Accepting session media.\n");
LOGP(DCC, LOGL_DEBUG, " -> network type = %s\n", osmo_cc_session_nettype2string(media->connection_data_local.nettype));
LOGP(DCC, LOGL_DEBUG, " -> address type = %s\n", osmo_cc_session_addrtype2string(media->connection_data_local.addrtype));
LOGP(DCC, LOGL_DEBUG, " -> address = %s\n", media->connection_data_local.address);
}
@ -412,11 +412,11 @@ void osmo_cc_session_accept_codec(osmo_cc_session_codec_t *codec, void (*encoder
/* when we accept a codec, we just use the same payload type as the remote */
codec->payload_type_local = codec->payload_type_remote;
PDEBUG(DCC, DEBUG_DEBUG, "Accepting session codec.\n");
PDEBUG(DCC, DEBUG_DEBUG, " -> payload type = %d\n", codec->payload_type_local);
PDEBUG(DCC, DEBUG_DEBUG, " -> payload name = %s\n", codec->payload_name);
PDEBUG(DCC, DEBUG_DEBUG, " -> payload rate = %d\n", codec->payload_rate);
PDEBUG(DCC, DEBUG_DEBUG, " -> payload channels = %d\n", codec->payload_channels);
LOGP(DCC, LOGL_DEBUG, "Accepting session codec.\n");
LOGP(DCC, LOGL_DEBUG, " -> payload type = %d\n", codec->payload_type_local);
LOGP(DCC, LOGL_DEBUG, " -> payload name = %s\n", codec->payload_name);
LOGP(DCC, LOGL_DEBUG, " -> payload rate = %d\n", codec->payload_rate);
LOGP(DCC, LOGL_DEBUG, " -> payload channels = %d\n", codec->payload_channels);
}
/* remove codecs/media that have not been accepted and generate SDP */
@ -427,7 +427,7 @@ const char *osmo_cc_session_send_answer(osmo_cc_session_t *session)
const char *sdp;
int rc;
PDEBUG(DCC, DEBUG_DEBUG, "Generating session answer.\n");
LOGP(DCC, LOGL_DEBUG, "Generating session answer.\n");
/* loop all media */
osmo_cc_session_for_each_media(session->media_list, media) {
@ -450,7 +450,7 @@ const char *osmo_cc_session_send_answer(osmo_cc_session_t *session)
rc = osmo_cc_session_check(session, 0);
if (rc < 0) {
PDEBUG(DCC, DEBUG_ERROR, "Please fix!\n");
LOGP(DCC, LOGL_ERROR, "Please fix!\n");
abort();
}
@ -470,7 +470,7 @@ static int osmo_cc_session_negotiate(osmo_cc_session_t *session_local, struct os
osmo_cc_session_codec_t *codec_local, *codec_remote, **codec_local_p;
int rc;
PDEBUG(DCC, DEBUG_DEBUG, "Negotiating session.\n");
LOGP(DCC, LOGL_DEBUG, "Negotiating session.\n");
/* copy remote session information */
session_local->origin_remote.username = strdup(session_remote->origin_remote.username);
@ -517,11 +517,11 @@ static int osmo_cc_session_negotiate(osmo_cc_session_t *session_local, struct os
}
}
if (media_local) {
PDEBUG(DCC, DEBUG_NOTICE, "Negotiation failed, because remote endpoint returns less media streams than we offered.\n");
LOGP(DCC, LOGL_NOTICE, "Negotiation failed, because remote endpoint returns less media streams than we offered.\n");
return -EINVAL;
}
if (media_remote) {
PDEBUG(DCC, DEBUG_NOTICE, "Negotiation failed, because remote endpoint returns more media streams than we offered.\n");
LOGP(DCC, LOGL_NOTICE, "Negotiation failed, because remote endpoint returns more media streams than we offered.\n");
return -EINVAL;
}
@ -550,7 +550,7 @@ int osmo_cc_session_receive_answer(osmo_cc_session_t *session, const char *sdp)
osmo_cc_session_t *session_remote;
int rc;
PDEBUG(DCC, DEBUG_DEBUG, "Parsing session answer.\n");
LOGP(DCC, LOGL_DEBUG, "Parsing session answer.\n");
osmo_cc_debug_sdp(sdp);
session_remote = osmo_cc_session_parsesdp(session->config, NULL, sdp);

View File

@ -1,3 +1,5 @@
#include <sys/socket.h>
/* configuration */
enum osmo_cc_session_nettype {
@ -80,6 +82,9 @@ typedef struct osmo_cc_session_media {
struct osmo_cc_session_codec *codec_list;
int send, receive;
void (*receiver)(struct osmo_cc_session_codec *codec, uint8_t marker, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len);
struct sockaddr_storage rtp_sa, rtcp_sa;
socklen_t rtp_slen, rtcp_slen;
uint16_t *rtp_sport, *rtcp_sport; // pointers to the port inside sa sockaddr
struct osmo_fd rtp_ofd;
struct osmo_fd rtcp_ofd;
uint32_t tx_ssrc, rx_ssrc;

View File

@ -55,7 +55,7 @@ static int _getaddrinfo(const char *host, uint16_t port, struct addrinfo **resul
rc = getaddrinfo(host, portstr, &hints, result);
if (rc < 0) {
PDEBUG(DCC, DEBUG_ERROR, "Failed to create socket for host '%s', port '%d': %s.\n", host, port, gai_strerror(rc));
LOGP(DCC, LOGL_ERROR, "Failed to create socket for host '%s', port '%d': %s.\n", host, port, gai_strerror(rc));
return rc;
}
return rc;
@ -98,7 +98,7 @@ static void rx_keepalive_timeout(void *data)
{
osmo_cc_conn_t *conn = data;
PDEBUG(DCC, DEBUG_ERROR, "OsmoCC-Socket failed due to timeout.\n");
LOGP(DCC, LOGL_ERROR, "OsmoCC-Socket failed due to timeout.\n");
close_conn(conn, OSMO_CC_SOCKET_CAUSE_TIMEOUT);
}
@ -121,7 +121,7 @@ try_again:
auto_port = 1;
}
PDEBUG(DCC, DEBUG_DEBUG, "Create socket for host %s port %d.\n", host, port);
LOGP(DCC, LOGL_DEBUG, "Create socket for host %s port %d.\n", host, port);
rc = _getaddrinfo(host, port, &result);
if (rc < 0)
@ -140,17 +140,17 @@ try_again:
freeaddrinfo(result);
if (rp == NULL) {
if (auto_port && port < OSMO_CC_DEFAULT_PORT_MAX) {
PDEBUG(DCC, DEBUG_DEBUG, "Failed to bind host %s port %d, trying again.\n", host, port);
LOGP(DCC, LOGL_DEBUG, "Failed to bind host %s port %d, trying again.\n", host, port);
goto try_again;
}
PDEBUG(DCC, DEBUG_ERROR, "Failed to bind given host %s port %d.\n", host, port);
LOGP(DCC, LOGL_ERROR, "Failed to bind given host %s port %d.\n", host, port);
return -EIO;
}
/* listen to socket */
rc = listen(sock, 10);
if (rc < 0) {
PDEBUG(DCC, DEBUG_ERROR, "Failed to listen on socket.\n");
LOGP(DCC, LOGL_ERROR, "Failed to listen on socket.\n");
close(sock);
return rc;
}
@ -178,7 +178,7 @@ static osmo_cc_conn_t *open_conn(osmo_cc_socket_t *os, int sock, uint32_t callre
/* create connection */
conn = calloc(1, sizeof(*conn));
if (!conn) {
PDEBUG(DCC, DEBUG_ERROR, "No mem!\n");
LOGP(DCC, LOGL_ERROR, "No mem!\n");
abort();
}
conn->os = os;
@ -200,7 +200,7 @@ static osmo_cc_conn_t *open_conn(osmo_cc_socket_t *os, int sock, uint32_t callre
timer_start(&conn->tx_keepalive_timer, OSMO_CC_SOCKET_TX_KEEPALIVE);
timer_start(&conn->rx_keepalive_timer, OSMO_CC_SOCKET_RX_KEEPALIVE);
PDEBUG(DCC, DEBUG_DEBUG, "New socket connection (callref %d).\n", conn->callref);
LOGP(DCC, LOGL_DEBUG, "New socket connection (callref %d).\n", conn->callref);
/* attach to list */
connp = &os->conn_list;
@ -228,7 +228,7 @@ static void close_conn(osmo_cc_conn_t *conn, uint8_t socket_cause)
rej_msg(conn->os, conn->callref, socket_cause, 0, 0);
}
PDEBUG(DCC, DEBUG_DEBUG, "Destroy socket connection (callref %d).\n", conn->callref);
LOGP(DCC, LOGL_DEBUG, "Destroy socket connection (callref %d).\n", conn->callref);
/* close socket */
if (conn->ofd.fd) {
@ -256,7 +256,7 @@ void osmo_cc_close_socket(osmo_cc_socket_t *os)
{
osmo_cc_msg_list_t *ml;
PDEBUG(DCC, DEBUG_DEBUG, "Destroy socket.\n");
LOGP(DCC, LOGL_DEBUG, "Destroy socket.\n");
/* free all connections */
while (os->conn_list)
@ -317,12 +317,12 @@ static int receive_conn(osmo_cc_conn_t *conn)
if (conn->read_version_pos == strlen(version_string)) {
conn->read_version = 0;
if (!!memcmp(conn->read_version_string, version_string, strlen(version_string) - 1)) {
PDEBUG(DCC, DEBUG_NOTICE, "Remote does not seem to be an Osmo-CC socket, rejecting!\n");
LOGP(DCC, LOGL_NOTICE, "Remote does not seem to be an Osmo-CC socket, rejecting!\n");
socket_cause = OSMO_CC_SOCKET_CAUSE_FAILED;
goto close;
}
if (conn->read_version_string[strlen(version_string) - 1] != version_string[strlen(version_string) - 1]) {
PDEBUG(DCC, DEBUG_NOTICE, "Remote Osmo-CC socket has wrong version (local=%s, remote=%s), rejecting!\n", version_string, conn->read_version_string);
LOGP(DCC, LOGL_NOTICE, "Remote Osmo-CC socket has wrong version (local=%s, remote=%s), rejecting!\n", version_string, conn->read_version_string);
socket_cause = OSMO_CC_SOCKET_CAUSE_VERSION_MISMATCH;
goto close;
}
@ -382,7 +382,7 @@ empty_message:
else
conn->os->recv_msg_cb(conn->os->priv, conn->callref, msg);
if (msg_type == OSMO_CC_MSG_REL_REQ || msg_type == OSMO_CC_MSG_REJ_REQ) {
PDEBUG(DCC, DEBUG_DEBUG, "closing socket because we received a release or reject message.\n");
LOGP(DCC, LOGL_DEBUG, "closing socket because we received a release or reject message.\n");
close_conn(conn, 0);
return 1; /* conn removed */
}
@ -391,7 +391,7 @@ empty_message:
return work;
close:
PDEBUG(DCC, DEBUG_ERROR, "OsmoCC-Socket failed, socket cause %d.\n", socket_cause);
LOGP(DCC, LOGL_ERROR, "OsmoCC-Socket failed, socket cause %d.\n", socket_cause);
close_conn(conn, socket_cause);
return work; /* conn removed */
}
@ -418,7 +418,7 @@ static int transmit_conn(osmo_cc_conn_t *conn)
goto close;
}
if (rc != strlen(version_string)) {
PDEBUG(DCC, DEBUG_ERROR, "short write, please fix handling!\n");
LOGP(DCC, LOGL_ERROR, "short write, please fix handling!\n");
abort();
}
conn->write_version = 0;
@ -437,12 +437,12 @@ static int transmit_conn(osmo_cc_conn_t *conn)
goto close;
}
if (rc != len) {
PDEBUG(DCC, DEBUG_ERROR, "short write, please fix handling!\n");
LOGP(DCC, LOGL_ERROR, "short write, please fix handling!\n");
abort();
}
/* close socket after sending release/reject message */
if (msg->type == OSMO_CC_MSG_REL_REQ || msg->type == OSMO_CC_MSG_REJ_REQ) {
PDEBUG(DCC, DEBUG_DEBUG, "closing socket because we sent a release or reject message.\n");
LOGP(DCC, LOGL_DEBUG, "closing socket because we sent a release or reject message.\n");
close_conn(conn, 0);
return work; /* conn removed */
}
@ -463,7 +463,7 @@ static int transmit_conn(osmo_cc_conn_t *conn)
return work;
close:
PDEBUG(DCC, DEBUG_NOTICE, "OsmoCC-Socket failed.\n");
LOGP(DCC, LOGL_NOTICE, "OsmoCC-Socket failed.\n");
close_conn(conn, socket_cause);
return work; /* conn removed */
}
@ -516,7 +516,7 @@ int osmo_cc_handle_socket(osmo_cc_socket_t *os)
/* reject, if this is not a setup message */
if (ml->msg->type != OSMO_CC_MSG_SETUP_REQ
&& ml->msg->type != OSMO_CC_MSG_ATTACH_REQ) {
PDEBUG(DCC, DEBUG_ERROR, "Message with unknown callref.\n");
LOGP(DCC, LOGL_ERROR, "Message with unknown callref.\n");
rej_msg(os, ml->callref, 0, OSMO_CC_ISDN_CAUSE_INVAL_CALLREF, 0);
/* drop message */
osmo_cc_free_msg(ml->msg);
@ -550,7 +550,7 @@ int osmo_cc_handle_socket(osmo_cc_socket_t *os)
}
freeaddrinfo(result);
if (rp == NULL) {
PDEBUG(DCC, DEBUG_ERROR, "Failed to connect to given host %s port %d.\n", ml->host, ml->port);
LOGP(DCC, LOGL_ERROR, "Failed to connect to given host %s port %d.\n", ml->host, ml->port);
rej_msg(os, ml->callref, OSMO_CC_SOCKET_CAUSE_FAILED, 0, 0);
/* drop message */
osmo_cc_free_msg(ml->msg);

22
src/r1/Makefile.am Normal file
View File

@ -0,0 +1,22 @@
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
bin_PROGRAMS = \
osmo-cc-r1-endpoint
osmo_cc_r1_endpoint_SOURCES = \
r1.c \
main.c
osmo_cc_r1_endpoint_LDADD = \
$(COMMON_LA) \
../common/libcommon.a \
../libdebug/libdebug.a \
../liboptions/liboptions.a \
../libsample/libsample.a \
../libtimer/libtimer.a \
../libselect/libselect.a \
../libjitter/libjitter.a \
../libosmocc/libosmocc.a \
../libg711/libg711.a \
../libfilter/libfilter.a

378
src/r1/main.c Normal file
View File

@ -0,0 +1,378 @@
/* osmo-cc-r1-endpoint main
*
* (C) 2020 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/>.
*/
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <termios.h>
#include "../libdebug/debug.h"
#include "../liboptions/options.h"
#include "../libg711/g711.h"
#include "r1.h"
#include "../common/display.h"
#include "../common/sit.h"
r1_endpoint_t *r1_ep_sunset = NULL, *r1_ep_sunrise = NULL;
int num_kanal = 2;
int endpoints = 1;
int links = 0;
int pulsedialing = 0;
int suppress_disconnect = 1;
int clear_back_timeout = 60;
int crosstalk = 1;
int delay_ms = 0;
double sense_db = 0;
#define MAX_CC_ARGS 1024
static int cc_argc_sunset, cc_argc_sunrise = 0;
static const char *cc_argv_sunset[MAX_CC_ARGS], *cc_argv_sunrise[MAX_CC_ARGS];
static void print_usage(const char *app)
{
printf("Usage: %s [<options>]\n", app);
printf("This will create pairs of R1 channels that are bridged together, so that\n");
printf("calls from one link to the other can be made using R1. The a bluebox can be\n");
printf("used to play with it.\n");
printf("If one endpoint is used (default), its name is 'sunset' and each pair of\n");
printf("channels are bridged together. If two endpoints are used, their names are\n");
printf("'sunset' and 'sunrise' and same channel index of both endpoints are bridged\n");
printf("together.\n");
}
static void print_help()
{
/* - - */
printf(" -h --help\n");
printf(" This help\n");
printf(" --config [~/]<path to config file>\n");
printf(" Give a config file to use. If it starts with '~/', path is at home dir.\n");
printf(" Each line in config file is one option, '-' or '--' must not be given!\n");
debug_print_help();
printf(" -2 --two\n");
printf(" Create two Osmo-CC endpoints instead of one.\n");
printf(" -c --channels\n");
printf(" Give number of channels per endpoint. If you use a single endpoint,\n");
printf(" you must define an even number. By default this is '2' for one\n");
printf(" endpoint and '1' for two endpoints.\n");
printf(" -s --suppress-disconnect 1 | 0\n");
printf(" When a 'busy-flash' or 'release-guard' is received a disconnect is\n");
printf(" forwarded towards OsmoCC. Set to 1 to suppress this. (Default is %d.)\n", suppress_disconnect);
printf(" -p --pulse-dialing 1 | 0\n");
printf(" Send/receive digits via pulse dialing (SF) instead of tones (MF).\n");
printf(" -x --crosstalk 1 | 0\n");
printf(" Enable or disable some minor crosstalk. This allows you to hear\n");
printf(" transmitted tones at a low volume. (Default is %d.)\n", crosstalk);
printf(" -d --delay <ms> | 0\n");
printf(" Add one-way delay to the connection between two R1 links. This allows\n");
printf(" to hear 'acknowlege' tones delayed. (Default is %d ms.)\n", delay_ms);
printf(" -T --clear-back-timeout 0 | <seconds>\n");
printf(" At the outgoing end: Time to wait while receiving clear-back (hangup)\n");
printf(" signal until releasing call. Use 0 to disable. (Default is %d s.)\n", clear_back_timeout);
printf(" --sense 0 | <db>\n");
printf(" Increase sensitivity of tone detector. A bluebox can have lower level\n");
printf(" than what the standard requires. (Default is %.0f dB.)\n", sense_db);
printf(" -C --cc \"<osmo-cc arg>\" [--cc ...]\n");
printf(" --cc2 \"<osmo-cc arg>\" [--cc2 ...]\n");
printf(" Pass arguments to Osmo-CC endpoint. Use '-cc help' for description.\n");
printf(" If you select two endpoints, use '--cc2' to pass arguments to the\n");
printf(" second endpoint.\n");
}
#define OPT_SENSE 256
#define OPT_CC2 257
static void add_options(void)
{
option_add('h', "help", 0);
option_add('v', "verbose", 1);
option_add('2', "two", 0);
option_add('c', "channels", 1);
option_add('s', "suppress-disconnect", 1);
option_add('p', "pulse-dialing", 1);
option_add('x', "crosstalk", 1);
option_add('d', "delay", 1);
option_add('T', "clear-back-timeout", 1);
option_add(OPT_SENSE, "sense", 1);
option_add('C', "cc", 1);
option_add(OPT_CC2, "cc2", 1);
}
static int handle_options(int short_option, int argi, char **argv)
{
int rc;
switch (short_option) {
case 'h':
print_usage(argv[0]);
print_help();
return 0;
case 'v':
if (!strcasecmp(argv[argi], "list")) {
debug_list_cat();
return 0;
}
rc = parse_debug_opt(argv[argi]);
if (rc < 0) {
fprintf(stderr, "Failed to parse debug option, please use -h for help.\n");
return rc;
}
break;
case '2':
endpoints = 2;
break;
case 'c':
links = atoi(argv[argi]);
break;
case 's':
suppress_disconnect = atoi(argv[argi]);
break;
case 'p':
pulsedialing = atoi(argv[argi]);
break;
case 'x':
crosstalk = atoi(argv[argi]);
break;
case 'd':
delay_ms = atoi(argv[argi]);
break;
case 'T':
clear_back_timeout = atoi(argv[argi]);
break;
case OPT_SENSE:
sense_db = (double)atoi(argv[argi]);
break;
case 'C':
if (!strcasecmp(argv[argi], "help")) {
osmo_cc_help();
return 0;
}
if (cc_argc_sunset == MAX_CC_ARGS) {
fprintf(stderr, "Too many osmo-cc args!\n");
break;
}
cc_argv_sunset[cc_argc_sunset++] = options_strdup(argv[argi]);
break;
case OPT_CC2:
if (!strcasecmp(argv[argi], "help")) {
osmo_cc_help();
return 0;
}
if (cc_argc_sunrise == MAX_CC_ARGS) {
fprintf(stderr, "Too many osmo-cc args!\n");
break;
}
cc_argv_sunrise[cc_argc_sunrise++] = options_strdup(argv[argi]);
break;
default:
return -EINVAL;
}
return 1;
}
static int quit = 0;
void sighandler(int sigset)
{
if (sigset == SIGHUP || sigset == SIGPIPE)
return;
fprintf(stderr, "\nSignal %d received.\n", sigset);
quit = 1;
}
static int get_char()
{
struct timeval tv = {0, 0};
fd_set fds;
char c = 0;
int __attribute__((__unused__)) rc;
FD_ZERO(&fds);
FD_SET(0, &fds);
select(0+1, &fds, NULL, NULL, &tv);
if (FD_ISSET(0, &fds)) {
rc = read(0, &c, 1);
return c;
} else
return -1;
}
struct timer clock_timer;
double last_time_clock = 0;
static void clock_timeout(void __attribute__((unused)) *data)
{
double now;
int c;
/* add timer to wait for next 20ms */
now = get_time();
if (now - last_time_clock >= 0.1)
last_time_clock = now;
last_time_clock += 0.020;
if (last_time_clock < now)
last_time_clock = now;
timer_start(&clock_timer, last_time_clock - now);
/* call audio clock every 20ms */
audio_clock((r1_ep_sunset) ? r1_ep_sunset->dsp_list : NULL, (r1_ep_sunrise) ? r1_ep_sunrise->dsp_list : NULL, 160);
/* process keyboard input */
c = get_char();
switch (c) {
case 3:
printf("CTRL+c received, quitting!\n");
quit = 1;
break;
case 'c':
display_status_on(-1);
}
}
int main(int argc, char *argv[])
{
int argi, rc;
struct termios term, term_orig;
/* init MF */
mf_init(0);
/* init codecs */
g711_init();
/* init sit */
init_sit(8000);
/* init dsp */
dsp_set_sf(-8.0, -27.0);
cc_argv_sunset[cc_argc_sunset++] = options_strdup("remote auto");
cc_argv_sunrise[cc_argc_sunrise++] = options_strdup("remote auto");
/* handle options / config file */
add_options();
rc = options_config_file(argc, argv, "~/.osmocom/r1/r1.conf", handle_options);
if (rc < 0)
return 0;
argi = options_command_line(argc, argv, handle_options);
if (argi <= 0)
return argi;
/* check links (per endpoint) */
if (!links)
links = (endpoints == 2) ? 1 : 2;
if (links == 1 && (endpoints % 1)) {
PDEBUG(DR1, DEBUG_ERROR, "You must define an even number of channels on a single endpoint!\n");
goto error;
}
/* create sunset and (optionally) sunrise */
r1_ep_sunset = r1_ep_create("sunset", links, suppress_disconnect, clear_back_timeout, crosstalk, delay_ms, sense_db, pulsedialing);
if (!r1_ep_sunset)
goto error;
rc = osmo_cc_new(&r1_ep_sunset->cc_ep, OSMO_CC_VERSION, "sunset", OSMO_CC_LOCATION_BEYOND_INTERWORKING, cc_message, NULL, r1_ep_sunset, cc_argc_sunset, cc_argv_sunset);
if (rc < 0)
goto error;
if (endpoints == 2) {
r1_ep_sunrise = r1_ep_create("sunrise", links, suppress_disconnect, clear_back_timeout, crosstalk, delay_ms, sense_db, pulsedialing);
if (!r1_ep_sunrise)
goto error;
rc = osmo_cc_new(&r1_ep_sunrise->cc_ep, OSMO_CC_VERSION, "sunrise", OSMO_CC_LOCATION_BEYOND_INTERWORKING, cc_message, NULL, r1_ep_sunrise, cc_argc_sunrise, cc_argv_sunrise);
if (rc < 0)
goto error;
PDEBUG(DR1, DEBUG_NOTICE, "Created endpoints 'sunset' and 'sunrise' with %d links that connect these endpoints.\n", links);
} else
PDEBUG(DR1, DEBUG_NOTICE, "Created endpoint 'sunset' with %d links, each pair connected.\n", links);
refresh_status();
/* init clock timer for clocking call */
timer_init(&clock_timer, clock_timeout, NULL);
timer_start(&clock_timer, 0.020);
/* prepare terminal */
tcgetattr(0, &term_orig);
term = term_orig;
term.c_lflag &= ~(ISIG|ICANON|ECHO);
term.c_cc[VMIN]=1;
term.c_cc[VTIME]=2;
tcsetattr(0, TCSANOW, &term);
/* catch signals */
signal(SIGINT, sighandler);
signal(SIGHUP, sighandler);
signal(SIGTERM, sighandler);
signal(SIGPIPE, sighandler);
while (!quit) {
int work;
double timeout;
do {
work = 0;
work |= osmo_cc_handle();
} while (work);
/* handle all timers
* timeout is 0, if there was an event
* -> handle FDs without waiting, continue this loop
* timeout is not 0, if there was no event
* -> wait until FD or timeout
*/
timeout = process_timer();
/* wait for FD event until given timeout */
osmo_fd_select(timeout);
}
/* reset signals */
signal(SIGINT, SIG_DFL);
signal(SIGTSTP, SIG_DFL);
signal(SIGHUP, SIG_DFL);
signal(SIGTERM, SIG_DFL);
signal(SIGPIPE, SIG_DFL);
/* reset terminal */
tcsetattr(0, TCSANOW, &term_orig);
error:
timer_exit(&clock_timer);
/* destroy endpoints */
if (r1_ep_sunset) {
osmo_cc_delete(&r1_ep_sunset->cc_ep);
r1_ep_destroy(r1_ep_sunset);
}
if (r1_ep_sunrise) {
osmo_cc_delete(&r1_ep_sunrise->cc_ep);
r1_ep_destroy(r1_ep_sunrise);
}
/* exit sit */
exit_sit();
/* exit MF */
mf_exit();
options_free();
return 0;
}

837
src/r1/r1.c Normal file
View File

@ -0,0 +1,837 @@
/* R1 process
*
* (C) 2023 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/>.
*/
#define CHAN r1->name
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include <errno.h>
#include <sys/types.h>
#include "../libdebug/debug.h"
#include "../libg711/g711.h"
#include "r1.h"
#include "../common/display.h"
#include "../common/common.h"
/* names of all R1 states */
const char *r1_state_names[] = {
"NULL",
/* idle line */
"IDLE",
/* outgoing call */
"SEIZING",
"OUT DELAY-DIALING",
"SEND DIGITS",
"OUT PROCEED",
"OUT ANSWER",
"OUT HANGUP",
/* incoming call */
"IN DELAY-DIALING",
"RECV DIGIT WAIT",
"RECV DIGIT ON",
"RECV PULSE WAIT",
"RECV PULSE ON",
"RECV PULSE OFF",
"IN PROCEED",
"IN ANSWER",
"IN HANGUP",
};
/* timers and durations */
#define INTERRUPT_RECOGNITION 0.030 /* an interruption of 30 ms is considered to be a stop of digit */
#define SPLIT_RECOGNITION 0.015 /* time until received audio is split (band-stop filter turned on) */
#define MF_RECOGNITION 0.025
#define KP_DIGIT_DURATION 0.100
#define OTHER_DIGIT_DURATION 0.068
#define DIGIT_PAUSE 0.068
#define PULSE_PAUSE 0.600
#define SIGN_RECOGNITION_FAST 0.030 /* all tones except clear forward */
#define SIGN_RECOGNITION_SLOW 0.300 /* clear forward after providing a register */
#define HANGUP_TIMEOUT 0.013 /* timeout after receiving hangup, then disconnect */
#define CLEAR_FORWARD 0.300 /* tone on for at least 300ms to recognise as clear-forward */
#define TO_SEIZING 5.0 /* timeout waiting for a register (double seizure detection) */
#define TO_DELAY_DIALING 0.140 /* time to wait until dialing register is available */
#define TO_DIALING 5.0 /* timeout when receiving no additional digits */
#define TO_PROCEEDING 60.0 /* timeout when there is no answer */
#define TO_PULSE 0.300 /* after this time the pulse is too long or states a new digit */
#define TO_GUARD_BUSY 1.250 /* guard time to wait until outgoing calls are allowed */
static struct osmo_cc_helper_audio_codecs codecs[] = {
{ "L16", 8000, 1, encode_l16, decode_l16 },
{ "PCMA", 8000, 1, g711_encode_alaw, g711_decode_alaw },
{ "PCMU", 8000, 1, g711_encode_ulaw, g711_decode_ulaw },
{ NULL, 0, 0, NULL, NULL},
};
void refresh_status(void)
{
osmo_cc_endpoint_t *ep;
r1_endpoint_t *r1_ep;
dsp_t *dsp;
r1_t *r1;
int i;
display_status_start();
for (ep = osmo_cc_endpoint_list; ep; ep = ep->next) {
r1_ep = ep->priv;
if (!r1_ep->dsp_list)
display_status_line(ep->local_name, 0, NULL, NULL, "");
for (i = 0, dsp = r1_ep->dsp_list; dsp; i++, dsp = dsp->next) {
r1 = dsp->priv;
display_status_line(ep->local_name, i, r1->callerid, r1->dialing, r1_state_names[r1->state]);
}
}
display_status_end();
}
#define r1_new_state(r1, state) _r1_new_state(r1, state, __LINE__)
void _r1_new_state(r1_t *r1, enum r1_state state, int line)
{
PDEBUG_CHAN(DR1, DEBUG_DEBUG, "Changing state '%s' -> '%s' (called from line %d)\n", r1_state_names[r1->state], r1_state_names[state], line);
r1->state = state;
/* must update (new state) */
refresh_status();
}
/*
* endpoints & links
*/
/* reset R1 link, but keep states, so audio generation/processing can continue */
static void link_reset(r1_t *r1)
{
/* unlink callref */
r1->dsp.cc_callref = 0;
/* stop timer */
timer_stop(&r1->timer);
/* free session description */
if (r1->dsp.cc_session) {
osmo_cc_free_session(r1->dsp.cc_session);
r1->dsp.cc_session = NULL;
r1->dsp.codec = NULL;
}
/* reset jitter buffer */
jitter_reset(&r1->dsp.tx_dejitter);
/* set recognition time */
set_sig_detect_duration(&r1->dsp, SIGN_RECOGNITION_FAST, 0.0);
/* make tone gerator non-transparent */
set_tone_transparent(&r1->dsp, 0);
/* reset all other states */
r1->callerid[0] = '\0';
r1->dialing[0] = '\0';
/* must update (e.g. caller and dialing) */
refresh_status();
}
static void r1_timeout(void *data);
static r1_t *link_create(r1_endpoint_t *r1_ep, const char *ep_name, int linkid, double samplerate, int crosstalk, int delay_ms, double sense_db, int pulsedialing)
{
r1_t *r1;
dsp_t **dsp_p;
r1 = calloc(1, sizeof(*r1));
if (!r1) {
PDEBUG(DR1, DEBUG_ERROR, "No memory!\n");
abort();
}
r1->r1_ep = r1_ep;
r1->pulsedialing = pulsedialing;
/* debug name */
snprintf(r1->name, sizeof(r1->name) - 1, "%s/%d", ep_name, linkid);
/* init dsp instance */
dsp_init_inst(&r1->dsp, r1, r1->name, samplerate, crosstalk, 0, delay_ms, sense_db, INTERRUPT_RECOGNITION, SPLIT_RECOGNITION, MF_RECOGNITION, KP_DIGIT_DURATION, OTHER_DIGIT_DURATION, DIGIT_PAUSE, PULSE_PAUSE, 2600.0, 0);
/* init timer */
timer_init(&r1->timer, r1_timeout, r1);
/* reset instance */
link_reset(r1);
/* Turn on SF */
set_tone(&r1->dsp, 'B', 0);
/* link */
dsp_p = &r1_ep->dsp_list;
while (*dsp_p)
dsp_p = &((*dsp_p)->next);
*dsp_p = &r1->dsp;
PDEBUG_CHAN(DR1, DEBUG_DEBUG, "created R1 instance\n");
return r1;
}
static void link_destroy(r1_t *r1)
{
dsp_t **dsp_p;
/* detach */
dsp_p = &r1->r1_ep->dsp_list;
while (*dsp_p) {
if (*dsp_p == &r1->dsp)
break;
dsp_p = &((*dsp_p)->next);
}
*dsp_p = r1->dsp.next;
/* state idle */
r1_new_state(r1, R1_STATE_NULL);
/* reset instance */
link_reset(r1);
/* exit timer */
timer_exit(&r1->timer);
/* cleanup dsp instance */
dsp_cleanup_inst(&r1->dsp);
PDEBUG_CHAN(DR1, DEBUG_DEBUG, "destroyed R1 instance\n");
free(r1);
}
r1_endpoint_t *r1_ep_create(const char *ep_name, int links, int suppress_disconnect, int clear_back_timeout, int crosstalk, int delay_ms, double sense_db, int pulsedialing)
{
r1_endpoint_t *r1_ep;
int i;
r1_ep = calloc(1, sizeof(*r1_ep));
if (!r1_ep) {
PDEBUG(DR1, DEBUG_ERROR, "No memory!\n");
abort();
}
r1_ep->suppress_disconnect = suppress_disconnect;
r1_ep->clear_back_timeout = clear_back_timeout;
for (i = 0; i < links; i++)
link_create(r1_ep, ep_name, i + 1, 8000.0, crosstalk, delay_ms, sense_db, pulsedialing);
PDEBUG(DR1, DEBUG_DEBUG, "R1 endpoint instance created\n");
return r1_ep;
}
void r1_ep_destroy(r1_endpoint_t *r1_ep)
{
/* destroy all calls */
while (r1_ep->dsp_list)
link_destroy(r1_ep->dsp_list->priv);
free(r1_ep);
PDEBUG(DR1, DEBUG_DEBUG, "R1 endpoint instance destroyed\n");
}
/*
* event handling
*/
void setup_call(r1_t *r1)
{
osmo_cc_msg_t *msg;
uint8_t type;
char dialing[sizeof(r1->dialing)];
int rc;
PDEBUG_CHAN(DR1, DEBUG_INFO, "Dialing '%s' is complete, sending setup message towards call control.\n", r1->dialing);
/* stop timer */
timer_stop(&r1->timer);
/* check and convert dial string, only do that for MF dialing */
if (r1->pulsedialing) {
type = OSMO_CC_TYPE_UNKNOWN;
strcpy(dialing, r1->dialing);
} else {
rc = parse_dial_string(&type, dialing, sizeof(dialing), r1->dialing);
if (rc < 0) {
/* state hangup */
r1_new_state(r1, R1_STATE_IN_HANGUP);
/* send SIT */
set_sit(&r1->dsp, 1);
return;
}
}
/* setup message */
msg = osmo_cc_new_msg(OSMO_CC_MSG_SETUP_IND);
/* network type */
osmo_cc_add_ie_calling_network(msg, OSMO_CC_NETWORK_R1_NONE, "");
/* called number */
osmo_cc_add_ie_called(msg, type, OSMO_CC_PLAN_TELEPHONY, dialing);
/* sdp offer */
r1->dsp.cc_session = osmo_cc_helper_audio_offer(&r1->r1_ep->cc_ep.session_config, &r1->dsp, codecs, down_audio, msg, 1);
if (!r1->dsp.cc_session) {
osmo_cc_free_msg(msg);
PDEBUG_CHAN(DR1, DEBUG_NOTICE, "Failed to offer audio, sending 'clear-back'.\n");
/* state hangup */
r1_new_state(r1, R1_STATE_IN_HANGUP);
/* send SIT */
set_sit(&r1->dsp, 1);
return;
}
/* create new call */
osmo_cc_call_t *cc_call = osmo_cc_call_new(&r1->r1_ep->cc_ep);
r1->dsp.cc_callref = cc_call->callref;
/* send message to CC */
osmo_cc_ll_msg(&r1->r1_ep->cc_ep, r1->dsp.cc_callref, msg);
/* change state */
r1_new_state(r1, R1_STATE_IN_PROCEED);
}
/* function that receives the signal or the cease of it (' ' or different signal) */
void receive_signal(void *priv, char signal, double dbm)
{
r1_t *r1 = priv;
const char *state_name = r1_state_names[r1->state];
int i;
if (signal > ' ')
PDEBUG_CHAN(DR1, DEBUG_DEBUG, "Received signal '%c' in '%s' state. (%.1f dBm)\n", signal, state_name, dbm);
else
PDEBUG_CHAN(DR1, DEBUG_DEBUG, "Received cease of signal in '%s' state.\n", state_name);
switch (r1->state) {
/* initial SF when link is connected */
case R1_STATE_NULL:
if (signal == 'B') {
PDEBUG_CHAN(DR1, DEBUG_INFO, "Received 'Idle' signal in '%s' state, line is connected, going idle.\n", state_name);
/* state idle */
r1_new_state(r1, R1_STATE_IDLE);
}
break;
/* outgoing call sends seize */
case R1_STATE_SEIZING:
if (signal != 'B') {
PDEBUG_CHAN(DR1, DEBUG_INFO, "Received 'Delay-Dialing' signal in '%s' state, waiting for dial register..\n", state_name);
/* start timer */
timer_start(&r1->timer, TO_SEIZING);
/* change state */
r1_new_state(r1, R1_STATE_OUT_DELAY_DIALING);
}
break;
/* outgoing call receives delay-dialing */
case R1_STATE_OUT_DELAY_DIALING:
if (signal == 'B') {
PDEBUG_CHAN(DR1, DEBUG_INFO, "Received 'proceed-to-send' signal in '%s' state, send digits.\n", state_name);
/* stop timer */
timer_stop(&r1->timer);
/* dial */
set_dial_string(&r1->dsp, r1->dialing, r1->pulsedialing);
/* change state */
r1_new_state(r1, R1_STATE_SEND_DIGITS);
}
break;
/* outgoing call receives answer */
case R1_STATE_SEND_DIGITS:
case R1_STATE_OUT_PROCEED:
if (signal == ' ') {
PDEBUG_CHAN(DR1, DEBUG_INFO, "Received 'answer' signal in '%s' state.\n", state_name);
/* change state */
r1_new_state(r1, R1_STATE_OUT_ANSWER);
/* indicate answer to upper layer */
answer_call(&r1->r1_ep->cc_ep, r1->dsp.cc_callref);
}
break;
/* outgoing call receives clear-back */
case R1_STATE_OUT_ANSWER:
if (signal == 'B') {
PDEBUG_CHAN(DR1, DEBUG_INFO, "Received 'clear-back' signal in '%s' state'.\n", state_name);
/* stop timer */
timer_stop(&r1->timer);
/* start timer */
if (r1->r1_ep->clear_back_timeout)
timer_start(&r1->timer, r1->r1_ep->clear_back_timeout);
/* change state */
r1_new_state(r1, R1_STATE_OUT_HANGUP);
if (!r1->r1_ep->suppress_disconnect) {
/* indicate disconnect w/tones to upper layer */
disconnect_call(&r1->r1_ep->cc_ep, r1->dsp.cc_callref, OSMO_CC_ISDN_CAUSE_NORM_CALL_CLEAR);
}
}
break;
/* outgoing call receives answer after clear-back */
case R1_STATE_OUT_HANGUP:
if (signal == ' ') {
PDEBUG_CHAN(DR1, DEBUG_INFO, "Received 'answer' signal in '%s' state.\n", state_name);
/* stop timer */
timer_stop(&r1->timer);
/* change state */
r1_new_state(r1, R1_STATE_OUT_ANSWER);
}
break;
/* incoming call receives seize */
case R1_STATE_IDLE:
if (signal == ' ') {
PDEBUG_CHAN(DR1, DEBUG_INFO, "Received 'seizing' signal in '%s' state, sending 'delay-dialing'.\n", state_name);
/* stop timer */
timer_stop(&r1->timer);
/* start timer */
timer_start(&r1->timer, TO_DELAY_DIALING);
/* change state */
r1_new_state(r1, R1_STATE_IN_DELAY_DIALING);
/* send proceed-to-send */
set_tone(&r1->dsp, ' ', 0);
/* make tone gerator transparent */
set_tone_transparent(&r1->dsp, 1);
}
break;
/* incoming call receives digits */
case R1_STATE_RECV_DIGIT_WAIT:
if (signal == 'B')
goto clear_forward;
if (!(signal >= '0' && signal <= '9') && !(signal >= 'a' && signal <= 'c')) {
break;
}
PDEBUG_CHAN(DR1, DEBUG_INFO, "Digit '%c' is detected in '%s' state.\n", signal, state_name);
/* add digit */
i = strlen(r1->dialing);
if (i + 1 == sizeof(r1->dialing))
break;
r1->dialing[i++] = signal;
r1->dialing[i] = '\0';
/* change state */
r1_new_state(r1, R1_STATE_RECV_DIGIT_ON);
/* restart timer */
timer_start(&r1->timer, TO_DIALING);
break;
case R1_STATE_RECV_DIGIT_ON:
if (signal == 'B')
goto clear_forward;
if (signal != ' ')
break;
/* check for end of dialing */
i = strlen(r1->dialing) - 1;
if (r1->dialing[i] == 'c') {
/* setup call */
setup_call(r1);
break;
}
/* change state */
r1_new_state(r1, R1_STATE_RECV_DIGIT_WAIT);
break;
/* incoming call receives first pulse */
case R1_STATE_RECV_PULSE_WAIT:
if (signal == 'B') {
/* stop timer */
timer_stop(&r1->timer);
/* start timer */
timer_start(&r1->timer, TO_PULSE);
/* change state */
r1_new_state(r1, R1_STATE_RECV_PULSE_ON);
/* start pulse counter */
r1->pulse_counter = 1;
}
break;
/* pulse goes off */
case R1_STATE_RECV_PULSE_ON:
if (signal == ' ') {
/* stop timer */
timer_stop(&r1->timer);
/* start timer */
timer_start(&r1->timer, TO_PULSE);
/* change state */
r1_new_state(r1, R1_STATE_RECV_PULSE_OFF);
}
break;
/* pulse goes back on */
case R1_STATE_RECV_PULSE_OFF:
if (signal == 'B') {
/* stop timer */
timer_stop(&r1->timer);
/* start timer */
timer_start(&r1->timer, TO_PULSE);
/* change state */
r1_new_state(r1, R1_STATE_RECV_PULSE_ON);
/* increment pulse counter */
r1->pulse_counter++;
}
break;
/* got a clear-forward */
case R1_STATE_IN_PROCEED:
case R1_STATE_IN_ANSWER:
case R1_STATE_IN_HANGUP:
if (signal == 'B') {
clear_forward:
PDEBUG_CHAN(DR1, DEBUG_INFO, "Received 'clear-forward' signal in '%s' state'.\n", state_name);
/* release outgoing call */
if (r1->dsp.cc_callref) {
/* send release indication towards CC */
release_call(&r1->r1_ep->cc_ep, r1->dsp.cc_callref, OSMO_CC_ISDN_CAUSE_NORM_CALL_CLEAR);
/* remove ref */
r1->dsp.cc_callref = 0;
}
/* stop SIT */
set_sit(&r1->dsp, 0);
/* Turn on SF */
set_tone(&r1->dsp, 'B', 0);
/* change state */
r1_new_state(r1, R1_STATE_IDLE);
/* reset inst */
link_reset(r1);
}
break;
default:
PDEBUG_CHAN(DR1, DEBUG_NOTICE, "Received signal '%c' in '%s' state is not handled!\n", signal, state_name);
}
}
/* dialing was completed */
void dialing_complete(void *priv)
{
r1_t *r1 = priv;
PDEBUG_CHAN(DR1, DEBUG_INFO, "Dialing is complete in '%s' state, waiting for remote party to answer.\n", r1_state_names[r1->state]);
/* start timer */
timer_start(&r1->timer, TO_PROCEEDING);
/* change state */
r1_new_state(r1, R1_STATE_OUT_PROCEED);
/* indicate alerting now, because there is no alerting signaling */
alert_call(&r1->r1_ep->cc_ep, r1->dsp.cc_callref);
}
/* timeouts */
static void r1_timeout(void *data)
{
r1_t *r1 = data;
const char *state_name = r1_state_names[r1->state];
int i;
switch (r1->state) {
case R1_STATE_OUT_DELAY_DIALING:
PDEBUG_CHAN(DR1, DEBUG_INFO, "Detected 'double seizing', releasing call, going idle.\n");
/* send 'idle' signal */
set_tone(&r1->dsp, 'B', 0);
/* state idle */
r1_new_state(r1, R1_STATE_IDLE);
/* send release indication towards CC */
release_call(&r1->r1_ep->cc_ep, r1->dsp.cc_callref, OSMO_CC_ISDN_CAUSE_NO_CIRCUIT_CHAN);
/* reset inst */
link_reset(r1);
break;
case R1_STATE_OUT_PROCEED:
PDEBUG_CHAN(DR1, DEBUG_INFO, "Received answer timeout, releasing call.\n");
/* send clear-forward */
set_tone(&r1->dsp, 'B', 0);
/* change state */
r1_new_state(r1, R1_STATE_IDLE);
/* release call */
release_call(&r1->r1_ep->cc_ep, r1->dsp.cc_callref, OSMO_CC_ISDN_CAUSE_USER_BUSY);
/* reset inst */
link_reset(r1);
break;
case R1_STATE_OUT_HANGUP:
PDEBUG_CHAN(DR1, DEBUG_INFO, "Received clear-back timeout, releasing call.\n");
/* send clear-forward */
set_tone(&r1->dsp, 'B', 0);
/* change state */
r1_new_state(r1, R1_STATE_IDLE);
/* release call */
release_call(&r1->r1_ep->cc_ep, r1->dsp.cc_callref, OSMO_CC_ISDN_CAUSE_NORM_CALL_CLEAR);
/* reset inst */
link_reset(r1);
break;
case R1_STATE_IN_DELAY_DIALING:
/* send 'proceed-to-send' signal */
set_tone(&r1->dsp, 'B', 0);
/* change state */
if (r1->pulsedialing)
r1_new_state(r1, R1_STATE_RECV_PULSE_WAIT);
else {
r1_new_state(r1, R1_STATE_RECV_DIGIT_WAIT);
/* set recognition time */
set_sig_detect_duration(&r1->dsp, SIGN_RECOGNITION_SLOW, 0.0);
}
/* start timer */
timer_start(&r1->timer, TO_DIALING);
break;
case R1_STATE_RECV_DIGIT_WAIT:
case R1_STATE_RECV_DIGIT_ON:
PDEBUG_CHAN(DR1, DEBUG_INFO, "Received dialing timeout in '%s' state, going to hangup state.\n", state_name);
/* change state */
r1_new_state(r1, R1_STATE_IN_HANGUP);
/* send SIT */
set_sit(&r1->dsp, 1);
break;
case R1_STATE_RECV_PULSE_WAIT:
PDEBUG_CHAN(DR1, DEBUG_INFO, "Received dialing timeout in '%s' state, setting up call.\n", state_name);
/* setup call */
setup_call(r1);
break;
case R1_STATE_RECV_PULSE_ON:
PDEBUG_CHAN(DR1, DEBUG_INFO, "Received pulse that was too long in '%s' state, assuming clear-forward.\n", state_name);
/* Turn on SF */
set_tone(&r1->dsp, 'B', 0);
/* change state */
r1_new_state(r1, R1_STATE_IDLE);
/* reset inst */
link_reset(r1);
break;
case R1_STATE_RECV_PULSE_OFF:
PDEBUG_CHAN(DR1, DEBUG_INFO, "Received complete pulse sequence, storing digit %c.\n", r1->pulse_counter);
/* start timer */
timer_start(&r1->timer, TO_DIALING);
/* add digit */
i = strlen(r1->dialing);
if (i + 1 == sizeof(r1->dialing))
break;
if (r1->pulse_counter <= 9)
r1->dialing[i++] = '0' + r1->pulse_counter;
else if (r1->pulse_counter == 10)
r1->dialing[i++] = '0';
else if (r1->pulse_counter == 11)
r1->dialing[i++] = '*';
else if (r1->pulse_counter == 12)
r1->dialing[i++] = '#';
else
r1->dialing[i++] = '?';
r1->dialing[i] = '\0';
/* change state (after adding digit) */
r1_new_state(r1, R1_STATE_RECV_PULSE_WAIT);
break;
case R1_STATE_IDLE:
PDEBUG_CHAN(DR1, DEBUG_INFO, "Received dialing timeout in '%s' state, guard timer has expired.\n", state_name);
break;
default:
;
}
}
/* message from call control */
void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg)
{
r1_endpoint_t *r1_ep = ep->priv;
dsp_t *dsp;
r1_t *r1;
const char *state_name;
osmo_cc_msg_t *new_msg;
uint8_t type, plan, present, screen;
char dialing[64];
const char *sdp;
int rc;
/* hunt for callref */
dsp = r1_ep->dsp_list;
while (dsp) {
if (dsp->cc_callref == callref)
break;
dsp = dsp->next;
}
r1 = (dsp) ? dsp->priv : NULL;
/* process SETUP */
if (!r1) {
if (msg->type != OSMO_CC_MSG_SETUP_REQ) {
PDEBUG(DR1, DEBUG_ERROR, "received message without r1 instance, please fix!\n");
goto done;
}
/* hunt free r1 instance */
dsp = r1_ep->dsp_list;
while (dsp) {
r1 = dsp->priv;
/* Must be IDLE and guard timer expired. */
if (r1->state == R1_STATE_IDLE && !timer_running(&r1->timer))
break;
dsp = dsp->next;
}
r1 = (dsp) ? dsp->priv : NULL;
if (!r1) {
PDEBUG(DR1, DEBUG_NOTICE, "No free r1 instance, rejecting.\n");
reject_call(ep, callref, OSMO_CC_ISDN_CAUSE_NO_CIRCUIT_CHAN);
goto done;
}
/* link with cc */
r1->dsp.cc_callref = callref;
}
state_name = r1_state_names[r1->state];
switch (msg->type) {
case OSMO_CC_MSG_SETUP_REQ: /* dial-out command received from epoint */
PDEBUG_CHAN(DR1, DEBUG_INFO, "Outgoing call in '%s' state, sending 'seizing'.\n", state_name);
/* caller id */
rc = osmo_cc_get_ie_calling(msg, 0, &type, &plan, &present, &screen, r1->callerid, sizeof(r1->callerid));
/* called number */
rc = osmo_cc_get_ie_called(msg, 0, &type, &plan, dialing, sizeof(dialing));
if (rc < 0 || !dialing[0]) {
PDEBUG_CHAN(DR1, DEBUG_NOTICE, "No number given, call is rejected!\n");
inv_nr:
/* reject call */
reject_call(&r1->r1_ep->cc_ep, r1->dsp.cc_callref, OSMO_CC_ISDN_CAUSE_INV_NR_FORMAT);
/* reset inst */
link_reset(r1);
goto done;
}
rc = generate_dial_string(type, dialing, r1->dialing, sizeof(r1->dialing));
if (rc < 0)
goto inv_nr;
/* sdp accept */
sdp = osmo_cc_helper_audio_accept(&r1->r1_ep->cc_ep.session_config, &r1->dsp, codecs, down_audio, msg, &r1->dsp.cc_session, &r1->dsp.codec, 0);
if (!sdp) {
/* reject call */
reject_call(&r1->r1_ep->cc_ep, r1->dsp.cc_callref, OSMO_CC_ISDN_CAUSE_RESOURCE_UNAVAIL);
/* reset inst */
link_reset(r1);
goto done;
}
/* proceed */
proceed_call(&r1->r1_ep->cc_ep, r1->dsp.cc_callref, sdp);
/* send seizing */
set_tone(&r1->dsp, 0, 0);
/* change state */
r1_new_state(r1, R1_STATE_SEIZING);
break;
case OSMO_CC_MSG_SETUP_ACK_REQ: /* more information is needed */
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, &r1->dsp.cc_session, &r1->dsp.codec);
if (rc < 0) {
codec_failed:
PDEBUG_CHAN(DR1, DEBUG_NOTICE, "Releasing, because codec negotiation failed.\n");
/* state hangup */
r1_new_state(r1, R1_STATE_IN_HANGUP);
/* send SIT */
set_sit(&r1->dsp, 1);
/* release call */
release_call(&r1->r1_ep->cc_ep, r1->dsp.cc_callref, OSMO_CC_ISDN_CAUSE_RESOURCE_UNAVAIL);
/* reset inst */
link_reset(r1);
goto done;
}
break;
case OSMO_CC_MSG_SETUP_RSP: /* call of endpoint is connected */
PDEBUG_CHAN(DR1, DEBUG_INFO, "Incoming call has answered in '%s' state, sending 'answer'.\n", state_name);
rc = osmo_cc_helper_audio_negotiate(msg, &r1->dsp.cc_session, &r1->dsp.codec);
if (rc < 0)
goto codec_failed;
/* connect acknowledge */
setup_comp_call(&r1->r1_ep->cc_ep, r1->dsp.cc_callref);
/* not in right state, which should never happen anyway */
if (r1->state != R1_STATE_IN_PROCEED)
break;
/* send answer */
set_tone(&r1->dsp, 0, 0);
/* change state */
r1_new_state(r1, R1_STATE_IN_ANSWER);
break;
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, &r1->dsp.cc_session, &r1->dsp.codec);
if (rc < 0)
goto codec_failed;
/* right state */
if (r1->state == R1_STATE_IN_PROCEED) {
PDEBUG_CHAN(DR1, DEBUG_INFO, "Incoming call has disconnected in '%s' state'.\n", state_name);
/* state hangup */
r1_new_state(r1, R1_STATE_IN_HANGUP);
if (msg->type == OSMO_CC_MSG_REL_REQ) {
/* send SIT */
set_sit(&r1->dsp, 1);
}
} else
if (r1->state == R1_STATE_IN_ANSWER) {
PDEBUG_CHAN(DR1, DEBUG_INFO, "Incoming call has disconnected in '%s' state, sending 'clear-back'.\n", state_name);
/* send clear-back */
set_tone(&r1->dsp, 'B', 0);
/* state hangup */
r1_new_state(r1, R1_STATE_IN_HANGUP);
if (msg->type == OSMO_CC_MSG_REL_REQ) {
/* send SIT */
set_sit(&r1->dsp, 1);
}
} else {
PDEBUG_CHAN(DR1, DEBUG_INFO, "Outgoing call has disconnected in '%s' state, sending 'clear-forward'.\n", state_name);
/* send clear-forward */
set_tone(&r1->dsp, 'B', 0);
/* start timer */
timer_start(&r1->timer, TO_GUARD_BUSY);
/* change state */
r1_new_state(r1, R1_STATE_IDLE);
if (msg->type == OSMO_CC_MSG_DISC_REQ) {
/* clone osmo-cc message to preserve cause */
new_msg = osmo_cc_clone_msg(msg);
new_msg->type = OSMO_CC_MSG_REL_IND;
/* send message to osmo-cc */
osmo_cc_ll_msg(&r1->r1_ep->cc_ep, r1->dsp.cc_callref, new_msg);
/* reset */
link_reset(r1);
break;
}
// note: link_reset is called below
}
/* on release, we confirm */
if (msg->type == OSMO_CC_MSG_REL_REQ) {
/* clone osmo-cc message to preserve cause */
new_msg = osmo_cc_clone_msg(msg);
new_msg->type = OSMO_CC_MSG_REL_CNF;
/* send message to osmo-cc */
osmo_cc_ll_msg(&r1->r1_ep->cc_ep, r1->dsp.cc_callref, new_msg);
}
/* on reject/release we reset/unlink call */
if (msg->type != OSMO_CC_MSG_DISC_REQ)
link_reset(r1);
break;
#if 0
case OSMO_CC_MSG_INFO_REQ: /* we are getting overlap dialing */
/* called number */
rc = osmo_cc_get_ie_called(msg, 0, &type, &plan, dialing, sizeof(dialing));
if (rc < 0 || !dialing[0]) {
PDEBUG_CHAN(DR1, DEBUG_NOTICE, "No number given, dialing ignored!\n");
break;
}
if (!pulse) {
PDEBUG_CHAN(DR1, DEBUG_NOTICE, "Overlap dialing only supported with pulse dialing.\n");
break;
}
/* concat overlap dialing to overlap register */
strcat(r1->overlap, dialing, sizeof(r1->overlap) - 1);
/* if inactive, dial the overlap string */
if (r1->state == R1_STATE_OUT_INACTIVE) {
/* dial */
set_dial_string(&r1->dsp, r1->overlap, r1->pulsedialing);
/* append the string to the dialed number */
strcat(r1->dialing, r1->overlap, sizeof(r1->dialing) - 1);
/* change state */
r1_new_state(r1, R1_STATE_SEND_DIGITS);
}
break;
#endif
}
done:
osmo_cc_free_msg(msg);
}

60
src/r1/r1.h Normal file
View File

@ -0,0 +1,60 @@
#include "../common/dsp.h"
enum r1_state {
R1_STATE_NULL = 0,
/* idle line */
R1_STATE_IDLE, /* idle, also sending disconnect signal */
/* outgoing call */
R1_STATE_SEIZING, /* sending seize, waiting for proceed-to-send */
R1_STATE_OUT_DELAY_DIALING, /* delay-dialing received, waiting for register to be available */
R1_STATE_SEND_DIGITS, /* proceed-to-send received, sending digits */
R1_STATE_OUT_PROCEED, /* waiting for called party to answer or being busy */
R1_STATE_OUT_ANSWER, /* detected answer */
R1_STATE_OUT_HANGUP, /* detected hangup */
/* incoming call */
R1_STATE_IN_DELAY_DIALING, /* seize received, waiting for procced-to-send */
R1_STATE_RECV_DIGIT_WAIT, /* sending proceed-to-send, waiting for digits */
R1_STATE_RECV_DIGIT_ON, /* digit received, waiting to cease */
R1_STATE_RECV_PULSE_WAIT, /* sending proceed-to-send, waiting for first pulse of digit */
R1_STATE_RECV_PULSE_ON, /* pulse received, waiting to cease */
R1_STATE_RECV_PULSE_OFF, /* pulse ceased, waiting to for next pulse of digit */
R1_STATE_IN_PROCEED, /* waiting for called party to answer or disconnect */
R1_STATE_IN_ANSWER, /* called party answered */
R1_STATE_IN_HANGUP, /* called party disconnected, sending hangup */
};
extern const char *r1_state_names[];
struct r1_endpoint;
/* R1 link definition */
typedef struct r1 {
struct r1_endpoint *r1_ep;
char name[32]; /* name of link for debugging */
/* call states */
enum r1_state state; /* state of link */
struct timer timer; /* for several timeouts */
char callerid[65]; /* current caller id (outgoing only) */
char dialing[33]; /* current dial string (send or receive) */
int pulsedialing; /* if set, pulses are sent/received via SF */
int pulse_counter; /* used to count received pulses */
/* audio processing */
dsp_t dsp; /* all dsp processing */
} r1_t;
/* R1 endpoint definition */
typedef struct r1_endpoint {
osmo_cc_endpoint_t cc_ep;
dsp_t *dsp_list;
int suppress_disconnect; /* do not forward disconnect towards CC */
int clear_back_timeout; /* time to disconnect when receiving clean back */
} r1_endpoint_t;
void refresh_status(void);
r1_endpoint_t *r1_ep_create(const char *ep_name, int links, int suppress_disconnect, int clear_back_timeout, int crosstalk, int delay_ms, double sense_db, int pulsedialing);
void r1_ep_destroy(r1_endpoint_t *r1_ep);
void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg);

View File

@ -4,14 +4,12 @@ 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

@ -1,46 +0,0 @@
struct ss5_endpoint;
typedef struct dsp {
void *priv;
double samplerate;
/* tone generation */
mf_mod_t *mf_mod; /* MF modulator */
char tone; /* current digit playing or 0 */
uint32_t tone_mask; /* bit-mask of which MF tones to play */
int tone_duration; /* counter of samples for length of tone */
char dial_string[33]; /* stores digits when dialing number sequence */
int dial_length; /* length of dial string, or 0 */
int dial_index; /* current position at dial string */
int digit_pause; /* flag that states if pause is played after digit */
/* tone detection */
mf_demod_t *mf_demod; /* MF demodulator */
double ms_per_sample; /* how many milliseconds between two samples */
double detect_interval; /* counts milliseconds */
int interrupt_duration; /* number of milliseconds until interruption is detected */
int interrupt_count; /* counter for interrupt condition */
int split_duration; /* number of milliseconds until split (mute) condition meats */
int split_count; /* counter for split condition */
int sig_detect_duration_AB; /* signaling tone duration in milliseconds (TONE A/B) */
int sig_detect_duration_C; /* signaling tone duration in milliseconds (TONE C) */
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 */
} dsp_t;
int dsp_init_inst(dsp_t *dsp, void *priv, double samplerate, 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 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);
void receive_digit(void *priv, char digit, double dbm);
void dialing_complete(void *priv);

View File

@ -29,7 +29,7 @@
#include "../liboptions/options.h"
#include "../libg711/g711.h"
#include "ss5.h"
#include "display.h"
#include "../common/display.h"
ss5_endpoint_t *ss5_ep_sunset = NULL, *ss5_ep_sunrise = NULL;
int num_kanal = 2;
@ -80,16 +80,16 @@ static void print_help()
printf(" Prevent blueboxing by making 'release-guard' 200 ms minimum length.\n");
printf(" -x --crosstalk 1 | 0\n");
printf(" Enable or disable some minor crosstalk. This allows you to hear\n");
printf(" transmitted tones at a low volume. (Default is %d.).\n", crosstalk);
printf(" transmitted tones at a low volume. (Default is %d.)\n", crosstalk);
printf(" -d --delay <ms> | 0\n");
printf(" Add one-way delay to the connection between two SS5 links. This allows\n");
printf(" to hear 'acknowlege' tones delayed. (Default is %d ms.).\n", delay_ms);
printf(" to hear 'acknowlege' tones delayed. (Default is %d ms.)\n", delay_ms);
printf(" -n --comfort-noise 1 | 0\n");
printf(" Add comfort noise whenever there is no audio from the remote link\n");
printf(" (before or after call). (Default is %d ms.).\n", comfort_noise);
printf(" (before or after call). (Default is %d ms.)\n", comfort_noise);
printf(" --sense 0 | <db>\n");
printf(" Change sensitivity (level) of tone detector. A bluebox must not be\n");
printf(" that loud. (Default is %.0f dB.).\n", sense_db);
printf(" Increase sensitivity of tone detector. A bluebox can have lower level\n");
printf(" than what the standard requires. (Default is %.0f dB.)\n", sense_db);
printf(" -C --cc \"<osmo-cc arg>\" [--cc ...]\n");
printf(" --cc2 \"<osmo-cc arg>\" [--cc2 ...]\n");
printf(" Pass arguments to Osmo-CC endpoint. Use '-cc help' for description.\n");
@ -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) ? ss5_ep_sunset->dsp_list : NULL, (ss5_ep_sunrise) ? ss5_ep_sunrise->dsp_list : NULL, 160);
/* process keyboard input */
c = get_char();
@ -259,6 +259,9 @@ int main(int argc, char *argv[])
/* init codecs */
g711_init();
/* init dsp */
dsp_set_sf(-9.0, -16.0);
cc_argv_sunset[cc_argc_sunset++] = options_strdup("remote auto");
cc_argv_sunrise[cc_argc_sunrise++] = options_strdup("remote auto");
@ -280,14 +283,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);

File diff suppressed because it is too large Load Diff

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);