2020-08-09 12:27:56 +00:00
|
|
|
/* interface between mobile network/phone implementation and OsmoCC
|
2016-03-01 17:40:38 +00:00
|
|
|
*
|
|
|
|
* (C) 2016 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 <stdint.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/time.h>
|
2020-08-09 12:27:56 +00:00
|
|
|
#include <arpa/inet.h>
|
2017-11-18 07:06:06 +00:00
|
|
|
#include "../libsample/sample.h"
|
2024-01-05 13:20:36 +00:00
|
|
|
#include "../liblogging/logging.h"
|
|
|
|
#include <osmocom/core/timer.h>
|
|
|
|
#include <osmocom/core/select.h>
|
|
|
|
#include <osmocom/cc/endpoint.h>
|
|
|
|
#include <osmocom/cc/helper.h>
|
|
|
|
#include <osmocom/cc/g711.h>
|
|
|
|
#include <osmocom/cc/rtp.h>
|
2020-08-09 12:27:56 +00:00
|
|
|
#include "cause.h"
|
2016-06-19 15:46:56 +00:00
|
|
|
#include "sender.h"
|
2016-03-01 17:40:38 +00:00
|
|
|
#include "call.h"
|
2020-08-09 12:27:56 +00:00
|
|
|
#include "console.h"
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2024-01-05 13:20:36 +00:00
|
|
|
#define DISC_TIMEOUT 30, 0
|
2016-06-19 15:46:56 +00:00
|
|
|
|
2017-01-29 06:25:12 +00:00
|
|
|
//#define DEBUG_LEVEL
|
|
|
|
|
|
|
|
#ifdef DEBUG_LEVEL
|
|
|
|
static double level_of(double *samples, int count)
|
|
|
|
{
|
|
|
|
double level = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
if (samples[i] > level)
|
|
|
|
level = samples[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
return level;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-01-12 15:45:16 +00:00
|
|
|
static int connect_on_setup; /* send patterns towards fixed network */
|
2020-08-09 12:27:56 +00:00
|
|
|
static int release_on_disconnect; /* release towards mobile phone, if OSMO-CC call disconnects, don't send disconnect tone */
|
|
|
|
|
|
|
|
osmo_cc_endpoint_t endpoint, *ep;
|
|
|
|
|
2022-11-24 20:16:43 +00:00
|
|
|
void encode_l16(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void __attribute__((unused)) *arg)
|
2020-08-09 12:27:56 +00:00
|
|
|
{
|
|
|
|
uint16_t *src = (uint16_t *)src_data, *dst;
|
|
|
|
int len = src_len / 2, i;
|
|
|
|
|
|
|
|
dst = malloc(len * 2);
|
|
|
|
if (!dst)
|
|
|
|
return;
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
dst[i] = htons(src[i]);
|
|
|
|
*dst_data = (uint8_t *)dst;
|
|
|
|
*dst_len = len * 2;
|
|
|
|
}
|
|
|
|
|
2022-11-24 20:16:43 +00:00
|
|
|
void decode_l16(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len, void __attribute__((unused)) *arg)
|
2020-08-09 12:27:56 +00:00
|
|
|
{
|
|
|
|
uint16_t *src = (uint16_t *)src_data, *dst;
|
|
|
|
int len = src_len / 2, i;
|
|
|
|
|
|
|
|
dst = malloc(len * 2);
|
|
|
|
if (!dst)
|
|
|
|
return;
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
dst[i] = ntohs(src[i]);
|
|
|
|
*dst_data = (uint8_t *)dst;
|
|
|
|
*dst_len = len * 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
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},
|
|
|
|
};
|
2017-10-28 05:11:40 +00:00
|
|
|
|
2023-11-15 19:37:40 +00:00
|
|
|
static int no_l16 = 0;
|
|
|
|
|
2016-03-01 17:40:38 +00:00
|
|
|
/* stream patterns/announcements */
|
2016-03-11 05:59:05 +00:00
|
|
|
int16_t *ringback_spl = NULL;
|
|
|
|
int ringback_size = 0;
|
|
|
|
int ringback_max = 0;
|
2017-10-28 05:11:40 +00:00
|
|
|
int16_t *hangup_spl = NULL;
|
|
|
|
int hangup_size = 0;
|
2016-05-01 17:51:56 +00:00
|
|
|
int hangup_max = 0;
|
2017-10-28 05:11:40 +00:00
|
|
|
int16_t *busy_spl = NULL;
|
|
|
|
int busy_size = 0;
|
2016-03-11 05:59:05 +00:00
|
|
|
int busy_max = 0;
|
2017-10-28 05:11:40 +00:00
|
|
|
int16_t *noanswer_spl = NULL;
|
|
|
|
int noanswer_size = 0;
|
2016-05-01 17:51:56 +00:00
|
|
|
int noanswer_max = 0;
|
2017-10-28 05:11:40 +00:00
|
|
|
int16_t *outoforder_spl = NULL;
|
|
|
|
int outoforder_size = 0;
|
2016-05-01 17:51:56 +00:00
|
|
|
int outoforder_max = 0;
|
2017-10-28 05:11:40 +00:00
|
|
|
int16_t *invalidnumber_spl = NULL;
|
|
|
|
int invalidnumber_size = 0;
|
2016-05-01 17:51:56 +00:00
|
|
|
int invalidnumber_max = 0;
|
2017-10-28 05:11:40 +00:00
|
|
|
int16_t *congestion_spl = NULL;
|
|
|
|
int congestion_size = 0;
|
2016-03-11 05:59:05 +00:00
|
|
|
int congestion_max = 0;
|
2017-10-28 05:11:40 +00:00
|
|
|
int16_t *recall_spl = NULL;
|
|
|
|
int recall_size = 0;
|
2017-08-06 09:30:39 +00:00
|
|
|
int recall_max = 0;
|
2016-03-01 17:40:38 +00:00
|
|
|
|
|
|
|
enum audio_pattern {
|
|
|
|
PATTERN_NONE = 0,
|
2016-08-03 05:48:26 +00:00
|
|
|
PATTERN_TEST,
|
2016-03-01 17:40:38 +00:00
|
|
|
PATTERN_RINGBACK,
|
2016-05-01 17:51:56 +00:00
|
|
|
PATTERN_HANGUP,
|
2016-03-01 17:40:38 +00:00
|
|
|
PATTERN_BUSY,
|
2016-05-01 17:51:56 +00:00
|
|
|
PATTERN_NOANSWER,
|
2016-03-01 17:40:38 +00:00
|
|
|
PATTERN_OUTOFORDER,
|
2016-05-01 17:51:56 +00:00
|
|
|
PATTERN_INVALIDNUMBER,
|
|
|
|
PATTERN_CONGESTION,
|
2017-08-06 09:30:39 +00:00
|
|
|
PATTERN_RECALL,
|
2016-03-01 17:40:38 +00:00
|
|
|
};
|
|
|
|
|
2017-10-28 05:11:40 +00:00
|
|
|
static void get_pattern(const int16_t **spl, int *size, int *max, enum audio_pattern pattern)
|
2016-03-11 05:59:05 +00:00
|
|
|
{
|
|
|
|
*spl = NULL;
|
|
|
|
*size = 0;
|
|
|
|
*max = 0;
|
|
|
|
|
|
|
|
switch (pattern) {
|
|
|
|
case PATTERN_RINGBACK:
|
2017-08-06 09:30:39 +00:00
|
|
|
no_recall:
|
2016-03-11 05:59:05 +00:00
|
|
|
*spl = ringback_spl;
|
|
|
|
*size = ringback_size;
|
|
|
|
*max = ringback_max;
|
|
|
|
break;
|
2016-05-01 17:51:56 +00:00
|
|
|
case PATTERN_HANGUP:
|
|
|
|
if (!hangup_spl)
|
|
|
|
goto no_hangup;
|
|
|
|
*spl = hangup_spl;
|
|
|
|
*size = hangup_size;
|
|
|
|
*max = hangup_max;
|
|
|
|
break;
|
2016-03-11 05:59:05 +00:00
|
|
|
case PATTERN_BUSY:
|
2016-05-01 17:51:56 +00:00
|
|
|
no_hangup:
|
|
|
|
no_noanswer:
|
2016-03-11 05:59:05 +00:00
|
|
|
*spl = busy_spl;
|
|
|
|
*size = busy_size;
|
|
|
|
*max = busy_max;
|
|
|
|
break;
|
2016-05-01 17:51:56 +00:00
|
|
|
case PATTERN_NOANSWER:
|
|
|
|
if (!noanswer_spl)
|
|
|
|
goto no_noanswer;
|
|
|
|
*spl = noanswer_spl;
|
|
|
|
*size = noanswer_size;
|
|
|
|
*max = noanswer_max;
|
2016-03-11 05:59:05 +00:00
|
|
|
break;
|
|
|
|
case PATTERN_OUTOFORDER:
|
|
|
|
if (!outoforder_spl)
|
|
|
|
goto no_outoforder;
|
|
|
|
*spl = outoforder_spl;
|
|
|
|
*size = outoforder_size;
|
|
|
|
*max = outoforder_max;
|
|
|
|
break;
|
2016-05-01 17:51:56 +00:00
|
|
|
case PATTERN_INVALIDNUMBER:
|
|
|
|
if (!invalidnumber_spl)
|
|
|
|
goto no_invalidnumber;
|
|
|
|
*spl = invalidnumber_spl;
|
|
|
|
*size = invalidnumber_size;
|
|
|
|
*max = invalidnumber_max;
|
|
|
|
break;
|
|
|
|
case PATTERN_CONGESTION:
|
|
|
|
no_outoforder:
|
|
|
|
no_invalidnumber:
|
|
|
|
*spl = congestion_spl;
|
|
|
|
*size = congestion_size;
|
|
|
|
*max = congestion_max;
|
|
|
|
break;
|
2017-08-06 09:30:39 +00:00
|
|
|
case PATTERN_RECALL:
|
|
|
|
if (!recall_spl)
|
|
|
|
goto no_recall;
|
|
|
|
*spl = recall_spl;
|
|
|
|
*size = recall_size;
|
|
|
|
*max = recall_max;
|
|
|
|
break;
|
2016-03-11 05:59:05 +00:00
|
|
|
default:
|
|
|
|
;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-01 17:40:38 +00:00
|
|
|
static enum audio_pattern cause2pattern(int cause)
|
|
|
|
{
|
|
|
|
int pattern;
|
|
|
|
|
|
|
|
switch (cause) {
|
2016-05-01 17:51:56 +00:00
|
|
|
case CAUSE_NORMAL:
|
|
|
|
pattern = PATTERN_HANGUP;
|
|
|
|
break;
|
2016-03-11 05:59:05 +00:00
|
|
|
case CAUSE_BUSY:
|
|
|
|
pattern = PATTERN_BUSY;
|
|
|
|
break;
|
2016-05-01 17:51:56 +00:00
|
|
|
case CAUSE_NOANSWER:
|
|
|
|
pattern = PATTERN_NOANSWER;
|
|
|
|
break;
|
2016-03-01 17:40:38 +00:00
|
|
|
case CAUSE_OUTOFORDER:
|
|
|
|
pattern = PATTERN_OUTOFORDER;
|
|
|
|
break;
|
2016-05-01 17:51:56 +00:00
|
|
|
case CAUSE_INVALNUMBER:
|
|
|
|
pattern = PATTERN_INVALIDNUMBER;
|
|
|
|
break;
|
|
|
|
case CAUSE_NOCHANNEL:
|
2016-03-11 05:59:05 +00:00
|
|
|
pattern = PATTERN_CONGESTION;
|
2016-05-01 17:51:56 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
pattern = PATTERN_HANGUP;
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return pattern;
|
|
|
|
}
|
|
|
|
|
2017-10-28 05:11:40 +00:00
|
|
|
enum process_state {
|
|
|
|
PROCESS_IDLE = 0, /* IDLE */
|
2020-08-09 12:27:56 +00:00
|
|
|
PROCESS_SETUP_RO, /* call from radio to OSMO-CC */
|
|
|
|
PROCESS_SETUP_RT, /* call from OSMO-CC to radio */
|
|
|
|
PROCESS_ALERTING_RO, /* call from radio to OSMO-CC */
|
|
|
|
PROCESS_ALERTING_RT, /* call from OSMO-CC to radio */
|
2017-10-28 05:11:40 +00:00
|
|
|
PROCESS_CONNECT,
|
|
|
|
PROCESS_DISCONNECT,
|
|
|
|
};
|
|
|
|
|
2020-08-09 12:27:56 +00:00
|
|
|
/* call process */
|
2016-03-01 17:40:38 +00:00
|
|
|
typedef struct process {
|
|
|
|
struct process *next;
|
|
|
|
int callref;
|
2017-10-28 05:11:40 +00:00
|
|
|
enum process_state state;
|
2016-03-01 17:40:38 +00:00
|
|
|
int audio_disconnected; /* if not associated with transceiver anymore */
|
|
|
|
enum audio_pattern pattern;
|
|
|
|
int audio_pos;
|
2016-06-19 15:46:56 +00:00
|
|
|
uint8_t cause;
|
2024-01-05 13:20:36 +00:00
|
|
|
struct osmo_timer_list timer;
|
2020-08-09 12:27:56 +00:00
|
|
|
osmo_cc_session_t *session;
|
|
|
|
osmo_cc_session_codec_t *codec; /* codec to send */
|
2016-03-01 17:40:38 +00:00
|
|
|
} process_t;
|
|
|
|
|
|
|
|
static process_t *process_head = NULL;
|
|
|
|
|
2023-01-20 17:03:44 +00:00
|
|
|
static void process_timeout(void *data);
|
2020-08-09 12:27:56 +00:00
|
|
|
static void indicate_disconnect_release(int callref, int cause, uint8_t msg_type);
|
2016-06-19 15:46:56 +00:00
|
|
|
|
2017-10-28 05:11:40 +00:00
|
|
|
static process_t *create_process(int callref, enum process_state state)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
|
|
|
process_t *process;
|
|
|
|
|
|
|
|
process = calloc(sizeof(*process), 1);
|
|
|
|
if (!process) {
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_ERROR, "No memory!\n");
|
2016-03-01 17:40:38 +00:00
|
|
|
abort();
|
|
|
|
}
|
2024-01-05 13:20:36 +00:00
|
|
|
osmo_timer_setup(&process->timer, process_timeout, process);
|
2016-03-01 17:40:38 +00:00
|
|
|
process->next = process_head;
|
|
|
|
process_head = process;
|
|
|
|
|
|
|
|
process->callref = callref;
|
|
|
|
process->state = state;
|
2017-10-28 05:11:40 +00:00
|
|
|
|
|
|
|
return process;
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void destroy_process(int callref)
|
|
|
|
{
|
|
|
|
process_t *process = process_head;
|
|
|
|
process_t **process_p = &process_head;
|
|
|
|
|
|
|
|
while (process) {
|
|
|
|
if (process->callref == callref) {
|
|
|
|
*process_p = process->next;
|
2024-01-05 13:20:36 +00:00
|
|
|
osmo_timer_del(&process->timer);
|
2020-08-09 12:27:56 +00:00
|
|
|
if (process->session)
|
|
|
|
osmo_cc_free_session(process->session);
|
2016-03-01 17:40:38 +00:00
|
|
|
free(process);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
process_p = &process->next;
|
|
|
|
process = process->next;
|
|
|
|
}
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_ERROR, "Process with callref %d not found!\n", callref);
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
|
2017-10-28 05:11:40 +00:00
|
|
|
static process_t *get_process(int callref)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
|
|
|
process_t *process = process_head;
|
|
|
|
|
|
|
|
while (process) {
|
|
|
|
if (process->callref == callref)
|
2017-10-28 05:11:40 +00:00
|
|
|
return process;
|
2016-03-01 17:40:38 +00:00
|
|
|
process = process->next;
|
|
|
|
}
|
2017-10-28 05:11:40 +00:00
|
|
|
return NULL;
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
|
2017-10-28 05:11:40 +00:00
|
|
|
static void new_state_process(int callref, enum process_state state)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
2017-10-28 05:11:40 +00:00
|
|
|
process_t *process = get_process(callref);
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2017-10-28 05:11:40 +00:00
|
|
|
if (!process) {
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_ERROR, "Process with callref %d not found!\n", callref);
|
2017-10-28 05:11:40 +00:00
|
|
|
return;
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_DEBUG, "Changing state for callref %d %d->%d\n", callref, process->state, state);
|
2017-10-28 05:11:40 +00:00
|
|
|
process->state = state;
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void set_pattern_process(int callref, enum audio_pattern pattern)
|
|
|
|
{
|
2017-10-28 05:11:40 +00:00
|
|
|
process_t *process = get_process(callref);
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2017-10-28 05:11:40 +00:00
|
|
|
if (!process) {
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_ERROR, "Process with callref %d not found!\n", callref);
|
2017-10-28 05:11:40 +00:00
|
|
|
return;
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
2017-10-28 05:11:40 +00:00
|
|
|
process->pattern = pattern;
|
|
|
|
process->audio_pos = 0;
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* disconnect audio, now send audio directly from pattern/announcement, not from transceiver */
|
|
|
|
static void disconnect_process(int callref, int cause)
|
|
|
|
{
|
2017-10-28 05:11:40 +00:00
|
|
|
process_t *process = get_process(callref);
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2017-10-28 05:11:40 +00:00
|
|
|
if (!process) {
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_ERROR, "Process with callref %d not found!\n", callref);
|
2017-10-28 05:11:40 +00:00
|
|
|
return;
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
2017-10-28 05:11:40 +00:00
|
|
|
process->pattern = cause2pattern(cause);
|
|
|
|
process->audio_disconnected = 1;
|
|
|
|
process->audio_pos = 0;
|
|
|
|
process->cause = cause;
|
2024-01-05 13:20:36 +00:00
|
|
|
osmo_timer_schedule(&process->timer, DISC_TIMEOUT);
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void get_process_patterns(process_t *process, int16_t *samples, int length)
|
|
|
|
{
|
2016-03-11 05:59:05 +00:00
|
|
|
const int16_t *spl;
|
|
|
|
int size, max, pos;
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2016-03-11 05:59:05 +00:00
|
|
|
get_pattern(&spl, &size, &max, process->pattern);
|
2016-03-01 17:40:38 +00:00
|
|
|
|
|
|
|
/* stream sample */
|
|
|
|
pos = process->audio_pos;
|
|
|
|
while(length--) {
|
|
|
|
if (pos >= size)
|
|
|
|
*samples++ = 0;
|
|
|
|
else
|
2019-12-04 16:23:15 +00:00
|
|
|
*samples++ = spl[pos] >> 2;
|
2016-03-01 17:40:38 +00:00
|
|
|
if (++pos == max)
|
|
|
|
pos = 0;
|
|
|
|
}
|
|
|
|
process->audio_pos = pos;
|
|
|
|
}
|
|
|
|
|
2023-01-20 17:03:44 +00:00
|
|
|
static void process_timeout(void *data)
|
2016-06-19 15:46:56 +00:00
|
|
|
{
|
2023-01-20 17:03:44 +00:00
|
|
|
process_t *process = data;
|
2016-06-19 15:46:56 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
/* announcement timeout */
|
2017-11-18 07:33:07 +00:00
|
|
|
if (process->state == PROCESS_DISCONNECT) {
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Call released toward mobile network (after timeout)\n");
|
2017-11-18 07:33:07 +00:00
|
|
|
call_down_release(process->callref, process->cause);
|
|
|
|
}
|
2020-08-09 12:27:56 +00:00
|
|
|
indicate_disconnect_release(process->callref, process->cause, OSMO_CC_MSG_REL_IND);
|
2016-06-19 15:46:56 +00:00
|
|
|
destroy_process(process->callref);
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-10 12:45:08 +00:00
|
|
|
static void down_audio(struct osmo_cc_session_codec *codec, uint8_t marker, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *payload, int payload_len)
|
2017-01-29 15:54:28 +00:00
|
|
|
{
|
2020-08-09 12:27:56 +00:00
|
|
|
process_t *process = codec->media->session->priv;
|
2024-03-10 12:45:08 +00:00
|
|
|
// sample_t samples[len / 2];
|
2017-01-29 15:54:28 +00:00
|
|
|
|
2020-08-09 12:27:56 +00:00
|
|
|
/* if we are disconnected, ignore audio */
|
|
|
|
if (!process || process->pattern != PATTERN_NONE)
|
|
|
|
return;
|
2024-03-10 12:45:08 +00:00
|
|
|
#if 0
|
2022-09-25 17:31:31 +00:00
|
|
|
int16_to_samples_speech(samples, (int16_t *)data, len / 2);
|
2020-08-09 12:27:56 +00:00
|
|
|
#ifdef DEBUG_LEVEL
|
|
|
|
double lev = level_of(samples, len / 2);
|
|
|
|
printf("festnetz-level: %s %.4f\n", debug_db(lev), (20 * log10(lev)));
|
|
|
|
#endif
|
2024-03-10 12:45:08 +00:00
|
|
|
#endif
|
|
|
|
call_down_audio(codec->decoder, process, process->callref, marker, sequence_number, timestamp, ssrc, payload, payload_len);
|
2017-01-29 15:54:28 +00:00
|
|
|
}
|
|
|
|
|
2020-08-09 12:27:56 +00:00
|
|
|
static void indicate_setup(process_t *process, const char *callerid, const char *dialing, uint8_t network_type, const char *network_id)
|
2016-12-11 13:21:22 +00:00
|
|
|
{
|
2020-08-09 12:27:56 +00:00
|
|
|
osmo_cc_msg_t *msg;
|
|
|
|
|
|
|
|
msg = osmo_cc_new_msg(OSMO_CC_MSG_SETUP_IND);
|
|
|
|
/* network type */
|
|
|
|
if (network_type)
|
|
|
|
osmo_cc_add_ie_calling_network(msg, network_type, network_id);
|
|
|
|
/* calling number */
|
|
|
|
if (callerid && callerid[0])
|
|
|
|
osmo_cc_add_ie_calling(msg, OSMO_CC_TYPE_SUBSCRIBER, OSMO_CC_PLAN_TELEPHONY, OSMO_CC_PRESENT_ALLOWED, OSMO_CC_SCREEN_NETWORK, callerid);
|
|
|
|
/* called number */
|
|
|
|
if (dialing && dialing[0])
|
|
|
|
osmo_cc_add_ie_called(msg, OSMO_CC_TYPE_UNKNOWN, OSMO_CC_PLAN_TELEPHONY, dialing);
|
|
|
|
/* bearer capability */
|
|
|
|
osmo_cc_add_ie_bearer(msg, OSMO_CC_CODING_ITU_T, OSMO_CC_CAPABILITY_AUDIO, OSMO_CC_MODE_CIRCUIT);
|
|
|
|
/* sdp offer */
|
2023-11-15 19:37:40 +00:00
|
|
|
process->session = osmo_cc_helper_audio_offer(&ep->session_config, process, codecs + no_l16, down_audio, msg, 1);
|
2020-08-09 12:27:56 +00:00
|
|
|
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Indicate OSMO-CC setup towards fixed network\n");
|
2020-08-09 12:27:56 +00:00
|
|
|
osmo_cc_ll_msg(ep, process->callref, msg);
|
|
|
|
}
|
2016-12-11 13:21:22 +00:00
|
|
|
|
2020-08-09 12:27:56 +00:00
|
|
|
static void indicate_proceeding(int callref, const char *sdp)
|
|
|
|
{
|
|
|
|
osmo_cc_msg_t *msg;
|
|
|
|
|
|
|
|
msg = osmo_cc_new_msg(OSMO_CC_MSG_PROC_IND);
|
|
|
|
|
|
|
|
/* sdp */
|
|
|
|
osmo_cc_add_ie_sdp(msg, sdp);
|
|
|
|
|
|
|
|
/* progress information */
|
|
|
|
osmo_cc_add_ie_progress(msg, OSMO_CC_CODING_ITU_T, OSMO_CC_LOCATION_BEYOND_INTERWORKING, OSMO_CC_PROGRESS_INBAND_INFO_AVAILABLE);
|
|
|
|
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Indicate OSMO-CC call confirm towards fixed network\n");
|
2020-08-09 12:27:56 +00:00
|
|
|
osmo_cc_ll_msg(ep, callref, msg);
|
2016-12-11 13:21:22 +00:00
|
|
|
}
|
2020-08-09 12:27:56 +00:00
|
|
|
|
|
|
|
static void indicate_alerting(int callref)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
2020-08-09 12:27:56 +00:00
|
|
|
osmo_cc_msg_t *msg;
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2020-08-09 12:27:56 +00:00
|
|
|
msg = osmo_cc_new_msg(OSMO_CC_MSG_ALERT_IND);
|
2016-07-09 09:16:50 +00:00
|
|
|
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Indicate OSMO-CC alerting towards fixed network\n");
|
2020-08-09 12:27:56 +00:00
|
|
|
osmo_cc_ll_msg(ep, callref, msg);
|
|
|
|
}
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2021-03-20 10:24:57 +00:00
|
|
|
static void indicate_answer(int callref, const char *sdp, const char *connectid)
|
2020-08-09 12:27:56 +00:00
|
|
|
{
|
|
|
|
osmo_cc_msg_t *msg;
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2020-08-09 12:27:56 +00:00
|
|
|
msg = osmo_cc_new_msg(OSMO_CC_MSG_SETUP_CNF);
|
|
|
|
/* calling number */
|
|
|
|
if (connectid && connectid[0])
|
|
|
|
osmo_cc_add_ie_calling(msg, OSMO_CC_TYPE_SUBSCRIBER, OSMO_CC_PLAN_TELEPHONY, OSMO_CC_PRESENT_ALLOWED, OSMO_CC_SCREEN_NETWORK, connectid);
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2021-03-20 10:24:57 +00:00
|
|
|
/* sdp */
|
|
|
|
if (sdp)
|
|
|
|
osmo_cc_add_ie_sdp(msg, sdp);
|
|
|
|
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Indicate OSMO-CC answer towards fixed network\n");
|
2020-08-09 12:27:56 +00:00
|
|
|
osmo_cc_ll_msg(ep, callref, msg);
|
|
|
|
}
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2020-08-09 12:27:56 +00:00
|
|
|
static void indicate_answer_ack(int callref)
|
|
|
|
{
|
|
|
|
osmo_cc_msg_t *msg;
|
|
|
|
|
|
|
|
msg = osmo_cc_new_msg(OSMO_CC_MSG_SETUP_COMP_IND);
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Indicate OSMO-CC setup complete towards fixed network\n");
|
2020-08-09 12:27:56 +00:00
|
|
|
osmo_cc_ll_msg(ep, callref, msg);
|
2017-10-28 05:11:40 +00:00
|
|
|
}
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2020-08-09 12:27:56 +00:00
|
|
|
static void indicate_disconnect_release(int callref, int cause, uint8_t msg_type)
|
2017-10-28 05:11:40 +00:00
|
|
|
{
|
2020-08-09 12:27:56 +00:00
|
|
|
osmo_cc_msg_t *msg;
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2020-08-09 12:27:56 +00:00
|
|
|
msg = osmo_cc_new_msg(msg_type);
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2020-08-09 12:27:56 +00:00
|
|
|
/* cause */
|
|
|
|
osmo_cc_add_ie_cause(msg, OSMO_CC_LOCATION_PRIV_SERV_LOC_USER, cause, 0, 0);
|
|
|
|
|
|
|
|
/* progress information */
|
|
|
|
if (msg_type == OSMO_CC_MSG_DISC_IND)
|
|
|
|
osmo_cc_add_ie_progress(msg, OSMO_CC_CODING_ITU_T, OSMO_CC_LOCATION_BEYOND_INTERWORKING, OSMO_CC_PROGRESS_INBAND_INFO_AVAILABLE);
|
|
|
|
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "%s OSMO-CC %s towards fixed network\n", (msg_type == OSMO_CC_MSG_REL_CNF) ? "Confirm" : "Indicated", (msg_type == OSMO_CC_MSG_DISC_IND) ? "disconnect" : "release");
|
2020-08-09 12:27:56 +00:00
|
|
|
osmo_cc_ll_msg(ep, callref, msg);
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
2020-08-09 12:27:56 +00:00
|
|
|
|
|
|
|
/* Setup is received from transceiver. */
|
|
|
|
int call_up_setup(const char *callerid, const char *dialing, uint8_t network, const char *network_id)
|
|
|
|
{
|
|
|
|
osmo_cc_call_t *call;
|
|
|
|
process_t *process;
|
|
|
|
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Incoming call from '%s' to '%s'\n", callerid ? : "unknown", dialing);
|
2020-08-09 12:27:56 +00:00
|
|
|
if (!strcmp(dialing, "010"))
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, " -> Call to Operator '%s'\n", dialing);
|
2020-08-09 12:27:56 +00:00
|
|
|
|
|
|
|
call = osmo_cc_call_new(ep);
|
|
|
|
|
|
|
|
process = create_process(call->callref, PROCESS_SETUP_RO);
|
|
|
|
|
|
|
|
indicate_setup(process, callerid, dialing, network, network_id);
|
|
|
|
|
|
|
|
return call->callref;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Transceiver indicates alerting. */
|
2017-10-28 05:11:40 +00:00
|
|
|
void call_up_alerting(int callref)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
2016-07-09 09:16:50 +00:00
|
|
|
if (!callref) {
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_DEBUG, "Ignoring alerting, because callref not set. (not for us)\n");
|
2016-07-09 09:16:50 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Call is alerting\n");
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2020-01-12 15:45:16 +00:00
|
|
|
if (!connect_on_setup)
|
2020-08-09 12:27:56 +00:00
|
|
|
indicate_alerting(callref);
|
2017-10-28 05:11:40 +00:00
|
|
|
set_pattern_process(callref, PATTERN_RINGBACK);
|
|
|
|
new_state_process(callref, PROCESS_ALERTING_RT);
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
|
2020-01-12 15:45:16 +00:00
|
|
|
/* Transceiver indicates early audio */
|
|
|
|
void call_up_early(int callref)
|
|
|
|
{
|
|
|
|
set_pattern_process(callref, PATTERN_NONE);
|
|
|
|
}
|
|
|
|
|
2016-03-01 17:40:38 +00:00
|
|
|
/* Transceiver indicates answer. */
|
2017-10-28 05:11:40 +00:00
|
|
|
void call_up_answer(int callref, const char *connect_id)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
2016-07-09 09:16:50 +00:00
|
|
|
if (!callref) {
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_DEBUG, "Ignoring answer, because callref not set. (not for us)\n");
|
2016-07-09 09:16:50 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Call has been answered by '%s'\n", connect_id);
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2020-01-12 15:45:16 +00:00
|
|
|
if (!connect_on_setup)
|
2021-03-20 10:24:57 +00:00
|
|
|
indicate_answer(callref, NULL, connect_id);
|
2017-10-28 05:11:40 +00:00
|
|
|
set_pattern_process(callref, PATTERN_NONE);
|
|
|
|
new_state_process(callref, PROCESS_CONNECT);
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Transceiver indicates release. */
|
2017-10-28 05:11:40 +00:00
|
|
|
void call_up_release(int callref, int cause)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
2017-10-28 05:11:40 +00:00
|
|
|
process_t *process;
|
|
|
|
|
2016-07-09 09:16:50 +00:00
|
|
|
if (!callref) {
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_DEBUG, "Ignoring release, because callref not set. (not for us)\n");
|
2016-07-09 09:16:50 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Call has been released with cause=%d\n", cause);
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2017-10-28 05:11:40 +00:00
|
|
|
process = get_process(callref);
|
|
|
|
if (process) {
|
2020-08-09 12:27:56 +00:00
|
|
|
/* just keep OSMO-CC connection if tones shall be sent.
|
2017-10-28 05:11:40 +00:00
|
|
|
* no tones while setting up / alerting the call. */
|
2020-01-12 15:45:16 +00:00
|
|
|
if (connect_on_setup
|
2017-11-11 04:55:32 +00:00
|
|
|
&& process->state != PROCESS_SETUP_RO
|
|
|
|
&& process->state != PROCESS_ALERTING_RO)
|
2017-10-28 05:11:40 +00:00
|
|
|
disconnect_process(callref, cause);
|
|
|
|
else
|
2017-11-11 04:55:32 +00:00
|
|
|
/* if no tones shall be sent, release on disconnect
|
|
|
|
* or RO setup states */
|
2017-10-28 05:11:40 +00:00
|
|
|
if (process->state == PROCESS_DISCONNECT
|
|
|
|
|| process->state == PROCESS_SETUP_RO
|
|
|
|
|| process->state == PROCESS_ALERTING_RO) {
|
|
|
|
destroy_process(callref);
|
2020-08-09 12:27:56 +00:00
|
|
|
indicate_disconnect_release(callref, cause, OSMO_CC_MSG_REL_IND);
|
2017-11-11 04:55:32 +00:00
|
|
|
/* if no tones shall be sent, disconnect on all other states */
|
2016-03-01 17:40:38 +00:00
|
|
|
} else {
|
2017-10-28 05:11:40 +00:00
|
|
|
disconnect_process(callref, cause);
|
2020-08-09 12:27:56 +00:00
|
|
|
indicate_disconnect_release(callref, cause, OSMO_CC_MSG_DISC_IND);
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
2017-10-28 05:11:40 +00:00
|
|
|
} else {
|
|
|
|
/* we don't know about the process, just send release to upper layer anyway */
|
2020-08-09 12:27:56 +00:00
|
|
|
indicate_disconnect_release(callref, cause, OSMO_CC_MSG_REL_IND);
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-06 09:30:39 +00:00
|
|
|
/* turn recall tone on or off */
|
|
|
|
void call_tone_recall(int callref, int on)
|
|
|
|
{
|
2017-10-28 05:11:40 +00:00
|
|
|
set_pattern_process(callref, (on) ? PATTERN_RECALL : PATTERN_NONE);
|
2017-08-06 09:30:39 +00:00
|
|
|
}
|
|
|
|
|
2020-08-09 12:27:56 +00:00
|
|
|
/* forward audio to OSMO-CC or call instance */
|
2024-03-10 12:45:08 +00:00
|
|
|
void call_up_audio(int callref, sample_t *samples, int len)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
2020-08-09 12:27:56 +00:00
|
|
|
process_t *process;
|
2024-03-10 12:45:08 +00:00
|
|
|
int16_t spl[len];
|
|
|
|
uint8_t *payload;
|
|
|
|
int payload_len;
|
2020-08-09 12:27:56 +00:00
|
|
|
|
2024-03-10 12:45:08 +00:00
|
|
|
if (len != 160) {
|
2017-10-28 05:11:40 +00:00
|
|
|
fprintf(stderr, "Samples must be 160, please fix!\n");
|
|
|
|
abort();
|
|
|
|
}
|
2016-07-09 09:16:50 +00:00
|
|
|
if (!callref)
|
|
|
|
return;
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2017-10-28 05:11:40 +00:00
|
|
|
/* if we are disconnected, ignore audio */
|
|
|
|
process = get_process(callref);
|
|
|
|
if (!process || process->pattern != PATTERN_NONE)
|
|
|
|
return;
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2024-03-10 12:45:08 +00:00
|
|
|
/* no codec negotiated (yet) */
|
|
|
|
if (!process->codec)
|
|
|
|
return;
|
|
|
|
|
2017-10-28 05:11:40 +00:00
|
|
|
/* forward audio */
|
2017-01-29 06:25:12 +00:00
|
|
|
#ifdef DEBUG_LEVEL
|
2024-03-10 12:45:08 +00:00
|
|
|
double lev = level_of(samples, len);
|
2017-10-28 05:11:40 +00:00
|
|
|
printf(" mobil-level: %s%.4f\n", debug_db(lev), (20 * log10(lev)));
|
2017-01-29 06:25:12 +00:00
|
|
|
#endif
|
2024-03-10 12:45:08 +00:00
|
|
|
/* real to integer */
|
|
|
|
samples_to_int16_speech(spl, samples, len);
|
|
|
|
/* encode and send via RTP */
|
|
|
|
process->codec->encoder((uint8_t *)spl, len * 2, &payload, &payload_len, process);
|
|
|
|
osmo_cc_rtp_send(process->codec, payload, payload_len, 0, 1, len);
|
|
|
|
free(payload);
|
2017-10-28 05:11:40 +00:00
|
|
|
/* don't destroy process here in case of an error */
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* clock that is used to transmit patterns */
|
2017-10-28 05:11:40 +00:00
|
|
|
void call_clock(void)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
|
|
|
process_t *process = process_head;
|
|
|
|
|
2020-01-12 06:54:25 +00:00
|
|
|
call_down_clock();
|
|
|
|
|
2016-03-01 17:40:38 +00:00
|
|
|
while(process) {
|
|
|
|
if (process->pattern != PATTERN_NONE) {
|
2024-03-10 12:45:08 +00:00
|
|
|
int16_t spl[160];
|
|
|
|
uint8_t *payload;
|
|
|
|
int payload_len;
|
2016-03-01 17:40:38 +00:00
|
|
|
/* try to get patterns, else copy the samples we got */
|
2024-03-10 12:45:08 +00:00
|
|
|
get_process_patterns(process, spl, 160);
|
2017-01-29 06:25:12 +00:00
|
|
|
#ifdef DEBUG_LEVEL
|
|
|
|
sample_t samples[160];
|
2024-03-10 12:45:08 +00:00
|
|
|
int16_to_samples(samples, (int16_t *)spl->data, 160);
|
2017-01-29 06:25:12 +00:00
|
|
|
double lev = level_of(samples, 160);
|
|
|
|
printf(" mobil-level: %s%.4f\n", debug_db(lev), (20 * log10(lev)));
|
2024-03-10 12:45:08 +00:00
|
|
|
samples_to_int16(spl, samples, 160);
|
2017-01-29 06:25:12 +00:00
|
|
|
#endif
|
2024-03-10 12:45:08 +00:00
|
|
|
/* encode and send via RTP */
|
|
|
|
process->codec->encoder((uint8_t *)spl, 160 * 2, &payload, &payload_len, process);
|
|
|
|
osmo_cc_rtp_send(process->codec, (uint8_t *)spl, 160 * 2, 0, 1, 160);
|
2017-10-28 05:11:40 +00:00
|
|
|
/* don't destroy process here in case of an error */
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
process = process->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-09 12:27:56 +00:00
|
|
|
/* messages received from fixed network */
|
2024-04-05 19:51:41 +00:00
|
|
|
static void ll_msg_cb(osmo_cc_endpoint_t __attribute__((unused)) *ep, uint32_t callref, osmo_cc_msg_t *msg)
|
2016-03-01 17:40:38 +00:00
|
|
|
{
|
2017-10-28 05:11:40 +00:00
|
|
|
process_t *process;
|
2020-08-09 12:27:56 +00:00
|
|
|
uint8_t coding, location, progress, isdn_cause, socket_cause;
|
2024-03-10 12:45:08 +00:00
|
|
|
uint16_t sip_cause, metering_connect_units;
|
2020-08-09 12:27:56 +00:00
|
|
|
uint8_t type, plan, present, screen, caller_type;
|
|
|
|
char caller_id[33], number[33];
|
2024-01-27 21:53:24 +00:00
|
|
|
struct timeval tv_meter = {};
|
2021-10-07 17:35:56 +00:00
|
|
|
const char *suffix, *invalid;
|
2020-08-09 12:27:56 +00:00
|
|
|
int rc;
|
2017-10-28 05:11:40 +00:00
|
|
|
|
|
|
|
process = get_process(callref);
|
|
|
|
if (!process) {
|
2020-08-09 12:27:56 +00:00
|
|
|
if (msg->type == OSMO_CC_MSG_SETUP_REQ)
|
2017-10-28 05:11:40 +00:00
|
|
|
process = create_process(callref, PROCESS_SETUP_RT);
|
|
|
|
else {
|
2020-08-09 12:27:56 +00:00
|
|
|
/* release collisions is not forbidden */
|
|
|
|
if (msg->type != OSMO_CC_MSG_REL_REQ)
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_ERROR, "No process!\n");
|
2020-08-09 12:27:56 +00:00
|
|
|
osmo_cc_free_msg(msg);
|
2017-10-28 05:11:40 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2017-10-28 05:11:40 +00:00
|
|
|
if (process->audio_disconnected) {
|
2020-08-09 12:27:56 +00:00
|
|
|
switch(msg->type) {
|
|
|
|
case OSMO_CC_MSG_DISC_REQ:
|
|
|
|
rc = osmo_cc_get_ie_cause(msg, 0, &location, &isdn_cause, &sip_cause, &socket_cause);
|
|
|
|
if (rc < 0)
|
|
|
|
isdn_cause = OSMO_CC_ISDN_CAUSE_NORM_CALL_CLEAR;
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Received OSMO-CC disconnect from fixed network with cause %d\n", isdn_cause);
|
|
|
|
LOGP(DCALL, LOGL_INFO, "Call disconnected, releasing!\n");
|
2016-03-01 17:40:38 +00:00
|
|
|
destroy_process(callref);
|
2020-08-09 12:27:56 +00:00
|
|
|
indicate_disconnect_release(callref, isdn_cause, OSMO_CC_MSG_REL_IND);
|
2016-03-01 17:40:38 +00:00
|
|
|
break;
|
2020-08-09 12:27:56 +00:00
|
|
|
case OSMO_CC_MSG_REL_REQ:
|
|
|
|
rc = osmo_cc_get_ie_cause(msg, 0, &location, &isdn_cause, &sip_cause, &socket_cause);
|
|
|
|
if (rc < 0)
|
|
|
|
isdn_cause = OSMO_CC_ISDN_CAUSE_NORM_CALL_CLEAR;
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Received OSMO-CC release from fixed network with cause %d\n", isdn_cause);
|
|
|
|
LOGP(DCALL, LOGL_INFO, "Call released\n");
|
2016-03-01 17:40:38 +00:00
|
|
|
destroy_process(callref);
|
2020-08-09 12:27:56 +00:00
|
|
|
indicate_disconnect_release(callref, isdn_cause, OSMO_CC_MSG_REL_CNF);
|
2016-03-01 17:40:38 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-08-09 12:27:56 +00:00
|
|
|
osmo_cc_free_msg(msg);
|
2016-03-01 17:40:38 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-03-10 12:45:08 +00:00
|
|
|
/* get metering information, tv_meter elements are 0, if no metering info available */
|
|
|
|
osmo_cc_get_ie_metering(msg, 0, &metering_connect_units, &tv_meter);
|
2024-01-27 21:53:24 +00:00
|
|
|
|
2020-08-09 12:27:56 +00:00
|
|
|
switch(msg->type) {
|
|
|
|
case OSMO_CC_MSG_SETUP_REQ:
|
|
|
|
{
|
|
|
|
const char *sdp;
|
2016-07-20 09:58:12 +00:00
|
|
|
|
2020-08-09 12:27:56 +00:00
|
|
|
/* sdp accept */
|
2023-11-15 19:37:40 +00:00
|
|
|
sdp = osmo_cc_helper_audio_accept(&ep->session_config, process, codecs + no_l16, down_audio, msg, &process->session, &process->codec, 0);
|
2020-08-09 12:27:56 +00:00
|
|
|
if (!sdp) {
|
|
|
|
disconnect_process(callref, 47);
|
2021-10-07 17:35:56 +00:00
|
|
|
indicate_disconnect_release(callref, 47, OSMO_CC_MSG_REJ_IND);
|
2016-07-20 09:58:12 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2020-08-09 12:27:56 +00:00
|
|
|
/* caller id */
|
|
|
|
rc = osmo_cc_get_ie_calling(msg, 0, &type, &plan, &present, &screen, caller_id, sizeof(caller_id));
|
2021-02-07 16:07:10 +00:00
|
|
|
if (rc < 0) {
|
2020-08-09 12:27:56 +00:00
|
|
|
caller_type = TYPE_NOTAVAIL;
|
2021-02-07 16:07:10 +00:00
|
|
|
caller_id[0] = '\0';
|
|
|
|
} else {
|
2020-08-09 12:27:56 +00:00
|
|
|
switch (type) {
|
|
|
|
case OSMO_CC_TYPE_INTERNATIONAL:
|
|
|
|
caller_type = TYPE_INTERNATIONAL;
|
|
|
|
break;
|
|
|
|
case OSMO_CC_TYPE_NATIONAL:
|
|
|
|
caller_type = TYPE_NATIONAL;
|
|
|
|
break;
|
|
|
|
case OSMO_CC_TYPE_SUBSCRIBER:
|
|
|
|
caller_type = TYPE_SUBSCRIBER;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
caller_type = TYPE_UNKNOWN;
|
|
|
|
}
|
|
|
|
if (present == OSMO_CC_PRESENT_RESTRICTED)
|
|
|
|
caller_type = TYPE_ANONYMOUS;
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
2021-10-07 17:35:56 +00:00
|
|
|
|
2020-08-09 12:27:56 +00:00
|
|
|
/* dialing */
|
|
|
|
rc = osmo_cc_get_ie_called(msg, 0, &type, &plan, number, sizeof(number));
|
|
|
|
if (rc < 0)
|
|
|
|
number[0] = '\0';
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Received OSMO-CC call from fixed network '%s' to mobile '%s'\n", caller_id, number);
|
2021-03-20 10:24:57 +00:00
|
|
|
if (!connect_on_setup)
|
|
|
|
indicate_proceeding(callref, sdp);
|
|
|
|
else {
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_DEBUG, "Early connecting after setup\n");
|
2021-03-20 10:24:57 +00:00
|
|
|
indicate_answer(callref, sdp, number);
|
|
|
|
}
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Outgoing call from '%s' to '%s'\n", caller_id, number);
|
2016-03-01 17:40:38 +00:00
|
|
|
|
2021-10-07 17:35:56 +00:00
|
|
|
/* insert '+' for international dialing */
|
|
|
|
if (type == OSMO_CC_TYPE_INTERNATIONAL && number[0] != '+') {
|
|
|
|
memmove(number + 1, number, sizeof(number) - 2);
|
|
|
|
number[0] = '+';
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove prefix, if any */
|
|
|
|
suffix = mobile_number_remove_prefix(number);
|
|
|
|
|
|
|
|
/* check suffix length */
|
|
|
|
invalid = mobile_number_check_length(suffix);
|
|
|
|
if (invalid) {
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_NOTICE, "Mobile number '%s' has invalid length: %s\n", suffix, invalid);
|
2021-10-07 17:35:56 +00:00
|
|
|
disconnect_process(callref, OSMO_CC_ISDN_CAUSE_INV_NR_FORMAT);
|
|
|
|
if (!connect_on_setup) {
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Disconnecting OSMO-CC call towards fixed network (cause=%d)\n", OSMO_CC_ISDN_CAUSE_INV_NR_FORMAT);
|
2021-10-07 17:35:56 +00:00
|
|
|
indicate_disconnect_release(callref, OSMO_CC_ISDN_CAUSE_INV_NR_FORMAT, OSMO_CC_MSG_DISC_IND);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check suffix digits */
|
|
|
|
invalid = mobile_number_check_digits(suffix);
|
|
|
|
if (invalid) {
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_NOTICE, "Mobile number '%s' has invalid digit: %s.\n", suffix, invalid);
|
2021-10-07 17:35:56 +00:00
|
|
|
disconnect_process(callref, OSMO_CC_ISDN_CAUSE_INV_NR_FORMAT);
|
|
|
|
if (!connect_on_setup) {
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Disconnecting OSMO-CC call towards fixed network (cause=%d)\n", OSMO_CC_ISDN_CAUSE_INV_NR_FORMAT);
|
2021-10-07 17:35:56 +00:00
|
|
|
indicate_disconnect_release(callref, OSMO_CC_ISDN_CAUSE_INV_NR_FORMAT, OSMO_CC_MSG_DISC_IND);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if suffix is valid */
|
|
|
|
if (mobile_number_check_valid) {
|
|
|
|
invalid = mobile_number_check_valid(suffix);
|
|
|
|
if (invalid) {
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_NOTICE, "Mobile number '%s' is invalid for this network: %s\n", suffix, invalid);
|
2021-10-07 17:35:56 +00:00
|
|
|
disconnect_process(callref, OSMO_CC_ISDN_CAUSE_INV_NR_FORMAT);
|
|
|
|
if (!connect_on_setup) {
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Disconnecting OSMO-CC call towards fixed network (cause=%d)\n", OSMO_CC_ISDN_CAUSE_INV_NR_FORMAT);
|
2021-10-07 17:35:56 +00:00
|
|
|
indicate_disconnect_release(callref, OSMO_CC_ISDN_CAUSE_INV_NR_FORMAT, OSMO_CC_MSG_DISC_IND);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* setup call */
|
|
|
|
rc = call_down_setup(callref, caller_id, caller_type, suffix);
|
2016-03-01 17:40:38 +00:00
|
|
|
if (rc < 0) {
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_NOTICE, "Call rejected, cause %d\n", -rc);
|
2021-03-20 10:24:57 +00:00
|
|
|
if (!connect_on_setup) {
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Disconnecting OSMO-CC call towards fixed network (cause=%d)\n", -rc);
|
2020-08-09 12:27:56 +00:00
|
|
|
indicate_disconnect_release(callref, -rc, OSMO_CC_MSG_DISC_IND);
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
2017-10-28 05:11:40 +00:00
|
|
|
disconnect_process(callref, -rc);
|
2016-03-01 17:40:38 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-08-09 12:27:56 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case OSMO_CC_MSG_SETUP_ACK_REQ:
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Received OSMO-CC overlap from fixed network\n");
|
2020-08-09 12:27:56 +00:00
|
|
|
rc = osmo_cc_helper_audio_negotiate(msg, &process->session, &process->codec);
|
|
|
|
if (rc < 0) {
|
|
|
|
nego_failed:
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Releasing, because codec negotiation failed.\n");
|
2020-08-09 12:27:56 +00:00
|
|
|
destroy_process(callref);
|
|
|
|
indicate_disconnect_release(callref, 47, OSMO_CC_MSG_REL_IND);
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Call released toward mobile network\n");
|
2020-08-09 12:27:56 +00:00
|
|
|
call_down_release(callref, 47);
|
2016-03-01 17:40:38 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2020-08-09 12:27:56 +00:00
|
|
|
case OSMO_CC_MSG_PROC_REQ:
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Received OSMO-CC proceeding from fixed network\n");
|
2020-08-09 12:27:56 +00:00
|
|
|
rc = osmo_cc_helper_audio_negotiate(msg, &process->session, &process->codec);
|
|
|
|
if (rc < 0)
|
|
|
|
goto nego_failed;
|
|
|
|
break;
|
|
|
|
case OSMO_CC_MSG_PROGRESS_REQ:
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Received OSMO-CC progress from fixed network\n");
|
2020-08-09 12:27:56 +00:00
|
|
|
rc = osmo_cc_helper_audio_negotiate(msg, &process->session, &process->codec);
|
|
|
|
if (rc < 0)
|
|
|
|
goto nego_failed;
|
|
|
|
break;
|
|
|
|
case OSMO_CC_MSG_ALERT_REQ:
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Received OSMO-CC alerting from fixed network\n");
|
2020-08-09 12:27:56 +00:00
|
|
|
rc = osmo_cc_helper_audio_negotiate(msg, &process->session, &process->codec);
|
|
|
|
if (rc < 0)
|
|
|
|
goto nego_failed;
|
2017-10-28 05:11:40 +00:00
|
|
|
new_state_process(callref, PROCESS_ALERTING_RO);
|
|
|
|
break;
|
2020-08-09 12:27:56 +00:00
|
|
|
case OSMO_CC_MSG_SETUP_RSP:
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Received OSMO-CC answer from fixed network\n");
|
2020-08-09 12:27:56 +00:00
|
|
|
rc = osmo_cc_helper_audio_negotiate(msg, &process->session, &process->codec);
|
|
|
|
if (rc < 0)
|
|
|
|
goto nego_failed;
|
2017-10-28 05:11:40 +00:00
|
|
|
new_state_process(callref, PROCESS_CONNECT);
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Call answered\n");
|
2024-01-27 21:53:24 +00:00
|
|
|
call_down_answer(callref, &tv_meter);
|
2020-08-09 12:27:56 +00:00
|
|
|
indicate_answer_ack(callref);
|
2016-03-01 17:40:38 +00:00
|
|
|
break;
|
2020-08-09 12:27:56 +00:00
|
|
|
case OSMO_CC_MSG_DISC_REQ:
|
|
|
|
rc = osmo_cc_helper_audio_negotiate(msg, &process->session, &process->codec);
|
|
|
|
if (rc < 0)
|
|
|
|
goto nego_failed;
|
|
|
|
rc = osmo_cc_get_ie_cause(msg, 0, &location, &isdn_cause, &sip_cause, &socket_cause);
|
|
|
|
if (rc < 0)
|
|
|
|
isdn_cause = OSMO_CC_ISDN_CAUSE_NORM_CALL_CLEAR;
|
|
|
|
rc = osmo_cc_get_ie_progress(msg, 0, &coding, &location, &progress);
|
|
|
|
if (rc < 0)
|
|
|
|
progress = 0;
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Received OSMO-CC disconnect from fixed network with cause %d\n", isdn_cause);
|
2020-08-09 12:27:56 +00:00
|
|
|
if (release_on_disconnect || (progress != 1 && progress != 8)) {
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Releasing, because we don't send disconnect tones to mobile phone\n");
|
2020-08-09 12:27:56 +00:00
|
|
|
destroy_process(callref);
|
|
|
|
indicate_disconnect_release(callref, isdn_cause, OSMO_CC_MSG_REL_IND);
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Call released toward mobile network\n");
|
2020-08-09 12:27:56 +00:00
|
|
|
call_down_release(callref, isdn_cause);
|
|
|
|
break;
|
2016-07-20 10:50:22 +00:00
|
|
|
}
|
2017-10-28 05:11:40 +00:00
|
|
|
new_state_process(callref, PROCESS_DISCONNECT);
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Call disconnected\n");
|
2020-08-09 12:27:56 +00:00
|
|
|
call_down_disconnect(callref, isdn_cause);
|
|
|
|
/* we might get released during disconnect handling!!! */
|
|
|
|
process = get_process(callref);
|
|
|
|
if (process && process->state == PROCESS_DISCONNECT)
|
2024-01-05 13:20:36 +00:00
|
|
|
osmo_timer_schedule(&process->timer, DISC_TIMEOUT);
|
2016-03-01 17:40:38 +00:00
|
|
|
break;
|
2020-08-09 12:27:56 +00:00
|
|
|
case OSMO_CC_MSG_REJ_REQ:
|
|
|
|
case OSMO_CC_MSG_REL_REQ:
|
|
|
|
rc = osmo_cc_get_ie_cause(msg, 0, &location, &isdn_cause, &sip_cause, &socket_cause);
|
|
|
|
if (rc < 0)
|
|
|
|
isdn_cause = OSMO_CC_ISDN_CAUSE_NORM_CALL_CLEAR;
|
2016-03-01 17:40:38 +00:00
|
|
|
destroy_process(callref);
|
2020-08-09 12:27:56 +00:00
|
|
|
if (msg->type == OSMO_CC_MSG_REL_REQ) {
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Received OSMO-CC release from fixed network with cause %d\n", isdn_cause);
|
2020-08-09 12:27:56 +00:00
|
|
|
indicate_disconnect_release(callref, isdn_cause, OSMO_CC_MSG_REL_CNF);
|
|
|
|
} else
|
2024-01-05 13:20:36 +00:00
|
|
|
LOGP(DCALL, LOGL_INFO, "Received OSMO-CC reject from fixed network with cause %d\n", isdn_cause);
|
|
|
|
LOGP(DCALL, LOGL_INFO, "Call released toward mobile network\n");
|
2020-08-09 12:27:56 +00:00
|
|
|
call_down_release(callref, isdn_cause);
|
2016-03-01 17:40:38 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-08-09 12:27:56 +00:00
|
|
|
osmo_cc_free_msg(msg);
|
2016-03-01 17:40:38 +00:00
|
|
|
}
|
|
|
|
|
2023-11-15 19:37:40 +00:00
|
|
|
int call_init(const char *name, int _send_patterns, int _release_on_disconnect, int use_socket, int argc, const char *argv[], int _no_l16)
|
2020-08-09 12:27:56 +00:00
|
|
|
{
|
|
|
|
int rc;
|
2017-10-28 05:11:40 +00:00
|
|
|
|
2020-08-09 12:27:56 +00:00
|
|
|
connect_on_setup = _send_patterns;
|
|
|
|
release_on_disconnect = _release_on_disconnect;
|
|
|
|
|
|
|
|
g711_init();
|
|
|
|
|
2023-11-15 19:37:40 +00:00
|
|
|
no_l16 = !!_no_l16;
|
2020-08-09 12:27:56 +00:00
|
|
|
ep = &endpoint;
|
|
|
|
rc = osmo_cc_new(ep, OSMO_CC_VERSION, name, OSMO_CC_LOCATION_PRIV_SERV_LOC_USER, ll_msg_cb, (use_socket) ? NULL : console_msg, NULL, argc, argv);
|
|
|
|
if (rc > 0)
|
|
|
|
return -EINVAL;
|
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void call_exit(void)
|
|
|
|
{
|
|
|
|
if (ep) {
|
|
|
|
osmo_cc_delete(ep);
|
|
|
|
ep = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int call_handle(void)
|
|
|
|
{
|
|
|
|
return osmo_cc_handle();
|
|
|
|
}
|
|
|
|
|