diff options
Diffstat (limited to 'src/libmobile/console.c')
-rwxr-xr-x[-rw-r--r--] | src/libmobile/console.c | 267 |
1 files changed, 157 insertions, 110 deletions
diff --git a/src/libmobile/console.c b/src/libmobile/console.c index a1198a9..a07aae6 100644..100755 --- a/src/libmobile/console.c +++ b/src/libmobile/console.c @@ -22,15 +22,19 @@ #include <unistd.h> #include <stdint.h> #include <stdlib.h> +#include <stdbool.h> #include <errno.h> #include <sys/time.h> +#include <sys/param.h> #include "../libsample/sample.h" #include "../libsamplerate/samplerate.h" #include "../libjitter/jitter.h" -#include "../libdebug/debug.h" -#include "../libtimer/timer.h" -#include "../libosmocc/endpoint.h" -#include "../libosmocc/helper.h" +#include "../liblogging/logging.h" +#include <osmocom/core/timer.h> +#include <osmocom/core/select.h> +#include <osmocom/cc/endpoint.h> +#include <osmocom/cc/helper.h> +#include <osmocom/cc/rtp.h> #include "testton.h" #include "console.h" #include "cause.h" @@ -71,13 +75,14 @@ typedef struct console { 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 */ + int buffer_size; /* sample buffer size 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 num_digits; /* number of digits to be dialed */ + const struct number_lengths *number_lengths;/* number of digits to be dialed */ + int number_max_length; /* number of digits of the longest number to be dialed */ int loopback; /* loopback test for echo */ int echo_test; /* send echo back to mobile phone */ const char *digits; /* list of dialable digits */ @@ -87,9 +92,6 @@ static console_t console; extern osmo_cc_endpoint_t *ep; -void encode_l16(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len); -void decode_l16(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len); - static struct osmo_cc_helper_audio_codecs codecs[] = { { "L16", 8000, 1, encode_l16, decode_l16 }, { NULL, 0, 0, NULL, NULL}, @@ -124,7 +126,7 @@ static void get_test_patterns(int16_t *samples, int length) static void console_new_state(enum console_state state) { - PDEBUG(DCC, DEBUG_DEBUG, "Call state '%s' -> '%s'\n", console_state_name[console.state], console_state_name[state]); + LOGP(DCALL, LOGL_DEBUG, "Call state '%s' -> '%s'\n", console_state_name[console.state], console_state_name[state]); console.state = state; console.test_audio_pos = 0; } @@ -139,28 +141,31 @@ static void free_console(void) console.callref = 0; } -void up_audio(struct osmo_cc_session_codec *codec, uint16_t __attribute__((unused)) sequence_number, uint32_t __attribute__((unused)) timestamp, uint8_t *data, int len) +static void up_audio(struct osmo_cc_session_codec *codec, uint8_t marker, uint16_t sequence, uint32_t timestamp, uint32_t ssrc, uint8_t *payload, int payload_len) { - int count = len / 2; - 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, count); - count = samplerate_upsample(&console.srstate, samples, count, up); - jitter_save(&console.dejitter, up, count); + jitter_frame_t *jf; + jf = jitter_frame_alloc(codec->decoder, &console, payload, payload_len, marker, sequence, timestamp, ssrc); + if (!jf) + return; + jitter_save(&console.dejitter, jf); return; } /* if echo test is used, send echo back to mobile */ if (console.echo_test) { - osmo_cc_rtp_send(codec, (uint8_t *)data, count * 2, 1, count); + osmo_cc_rtp_send_ts(codec, payload, payload_len, marker, sequence, timestamp); return; } /* if no sound is used, send test tone to mobile */ if (console.state == CONSOLE_CONNECT) { - get_test_patterns((int16_t *)data, count); - osmo_cc_rtp_send(codec, (uint8_t *)data, count * 2, 1, count); + int16_t spl[160]; + uint8_t *payload; + int payload_len; + get_test_patterns(spl, 160); + codec->encoder((uint8_t *)spl, 160 * 2, &payload, &payload_len, &console); + osmo_cc_rtp_send(codec, payload, payload_len, 0, 1, 160); + free(payload); return; } } @@ -226,7 +231,7 @@ void console_msg(osmo_cc_call_t *call, osmo_cc_msg_t *msg) int rc; if (msg->type != OSMO_CC_MSG_SETUP_IND && console.callref != call->callref) { - PDEBUG(DCC, DEBUG_ERROR, "invalid call ref %u (msg=0x%02x).\n", call->callref, msg->type); + LOGP(DCALL, LOGL_ERROR, "invalid call ref %u (msg=0x%02x).\n", call->callref, msg->type); request_disconnect_release_reject(call->callref, CAUSE_INVALCALLREF, OSMO_CC_MSG_REL_REQ); osmo_cc_free_msg(msg); return; @@ -243,10 +248,10 @@ void console_msg(osmo_cc_call_t *call, osmo_cc_msg_t *msg) rc = osmo_cc_get_ie_called(msg, 0, &type, &plan, number, sizeof(number)); if (rc < 0) number[0] = '\0'; - PDEBUG(DCC, DEBUG_INFO, "Incoming call from '%s'\n", caller_id); + LOGP(DCALL, LOGL_INFO, "Incoming call from '%s'\n", caller_id); /* setup is also allowed on disconnected call */ if (console.state == CONSOLE_DISCONNECT_RO) { - PDEBUG(DCC, DEBUG_INFO, "Releasing pending disconnected call\n"); + LOGP(DCALL, LOGL_INFO, "Releasing pending disconnected call\n"); if (console.callref) { request_disconnect_release_reject(console.callref, CAUSE_NORMAL, OSMO_CC_MSG_REL_REQ); free_console(); @@ -254,7 +259,7 @@ void console_msg(osmo_cc_call_t *call, osmo_cc_msg_t *msg) console_new_state(CONSOLE_IDLE); } if (console.state != CONSOLE_IDLE) { - PDEBUG(DCC, DEBUG_NOTICE, "We are busy, rejecting.\n"); + LOGP(DCALL, LOGL_NOTICE, "We are busy, rejecting.\n"); request_disconnect_release_reject(console.callref, CAUSE_NORMAL, OSMO_CC_MSG_REJ_REQ); osmo_cc_free_msg(msg); return; @@ -263,19 +268,19 @@ void console_msg(osmo_cc_call_t *call, osmo_cc_msg_t *msg) /* sdp accept */ sdp = osmo_cc_helper_audio_accept(&ep->session_config, NULL, codecs, up_audio, msg, &console.session, &console.codec, 0); if (!sdp) { - PDEBUG(DCC, DEBUG_NOTICE, "Cannot accept codec, rejecting.\n"); + LOGP(DCALL, LOGL_NOTICE, "Cannot accept codec, rejecting.\n"); request_disconnect_release_reject(console.callref, CAUSE_RESOURCE_UNAVAIL, OSMO_CC_MSG_REJ_REQ); osmo_cc_free_msg(msg); return; } if (caller_id[0]) { - strncpy(console.station_id, caller_id, console.num_digits); - console.station_id[console.num_digits] = '\0'; + strncpy(console.station_id, caller_id, sizeof(console.station_id)); + console.station_id[sizeof(console.station_id) - 1] = '\0'; } strncpy(console.dialing, number, sizeof(console.dialing) - 1); console.dialing[sizeof(console.dialing) - 1] = '\0'; console_new_state(CONSOLE_CONNECT); - PDEBUG(DCC, DEBUG_INFO, "Call automatically answered\n"); + LOGP(DCALL, LOGL_INFO, "Call automatically answered\n"); request_answer(console.callref, number, sdp); break; } @@ -284,7 +289,7 @@ void console_msg(osmo_cc_call_t *call, osmo_cc_msg_t *msg) osmo_cc_helper_audio_negotiate(msg, &console.session, &console.codec); break; case OSMO_CC_MSG_ALERT_IND: - PDEBUG(DCC, DEBUG_INFO, "Call alerting\n"); + LOGP(DCALL, LOGL_INFO, "Call alerting\n"); osmo_cc_helper_audio_negotiate(msg, &console.session, &console.codec); console_new_state(CONSOLE_ALERTING_RT); break; @@ -294,11 +299,13 @@ void console_msg(osmo_cc_call_t *call, osmo_cc_msg_t *msg) rc = osmo_cc_get_ie_calling(msg, 0, &type, &plan, &present, &screen, caller_id, sizeof(caller_id)); if (rc < 0) caller_id[0] = '\0'; - PDEBUG(DCC, DEBUG_INFO, "Call connected to '%s'\n", caller_id); + LOGP(DCALL, LOGL_INFO, "Call connected to '%s'\n", caller_id); osmo_cc_helper_audio_negotiate(msg, &console.session, &console.codec); console_new_state(CONSOLE_CONNECT); - strncpy(console.station_id, caller_id, console.num_digits); - console.station_id[console.num_digits] = '\0'; + if (caller_id[0]) { + strncpy(console.station_id, caller_id, sizeof(console.station_id)); + console.station_id[sizeof(console.station_id) - 1] = '\0'; + } request_answer_ack(console.callref); break; } @@ -311,11 +318,11 @@ void console_msg(osmo_cc_call_t *call, osmo_cc_msg_t *msg) rc = osmo_cc_get_ie_progress(msg, 0, &coding, &location, &progress); osmo_cc_helper_audio_negotiate(msg, &console.session, &console.codec); if (rc >= 0 && (progress == 1 || progress == 8)) { - PDEBUG(DCC, DEBUG_INFO, "Call disconnected with audio (%s)\n", cause_name(isdn_cause)); + LOGP(DCALL, LOGL_INFO, "Call disconnected with audio (%s)\n", cause_name(isdn_cause)); console_new_state(CONSOLE_DISCONNECT_RO); console.disc_cause = isdn_cause; } else { - PDEBUG(DCC, DEBUG_INFO, "Call disconnected without audio (%s)\n", cause_name(isdn_cause)); + LOGP(DCALL, LOGL_INFO, "Call disconnected without audio (%s)\n", cause_name(isdn_cause)); request_disconnect_release_reject(console.callref, isdn_cause, OSMO_CC_MSG_REL_REQ); console_new_state(CONSOLE_IDLE); free_console(); @@ -326,7 +333,7 @@ void console_msg(osmo_cc_call_t *call, osmo_cc_msg_t *msg) 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(DCC, DEBUG_INFO, "Call released (%s)\n", cause_name(isdn_cause)); + LOGP(DCALL, LOGL_INFO, "Call released (%s)\n", cause_name(isdn_cause)); console_new_state(CONSOLE_IDLE); free_console(); break; @@ -335,61 +342,47 @@ void console_msg(osmo_cc_call_t *call, osmo_cc_msg_t *msg) } static char console_text[256]; -static char console_clear[256]; static int console_len = 0; -static 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; -} - -static void _print_console_text(void) -{ - if (!console_len) - return; - - printf("\033[1;37m"); - fwrite(console_text, console_len, 1, stdout); - printf("\033[0;39m"); -} - -int console_init(const char *station_id, const char *audiodev, int samplerate, int latency, int num_digits, int loopback, int echo_test, const char *digits) +int console_init(const char *audiodev, int samplerate, int buffer, int loopback, int echo_test, const char *digits, const struct number_lengths *lengths, const char *station_id) { int rc = 0; + int i; init_testton(); - clear_console_text = _clear_console_text; - print_console_text = _print_console_text; + /* Put scrolling window one line above bottom. */ + logging_limit_scroll_bottom(1); memset(&console, 0, sizeof(console)); - if (station_id) - 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.num_digits = num_digits; + console.buffer_size = buffer * samplerate / 1000; console.loopback = loopback; console.echo_test = echo_test; console.digits = digits; + console.number_lengths = lengths; + if (lengths) { + for (i = 0; lengths[i].usage; i++) { + if (lengths[i].digits > console.number_max_length) + console.number_max_length = lengths[i].digits; + } + } + if (station_id) + strncpy(console.station_id, station_id, sizeof(console.station_id) - 1); 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"); + LOGP(DSENDER, LOGL_ERROR, "Failed to init sample rate conversion!\n"); goto error; } - rc = jitter_create(&console.dejitter, samplerate / 5); + rc = jitter_create(&console.dejitter, "console", 8000, 0.040, 0.200, JITTER_FLAG_NONE); if (rc < 0) { - PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create and init dejitter buffer!\n"); + LOGP(DSENDER, LOGL_ERROR, "Failed to create and init dejitter buffer!\n"); goto error; } @@ -400,7 +393,7 @@ error: return rc; } -int console_open_audio(int __attribute__((unused)) latspl) +int console_open_audio(int __attribute__((unused)) buffer_size, double __attribute__((unused)) interval) { if (!console.audiodev[0]) return 0; @@ -408,13 +401,13 @@ int console_open_audio(int __attribute__((unused)) latspl) #ifdef HAVE_ALSA /* 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, NULL, 1, 0.0, console.samplerate, latspl, 1.4, 4000.0, 2.0); + console.sound = sound_open(SOUND_DIR_DUPLEX, console.audiodev, NULL, NULL, NULL, 1, 0.0, console.samplerate, buffer_size, interval, 1.4, 4000.0, 2.0); if (!console.sound) { - PDEBUG(DSENDER, DEBUG_ERROR, "No sound device!\n"); + LOGP(DSENDER, LOGL_ERROR, "No sound device!\n"); return -EIO; } #else - PDEBUG(DSENDER, DEBUG_ERROR, "No sound card support compiled in!\n"); + LOGP(DSENDER, LOGL_ERROR, "No sound card support compiled in!\n"); return -ENOTSUP; #endif @@ -451,16 +444,20 @@ void console_cleanup(void) } } +/* process input from console + * it is not called at loopback mode + * calling this implies that the console.number_lengths is set + */ static void process_ui(int c) { char text[256] = ""; - int len; + int len, w, h; int i; switch (console.state) { case CONSOLE_IDLE: if (c > 0) { - if ((int)strlen(console.station_id) < console.num_digits) { + if ((int)strlen(console.station_id) < console.number_max_length) { for (i = 0; i < (int)strlen(console.digits); i++) { if (c == console.digits[i]) { console.station_id[strlen(console.station_id) + 1] = '\0'; @@ -471,18 +468,32 @@ static void process_ui(int 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.num_digits) { - PDEBUG(DCC, DEBUG_INFO, "Outgoing call to '%s'\n", console.station_id); + len = strlen(console.station_id); + for (i = 0; console.number_lengths[i].usage; i++) { + if (len == console.number_lengths[i].digits) + break; + } + if (c == 'd' && console.number_lengths[i].usage) { + LOGP(DCALL, LOGL_INFO, "Outgoing call to '%s'\n", console.station_id); console.dialing[0] = '\0'; console_new_state(CONSOLE_SETUP_RT); console.callref = osmo_cc_new_callref(); request_setup(console.callref, console.station_id); } } - if (console.num_digits != (int)strlen(console.station_id)) - sprintf(text, "on-hook: %s%s (enter digits 0..9)\r", console.station_id, "..............." + 15 - console.num_digits + strlen(console.station_id)); - else - sprintf(text, "on-hook: %s (press d=dial)\r", console.station_id); + sprintf(text, "on-hook: %s%s ", console.station_id, "................................" + 32 - console.number_max_length + strlen(console.station_id)); + len = strlen(console.station_id); + for (i = 0; console.number_lengths[i].usage; i++) { + if (len == console.number_lengths[i].digits) + break; + } + if (console.number_lengths[i].usage) { + if (console.number_lengths[i + 1].usage) + sprintf(strchr(text, '\0'), "(enter digits %s or press d=dial)", console.digits); + else + sprintf(strchr(text, '\0'), "(press d=dial)"); + } else + sprintf(strchr(text, '\0'), "(enter digits %s)", console.digits); break; case CONSOLE_SETUP_RO: case CONSOLE_SETUP_RT: @@ -492,7 +503,7 @@ dial_after_hangup: case CONSOLE_DISCONNECT_RO: if (c > 0) { if (c == 'h' || (c == 'd' && console.state == CONSOLE_DISCONNECT_RO)) { - PDEBUG(DCC, DEBUG_INFO, "Call hangup\n"); + LOGP(DCALL, LOGL_INFO, "Call hangup\n"); if (console.callref) { if (console.state == CONSOLE_SETUP_RO) request_disconnect_release_reject(console.callref, CAUSE_NORMAL, OSMO_CC_MSG_REJ_REQ); @@ -506,84 +517,103 @@ dial_after_hangup: } } if (console.state == CONSOLE_SETUP_RT) - sprintf(text, "call setup: %s (press h=hangup)\r", console.station_id); + sprintf(text, "call setup: %s (press h=hangup)", console.station_id); if (console.state == CONSOLE_ALERTING_RT) - sprintf(text, "call ringing: %s (press h=hangup)\r", console.station_id); + sprintf(text, "call ringing: %s (press h=hangup)", 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); + sprintf(text, "call active: %s->%s (press h=hangup)", console.station_id, console.dialing); else - sprintf(text, "call active: %s (press h=hangup)\r", console.station_id); + sprintf(text, "call active: %s (press h=hangup)", console.station_id); } if (console.state == CONSOLE_DISCONNECT_RO) - sprintf(text, "call disconnected: %s (press h=hangup d=redial)\r", cause_name(console.disc_cause)); + sprintf(text, "call disconnected: %s (press h=hangup d=redial)", 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(); + /* lock logging */ + lock_logging(); + /* disable window */ + enable_limit_scroll(false); + /* geht height */ + get_win_size(&w, &h); + /* save cursor go to bottom, use white color */ + printf("\0337\033[%d;1H\033[1;37m", h); + /* copy text and pad with spaces */ console_len = len; - memcpy(console_text, text, len); - memset(console_clear, ' ', len - 1); - console_clear[len - 1] = '\r'; - print_console_text(); + memcpy(console_text, text, console_len); + if (console_len < (int)MIN(sizeof(console_text), w)) + memset(console_text + console_len, ' ', MIN(sizeof(console_text), w) - console_len); + /* write text */ + fwrite(console_text, MIN(sizeof(console_text), w), 1, stdout); + /* reset color, go back to previous line, flush */ + printf("\033[0;39m\0338"); + /* flush output */ fflush(stdout); + /* enable window */ + enable_limit_scroll(true); + /* unlock logging */ + unlock_logging(); } /* get keys from keyboard to control call via console * returns 1 on exit (ctrl+c) */ void process_console(int c) { - if (!console.loopback && console.num_digits) + if (!console.loopback && console.number_max_length) process_ui(c); - if (console.session) - osmo_cc_session_handle(console.session); - if (!console.sound) return; #ifdef HAVE_ALSA /* handle audio, if sound device is used */ - sample_t samples[console.latspl + 10], *samples_list[1]; + sample_t samples[console.buffer_size + 10], *samples_list[1]; uint8_t *power_list[1]; - int count; + int count, input_num; int rc; - count = sound_get_tosend(console.sound, console.latspl); + count = sound_get_tosend(console.sound, console.buffer_size); if (count < 0) { - PDEBUG(DSENDER, DEBUG_ERROR, "Failed to get samples in buffer (rc = %d)!\n", count); + LOGP(DSENDER, LOGL_ERROR, "Failed to get samples in buffer (rc = %d)!\n", count); if (count == -EPIPE) - PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n"); + LOGP(DSENDER, LOGL_ERROR, "Trying to recover.\n"); return; } if (count > 0) { - jitter_load(&console.dejitter, samples, count); + /* load and upsample */ + input_num = samplerate_upsample_input_num(&console.srstate, count); + { + int16_t spl[input_num]; + jitter_load_samples(&console.dejitter, (uint8_t *)spl, input_num, sizeof(*spl), jitter_conceal_s16, NULL); + int16_to_samples_speech(samples, spl, input_num); + } + samplerate_upsample(&console.srstate, samples, input_num, samples, count); + /* write to sound device */ 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); + LOGP(DSENDER, LOGL_ERROR, "Failed to write TX data to sound device (rc = %d)\n", rc); if (rc == -EPIPE) - PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n"); + LOGP(DSENDER, LOGL_ERROR, "Trying to recover.\n"); return; } } samples_list[0] = samples; - count = sound_read(console.sound, samples_list, console.latspl, 1, NULL); + count = sound_read(console.sound, samples_list, console.buffer_size, 1, NULL); if (count < 0) { - PDEBUG(DSENDER, DEBUG_ERROR, "Failed to read from sound device (rc = %d)!\n", count); + LOGP(DSENDER, LOGL_ERROR, "Failed to read from sound device (rc = %d)!\n", count); if (count == -EPIPE) - PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n"); + LOGP(DSENDER, LOGL_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++) { @@ -593,9 +623,12 @@ void process_console(int c) console.tx_buffer_pos = 0; /* only if we have a call */ if (console.callref && console.codec) { - int16_t data[160]; - samples_to_int16(data, console.tx_buffer, 160); - osmo_cc_rtp_send(console.codec, (uint8_t *)data, 160 * 2, 1, 160); + int16_t spl[160]; + uint8_t *payload; + int payload_len; + samples_to_int16_speech(spl, console.tx_buffer, 160); + console.codec->encoder((uint8_t *)spl, 160 * 2, &payload, &payload_len, &console); + osmo_cc_rtp_send(console.codec, payload, payload_len, 0, 1, 160); } } } @@ -603,3 +636,17 @@ void process_console(int c) #endif } +/* Call this for every inscription. If the console's dial string is empty, it is set to the number that has been inscribed. */ +int console_inscription(const char *station_id) +{ + if (console.loopback || !console.number_max_length) + return -EINVAL; + + if (console.station_id[0]) + return 1; + + strncpy(console.station_id, station_id, sizeof(console.station_id) - 1); + process_ui(-1); + return 0; +} + |