Compare commits
5 Commits
6caaad2059
...
49c2600165
Author | SHA1 | Date |
---|---|---|
Andreas Eversberg | 49c2600165 | |
Andreas Eversberg | d0c08f4f7d | |
Andreas Eversberg | 2483f1c2b1 | |
Andreas Eversberg | 91e8521071 | |
Andreas Eversberg | 48dd37e1ae |
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -10,5 +10,7 @@ SUBDIRS = \
|
|||
libosmocc \
|
||||
libg711 \
|
||||
libfilter \
|
||||
ss5
|
||||
common \
|
||||
ss5 \
|
||||
r1
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
|
|
@ -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 */
|
|
@ -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)
|
|
@ -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);
|
||||
|
|
@ -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;
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
void init_sit(int samplerate);
|
||||
void exit_sit(void);
|
||||
int sit_play(sample_t *samples, int count, int length);
|
||||
|
|
@ -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" },
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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], ¬ify);
|
||||
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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
|
|
610
src/ss5/ss5.c
610
src/ss5/ss5.c
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue