Replaced MNCC by OSMO-CC
This commit is contained in:
640
src/libmobile/call.c
Executable file → Normal file
640
src/libmobile/call.c
Executable file → Normal file
@@ -1,4 +1,4 @@
|
||||
/* interface between mobile network/phone implementation and MNCC
|
||||
/* interface between mobile network/phone implementation and OsmoCC
|
||||
*
|
||||
* (C) 2016 by Andreas Eversberg <jolly@eversberg.eu>
|
||||
* All Rights Reserved
|
||||
@@ -24,13 +24,17 @@
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "../libsample/sample.h"
|
||||
#include "../libdebug/debug.h"
|
||||
#include "../libtimer/timer.h"
|
||||
#include "../libosmocc/endpoint.h"
|
||||
#include "../libosmocc/helper.h"
|
||||
#include "../libg711/g711.h"
|
||||
#include "cause.h"
|
||||
#include "sender.h"
|
||||
#include "call.h"
|
||||
#include "../libtimer/timer.h"
|
||||
#include "../libmncc/mncc.h"
|
||||
#include "../libmncc/cause.h"
|
||||
#include "console.h"
|
||||
|
||||
#define DISC_TIMEOUT 30
|
||||
|
||||
@@ -52,7 +56,44 @@ static double level_of(double *samples, int count)
|
||||
#endif
|
||||
|
||||
static int connect_on_setup; /* send patterns towards fixed network */
|
||||
static int release_on_disconnect; /* release towards mobile phone, if MNCC call disconnects, don't send disconnect tone */
|
||||
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;
|
||||
|
||||
void encode_l16(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
void decode_l16(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len)
|
||||
{
|
||||
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},
|
||||
};
|
||||
|
||||
/* stream patterns/announcements */
|
||||
int16_t *ringback_spl = NULL;
|
||||
@@ -192,15 +233,15 @@ static enum audio_pattern cause2pattern(int cause)
|
||||
|
||||
enum process_state {
|
||||
PROCESS_IDLE = 0, /* IDLE */
|
||||
PROCESS_SETUP_RO, /* call from radio to MNCC */
|
||||
PROCESS_SETUP_RT, /* call from MNCC to radio */
|
||||
PROCESS_ALERTING_RO, /* call from radio to MNCC */
|
||||
PROCESS_ALERTING_RT, /* call from MNCC to radio */
|
||||
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 */
|
||||
PROCESS_CONNECT,
|
||||
PROCESS_DISCONNECT,
|
||||
};
|
||||
|
||||
/* MNCC call instance */
|
||||
/* call process */
|
||||
typedef struct process {
|
||||
struct process *next;
|
||||
int callref;
|
||||
@@ -210,11 +251,14 @@ typedef struct process {
|
||||
int audio_pos;
|
||||
uint8_t cause;
|
||||
struct timer timer;
|
||||
osmo_cc_session_t *session;
|
||||
osmo_cc_session_codec_t *codec; /* codec to send */
|
||||
} process_t;
|
||||
|
||||
static process_t *process_head = NULL;
|
||||
|
||||
static void process_timeout(struct timer *timer);
|
||||
static void indicate_disconnect_release(int callref, int cause, uint8_t msg_type);
|
||||
|
||||
static process_t *create_process(int callref, enum process_state state)
|
||||
{
|
||||
@@ -244,13 +288,15 @@ static void destroy_process(int callref)
|
||||
if (process->callref == callref) {
|
||||
*process_p = process->next;
|
||||
timer_exit(&process->timer);
|
||||
if (process->session)
|
||||
osmo_cc_free_session(process->session);
|
||||
free(process);
|
||||
return;
|
||||
}
|
||||
process_p = &process->next;
|
||||
process = process->next;
|
||||
}
|
||||
PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref);
|
||||
PDEBUG(DCALL, DEBUG_ERROR, "Process with callref %d not found!\n", callref);
|
||||
}
|
||||
|
||||
static process_t *get_process(int callref)
|
||||
@@ -270,9 +316,10 @@ static void new_state_process(int callref, enum process_state state)
|
||||
process_t *process = get_process(callref);
|
||||
|
||||
if (!process) {
|
||||
PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref);
|
||||
PDEBUG(DCALL, DEBUG_ERROR, "Process with callref %d not found!\n", callref);
|
||||
return;
|
||||
}
|
||||
PDEBUG(DCALL, DEBUG_DEBUG, "Changing state for callref %d %d->%d\n", callref, process->state, state);
|
||||
process->state = state;
|
||||
}
|
||||
|
||||
@@ -281,7 +328,7 @@ static void set_pattern_process(int callref, enum audio_pattern pattern)
|
||||
process_t *process = get_process(callref);
|
||||
|
||||
if (!process) {
|
||||
PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref);
|
||||
PDEBUG(DCALL, DEBUG_ERROR, "Process with callref %d not found!\n", callref);
|
||||
return;
|
||||
}
|
||||
process->pattern = pattern;
|
||||
@@ -294,7 +341,7 @@ static void disconnect_process(int callref, int cause)
|
||||
process_t *process = get_process(callref);
|
||||
|
||||
if (!process) {
|
||||
PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref);
|
||||
PDEBUG(DCALL, DEBUG_ERROR, "Process with callref %d not found!\n", callref);
|
||||
return;
|
||||
}
|
||||
process->pattern = cause2pattern(cause);
|
||||
@@ -330,106 +377,140 @@ static void process_timeout(struct timer *timer)
|
||||
|
||||
{
|
||||
/* announcement timeout */
|
||||
uint8_t buf[sizeof(struct gsm_mncc)];
|
||||
struct gsm_mncc *mncc = (struct gsm_mncc *)buf;
|
||||
|
||||
if (process->state == PROCESS_DISCONNECT) {
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Call released toward mobile network (after timeout)\n");
|
||||
call_down_release(process->callref, process->cause);
|
||||
}
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
mncc->msg_type = MNCC_REL_IND;
|
||||
mncc->callref = process->callref;
|
||||
mncc->fields |= MNCC_F_CAUSE;
|
||||
mncc->cause.location = LOCATION_PRIVATE_LOCAL;
|
||||
mncc->cause.value = process->cause;
|
||||
|
||||
indicate_disconnect_release(process->callref, process->cause, OSMO_CC_MSG_REL_IND);
|
||||
destroy_process(process->callref);
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Releasing MNCC call towards fixed network (after timeout)\n");
|
||||
mncc_up(buf, sizeof(struct gsm_mncc));
|
||||
}
|
||||
}
|
||||
|
||||
int call_init(int _send_patterns, int _release_on_disconnect)
|
||||
void down_audio(struct osmo_cc_session_codec *codec, uint16_t __attribute__((unused)) sequence_number, uint32_t __attribute__((unused)) timestamp, uint8_t *data, int len)
|
||||
{
|
||||
connect_on_setup = _send_patterns;
|
||||
release_on_disconnect = _release_on_disconnect;
|
||||
process_t *process = codec->media->session->priv;
|
||||
sample_t samples[len / 2];
|
||||
|
||||
return 0;
|
||||
/* if we are disconnected, ignore audio */
|
||||
if (!process || process->pattern != PATTERN_NONE)
|
||||
return;
|
||||
int16_to_samples(samples, (int16_t *)data, len / 2);
|
||||
#ifdef DEBUG_LEVEL
|
||||
double lev = level_of(samples, len / 2);
|
||||
printf("festnetz-level: %s %.4f\n", debug_db(lev), (20 * log10(lev)));
|
||||
#endif
|
||||
call_down_audio(process->callref, samples, len / 2);
|
||||
}
|
||||
|
||||
static void indicate_setup(process_t *process, const char *callerid, const char *dialing, uint8_t network_type, const char *network_id)
|
||||
{
|
||||
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 */
|
||||
process->session = osmo_cc_helper_audio_offer(process, codecs, down_audio, msg, 1);
|
||||
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Indicate OSMO-CC setup towards fixed network\n");
|
||||
osmo_cc_ll_msg(ep, process->callref, msg);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Indicate OSMO-CC call confirm towards fixed network\n");
|
||||
osmo_cc_ll_msg(ep, callref, msg);
|
||||
}
|
||||
|
||||
static void indicate_alerting(int callref)
|
||||
{
|
||||
osmo_cc_msg_t *msg;
|
||||
|
||||
msg = osmo_cc_new_msg(OSMO_CC_MSG_ALERT_IND);
|
||||
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Indicate OSMO-CC alerting towards fixed network\n");
|
||||
osmo_cc_ll_msg(ep, callref, msg);
|
||||
}
|
||||
|
||||
static void indicate_answer(int callref, const char *connectid)
|
||||
{
|
||||
osmo_cc_msg_t *msg;
|
||||
|
||||
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);
|
||||
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Indicate OSMO-CC answer towards fixed network\n");
|
||||
osmo_cc_ll_msg(ep, callref, msg);
|
||||
}
|
||||
|
||||
static void indicate_answer_ack(int callref)
|
||||
{
|
||||
osmo_cc_msg_t *msg;
|
||||
|
||||
msg = osmo_cc_new_msg(OSMO_CC_MSG_SETUP_COMP_IND);
|
||||
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Indicate OSMO-CC setup complete towards fixed network\n");
|
||||
osmo_cc_ll_msg(ep, callref, msg);
|
||||
}
|
||||
|
||||
static void indicate_disconnect_release(int callref, int cause, uint8_t msg_type)
|
||||
{
|
||||
osmo_cc_msg_t *msg;
|
||||
|
||||
msg = osmo_cc_new_msg(msg_type);
|
||||
|
||||
/* 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);
|
||||
|
||||
PDEBUG(DCALL, DEBUG_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");
|
||||
osmo_cc_ll_msg(ep, callref, msg);
|
||||
}
|
||||
|
||||
/* Setup is received from transceiver. */
|
||||
static int _indicate_setup(int callref, const char *callerid, const char *dialing)
|
||||
int call_up_setup(const char *callerid, const char *dialing, uint8_t network, const char *network_id)
|
||||
{
|
||||
uint8_t buf[sizeof(struct gsm_mncc)];
|
||||
struct gsm_mncc *mncc = (struct gsm_mncc *)buf;
|
||||
int rc;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
mncc->msg_type = MNCC_SETUP_IND;
|
||||
mncc->callref = callref;
|
||||
mncc->fields |= MNCC_F_CALLING;
|
||||
if (callerid) {
|
||||
strncpy(mncc->calling.number, callerid, sizeof(mncc->calling.number) - 1);
|
||||
mncc->calling.type = 4; /* caller ID is of type 'subscriber' */
|
||||
} // otherwise unknown and no number
|
||||
mncc->fields |= MNCC_F_CALLED;
|
||||
strncpy(mncc->called.number, dialing, sizeof(mncc->called.number) - 1);
|
||||
mncc->called.type = 0; /* dialing is of type 'unknown' */
|
||||
mncc->lchan_type = GSM_LCHAN_TCH_F;
|
||||
mncc->fields |= MNCC_F_BEARER_CAP;
|
||||
mncc->bearer_cap.speech_ver[0] = BCAP_ANALOG_8000HZ;
|
||||
mncc->bearer_cap.speech_ver[1] = -1;
|
||||
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC setup towards fixed network\n");
|
||||
rc = mncc_up(buf, sizeof(struct gsm_mncc));
|
||||
if (rc < 0)
|
||||
destroy_process(callref);
|
||||
return rc;
|
||||
}
|
||||
int call_up_setup(int callref, const char *callerid, const char *dialing)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!callref) {
|
||||
PDEBUG(DCALL, DEBUG_DEBUG, "Ignoring setup, because callref not set. (not for us)\n");
|
||||
return -CAUSE_INVALCALLREF;
|
||||
}
|
||||
|
||||
if (callref < 0x4000000) {
|
||||
PDEBUG(DCALL, DEBUG_ERROR, "Invalid callref from mobile station, please fix!\n");
|
||||
abort();
|
||||
}
|
||||
osmo_cc_call_t *call;
|
||||
process_t *process;
|
||||
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Incoming call from '%s' to '%s'\n", callerid ? : "unknown", dialing);
|
||||
if (!strcmp(dialing, "010"))
|
||||
PDEBUG(DCALL, DEBUG_INFO, " -> Call to Operator '%s'\n", dialing);
|
||||
|
||||
call = osmo_cc_call_new(ep);
|
||||
|
||||
create_process(callref, PROCESS_SETUP_RO);
|
||||
process = create_process(call->callref, PROCESS_SETUP_RO);
|
||||
|
||||
rc = _indicate_setup(callref, callerid, dialing);
|
||||
indicate_setup(process, callerid, dialing, network, network_id);
|
||||
|
||||
return rc;
|
||||
return call->callref;
|
||||
}
|
||||
|
||||
/* Transceiver indicates alerting. */
|
||||
static void _indicate_alerting(int callref)
|
||||
{
|
||||
uint8_t buf[sizeof(struct gsm_mncc)];
|
||||
struct gsm_mncc *mncc = (struct gsm_mncc *)buf;
|
||||
int rc;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
mncc->msg_type = MNCC_ALERT_IND;
|
||||
mncc->callref = callref;
|
||||
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC alerting towards fixed network\n");
|
||||
rc = mncc_up(buf, sizeof(struct gsm_mncc));
|
||||
if (rc < 0)
|
||||
destroy_process(callref);
|
||||
}
|
||||
void call_up_alerting(int callref)
|
||||
{
|
||||
if (!callref) {
|
||||
@@ -440,7 +521,7 @@ void call_up_alerting(int callref)
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Call is alerting\n");
|
||||
|
||||
if (!connect_on_setup)
|
||||
_indicate_alerting(callref);
|
||||
indicate_alerting(callref);
|
||||
set_pattern_process(callref, PATTERN_RINGBACK);
|
||||
new_state_process(callref, PROCESS_ALERTING_RT);
|
||||
}
|
||||
@@ -452,28 +533,6 @@ void call_up_early(int callref)
|
||||
}
|
||||
|
||||
/* Transceiver indicates answer. */
|
||||
static void _indicate_answer(int callref, const char *connect_id)
|
||||
{
|
||||
uint8_t buf[sizeof(struct gsm_mncc)];
|
||||
struct gsm_mncc *mncc = (struct gsm_mncc *)buf;
|
||||
int rc;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
mncc->msg_type = MNCC_SETUP_CNF;
|
||||
mncc->callref = callref;
|
||||
mncc->fields |= MNCC_F_CONNECTED;
|
||||
/* copy connected number as subscriber number */
|
||||
strncpy(mncc->connected.number, connect_id, sizeof(mncc->connected.number));
|
||||
mncc->connected.type = 4;
|
||||
mncc->connected.plan = 1;
|
||||
mncc->connected.present = 0;
|
||||
mncc->connected.screen = 3;
|
||||
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC answer towards fixed network\n");
|
||||
rc = mncc_up(buf, sizeof(struct gsm_mncc));
|
||||
if (rc < 0)
|
||||
destroy_process(callref);
|
||||
}
|
||||
void call_up_answer(int callref, const char *connect_id)
|
||||
{
|
||||
if (!callref) {
|
||||
@@ -484,30 +543,12 @@ void call_up_answer(int callref, const char *connect_id)
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Call has been answered by '%s'\n", connect_id);
|
||||
|
||||
if (!connect_on_setup)
|
||||
_indicate_answer(callref, connect_id);
|
||||
indicate_answer(callref, connect_id);
|
||||
set_pattern_process(callref, PATTERN_NONE);
|
||||
new_state_process(callref, PROCESS_CONNECT);
|
||||
}
|
||||
|
||||
/* Transceiver indicates release. */
|
||||
static void _indicate_disconnect_release(int callref, int cause, int disc)
|
||||
{
|
||||
uint8_t buf[sizeof(struct gsm_mncc)];
|
||||
struct gsm_mncc *mncc = (struct gsm_mncc *)buf;
|
||||
int rc;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
mncc->msg_type = (disc) ? MNCC_DISC_IND : MNCC_REL_IND;
|
||||
mncc->callref = callref;
|
||||
mncc->fields |= MNCC_F_CAUSE;
|
||||
mncc->cause.location = LOCATION_PRIVATE_LOCAL;
|
||||
mncc->cause.value = cause;
|
||||
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC %s towards fixed network\n", (disc) ? "disconnect" : "release");
|
||||
rc = mncc_up(buf, sizeof(struct gsm_mncc));
|
||||
if (rc < 0)
|
||||
destroy_process(callref);
|
||||
}
|
||||
void call_up_release(int callref, int cause)
|
||||
{
|
||||
process_t *process;
|
||||
@@ -521,7 +562,7 @@ void call_up_release(int callref, int cause)
|
||||
|
||||
process = get_process(callref);
|
||||
if (process) {
|
||||
/* just keep MNCC connection if tones shall be sent.
|
||||
/* just keep OSMO-CC connection if tones shall be sent.
|
||||
* no tones while setting up / alerting the call. */
|
||||
if (connect_on_setup
|
||||
&& process->state != PROCESS_SETUP_RO
|
||||
@@ -534,15 +575,15 @@ void call_up_release(int callref, int cause)
|
||||
|| process->state == PROCESS_SETUP_RO
|
||||
|| process->state == PROCESS_ALERTING_RO) {
|
||||
destroy_process(callref);
|
||||
_indicate_disconnect_release(callref, cause, 0);
|
||||
indicate_disconnect_release(callref, cause, OSMO_CC_MSG_REL_IND);
|
||||
/* if no tones shall be sent, disconnect on all other states */
|
||||
} else {
|
||||
disconnect_process(callref, cause);
|
||||
_indicate_disconnect_release(callref, cause, 1);
|
||||
indicate_disconnect_release(callref, cause, OSMO_CC_MSG_DISC_IND);
|
||||
}
|
||||
} else {
|
||||
/* we don't know about the process, just send release to upper layer anyway */
|
||||
_indicate_disconnect_release(callref, cause, 0);
|
||||
indicate_disconnect_release(callref, cause, OSMO_CC_MSG_REL_IND);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -552,18 +593,16 @@ void call_tone_recall(int callref, int on)
|
||||
set_pattern_process(callref, (on) ? PATTERN_RECALL : PATTERN_NONE);
|
||||
}
|
||||
|
||||
/* forward audio to MNCC or call instance */
|
||||
/* forward audio to OSMO-CC or call instance */
|
||||
void call_up_audio(int callref, sample_t *samples, int count)
|
||||
{
|
||||
process_t *process;
|
||||
int16_t data[count];
|
||||
|
||||
if (count != 160) {
|
||||
fprintf(stderr, "Samples must be 160, please fix!\n");
|
||||
abort();
|
||||
}
|
||||
/* is MNCC us used, forward audio */
|
||||
uint8_t buf[sizeof(struct gsm_data_frame) + 160 * sizeof(int16_t)];
|
||||
struct gsm_data_frame *data = (struct gsm_data_frame *)buf;
|
||||
process_t *process;
|
||||
|
||||
if (!callref)
|
||||
return;
|
||||
|
||||
@@ -573,15 +612,12 @@ void call_up_audio(int callref, sample_t *samples, int count)
|
||||
return;
|
||||
|
||||
/* forward audio */
|
||||
data->msg_type = ANALOG_8000HZ;
|
||||
data->callref = callref;
|
||||
#ifdef DEBUG_LEVEL
|
||||
double lev = level_of(samples, count);
|
||||
printf(" mobil-level: %s%.4f\n", debug_db(lev), (20 * log10(lev)));
|
||||
#endif
|
||||
samples_to_int16((int16_t *)data->data, samples, count);
|
||||
|
||||
mncc_up(buf, sizeof(buf));
|
||||
samples_to_int16(data, samples, count);
|
||||
osmo_cc_rtp_send(process->codec, (uint8_t *)data, count * 2, 1, count);
|
||||
/* don't destroy process here in case of an error */
|
||||
}
|
||||
|
||||
@@ -589,140 +625,115 @@ void call_up_audio(int callref, sample_t *samples, int count)
|
||||
void call_clock(void)
|
||||
{
|
||||
process_t *process = process_head;
|
||||
uint8_t buf[sizeof(struct gsm_data_frame) + 160 * sizeof(int16_t)];
|
||||
struct gsm_data_frame *data = (struct gsm_data_frame *)buf;
|
||||
|
||||
call_down_clock();
|
||||
|
||||
while(process) {
|
||||
if (process->pattern != PATTERN_NONE) {
|
||||
data->msg_type = ANALOG_8000HZ;
|
||||
data->callref = process->callref;
|
||||
int16_t data[160];
|
||||
/* try to get patterns, else copy the samples we got */
|
||||
get_process_patterns(process, (int16_t *)data->data, 160);
|
||||
get_process_patterns(process, data, 160);
|
||||
#ifdef DEBUG_LEVEL
|
||||
sample_t samples[160];
|
||||
int16_to_samples(samples, (int16_t *)data->data, 160);
|
||||
double lev = level_of(samples, 160);
|
||||
printf(" mobil-level: %s%.4f\n", debug_db(lev), (20 * log10(lev)));
|
||||
samples_to_int16((int16_t *)data->data, samples, 160);
|
||||
samples_to_int16(data, samples, 160);
|
||||
#endif
|
||||
mncc_up(buf, sizeof(buf));
|
||||
osmo_cc_rtp_send(process->codec, (uint8_t *)data, 160 * 2, 1, 160);
|
||||
/* don't destroy process here in case of an error */
|
||||
}
|
||||
process = process->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* mncc messages received from fixed network */
|
||||
void mncc_down(uint8_t *buf, int length)
|
||||
/* messages received from fixed network */
|
||||
void ll_msg_cb(osmo_cc_endpoint_t __attribute__((unused)) *ep, uint32_t callref, osmo_cc_msg_t *msg)
|
||||
{
|
||||
struct gsm_mncc *mncc = (struct gsm_mncc *)buf;
|
||||
char number[sizeof(mncc->called.number)];
|
||||
char caller_id[sizeof(mncc->calling.number)];
|
||||
enum number_type caller_type;
|
||||
int callref;
|
||||
int rc;
|
||||
process_t *process;
|
||||
uint8_t coding, location, progress, isdn_cause, socket_cause;
|
||||
uint16_t sip_cause;
|
||||
uint8_t type, plan, present, screen, caller_type;
|
||||
char caller_id[33], number[33];
|
||||
int rc;
|
||||
|
||||
callref = mncc->callref;
|
||||
process = get_process(callref);
|
||||
if (!process) {
|
||||
if (mncc->msg_type == MNCC_SETUP_REQ)
|
||||
if (msg->type == OSMO_CC_MSG_SETUP_REQ)
|
||||
process = create_process(callref, PROCESS_SETUP_RT);
|
||||
else {
|
||||
/* release collisions and audio packet are not forbidden */
|
||||
if (mncc->msg_type != MNCC_REL_REQ && mncc->msg_type != ANALOG_8000HZ)
|
||||
/* release collisions is not forbidden */
|
||||
if (msg->type != OSMO_CC_MSG_REL_REQ)
|
||||
PDEBUG(DCALL, DEBUG_ERROR, "No process!\n");
|
||||
osmo_cc_free_msg(msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (mncc->msg_type == ANALOG_8000HZ) {
|
||||
struct gsm_data_frame *data = (struct gsm_data_frame *)buf;
|
||||
sample_t samples[160];
|
||||
|
||||
/* if we are disconnected, ignore audio */
|
||||
if (process->pattern != PATTERN_NONE)
|
||||
return;
|
||||
int16_to_samples(samples, (int16_t *)data->data, 160);
|
||||
#ifdef DEBUG_LEVEL
|
||||
double lev = level_of(samples, 160);
|
||||
printf("festnetz-level: %s %.4f\n", debug_db(lev), (20 * log10(lev)));
|
||||
#endif
|
||||
call_down_audio(callref, samples, 160);
|
||||
return;
|
||||
}
|
||||
|
||||
if (process->audio_disconnected) {
|
||||
switch(mncc->msg_type) {
|
||||
case MNCC_DISC_REQ:
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Received MNCC disconnect from fixed network with cause %d\n", mncc->cause.value);
|
||||
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Call disconnected, releasing!\n");
|
||||
|
||||
destroy_process(callref);
|
||||
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC release towards fixed network\n");
|
||||
mncc->msg_type = MNCC_REL_IND;
|
||||
rc = mncc_up(buf, sizeof(struct gsm_mncc));
|
||||
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)
|
||||
destroy_process(callref);
|
||||
break;
|
||||
case MNCC_REL_REQ:
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Received MNCC release from fixed network with cause %d\n", mncc->cause.value);
|
||||
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Call released\n");
|
||||
|
||||
isdn_cause = OSMO_CC_ISDN_CAUSE_NORM_CALL_CLEAR;
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Received OSMO-CC disconnect from fixed network with cause %d\n", isdn_cause);
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Call disconnected, releasing!\n");
|
||||
destroy_process(callref);
|
||||
indicate_disconnect_release(callref, isdn_cause, OSMO_CC_MSG_REL_IND);
|
||||
break;
|
||||
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;
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Received OSMO-CC release from fixed network with cause %d\n", isdn_cause);
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Call released\n");
|
||||
destroy_process(callref);
|
||||
indicate_disconnect_release(callref, isdn_cause, OSMO_CC_MSG_REL_CNF);
|
||||
break;
|
||||
}
|
||||
osmo_cc_free_msg(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
switch(mncc->msg_type) {
|
||||
case MNCC_SETUP_REQ:
|
||||
strcpy(number, mncc->called.number);
|
||||
switch(msg->type) {
|
||||
case OSMO_CC_MSG_SETUP_REQ:
|
||||
{
|
||||
const char *sdp;
|
||||
|
||||
/* caller ID conversion */
|
||||
strcpy(caller_id, mncc->calling.number);
|
||||
switch(mncc->calling.type) {
|
||||
case 1:
|
||||
caller_type = TYPE_INTERNATIONAL;
|
||||
break;
|
||||
case 2:
|
||||
caller_type = TYPE_NATIONAL;
|
||||
break;
|
||||
case 4:
|
||||
caller_type = TYPE_SUBSCRIBER;
|
||||
break;
|
||||
default: /* or 0 */
|
||||
caller_type = TYPE_UNKNOWN;
|
||||
/* sdp accept */
|
||||
sdp = osmo_cc_helper_audio_accept(process, codecs, down_audio, msg, &process->session, &process->codec, 0);
|
||||
if (!sdp) {
|
||||
disconnect_process(callref, 47);
|
||||
break;
|
||||
}
|
||||
if (!caller_id[0])
|
||||
|
||||
/* caller id */
|
||||
rc = osmo_cc_get_ie_calling(msg, 0, &type, &plan, &present, &screen, caller_id, sizeof(caller_id));
|
||||
if (rc < 0)
|
||||
caller_type = TYPE_NOTAVAIL;
|
||||
if (mncc->calling.present == 1)
|
||||
caller_type = TYPE_ANONYMOUS;
|
||||
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Received MNCC call from fixed network '%s' to mobile '%s'\n", caller_id, number);
|
||||
|
||||
if (mncc->callref >= 0x4000000) {
|
||||
fprintf(stderr, "Invalid callref from fixed network, please fix!\n");
|
||||
abort();
|
||||
else {
|
||||
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;
|
||||
}
|
||||
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC call confirm towards fixed network\n");
|
||||
memset(buf, 0, length);
|
||||
mncc->msg_type = MNCC_CALL_CONF_IND;
|
||||
mncc->callref = callref;
|
||||
mncc->lchan_type = GSM_LCHAN_TCH_F;
|
||||
mncc->fields |= MNCC_F_BEARER_CAP;
|
||||
mncc->bearer_cap.speech_ver[0] = BCAP_ANALOG_8000HZ;
|
||||
mncc->bearer_cap.speech_ver[1] = -1;
|
||||
|
||||
mncc_up(buf, sizeof(struct gsm_mncc));
|
||||
|
||||
/* dialing */
|
||||
rc = osmo_cc_get_ie_called(msg, 0, &type, &plan, number, sizeof(number));
|
||||
if (rc < 0)
|
||||
number[0] = '\0';
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Received OSMO-CC call from fixed network '%s' to mobile '%s'\n", caller_id, number);
|
||||
indicate_proceeding(callref, sdp);
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Outgoing call from '%s' to '%s'\n", caller_id, number);
|
||||
|
||||
rc = call_down_setup(callref, caller_id, caller_type, number);
|
||||
@@ -730,10 +741,10 @@ void mncc_down(uint8_t *buf, int length)
|
||||
PDEBUG(DCALL, DEBUG_NOTICE, "Call rejected, cause %d\n", -rc);
|
||||
if (connect_on_setup) {
|
||||
PDEBUG(DCALL, DEBUG_DEBUG, "Early connecting after setup\n");
|
||||
_indicate_answer(callref, number);
|
||||
indicate_answer(callref, number);
|
||||
} else {
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Disconnecting MNCC call towards fixed network (cause=%d)\n", -rc);
|
||||
_indicate_disconnect_release(callref, -rc, 1);
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Disconnecting OSMO-CC call towards fixed network (cause=%d)\n", -rc);
|
||||
indicate_disconnect_release(callref, -rc, OSMO_CC_MSG_DISC_IND);
|
||||
}
|
||||
disconnect_process(callref, -rc);
|
||||
break;
|
||||
@@ -741,65 +752,138 @@ void mncc_down(uint8_t *buf, int length)
|
||||
|
||||
if (connect_on_setup) {
|
||||
PDEBUG(DCALL, DEBUG_DEBUG, "Early connecting after setup\n");
|
||||
_indicate_answer(callref, number);
|
||||
indicate_answer(callref, number);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MNCC_ALERT_REQ:
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Received MNCC alerting from fixed network\n");
|
||||
}
|
||||
case OSMO_CC_MSG_SETUP_ACK_REQ:
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Received OSMO-CC overlap from fixed network\n");
|
||||
rc = osmo_cc_helper_audio_negotiate(msg, &process->session, &process->codec);
|
||||
if (rc < 0) {
|
||||
nego_failed:
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Releasing, because codec negotiation failed.\n");
|
||||
destroy_process(callref);
|
||||
indicate_disconnect_release(callref, 47, OSMO_CC_MSG_REL_IND);
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Call released toward mobile network\n");
|
||||
call_down_release(callref, 47);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case OSMO_CC_MSG_PROC_REQ:
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Received OSMO-CC proceeding from fixed network\n");
|
||||
rc = osmo_cc_helper_audio_negotiate(msg, &process->session, &process->codec);
|
||||
if (rc < 0)
|
||||
goto nego_failed;
|
||||
break;
|
||||
case OSMO_CC_MSG_PROGRESS_REQ:
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Received OSMO-CC progress from fixed network\n");
|
||||
rc = osmo_cc_helper_audio_negotiate(msg, &process->session, &process->codec);
|
||||
if (rc < 0)
|
||||
goto nego_failed;
|
||||
break;
|
||||
case OSMO_CC_MSG_ALERT_REQ:
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Received OSMO-CC alerting from fixed network\n");
|
||||
rc = osmo_cc_helper_audio_negotiate(msg, &process->session, &process->codec);
|
||||
if (rc < 0)
|
||||
goto nego_failed;
|
||||
new_state_process(callref, PROCESS_ALERTING_RO);
|
||||
break;
|
||||
case MNCC_SETUP_RSP:
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Received MNCC answer from fixed network\n");
|
||||
case OSMO_CC_MSG_SETUP_RSP:
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Received OSMO-CC answer from fixed network\n");
|
||||
rc = osmo_cc_helper_audio_negotiate(msg, &process->session, &process->codec);
|
||||
if (rc < 0)
|
||||
goto nego_failed;
|
||||
new_state_process(callref, PROCESS_CONNECT);
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Call answered\n");
|
||||
call_down_answer(callref);
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC setup complete towards fixed network\n");
|
||||
memset(buf, 0, length);
|
||||
mncc->msg_type = MNCC_SETUP_COMPL_IND;
|
||||
mncc->callref = callref;
|
||||
rc = mncc_up(buf, sizeof(struct gsm_mncc));
|
||||
if (rc < 0)
|
||||
destroy_process(callref);
|
||||
indicate_answer_ack(callref);
|
||||
break;
|
||||
case MNCC_DISC_REQ:
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Received MNCC disconnect from fixed network with cause %d\n", mncc->cause.value);
|
||||
|
||||
process = get_process(callref);
|
||||
if (process && process->state == PROCESS_CONNECT && release_on_disconnect) {
|
||||
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;
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Received OSMO-CC disconnect from fixed network with cause %d\n", isdn_cause);
|
||||
if (release_on_disconnect || (progress != 1 && progress != 8)) {
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Releasing, because we don't send disconnect tones to mobile phone\n");
|
||||
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC release towards fixed network\n");
|
||||
mncc->msg_type = MNCC_REL_IND;
|
||||
mncc_up(buf, sizeof(struct gsm_mncc));
|
||||
goto release;
|
||||
destroy_process(callref);
|
||||
indicate_disconnect_release(callref, isdn_cause, OSMO_CC_MSG_REL_IND);
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Call released toward mobile network\n");
|
||||
call_down_release(callref, isdn_cause);
|
||||
break;
|
||||
}
|
||||
new_state_process(callref, PROCESS_DISCONNECT);
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Call disconnected\n");
|
||||
call_down_disconnect(callref, mncc->cause.value);
|
||||
timer_start(&process->timer, DISC_TIMEOUT);
|
||||
call_down_disconnect(callref, isdn_cause);
|
||||
/* we might get released during disconnect handling!!! */
|
||||
process = get_process(callref);
|
||||
if (process && process->state == PROCESS_DISCONNECT)
|
||||
timer_start(&process->timer, DISC_TIMEOUT);
|
||||
break;
|
||||
case MNCC_REL_REQ:
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Received MNCC release from fixed network with cause %d\n", mncc->cause.value);
|
||||
|
||||
release:
|
||||
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;
|
||||
destroy_process(callref);
|
||||
if (msg->type == OSMO_CC_MSG_REL_REQ) {
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Received OSMO-CC release from fixed network with cause %d\n", isdn_cause);
|
||||
indicate_disconnect_release(callref, isdn_cause, OSMO_CC_MSG_REL_CNF);
|
||||
} else
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Received OSMO-CC reject from fixed network with cause %d\n", isdn_cause);
|
||||
PDEBUG(DCALL, DEBUG_INFO, "Call released toward mobile network\n");
|
||||
call_down_release(callref, mncc->cause.value);
|
||||
call_down_release(callref, isdn_cause);
|
||||
break;
|
||||
}
|
||||
osmo_cc_free_msg(msg);
|
||||
}
|
||||
|
||||
int (*mncc_up)(uint8_t *buf, int length) = NULL;
|
||||
|
||||
/* break down of MNCC socket */
|
||||
void mncc_flush(void)
|
||||
int call_init(const char *name, int _send_patterns, int _release_on_disconnect, int use_socket, int argc, const char *argv[])
|
||||
{
|
||||
while(process_head) {
|
||||
PDEBUG(DCALL, DEBUG_NOTICE, "MNCC socket closed, releasing call\n");
|
||||
call_down_release(process_head->callref, CAUSE_TEMPFAIL);
|
||||
destroy_process(process_head->callref);
|
||||
/* note: callref is released by sender's instance */
|
||||
int rc;
|
||||
|
||||
connect_on_setup = _send_patterns;
|
||||
release_on_disconnect = _release_on_disconnect;
|
||||
|
||||
g711_init();
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void call_media_handle(void)
|
||||
{
|
||||
process_t *process = process_head;
|
||||
|
||||
while(process) {
|
||||
if (process->session)
|
||||
osmo_cc_session_handle(process->session);
|
||||
process = process->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user