aboutsummaryrefslogtreecommitdiffstats
path: root/src/common
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2017-10-28 07:11:40 +0200
committerAndreas Eversberg <jolly@eversberg.eu>2017-11-05 16:58:31 +0100
commitee3fbeb03b503bedcc1f61791e678eb9998c4d3e (patch)
treed83e927305dbb86fd08c39bf90ef8239121c957d /src/common
parent7cbebaeb75211bbeb4d3f3b7bfe59ea6bce12aa1 (diff)
Split call control from built-in call console by using MNCC layer
Diffstat (limited to 'src/common')
-rw-r--r--src/common/Makefile.am1
-rw-r--r--src/common/call.c942
-rw-r--r--src/common/call.h40
-rw-r--r--src/common/cause.h3
-rw-r--r--src/common/debug.c4
-rw-r--r--src/common/main_mobile.c41
-rw-r--r--src/common/mncc_console.c473
-rw-r--r--src/common/mncc_console.h10
-rw-r--r--src/common/mncc_sock.c31
-rw-r--r--src/common/mncc_sock.h7
10 files changed, 812 insertions, 740 deletions
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 0ae7f9c..3b3375e 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -27,6 +27,7 @@ libmobile_a_SOURCES = \
cause.c \
call.c \
testton.c \
+ mncc_console.c \
mncc_sock.c \
hagelbarger.c \
display_status.c \
diff --git a/src/common/call.c b/src/common/call.c
index 1bfc233..53c0886 100644
--- a/src/common/call.c
+++ b/src/common/call.c
@@ -1,4 +1,4 @@
-/* built-in call control
+/* interface between mobile network/phone implementation and MNCC
*
* (C) 2016 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
@@ -30,8 +30,7 @@
#include "cause.h"
#include "call.h"
#include "timer.h"
-#include "mncc_sock.h"
-#include "testton.h"
+#include "mncc.h"
#define DISC_TIMEOUT 30
@@ -52,53 +51,35 @@ static double level_of(double *samples, int count)
}
#endif
+static int send_patterns; /* send patterns towards fixed network */
+static int release_on_disconnect; /* release towards mobile phone, if MNCC call disconnects, don't send disconnect tone */
+
/* stream patterns/announcements */
-int16_t *test_spl = NULL;
int16_t *ringback_spl = NULL;
-int16_t *hangup_spl = NULL;
-int16_t *busy_spl = NULL;
-int16_t *noanswer_spl = NULL;
-int16_t *outoforder_spl = NULL;
-int16_t *invalidnumber_spl = NULL;
-int16_t *congestion_spl = NULL;
-int16_t *recall_spl = NULL;
-int test_size = 0;
int ringback_size = 0;
-int hangup_size = 0;
-int busy_size = 0;
-int noanswer_size = 0;
-int outoforder_size = 0;
-int invalidnumber_size = 0;
-int congestion_size = 0;
-int recall_size = 0;
-int test_max = 0;
int ringback_max = 0;
+int16_t *hangup_spl = NULL;
+int hangup_size = 0;
int hangup_max = 0;
+int16_t *busy_spl = NULL;
+int busy_size = 0;
int busy_max = 0;
+int16_t *noanswer_spl = NULL;
+int noanswer_size = 0;
int noanswer_max = 0;
+int16_t *outoforder_spl = NULL;
+int outoforder_size = 0;
int outoforder_max = 0;
+int16_t *invalidnumber_spl = NULL;
+int invalidnumber_size = 0;
int invalidnumber_max = 0;
+int16_t *congestion_spl = NULL;
+int congestion_size = 0;
int congestion_max = 0;
+int16_t *recall_spl = NULL;
+int recall_size = 0;
int recall_max = 0;
-enum call_state {
- CALL_IDLE = 0,
- CALL_SETUP_MO,
- CALL_SETUP_MT,
- CALL_ALERTING,
- CALL_CONNECT,
- CALL_DISCONNECTED,
-};
-
-static const char *call_state_name[] = {
- "IDLE",
- "SETUP_MO",
- "SETUP_MT",
- "ALERTING",
- "CONNECT",
- "DISCONNECTED",
-};
-
enum audio_pattern {
PATTERN_NONE = 0,
PATTERN_TEST,
@@ -112,18 +93,13 @@ enum audio_pattern {
PATTERN_RECALL,
};
-void get_pattern(const int16_t **spl, int *size, int *max, enum audio_pattern pattern)
+static void get_pattern(const int16_t **spl, int *size, int *max, enum audio_pattern pattern)
{
*spl = NULL;
*size = 0;
*max = 0;
switch (pattern) {
- case PATTERN_TEST:
- *spl = test_spl;
- *size = test_size;
- *max = test_max;
- break;
case PATTERN_RINGBACK:
no_recall:
*spl = ringback_spl;
@@ -184,82 +160,6 @@ no_invalidnumber:
}
}
-static int new_callref = 0; /* toward mobile */
-
-/* built in call instance */
-typedef struct call {
- int callref;
- enum call_state state;
- int disc_cause; /* cause that has been sent by transceiver instance for release */
- char station_id[16];
- char dialing[16];
- char audiodev[64]; /* headphone interface, if used */
- int samplerate; /* sample rate of headphone interface */
- void *sound; /* headphone interface */
- int latspl; /* sample latency at headphone interface */
- samplerate_t srstate; /* patterns/announcement upsampling */
- jitter_t dejitter; /* headphone audio dejittering */
- int audio_pos; /* position when playing patterns */
- int test_audio_pos; /* position for test tone toward mobile */
- int dial_digits; /* number of digits to be dialed */
- int loopback; /* loopback test for echo */
- int echo_test; /* send echo back to mobile phone */
- int use_mncc_sock; /* use MNCC socket instead of built-in call control */
- int send_patterns; /* send patterns towards fixed network */
- int release_on_disconnect; /* release towards mobile phone, if MNCC call disconnects, don't send disconnect tone */
-
-} call_t;
-
-static call_t call;
-
-static void call_new_state(enum call_state state)
-{
- PDEBUG(DCALL, DEBUG_DEBUG, "Call state '%s' -> '%s'\n", call_state_name[call.state], call_state_name[state]);
- call.state = state;
- call.audio_pos = 0;
- call.test_audio_pos = 0;
-}
-
-static void get_call_patterns(int16_t *samples, int length, enum audio_pattern pattern)
-{
- const int16_t *spl;
- int size, max, pos;
-
- get_pattern(&spl, &size, &max, pattern);
-
- /* stream sample */
- pos = call.audio_pos;
- while(length--) {
- if (pos >= size)
- *samples++ = 0;
- else
- *samples++ = spl[pos] >> 1;
- if (++pos == max)
- pos = 0;
- }
- call.audio_pos = pos;
-}
-
-static void get_test_patterns(int16_t *samples, int length)
-{
- const int16_t *spl;
- int size, max, pos;
-
- get_pattern(&spl, &size, &max, PATTERN_TEST);
-
- /* stream sample */
- pos = call.test_audio_pos;
- while(length--) {
- if (pos >= size)
- *samples++ = 0;
- else
- *samples++ = spl[pos] >> 2;
- if (++pos == max)
- pos = 0;
- }
- call.test_audio_pos = pos;
-}
-
static enum audio_pattern cause2pattern(int cause)
{
int pattern;
@@ -290,11 +190,21 @@ static enum audio_pattern cause2pattern(int cause)
return pattern;
}
+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_CONNECT,
+ PROCESS_DISCONNECT,
+};
+
/* MNCC call instance */
typedef struct process {
struct process *next;
int callref;
- enum call_state state;
+ enum process_state state;
int audio_disconnected; /* if not associated with transceiver anymore */
enum audio_pattern pattern;
int audio_pos;
@@ -306,7 +216,7 @@ static process_t *process_head = NULL;
static void process_timeout(struct timer *timer);
-static void create_process(int callref, int state)
+static process_t *create_process(int callref, enum process_state state)
{
process_t *process;
@@ -321,6 +231,8 @@ static void create_process(int callref, int state)
process->callref = callref;
process->state = state;
+
+ return process;
}
static void destroy_process(int callref)
@@ -341,108 +253,55 @@ static void destroy_process(int callref)
PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref);
}
-static int is_process(int callref)
-{
- process_t *process = process_head;
-
- while (process) {
- if (process->callref == callref)
- return 1;
- process = process->next;
- }
- return 0;
-}
-
-static enum call_state is_process_state(int callref)
+static process_t *get_process(int callref)
{
process_t *process = process_head;
while (process) {
if (process->callref == callref)
- return process->state;
+ return process;
process = process->next;
}
- return CALL_IDLE;
+ return NULL;
}
-static void set_state_process(int callref, enum call_state state)
+static void new_state_process(int callref, enum process_state state)
{
- process_t *process = process_head;
+ process_t *process = get_process(callref);
- while (process) {
- if (process->callref == callref) {
- process->state = state;
- return;
- }
- process = process->next;
+ if (!process) {
+ PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref);
+ return;
}
- PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref);
+ process->state = state;
}
static void set_pattern_process(int callref, enum audio_pattern pattern)
{
- process_t *process = process_head;
+ process_t *process = get_process(callref);
- while (process) {
- if (process->callref == callref) {
- process->pattern = pattern;
- process->audio_pos = 0;
- return;
- }
- process = process->next;
+ if (!process) {
+ PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref);
+ return;
}
- PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref);
+ process->pattern = pattern;
+ process->audio_pos = 0;
}
/* disconnect audio, now send audio directly from pattern/announcement, not from transceiver */
static void disconnect_process(int callref, int cause)
{
- process_t *process = process_head;
-
- while (process) {
- if (process->callref == callref) {
- process->pattern = cause2pattern(cause);
- process->audio_disconnected = 1;
- process->audio_pos = 0;
- process->cause = cause;
- timer_start(&process->timer, DISC_TIMEOUT);
- return;
- }
- process = process->next;
- }
- PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref);
-}
+ process_t *process = get_process(callref);
-/* check if audio is disconnected */
-static int is_process_disconnected(int callref)
-{
- process_t *process = process_head;
-
- while (process) {
- if (process->callref == callref) {
- return process->audio_disconnected;
- }
- process = process->next;
- }
- PDEBUG(DCALL, DEBUG_DEBUG, "Process with callref 0x%x not found, this is ok!\n", callref);
-
- return 0;
-}
-
-/* check if pattern is set, so we send patterns and announcements */
-static int is_process_pattern(int callref)
-{
- process_t *process = process_head;
-
- while (process) {
- if (process->callref == callref) {
- return (process->pattern != PATTERN_NONE);
- }
- process = process->next;
+ if (!process) {
+ PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref);
+ return;
}
- PDEBUG(DCALL, DEBUG_DEBUG, "Process with callref 0x%x not found, this is ok!\n", callref);
-
- return 0;
+ process->pattern = cause2pattern(cause);
+ process->audio_disconnected = 1;
+ process->audio_pos = 0;
+ process->cause = cause;
+ timer_start(&process->timer, DISC_TIMEOUT);
}
static void get_process_patterns(process_t *process, int16_t *samples, int length)
@@ -478,301 +337,56 @@ static void process_timeout(struct timer *timer)
mncc->msg_type = MNCC_REL_IND;
mncc->callref = process->callref;
mncc->fields |= MNCC_F_CAUSE;
- mncc->cause.location = 1; /* private local */
+ mncc->cause.location = LOCATION_PRIVATE_LOCAL;
mncc->cause.value = process->cause;
destroy_process(process->callref);
- PDEBUG(DMNCC, DEBUG_INFO, "Releasing MNCC call towards Network (after timeout)\n");
- mncc_write(buf, sizeof(struct gsm_mncc));
- }
-}
-
-int call_init(const char *station_id, const char *audiodev, int samplerate, int latency, int dial_digits, int loopback, int use_mncc_sock, int send_patterns, int release_on_disconnect, int echo_test)
-{
- int rc = 0;
-
- init_testton();
-
- memset(&call, 0, sizeof(call));
- strncpy(call.station_id, station_id, sizeof(call.station_id) - 1);
- call.latspl = latency * samplerate / 1000;
- call.dial_digits = dial_digits;
- call.loopback = loopback;
- call.echo_test = echo_test;
- call.use_mncc_sock = use_mncc_sock;
- call.send_patterns = send_patterns;
- call.release_on_disconnect = release_on_disconnect;
- call.samplerate = samplerate;
- strncpy(call.audiodev, audiodev, sizeof(call.audiodev) - 1);
-
- if (use_mncc_sock && audiodev[0]) {
- PDEBUG(DSENDER, DEBUG_ERROR, "You selected MNCC interface, but it cannot be used with call device (headset).\n");
- rc = -EINVAL;
- goto error;
- }
- if (use_mncc_sock && echo_test) {
- PDEBUG(DSENDER, DEBUG_ERROR, "You selected MNCC interface, but it cannot be used with echo test.\n");
- rc = -EINVAL;
- goto error;
- }
- if (audiodev[0] && echo_test) {
- PDEBUG(DSENDER, DEBUG_ERROR, "You selected call device (headset), but it cannot be used with echo test.\n");
- rc = -EINVAL;
- goto error;
- }
-
- if (use_mncc_sock)
- return 0;
-
- if (!audiodev[0])
- return 0;
-
- rc = init_samplerate(&call.srstate, 8000.0, (double)samplerate, 3300.0);
- if (rc < 0) {
- PDEBUG(DSENDER, DEBUG_ERROR, "Failed to init sample rate conversion!\n");
- goto error;
- }
-
- rc = jitter_create(&call.dejitter, samplerate / 5);
- if (rc < 0) {
- PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create and init dejitter buffer!\n");
- goto error;
+ PDEBUG(DCALL, DEBUG_INFO, "Releasing MNCC call towards fixed network (after timeout)\n");
+ mncc_up(buf, sizeof(struct gsm_mncc));
}
-
- return 0;
-
-error:
- call_cleanup();
- return rc;
}
-int call_open_audio(int latspl)
+int call_init(int _send_patterns, int _release_on_disconnect)
{
- if (!call.audiodev[0])
- return 0;
-
- /* open sound device for call control */
- /* use factor 1.4 of speech level for complete range of sound card */
- call.sound = sound_open(call.audiodev, NULL, NULL, 1, 0.0, call.samplerate, latspl, 1.4, 4000.0);
- if (!call.sound) {
- PDEBUG(DSENDER, DEBUG_ERROR, "No sound device!\n");
- return -EIO;
- }
+ send_patterns = _send_patterns;
+ release_on_disconnect = _release_on_disconnect;
return 0;
}
-int call_start_audio(void)
-{
- if (!call.audiodev[0])
- return 0;
-
- return sound_start(call.sound);
-}
-
-void call_cleanup(void)
-{
- if (call.use_mncc_sock)
- return;
-
- /* close sound devoice */
- if (call.sound)
- sound_close(call.sound);
-
- jitter_destroy(&call.dejitter);
-
- if (process_head) {
- PDEBUG(DMNCC, DEBUG_ERROR, "Not all MNCC instances have been released!\n");
- }
-}
-
-static char console_text[256];
-static char console_clear[256];
-static int console_len = 0;
-
-static void process_ui(int c)
-{
- char text[256];
- int len;
-
- switch (call.state) {
- case CALL_IDLE:
- if (c > 0) {
- if (c >= '0' && c <= '9' && (int)strlen(call.station_id) < call.dial_digits) {
- call.station_id[strlen(call.station_id) + 1] = '\0';
- call.station_id[strlen(call.station_id)] = c;
- }
- if ((c == 8 || c == 127) && strlen(call.station_id))
- call.station_id[strlen(call.station_id) - 1] = '\0';
-dial_after_hangup:
- if (c == 'd' && (int)strlen(call.station_id) == call.dial_digits) {
- int rc;
- int callref = ++new_callref;
-
- PDEBUG(DCALL, DEBUG_INFO, "Outgoing call to %s\n", call.station_id);
- call.dialing[0] = '\0';
- call_new_state(CALL_SETUP_MT);
- call.callref = callref;
- rc = call_out_setup(callref, "", TYPE_NOTAVAIL, call.station_id);
- if (rc < 0) {
- PDEBUG(DCALL, DEBUG_NOTICE, "Call rejected, cause %d\n", -rc);
- call_new_state(CALL_DISCONNECTED);
- call.callref = 0;
- call.disc_cause = -rc;
- }
- }
- }
- if (call.dial_digits != (int)strlen(call.station_id))
- sprintf(text, "on-hook: %s%s (enter digits 0..9)\r", call.station_id, "..............." + 15 - call.dial_digits + strlen(call.station_id));
- else
- sprintf(text, "on-hook: %s (press d=dial)\r", call.station_id);
- break;
- case CALL_SETUP_MO:
- case CALL_SETUP_MT:
- case CALL_ALERTING:
- case CALL_CONNECT:
- case CALL_DISCONNECTED:
- if (c > 0) {
- if (c == 'h' || (c == 'd' && call.state == CALL_DISCONNECTED)) {
- PDEBUG(DCALL, DEBUG_INFO, "Call hangup\n");
- call_new_state(CALL_IDLE);
- if (call.callref) {
- call_out_release(call.callref, CAUSE_NORMAL);
- call.callref = 0;
- }
- if (c == 'd')
- goto dial_after_hangup;
- }
- }
- if (call.state == CALL_SETUP_MT)
- sprintf(text, "call setup: %s (press h=hangup)\r", call.station_id);
- if (call.state == CALL_ALERTING)
- sprintf(text, "call ringing: %s (press h=hangup)\r", call.station_id);
- if (call.state == CALL_CONNECT) {
- if (call.dialing[0])
- sprintf(text, "call active: %s->%s (press h=hangup)\r", call.station_id, call.dialing);
- else
- sprintf(text, "call active: %s (press h=hangup)\r", call.station_id);
- }
- if (call.state == CALL_DISCONNECTED)
- sprintf(text, "call disconnected: %s (press h=hangup d=redial)\r", cause_name(call.disc_cause));
- break;
- }
- /* skip if nothing has changed */
- len = strlen(text);
- if (console_len == len && !memcmp(console_text, text, len))
- return;
- clear_console_text();
- console_len = len;
- memcpy(console_text, text, len);
- memset(console_clear, ' ', len - 1);
- console_clear[len - 1] = '\r';
- print_console_text();
- fflush(stdout);
-}
-
-void clear_console_text(void)
-{
- if (!console_len)
- return;
-
- fwrite(console_clear, console_len, 1, stdout);
- // note: fflused by user of this function
- console_len = 0;
-}
-
-void print_console_text(void)
+/* Setup is received from transceiver. */
+static int _indicate_setup(int callref, const char *callerid, const char *dialing)
{
- if (!console_len)
- return;
+ uint8_t buf[sizeof(struct gsm_mncc)];
+ struct gsm_mncc *mncc = (struct gsm_mncc *)buf;
+ int rc;
- printf("\033[1;37m");
- fwrite(console_text, console_len, 1, stdout);
- printf("\033[0;39m");
+ 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;
}
-
-/* get keys from keyboad to control call via console
- * returns 1 on exit (ctrl+c) */
-void process_call(int c)
+int call_up_setup(int callref, const char *callerid, const char *dialing)
{
- if (call.use_mncc_sock) {
- mncc_handle();
- return;
- }
-
- if (!call.loopback)
- process_ui(c);
-
- if (!call.sound)
- return;
-
- /* handle audio, if sound device is used */
- sample_t samples[call.latspl + 10], *samples_list[1];
- uint8_t *power_list[1];
- double rf_level_db[1];
- int count;
int rc;
- count = sound_get_tosend(call.sound, call.latspl);
- if (count < 0) {
- PDEBUG(DSENDER, DEBUG_ERROR, "Failed to get samples in buffer (rc = %d)!\n", count);
- if (count == -EPIPE)
- PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n");
- return;
- }
- if (count > 0) {
- int16_t spl[count + 10]; /* more than enough, count will be reduced by scaling with factor */
- switch(call.state) {
- case CALL_ALERTING:
- /* the count will be an approximation that will be upsampled */
- count = (int)((double)count / call.srstate.factor + 0.5);
- get_call_patterns(spl, count, PATTERN_RINGBACK);
- int16_to_samples(samples, spl, count);
- count = samplerate_upsample(&call.srstate, samples, count, samples);
- /* prevent click after hangup */
- jitter_clear(&call.dejitter);
- break;
- case CALL_DISCONNECTED:
- /* the count will be an approximation that will be upsampled */
- count = (int)((double)count / call.srstate.factor + 0.5);
- get_call_patterns(spl, count, cause2pattern(call.disc_cause));
- int16_to_samples(samples, spl, count);
- count = samplerate_upsample(&call.srstate, samples, count, samples);
- /* prevent click after hangup */
- jitter_clear(&call.dejitter);
- break;
- default:
- jitter_load(&call.dejitter, samples, count);
- }
- samples_list[0] = samples;
- power_list[0] = NULL;
- rc = sound_write(call.sound, samples_list, power_list, count, NULL, NULL, 1);
- if (rc < 0) {
- PDEBUG(DSENDER, DEBUG_ERROR, "Failed to write TX data to sound device (rc = %d)\n", rc);
- if (rc == -EPIPE)
- PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n");
- return;
- }
- }
- samples_list[0] = samples;
- count = sound_read(call.sound, samples_list, call.latspl, 1, rf_level_db);
- if (count < 0) {
- PDEBUG(DSENDER, DEBUG_ERROR, "Failed to read from sound device (rc = %d)!\n", count);
- if (count == -EPIPE)
- PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n");
- return;
- }
- if (count) {
- if (call.loopback == 3)
- jitter_save(&call.dejitter, samples, count);
- count = samplerate_downsample(&call.srstate, samples, count);
- call_rx_audio(call.callref, samples, count);
- }
-}
-
-/* Setup is received from transceiver. */
-int call_in_setup(int callref, const char *callerid, const char *dialing)
-{
if (!callref) {
PDEBUG(DCALL, DEBUG_DEBUG, "Ignoring setup, because callref not set. (not for us)\n");
return -CAUSE_INVALCALLREF;
@@ -787,63 +401,31 @@ int call_in_setup(int callref, const char *callerid, const char *dialing)
if (!strcmp(dialing, "010"))
PDEBUG(DCALL, DEBUG_INFO, " -> Call to Operator '%s'\n", dialing);
- if (call.use_mncc_sock) {
- 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;
+ create_process(callref, PROCESS_SETUP_RO);
- PDEBUG(DMNCC, DEBUG_INFO, "Sending MNCC call towards Network\n");
+ rc = _indicate_setup(callref, callerid, dialing);
- create_process(callref, CALL_SETUP_MO);
+ return rc;
+}
- rc = mncc_write(buf, sizeof(struct gsm_mncc));
- if (rc < 0) {
- PDEBUG(DCALL, DEBUG_NOTICE, "We have no MNCC connection, rejecting.\n");
- destroy_process(callref);
- return -CAUSE_TEMPFAIL;
- }
- return 0;
- }
+/* 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;
- /* setup is also allowed on disconnected call */
- if (call.state == CALL_DISCONNECTED)
- call_new_state(CALL_IDLE);
- if (call.state != CALL_IDLE) {
- PDEBUG(DCALL, DEBUG_NOTICE, "We are busy, rejecting.\n");
- return -CAUSE_BUSY;
- }
- call.callref = callref;
- if (callerid) {
- strncpy(call.station_id, callerid, call.dial_digits);
- call.station_id[call.dial_digits] = '\0';
- }
- strncpy(call.dialing, dialing, sizeof(call.dialing) - 1);
- call.dialing[sizeof(call.dialing) - 1] = '\0';
- call_new_state(CALL_CONNECT);
- PDEBUG(DCALL, DEBUG_INFO, "Call automatically answered\n");
- call_out_answer(callref);
+ memset(buf, 0, sizeof(buf));
+ mncc->msg_type = MNCC_ALERT_IND;
+ mncc->callref = callref;
- return 0;
+ 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);
}
-
-/* Transceiver indicates alerting. */
-void call_in_alerting(int callref)
+void call_up_alerting(int callref)
{
if (!callref) {
PDEBUG(DCALL, DEBUG_DEBUG, "Ignoring alerting, because callref not set. (not for us)\n");
@@ -852,27 +434,10 @@ void call_in_alerting(int callref)
PDEBUG(DCALL, DEBUG_INFO, "Call is alerting\n");
- if (call.use_mncc_sock) {
- uint8_t buf[sizeof(struct gsm_mncc)];
- struct gsm_mncc *mncc = (struct gsm_mncc *)buf;
-
- if (!call.send_patterns) {
- memset(buf, 0, sizeof(buf));
- mncc->msg_type = MNCC_ALERT_IND;
- mncc->callref = callref;
- PDEBUG(DMNCC, DEBUG_INFO, "Indicate MNCC alerting towards Network\n");
- mncc_write(buf, sizeof(struct gsm_mncc));
- } else
- set_pattern_process(callref, PATTERN_RINGBACK);
- return;
- }
-
- if (call.callref != callref) {
- PDEBUG(DCALL, DEBUG_ERROR, "invalid call ref.\n");
- call_out_release(callref, CAUSE_INVALCALLREF);
- return;
- }
- call_new_state(CALL_ALERTING);
+ if (!send_patterns)
+ _indicate_alerting(callref);
+ set_pattern_process(callref, PATTERN_RINGBACK);
+ new_state_process(callref, PROCESS_ALERTING_RT);
}
/* Transceiver indicates answer. */
@@ -880,6 +445,7 @@ 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;
@@ -892,11 +458,12 @@ static void _indicate_answer(int callref, const char *connect_id)
mncc->connected.present = 0;
mncc->connected.screen = 3;
-
- PDEBUG(DMNCC, DEBUG_INFO, "Indicate MNCC answer towards Network\n");
- mncc_write(buf, sizeof(struct gsm_mncc));
+ 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_in_answer(int callref, const char *connect_id)
+void call_up_answer(int callref, const char *connect_id)
{
if (!callref) {
PDEBUG(DCALL, DEBUG_DEBUG, "Ignoring answer, because callref not set. (not for us)\n");
@@ -905,26 +472,35 @@ void call_in_answer(int callref, const char *connect_id)
PDEBUG(DCALL, DEBUG_INFO, "Call has been answered by '%s'\n", connect_id);
- if (call.use_mncc_sock) {
+ if (!send_patterns)
_indicate_answer(callref, connect_id);
- set_pattern_process(callref, PATTERN_NONE);
- set_state_process(callref, CALL_CONNECT);
- return;
- }
-
- if (call.callref != callref) {
- PDEBUG(DCALL, DEBUG_ERROR, "invalid call ref.\n");
- call_out_release(callref, CAUSE_INVALCALLREF);
- return;
- }
- call_new_state(CALL_CONNECT);
- strncpy(call.station_id, connect_id, call.dial_digits);
- call.station_id[call.dial_digits] = '\0';
+ set_pattern_process(callref, PATTERN_NONE);
+ new_state_process(callref, PROCESS_CONNECT);
}
/* Transceiver indicates release. */
-void call_in_release(int callref, int cause)
+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;
+
if (!callref) {
PDEBUG(DCALL, DEBUG_DEBUG, "Ignoring release, because callref not set. (not for us)\n");
return;
@@ -932,99 +508,69 @@ void call_in_release(int callref, int cause)
PDEBUG(DCALL, DEBUG_INFO, "Call has been released with cause=%d\n", cause);
- if (call.use_mncc_sock) {
- uint8_t buf[sizeof(struct gsm_mncc)];
- struct gsm_mncc *mncc = (struct gsm_mncc *)buf;
-
- memset(buf, 0, sizeof(buf));
- mncc->msg_type = MNCC_REL_IND;
- mncc->callref = callref;
- mncc->fields |= MNCC_F_CAUSE;
- mncc->cause.location = 1; /* private local */
- mncc->cause.value = cause;
-
- if (is_process(callref)) {
- if (!call.send_patterns
- || is_process_state(callref) == CALL_DISCONNECTED
- || is_process_state(callref) == CALL_SETUP_MO) {
- PDEBUG(DMNCC, DEBUG_INFO, "Releasing MNCC call towards Network\n");
- destroy_process(callref);
- mncc_write(buf, sizeof(struct gsm_mncc));
- } else {
- disconnect_process(callref, cause);
- }
+ process = get_process(callref);
+ if (process) {
+ /* just keep MNCC connection it tones shall be sent.
+ * no tones while setting up / alerting the call. */
+ if (send_patterns && !process->state == PROCESS_SETUP_RO && !process->state == PROCESS_ALERTING_RO)
+ disconnect_process(callref, cause);
+ else
+ if (process->state == PROCESS_DISCONNECT
+ || process->state == PROCESS_SETUP_RO
+ || process->state == PROCESS_ALERTING_RO) {
+ destroy_process(callref);
+ _indicate_disconnect_release(callref, cause, 0);
} else {
- PDEBUG(DMNCC, DEBUG_INFO, "Releasing MNCC call towards Network\n");
- mncc_write(buf, sizeof(struct gsm_mncc));
+ disconnect_process(callref, cause);
+ _indicate_disconnect_release(callref, cause, 1);
}
- return;
- }
-
- if (call.callref != callref) {
- PDEBUG(DCALL, DEBUG_ERROR, "invalid call ref.\n");
- /* don't send release, because caller already released */
- return;
+ } else {
+ /* we don't know about the process, just send release to upper layer anyway */
+ _indicate_disconnect_release(callref, cause, 0);
}
- call_new_state(CALL_DISCONNECTED);
- call.callref = 0;
- call.disc_cause = cause;
}
/* turn recall tone on or off */
void call_tone_recall(int callref, int on)
{
- /* can do that only with MNCC socket */
- if (call.use_mncc_sock)
- set_pattern_process(callref, (on) ? PATTERN_RECALL : PATTERN_NONE);
+ set_pattern_process(callref, (on) ? PATTERN_RECALL : PATTERN_NONE);
}
/* forward audio to MNCC or call instance */
-void call_tx_audio(int callref, sample_t *samples, int count)
+void call_up_audio(int callref, sample_t *samples, int 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;
- /* is MNCC us used, forward audio */
- if (call.use_mncc_sock) {
- uint8_t buf[sizeof(struct gsm_data_frame) + count * sizeof(int16_t)];
- struct gsm_data_frame *data = (struct gsm_data_frame *)buf;
-
- /* if we are disconnected, ignore audio */
- if (is_process_pattern(callref))
- return;
+ /* if we are disconnected, ignore audio */
+ process = get_process(callref);
+ if (!process || process->pattern != PATTERN_NONE)
+ return;
- /* forward audio */
- data->msg_type = ANALOG_8000HZ;
- data->callref = callref;
+ /* 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)));
+ 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_write(buf, sizeof(buf));
- } else
- /* else, save audio from transceiver to jitter buffer */
- if (call.sound) {
- sample_t up[(int)((double)count * call.srstate.factor + 0.5) + 10];
- count = samplerate_upsample(&call.srstate, samples, count, up);
- jitter_save(&call.dejitter, up, count);
- } else
- /* else, if echo test is used, send echo back to mobile */
- if (call.echo_test) {
- call_rx_audio(callref, samples, count);
- } else
- /* else, if no sound is used, send test tone to mobile */
- if (call.state == CALL_CONNECT) {
- int16_t spl[count];
- get_test_patterns(spl, count);
- int16_to_samples(samples, spl, count);
- call_rx_audio(callref, samples, count);
- }
+ samples_to_int16((int16_t *)data->data, samples, count);
+
+ mncc_up(buf, sizeof(buf));
+ /* don't destroy process here in case of an error */
}
/* clock that is used to transmit patterns */
-void call_mncc_clock(void)
+void call_clock(void)
{
process_t *process = process_head;
uint8_t buf[sizeof(struct gsm_data_frame) + 160 * sizeof(int16_t)];
@@ -1043,14 +589,15 @@ void call_mncc_clock(void)
printf(" mobil-level: %s%.4f\n", debug_db(lev), (20 * log10(lev)));
samples_to_int16((int16_t *)data->data, samples, 160);
#endif
- mncc_write(buf, sizeof(buf));
+ mncc_up(buf, sizeof(buf));
+ /* don't destroy process here in case of an error */
}
process = process->next;
}
}
-/* mncc messages received from network */
-void call_mncc_recv(uint8_t *buf, int length)
+/* mncc messages received from fixed network */
+void mncc_down(uint8_t *buf, int length)
{
struct gsm_mncc *mncc = (struct gsm_mncc *)buf;
char number[sizeof(mncc->called.number)];
@@ -1058,41 +605,53 @@ void call_mncc_recv(uint8_t *buf, int length)
enum number_type caller_type;
int callref;
int rc;
+ process_t *process;
+
+ callref = mncc->callref;
+ process = get_process(callref);
+ if (!process) {
+ if (mncc->msg_type == MNCC_SETUP_REQ)
+ process = create_process(callref, PROCESS_SETUP_RT);
+ else {
+ if (mncc->msg_type != MNCC_REL_REQ)
+ PDEBUG(DCALL, DEBUG_ERROR, "No process!\n");
+ return;
+ }
+ }
if (mncc->msg_type == ANALOG_8000HZ) {
struct gsm_data_frame *data = (struct gsm_data_frame *)buf;
- int count = (length - sizeof(struct gsm_data_frame)) / 2;
- sample_t samples[count];
+ sample_t samples[160];
/* if we are disconnected, ignore audio */
- if (is_process_pattern(data->callref))
+ if (process->pattern != PATTERN_NONE)
return;
- int16_to_samples(samples, (int16_t *)data->data, count);
+ int16_to_samples(samples, (int16_t *)data->data, 160);
#ifdef DEBUG_LEVEL
- double lev = level_of(samples, count);
+ double lev = level_of(samples, 160);
printf("festnetz-level: %s %.4f\n", debug_db(lev), (20 * log10(lev)));
#endif
- call_rx_audio(data->callref, samples, count);
+ call_down_audio(callref, samples, 160);
return;
}
- callref = mncc->callref;
-
- if (is_process_disconnected(callref)) {
+ if (process->audio_disconnected) {
switch(mncc->msg_type) {
case MNCC_DISC_REQ:
- PDEBUG(DMNCC, DEBUG_INFO, "Received MNCC disconnect from Network with cause %d\n", mncc->cause.value);
+ 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(DMNCC, DEBUG_INFO, "Releasing MNCC call towards Network\n");
+ PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC release towards fixed network\n");
mncc->msg_type = MNCC_REL_IND;
- mncc_write(buf, sizeof(struct gsm_mncc));
+ rc = mncc_up(buf, sizeof(struct gsm_mncc));
+ if (rc < 0)
+ destroy_process(callref);
break;
case MNCC_REL_REQ:
- PDEBUG(DMNCC, DEBUG_INFO, "Received MNCC release from Network with cause %d\n", mncc->cause.value);
+ PDEBUG(DCALL, DEBUG_INFO, "Received MNCC release from fixed network with cause %d\n", mncc->cause.value);
PDEBUG(DCALL, DEBUG_INFO, "Call released\n");
@@ -1127,14 +686,14 @@ void call_mncc_recv(uint8_t *buf, int length)
if (mncc->calling.present == 1)
caller_type = TYPE_ANONYMOUS;
- PDEBUG(DMNCC, DEBUG_INFO, "Received MNCC call from Network to '%s'\n", caller_id);
+ 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 network, please fix!\n");
+ fprintf(stderr, "Invalid callref from fixed network, please fix!\n");
abort();
}
- PDEBUG(DMNCC, DEBUG_INFO, "Confirming MNCC call to Network\n");
+ 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;
@@ -1143,77 +702,82 @@ void call_mncc_recv(uint8_t *buf, int length)
mncc->bearer_cap.speech_ver[0] = BCAP_ANALOG_8000HZ;
mncc->bearer_cap.speech_ver[1] = -1;
- mncc_write(buf, sizeof(struct gsm_mncc));
+ mncc_up(buf, sizeof(struct gsm_mncc));
PDEBUG(DCALL, DEBUG_INFO, "Outgoing call from '%s' to '%s'\n", caller_id, number);
- create_process(callref, CALL_SETUP_MT);
-
- rc = call_out_setup(callref, caller_id, caller_type, number);
+ rc = call_down_setup(callref, caller_id, caller_type, number);
if (rc < 0) {
PDEBUG(DCALL, DEBUG_NOTICE, "Call rejected, cause %d\n", -rc);
- if (call.send_patterns) {
+ if (send_patterns) {
PDEBUG(DCALL, DEBUG_DEBUG, "Early connecting after setup\n");
_indicate_answer(callref, number);
- disconnect_process(callref, -rc);
- break;
+ } else {
+ PDEBUG(DCALL, DEBUG_INFO, "Disconnecting MNCC call towards fixed network (cause=%d)\n", -rc);
+ _indicate_disconnect_release(callref, -rc, 1);
}
- PDEBUG(DMNCC, DEBUG_INFO, "Rejecting MNCC call towards Network (cause=%d)\n", -rc);
- memset(buf, 0, length);
- mncc->msg_type = MNCC_REL_IND;
- mncc->callref = callref;
- mncc->fields |= MNCC_F_CAUSE;
- mncc->cause.location = 1; /* private local */
- mncc->cause.value = -rc;
- mncc_write(buf, sizeof(struct gsm_mncc));
- destroy_process(callref);
+ disconnect_process(callref, -rc);
break;
}
- if (call.send_patterns) {
+ if (send_patterns) {
PDEBUG(DCALL, DEBUG_DEBUG, "Early connecting after setup\n");
_indicate_answer(callref, number);
break;
}
break;
+ case MNCC_ALERT_REQ:
+ PDEBUG(DCALL, DEBUG_INFO, "Received MNCC alerting from fixed network\n");
+ new_state_process(callref, PROCESS_ALERTING_RO);
+ break;
case MNCC_SETUP_RSP:
- PDEBUG(DMNCC, DEBUG_INFO, "Received MNCC answer from Network\n");
- set_state_process(callref, CALL_CONNECT);
+ PDEBUG(DCALL, DEBUG_INFO, "Received MNCC answer from fixed network\n");
+ new_state_process(callref, PROCESS_CONNECT);
PDEBUG(DCALL, DEBUG_INFO, "Call answered\n");
- call_out_answer(callref);
+ 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);
break;
case MNCC_DISC_REQ:
- PDEBUG(DMNCC, DEBUG_INFO, "Received MNCC disconnect from Network with cause %d\n", mncc->cause.value);
+ PDEBUG(DCALL, DEBUG_INFO, "Received MNCC disconnect from fixed network with cause %d\n", mncc->cause.value);
- if (is_process_state(callref) == CALL_CONNECT && call.release_on_disconnect) {
+ process = get_process(callref);
+ if (process && process->state == PROCESS_CONNECT && release_on_disconnect) {
PDEBUG(DCALL, DEBUG_INFO, "Releasing, because we don't send disconnect tones to mobile phone\n");
- PDEBUG(DMNCC, DEBUG_INFO, "Releasing MNCC call towards Network\n");
+ PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC release towards fixed network\n");
mncc->msg_type = MNCC_REL_IND;
- mncc_write(buf, sizeof(struct gsm_mncc));
+ mncc_up(buf, sizeof(struct gsm_mncc));
goto release;
}
- set_state_process(callref, CALL_DISCONNECTED);
+ new_state_process(callref, PROCESS_DISCONNECT);
PDEBUG(DCALL, DEBUG_INFO, "Call disconnected\n");
- call_out_disconnect(callref, mncc->cause.value);
+ call_down_disconnect(callref, mncc->cause.value);
break;
case MNCC_REL_REQ:
- PDEBUG(DMNCC, DEBUG_INFO, "Received MNCC release from Network with cause %d\n", mncc->cause.value);
+ PDEBUG(DCALL, DEBUG_INFO, "Received MNCC release from fixed network with cause %d\n", mncc->cause.value);
release:
destroy_process(callref);
PDEBUG(DCALL, DEBUG_INFO, "Call released\n");
- call_out_release(callref, mncc->cause.value);
+ call_down_release(callref, mncc->cause.value);
break;
}
}
+int (*mncc_up)(uint8_t *buf, int length) = NULL;
+
/* break down of MNCC socket */
-void call_mncc_flush(void)
+void mncc_flush(void)
{
while(process_head) {
- PDEBUG(DMNCC, DEBUG_NOTICE, "MNCC socket closed, releasing call\n");
- call_out_release(process_head->callref, CAUSE_TEMPFAIL);
+ 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 */
}
diff --git a/src/common/call.h b/src/common/call.h
index e9462d6..7273a1e 100644
--- a/src/common/call.h
+++ b/src/common/call.h
@@ -9,34 +9,32 @@ enum number_type {
TYPE_INTERNATIONAL,
};
-int call_init(const char *station_id, const char *audiodev, int samplerate, int latency, int dial_digits, int loopback, int use_mncc_sock, int send_patterns, int release_on_disconnect, int echo_test);
-void call_cleanup(void);
-int call_open_audio(int latspl);
-int call_start_audio(void);
-void process_call(int c);
-void clear_console_text(void);
-void print_console_text(void);
+int call_init(int _send_patterns, int _release_on_disconnect);
+
+/* function pointer to delive MNCC messages to upper layer */
+extern int (*mncc_up)(uint8_t *buf, int length);
+/* MNCC messages from upper layer */
+void mncc_down(uint8_t *buf, int length);
+/* flush all calls in case of MNCC socket failure */
+void mncc_flush(void);
/* received messages */
-int call_in_setup(int callref, const char *callerid, const char *dialing);
-void call_in_alerting(int callref);
-void call_in_answer(int callref, const char *connect_id);
-void call_in_release(int callref, int cause);
+int call_up_setup(int callref, const char *callerid, const char *dialing);
+void call_up_alerting(int callref);
+void call_up_answer(int callref, const char *connect_id);
+void call_up_release(int callref, int cause);
void call_tone_recall(int callref, int on);
/* send messages */
-int call_out_setup(int callref, const char *caller_id, enum number_type caller_type, const char *dialing);
-void call_out_answer(int callref);
-void call_out_disconnect(int callref, int cause);
-void call_out_release(int callref, int cause);
+int call_down_setup(int callref, const char *caller_id, enum number_type caller_type, const char *dialing);
+void call_down_answer(int callref);
+void call_down_disconnect(int callref, int cause);
+void call_down_release(int callref, int cause);
/* send and receive audio */
-void call_rx_audio(int callref, sample_t *samples, int count);
-void call_tx_audio(int callref, sample_t *samples, int count);
+void call_up_audio(int callref, sample_t *samples, int count);
+void call_down_audio(int callref, sample_t *samples, int count);
-/* receive from mncc */
-void call_mncc_recv(uint8_t *buf, int length);
-void call_mncc_flush(void);
/* clock to transmit to */
-void call_mncc_clock(void);
+void call_clock(void);
diff --git a/src/common/cause.h b/src/common/cause.h
index a6333c6..d7781a1 100644
--- a/src/common/cause.h
+++ b/src/common/cause.h
@@ -7,6 +7,9 @@
#define CAUSE_TEMPFAIL 41
#define CAUSE_INVALCALLREF 81
+#define LOCATION_USER 0
+#define LOCATION_PRIVATE_LOCAL 1
+
const char *cause_name(int cause);
diff --git a/src/common/debug.c b/src/common/debug.c
index d2eedb8..2bf48d1 100644
--- a/src/common/debug.c
+++ b/src/common/debug.c
@@ -27,7 +27,7 @@
#include "sample.h"
#include "debug.h"
#include "display.h"
-#include "call.h"
+#include "mncc_console.h"
const char *debug_level[] = {
"debug ",
@@ -51,7 +51,7 @@ struct debug_cat {
{ "amps", "\033[1;34m" },
{ "r2000", "\033[1;34m" },
{ "frame", "\033[0;36m" },
- { "call", "\033[1;37m" },
+ { "call", "\033[0;37m" },
{ "mncc", "\033[1;32m" },
{ "database", "\033[0;33m" },
{ "transaction", "\033[0;32m" },
diff --git a/src/common/main_mobile.c b/src/common/main_mobile.c
index f906d6d..bab9579 100644
--- a/src/common/main_mobile.c
+++ b/src/common/main_mobile.c
@@ -35,6 +35,7 @@
#include "sender.h"
#include "timer.h"
#include "call.h"
+#include "mncc_console.h"
#include "mncc_sock.h"
#ifdef HAVE_SDR
#include "sdr.h"
@@ -425,6 +426,20 @@ void main_mobile(int *quit, int latency, int interval, void (*myhandler)(void),
/* latency of send buffer in samples */
latspl = samplerate * latency / 1000;
+ /* check MNCC support */
+ if (use_mncc_sock && call_audiodev[0]) {
+ fprintf(stderr, "You selected MNCC interface, but it cannot be used with call device (headset).\n");
+ return;
+ }
+ if (use_mncc_sock && echo_test) {
+ fprintf(stderr, "You selected MNCC interface, but it cannot be used with echo test.\n");
+ return;
+ }
+ if (echo_test && call_audiodev[0]) {
+ fprintf(stderr, "You selected call device (headset), but it cannot be used with echo test.\n");
+ return;
+ }
+
/* init mncc */
if (use_mncc_sock) {
char mncc_sock_name[64];
@@ -433,15 +448,17 @@ void main_mobile(int *quit, int latency, int interval, void (*myhandler)(void),
mncc_sock_name[sizeof(mncc_sock_name) - 1] = '\0';
} else
strcpy(mncc_sock_name, "/tmp/bsc_mncc");
- rc = mncc_init(mncc_sock_name);
+ rc = mncc_sock_init(mncc_sock_name);
if (rc < 0) {
fprintf(stderr, "Failed to setup MNCC socket. Quitting!\n");
return;
}
+ } else {
+ console_init(station_id, call_audiodev, call_samplerate, latency, station_id_digits, loopback, echo_test);
}
- /* init call device */
- rc = call_init(station_id, call_audiodev, call_samplerate, latency, station_id_digits, loopback, use_mncc_sock, send_patterns, release_on_disconnect, echo_test);
+ /* init call control instance */
+ rc = call_init((use_mncc_sock) ? send_patterns : 0, release_on_disconnect);
if (rc < 0) {
fprintf(stderr, "Failed to create call control instance. Quitting!\n");
return;
@@ -456,7 +473,7 @@ void main_mobile(int *quit, int latency, int interval, void (*myhandler)(void),
/* open audio */
if (sender_open_audio(latspl))
return;
- if (call_open_audio(latspl))
+ if (console_open_audio(latspl))
return;
/* real time priority */
@@ -488,7 +505,7 @@ void main_mobile(int *quit, int latency, int interval, void (*myhandler)(void),
/* start streaming */
if (sender_start_audio())
*quit = 1;
- if (call_start_audio())
+ if (console_start_audio())
*quit = 1;
while(!(*quit)) {
@@ -512,7 +529,7 @@ void main_mobile(int *quit, int latency, int interval, void (*myhandler)(void),
if (now - last_time_call >= 0.020) {
last_time_call += 0.020;
/* call clock every 20ms */
- call_mncc_clock();
+ call_clock();
}
next_char:
@@ -578,8 +595,11 @@ next_char:
goto next_char;
}
- /* process audio of built-in call control */
- process_call(c);
+ /* process call control */
+ if (use_mncc_sock)
+ mncc_sock_handle();
+ else
+ process_console(c);
if (myhandler)
myhandler();
@@ -619,10 +639,11 @@ next_char:
}
/* cleanup call control */
- call_cleanup();
+ if (!use_mncc_sock)
+ console_cleanup();
/* close mncc socket */
if (use_mncc_sock)
- mncc_exit();
+ mncc_sock_exit();
}
diff --git a/src/common/mncc_console.c b/src/common/mncc_console.c
new file mode 100644
index 0000000..1e65d04
--- /dev/null
+++ b/src/common/mncc_console.c
@@ -0,0 +1,473 @@
+/* built-in console to talk to a phone
+ *
+ * (C) 2017 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
+ G* 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>
+#include "sample.h"
+#include "samplerate.h"
+#include "jitter.h"
+#include "debug.h"
+#include "testton.h"
+#include "mncc.h"
+#include "call.h"
+#include "cause.h"
+#include "mncc_console.h"
+#include "sound.h"
+
+static int new_callref = 0; /* toward mobile */
+
+enum console_state {
+ CONSOLE_IDLE = 0, /* IDLE */
+ CONSOLE_SETUP_RO, /* call from radio to console */
+ CONSOLE_SETUP_RT, /* call from console to radio */
+ CONSOLE_ALERTING_RO, /* call from radio to console */
+ CONSOLE_ALERTING_RT, /* call from console to radio */
+ CONSOLE_CONNECT,
+ CONSOLE_DISCONNECT,
+};
+
+static const char *console_state_name[] = {
+ "IDLE",
+ "SETUP_RO",
+ "SETUP_RT",
+ "ALERTING_RO",
+ "ALERTING_RT",
+ "CONNECT",
+ "DISCONNECT",
+};
+
+/* console call instance */
+typedef struct console {
+ uint32_t callref;
+ enum console_state state;
+ int disc_cause; /* cause that has been sent by transceiver instance for release */
+ char station_id[16];
+ char dialing[16];
+ char audiodev[64]; /* headphone interface, if used */
+ int samplerate; /* sample rate of headphone interface */
+ void *sound; /* headphone interface */
+ int latspl; /* sample latency at headphone interface */
+ samplerate_t srstate; /* patterns/announcement upsampling */
+ jitter_t dejitter; /* headphone audio dejittering */
+ int test_audio_pos; /* position for test tone toward mobile */
+ sample_t tx_buffer[160];/* transmit audio buffer */
+ int tx_buffer_pos; /* current position in transmit audio buffer */
+ int dial_digits; /* number of digits to be dialed */
+ int loopback; /* loopback test for echo */
+ int echo_test; /* send echo back to mobile phone */
+} console_t;
+
+static console_t console;
+
+/* stream test music */
+int16_t *test_spl = NULL;
+int test_size = 0;
+int test_max = 0;
+
+static void get_test_patterns(int16_t *samples, int length)
+{
+ const int16_t *spl;
+ int size, max, pos;
+
+ spl = test_spl;
+ size = test_size;
+ max = test_max;
+
+ /* stream sample */
+ pos = console.test_audio_pos;
+ while(length--) {
+ if (pos >= size)
+ *samples++ = 0;
+ else
+ *samples++ = spl[pos] >> 2;
+ if (++pos == max)
+ pos = 0;
+ }
+ console.test_audio_pos = pos;
+}
+
+static void console_new_state(enum console_state state)
+{
+ PDEBUG(DMNCC, DEBUG_DEBUG, "Call state '%s' -> '%s'\n", console_state_name[console.state], console_state_name[state]);
+ console.state = state;
+ console.test_audio_pos = 0;
+}
+
+static int console_mncc_up(uint8_t *buf, int length)
+{
+ struct gsm_mncc *mncc = (struct gsm_mncc *)buf;
+
+ if (mncc->msg_type == ANALOG_8000HZ) {
+ struct gsm_data_frame *data = (struct gsm_data_frame *)buf;
+ int count = 160;
+ sample_t samples[count];
+
+ /* save audio from transceiver to jitter buffer */
+ if (console.sound) {
+ sample_t up[(int)((double)count * console.srstate.factor + 0.5) + 10];
+ int16_to_samples(samples, (int16_t *)data->data, count);
+ count = samplerate_upsample(&console.srstate, samples, count, up);
+ jitter_save(&console.dejitter, up, count);
+ return 0;
+ }
+ /* if echo test is used, send echo back to mobile */
+ if (console.echo_test) {
+ /* send down reused MNCC */
+ mncc_down(buf, length);
+ return 0;
+ }
+ /* if no sound is used, send test tone to mobile */
+ if (console.state == CONSOLE_CONNECT) {
+ /* send down reused MNCC */
+ get_test_patterns((int16_t *)data->data, count);
+ mncc_down(buf, length);
+ return 0;
+ }
+ return 0;
+ }
+
+ if (mncc->msg_type != MNCC_SETUP_IND && console.callref != mncc->callref) {
+ PDEBUG(DMNCC, DEBUG_ERROR, "invalid call ref.\n");
+ /* send down reused MNCC */
+ mncc->msg_type = MNCC_REL_REQ;
+ mncc->fields |= MNCC_F_CAUSE;
+ mncc->cause.location = LOCATION_USER;
+ mncc->cause.value = CAUSE_INVALCALLREF;
+ mncc_down(buf, length);
+ return 0;
+ }
+
+ switch(mncc->msg_type) {
+ case MNCC_SETUP_IND:
+ PDEBUG(DMNCC, DEBUG_INFO, "Incoming call from '%s'\n", mncc->calling.number);
+ /* setup is also allowed on disconnected call */
+ if (console.state == CONSOLE_DISCONNECT)
+ console_new_state(CONSOLE_IDLE);
+ if (console.state != CONSOLE_IDLE) {
+ PDEBUG(DMNCC, DEBUG_NOTICE, "We are busy, rejecting.\n");
+ return -CAUSE_BUSY;
+ }
+ console.callref = mncc->callref;
+ if (mncc->calling.number[0]) {
+ strncpy(console.station_id, mncc->calling.number, console.dial_digits);
+ console.station_id[console.dial_digits] = '\0';
+ }
+ strncpy(console.dialing, mncc->called.number, sizeof(console.dialing) - 1);
+ console.dialing[sizeof(console.dialing) - 1] = '\0';
+ console_new_state(CONSOLE_CONNECT);
+ PDEBUG(DMNCC, DEBUG_INFO, "Call automatically answered\n");
+ /* send down reused MNCC */
+ mncc->msg_type = MNCC_SETUP_RSP;
+ mncc_down(buf, length);
+ break;
+ case MNCC_ALERT_IND:
+ PDEBUG(DMNCC, DEBUG_INFO, "Call alerting\n");
+ console_new_state(CONSOLE_ALERTING_RT);
+ break;
+ case MNCC_SETUP_CNF:
+ PDEBUG(DMNCC, DEBUG_INFO, "Call connected to '%s'\n", mncc->connected.number);
+ console_new_state(CONSOLE_CONNECT);
+ strncpy(console.station_id, mncc->connected.number, console.dial_digits);
+ console.station_id[console.dial_digits] = '\0';
+ /* send down reused MNCC */
+ mncc->msg_type = MNCC_SETUP_COMPL_REQ;
+ mncc_down(buf, length);
+ break;
+ case MNCC_DISC_IND:
+ PDEBUG(DMNCC, DEBUG_INFO, "Call disconnected (%s)\n", cause_name(mncc->cause.value));
+ console_new_state(CONSOLE_DISCONNECT);
+ console.disc_cause = mncc->cause.value;
+ break;
+ case MNCC_REL_IND:
+ PDEBUG(DMNCC, DEBUG_INFO, "Call released (%s)\n", cause_name(mncc->cause.value));
+ console_new_state(CONSOLE_IDLE);
+ console.callref = 0;
+ break;
+ }
+ return 0;
+}
+
+int console_init(const char *station_id, const char *audiodev, int samplerate, int latency, int dial_digits, int loopback, int echo_test)
+{
+ int rc = 0;
+
+ init_testton();
+
+ memset(&console, 0, sizeof(console));
+ strncpy(console.station_id, station_id, sizeof(console.station_id) - 1);
+ strncpy(console.audiodev, audiodev, sizeof(console.audiodev) - 1);
+ console.samplerate = samplerate;
+ console.latspl = latency * samplerate / 1000;
+ console.dial_digits = dial_digits;
+ console.loopback = loopback;
+ console.echo_test = echo_test;
+
+ mncc_up = console_mncc_up;
+
+ if (!audiodev[0])
+ return 0;
+
+ rc = init_samplerate(&console.srstate, 8000.0, (double)samplerate, 3300.0);
+ if (rc < 0) {
+ PDEBUG(DSENDER, DEBUG_ERROR, "Failed to init sample rate conversion!\n");
+ goto error;
+ }
+
+ rc = jitter_create(&console.dejitter, samplerate / 5);
+ if (rc < 0) {
+ PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create and init dejitter buffer!\n");
+ goto error;
+ }
+
+ return 0;
+
+error:
+ console_cleanup();
+ return rc;
+}
+
+int console_open_audio(int latspl)
+{
+ if (!console.audiodev[0])
+ return 0;
+
+ /* open sound device for call control */
+ /* use factor 1.4 of speech level for complete range of sound card */
+ console.sound = sound_open(console.audiodev, NULL, NULL, 1, 0.0, console.samplerate, latspl, 1.4, 4000.0);
+ if (!console.sound) {
+ PDEBUG(DSENDER, DEBUG_ERROR, "No sound device!\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int console_start_audio(void)
+{
+ if (!console.audiodev[0])
+ return 0;
+
+ return sound_start(console.sound);
+}
+
+void console_cleanup(void)
+{
+ /* close sound devoice */
+ if (console.sound)
+ sound_close(console.sound);
+
+ jitter_destroy(&console.dejitter);
+}
+
+static char console_text[256];
+static char console_clear[256];
+static int console_len = 0;
+
+static void process_ui(int c)
+{
+ char text[256];
+ int len;
+
+ switch (console.state) {
+ case CONSOLE_IDLE:
+ if (c > 0) {
+ if (c >= '0' && c <= '9' && (int)strlen(console.station_id) < console.dial_digits) {
+ console.station_id[strlen(console.station_id) + 1] = '\0';
+ console.station_id[strlen(console.station_id)] = c;
+ }
+ if ((c == 8 || c == 127) && strlen(console.station_id))
+ console.station_id[strlen(console.station_id) - 1] = '\0';
+dial_after_hangup:
+ if (c == 'd' && (int)strlen(console.station_id) == console.dial_digits) {
+ int callref = ++new_callref;
+ uint8_t buf[sizeof(struct gsm_mncc)];
+ struct gsm_mncc *mncc = (struct gsm_mncc *)buf;
+
+ PDEBUG(DMNCC, DEBUG_INFO, "Outgoing call to '%s'\n", console.station_id);
+ console.dialing[0] = '\0';
+ console_new_state(CONSOLE_SETUP_RT);
+ console.callref = callref;
+ memset(buf, 0, sizeof(buf));
+ mncc->msg_type = MNCC_SETUP_REQ;
+ mncc->callref = callref;
+ mncc->fields |= MNCC_F_CALLED;
+ strncpy(mncc->called.number, console.station_id, 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;
+ mncc_down(buf, sizeof(struct gsm_mncc));
+ }
+ }
+ if (console.dial_digits != (int)strlen(console.station_id))
+ sprintf(text, "on-hook: %s%s (enter digits 0..9)\r", console.station_id, "..............." + 15 - console.dial_digits + strlen(console.station_id));
+ else
+ sprintf(text, "on-hook: %s (press d=dial)\r", console.station_id);
+ break;
+ case CONSOLE_SETUP_RO:
+ case CONSOLE_SETUP_RT:
+ case CONSOLE_ALERTING_RO:
+ case CONSOLE_ALERTING_RT:
+ case CONSOLE_CONNECT:
+ case CONSOLE_DISCONNECT:
+ if (c > 0) {
+ if (c == 'h' || (c == 'd' && console.state == CONSOLE_DISCONNECT)) {
+ PDEBUG(DMNCC, DEBUG_INFO, "Call hangup\n");
+ console_new_state(CONSOLE_IDLE);
+ if (console.callref) {
+ uint8_t buf[sizeof(struct gsm_mncc)];
+ struct gsm_mncc *mncc = (struct gsm_mncc *)buf;
+
+ memset(buf, 0, sizeof(buf));
+ mncc->msg_type = MNCC_REL_REQ;
+ mncc->callref = console.callref;
+ mncc->fields |= MNCC_F_CAUSE;
+ mncc->cause.location = LOCATION_USER;
+ mncc->cause.value = CAUSE_NORMAL;
+ mncc_down(buf, sizeof(struct gsm_mncc));
+ console.callref = 0;
+ }
+ if (c == 'd')
+ goto dial_after_hangup;
+ }
+ }
+ if (console.state == CONSOLE_SETUP_RT)
+ sprintf(text, "call setup: %s (press h=hangup)\r", console.station_id);
+ if (console.state == CONSOLE_ALERTING_RT)
+ sprintf(text, "call ringing: %s (press h=hangup)\r", console.station_id);
+ if (console.state == CONSOLE_CONNECT) {
+ if (console.dialing[0])
+ sprintf(text, "call active: %s->%s (press h=hangup)\r", console.station_id, console.dialing);
+ else
+ sprintf(text, "call active: %s (press h=hangup)\r", console.station_id);
+ }
+ if (console.state == CONSOLE_DISCONNECT)
+ sprintf(text, "call disconnected: %s (press h=hangup d=redial)\r", cause_name(console.disc_cause));
+ break;
+ }
+ /* skip if nothing has changed */
+ len = strlen(text);
+ if (console_len == len && !memcmp(console_text, text, len))
+ return;
+ clear_console_text();
+ console_len = len;
+ memcpy(console_text, text, len);
+ memset(console_clear, ' ', len - 1);
+ console_clear[len - 1] = '\r';
+ print_console_text();
+ fflush(stdout);
+}
+
+void clear_console_text(void)
+{
+ if (!console_len)
+ return;
+
+ fwrite(console_clear, console_len, 1, stdout);
+ // note: fflused by user of this function
+ console_len = 0;
+}
+
+void print_console_text(void)
+{
+ if (!console_len)
+ return;
+
+ printf("\033[1;37m");
+ fwrite(console_text, console_len, 1, stdout);
+ printf("\033[0;39m");
+}
+
+/* get keys from keyboad to control call via console
+ * returns 1 on exit (ctrl+c) */
+void process_console(int c)
+{
+ if (!console.loopback)
+ process_ui(c);
+
+ if (!console.sound)
+ return;
+
+ /* handle audio, if sound device is used */
+ sample_t samples[console.latspl + 10], *samples_list[1];
+ uint8_t *power_list[1];
+ double rf_level_db[1];
+ int count;
+ int rc;
+
+ count = sound_get_tosend(console.sound, console.latspl);
+ if (count < 0) {
+ PDEBUG(DSENDER, DEBUG_ERROR, "Failed to get samples in buffer (rc = %d)!\n", count);
+ if (count == -EPIPE)
+ PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n");
+ return;
+ }
+ if (count > 0) {
+ jitter_load(&console.dejitter, samples, count);
+ samples_list[0] = samples;
+ power_list[0] = NULL;
+ rc = sound_write(console.sound, samples_list, power_list, count, NULL, NULL, 1);
+ if (rc < 0) {
+ PDEBUG(DSENDER, DEBUG_ERROR, "Failed to write TX data to sound device (rc = %d)\n", rc);
+ if (rc == -EPIPE)
+ PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n");
+ return;
+ }
+ }
+ samples_list[0] = samples;
+ count = sound_read(console.sound, samples_list, console.latspl, 1, rf_level_db);
+ if (count < 0) {
+ PDEBUG(DSENDER, DEBUG_ERROR, "Failed to read from sound device (rc = %d)!\n", count);
+ if (count == -EPIPE)
+ PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n");
+ return;
+ }
+ if (count) {
+ int i;
+
+ if (console.loopback == 3)
+ jitter_save(&console.dejitter, samples, count);
+ count = samplerate_downsample(&console.srstate, samples, count);
+ /* put samples into ring buffer */
+ for (i = 0; i < count; i++) {
+ console.tx_buffer[console.tx_buffer_pos] = samples[i];
+ /* if ring buffer wrapps, deliver data down to call process */
+ if (++console.tx_buffer_pos == 160) {
+ console.tx_buffer_pos = 0;
+ /* only if we have a call */
+ if (console.callref) {
+ uint8_t buf[sizeof(struct gsm_data_frame) + 160 * sizeof(int16_t)];
+ struct gsm_data_frame *data = (struct gsm_data_frame *)buf;
+
+ data->msg_type = ANALOG_8000HZ;
+ data->callref = console.callref;
+ samples_to_int16((int16_t *)data->data, console.tx_buffer, 160);
+ mncc_down(buf, sizeof(struct gsm_mncc));
+ }
+ }
+ }
+ }
+}
+
diff --git a/src/common/mncc_console.h b/src/common/mncc_console.h
new file mode 100644
index 0000000..f61c8a4
--- /dev/null
+++ b/src/common/mncc_console.h
@@ -0,0 +1,10 @@
+
+int console_init(const char *station_id, const char *audiodev, int samplerate, int latency, int dial_digits, int loopback, int echo_test);
+void console_cleanup(void);
+int console_open_audio(int latspl);
+int console_start_audio(void);
+void console_process(int c);
+void clear_console_text(void);
+void print_console_text(void);
+void process_console(int c);
+
diff --git a/src/common/mncc_sock.c b/src/common/mncc_sock.c
index 437dec1..4e97c52 100644
--- a/src/common/mncc_sock.c
+++ b/src/common/mncc_sock.c
@@ -29,33 +29,34 @@
#include "sample.h"
#include "debug.h"
#include "call.h"
+#include "cause.h"
#include "mncc_sock.h"
static int listen_sock = -1;
static int mncc_sock = -1;
/* write to mncc socket, return error or -EIO if no socket connection */
-int mncc_write(uint8_t *buf, int length)
+static int mncc_write(uint8_t *buf, int length)
{
int rc;
if (mncc_sock <= 0) {
- PDEBUG(DMNCC, DEBUG_NOTICE, "MNCC not connected.\n");
- return -EIO;
+ PDEBUG(DMNCC, DEBUG_NOTICE, "We have no MNCC connection, rejecting.\n");
+ return -CAUSE_TEMPFAIL;
}
rc = send(mncc_sock, buf, length, 0);
if (rc < 0) {
PDEBUG(DMNCC, DEBUG_ERROR, "MNCC connection failed (errno = %d).\n", errno);
mncc_sock_close();
- return 0;
+ return -CAUSE_TEMPFAIL;
}
if (rc != length) {
PDEBUG(DMNCC, DEBUG_NOTICE, "MNCC write failed.\n");
mncc_sock_close();
- return 0;
+ return -CAUSE_TEMPFAIL;
}
- return rc;
+ return 0;
}
@@ -80,7 +81,7 @@ static int mncc_read(void)
return -errno;
}
- call_mncc_recv(buf, rc);
+ mncc_down(buf, rc);
return rc;
}
@@ -141,7 +142,7 @@ static int mncc_accept(void)
return 1;
}
-void mncc_handle(void)
+void mncc_sock_handle(void)
{
mncc_accept();
@@ -159,11 +160,11 @@ void mncc_sock_close(void)
close(mncc_sock);
mncc_sock = -1;
/* clear all call instances */
- call_mncc_flush();
+ mncc_flush();
}
}
-int mncc_init(const char *sock_name)
+int mncc_sock_init(const char *sock_name)
{
struct sockaddr_un local;
unsigned int namelen;
@@ -197,14 +198,14 @@ int mncc_init(const char *sock_name)
if (rc < 0) {
PDEBUG(DMNCC, DEBUG_ERROR, "Failed to bind the unix domain "
"socket. '%s'\n", local.sun_path);
- mncc_exit();
+ mncc_sock_exit();
return rc;
}
rc = listen(listen_sock, 0);
if (rc < 0) {
PDEBUG(DMNCC, DEBUG_ERROR, "Failed to listen.\n");
- mncc_exit();
+ mncc_sock_exit();
return rc;
}
@@ -213,16 +214,18 @@ int mncc_init(const char *sock_name)
rc = fcntl(listen_sock, F_SETFL, flags | O_NONBLOCK);
if (rc < 0) {
PDEBUG(DMNCC, DEBUG_ERROR, "Failed to set socket into non-blocking IO mode.\n");
- mncc_exit();
+ mncc_sock_exit();
return rc;
}
+ mncc_up = mncc_write;
+
PDEBUG(DMNCC, DEBUG_DEBUG, "MNCC socket at '%s' initialized, waiting for connection.\n", sock_name);
return 0;
}
-void mncc_exit(void)
+void mncc_sock_exit(void)
{
mncc_sock_close();
diff --git a/src/common/mncc_sock.h b/src/common/mncc_sock.h
index 3f2ac4b..7406dbe 100644
--- a/src/common/mncc_sock.h
+++ b/src/common/mncc_sock.h
@@ -1,8 +1,7 @@
#include "mncc.h"
-int mncc_write(uint8_t *buf, int length);
-void mncc_handle(void);
+void mncc_sock_handle(void);
void mncc_sock_close(void);
-int mncc_init(const char *sock_name);
-void mncc_exit(void);
+int mncc_sock_init(const char *sock_name);
+void mncc_sock_exit(void);