diff options
Diffstat (limited to 'src/telephone/main.c')
-rw-r--r-- | src/telephone/main.c | 326 |
1 files changed, 326 insertions, 0 deletions
diff --git a/src/telephone/main.c b/src/telephone/main.c new file mode 100644 index 0000000..8bf604a --- /dev/null +++ b/src/telephone/main.c @@ -0,0 +1,326 @@ +/* osmo-cc-alsa-endpoint main + * + * (C) 2020 by Andreas Eversberg <jolly@eversberg.eu> + * All Rights Reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> +#include <string.h> +#include <stdint.h> +#include <stdlib.h> +#include <termios.h> +#include <sched.h> +#include "../libdebug/debug.h" +#include "../liboptions/options.h" +#include "../libg711/g711.h" +#include "telephone.h" + +telephone_t *telephone_ep = NULL; +int num_kanal = 1; + +static const char *name = "alsa"; +static const char *audiodev = NULL; +static int samplerate = 48000; +static int latency = 50; +static int rt_prio = 1; +static const char *caller_id = ""; +static int early_audio = 0; +static int autoalert = 0, autoanswer = 1; +#define MAX_CC_ARGS 1024 +static int cc_argc = 0; +static const char *cc_argv[MAX_CC_ARGS]; + +static void print_usage(const char *app) +{ + printf("Usage: %s -a hw:<card>,<device> [<options>] [dialing]\n", app); +} + +static void print_help() +{ + /* - - */ + printf(" -h --help\n"); + printf(" This help\n"); + printf(" --config [~/]<path to config file>\n"); + printf(" Give a config file to use. If it starts with '~/', path is at home dir.\n"); + printf(" Each line in config file is one option, '-' or '--' must not be given!\n"); + printf(" -v --verbose <level> | <level>,<category>[,<category>[,...]] | list\n"); + printf(" Use 'list' to get a list of all levels and categories\n"); + printf(" Verbose level: digit of debug level (default = '%d')\n", debuglevel); + printf(" Verbose level+category: level digit followed by one or more categories\n"); + printf(" -> If no category is specified, all categories are selected\n"); + printf(" -n --name <interface name>\n"); + printf(" Give name of this interface. It will be sent in each call towards\n"); + printf(" -I --caller-id <caller id>\n"); + printf(" What caller ID to send on calls made from terminal. (default = '%s')\n", caller_id); + printf(" -A --auto alerting | answer | off\n"); + printf(" An incoming call can be responded automatically with an alerting or an\n"); + printf(" answer, or not be responded automatically. (default = 'answer')\n"); + printf(" -E --early-audio\n"); + printf(" Send early audio when call is not yet connected. Must be used in\n"); + printf(" conjunction with --auto\n"); + printf(" -a --audio-device hw:<card>,<device>\n"); + printf(" Sound card and device number (default = '%s')\n", audiodev); + printf(" -s --samplerate <rate>\n"); + printf(" Sample rate of sound device (default = '%d')\n", samplerate); + printf(" -b --buffer <ms>\n"); + printf(" How many milliseconds are processed in advance (default = '%d')\n", latency); + printf(" -r --realtime <prio>\n"); + printf(" Set prio: 0 to disable, 99 for maximum (default = %d)\n", rt_prio); + printf(" -C --cc \"<osmo-cc arg>\" [--cc ...]\n"); + printf(" Pass arguments to Osmo-CC endpoint. Use '-cc help' for description.\n"); +} + +static void add_options(void) +{ + option_add('h', "help", 0); + option_add('v', "verbose", 1); + option_add('n', "name", 1); + option_add('I', "caller-id", 1); + option_add('A', "auto", 1); + option_add('E', "early-audio", 0); + option_add('a', "audio-device", 1); + option_add('s', "samplerate", 1); + option_add('b', "buffer", 1); + option_add('r', "realtime", 1); + option_add('C', "cc", 1); +} + +static int handle_options(int short_option, int argi, char **argv) +{ + int rc; + + switch (short_option) { + case 'h': + print_usage(argv[0]); + print_help(); + return 0; + case 'v': + if (!strcasecmp(argv[argi], "list")) { + debug_list_cat(); + return 0; + } + rc = parse_debug_opt(argv[argi]); + if (rc < 0) { + fprintf(stderr, "Failed to parse debug option, please use -h for help.\n"); + return rc; + } + break; + case 'n': + name = options_strdup(argv[argi]); + break; + case 'I': + caller_id = options_strdup(argv[argi]); + break; + case 'A': + if (!strcasecmp(argv[argi], "alerting")) { + autoalert = 1; + autoanswer = 0; + } else + if (!strcasecmp(argv[argi], "answer")) { + autoalert = 0; + autoanswer = 1; + } else + if (!strcasecmp(argv[argi], "off")) { + autoalert = 0; + autoanswer = 0; + } else { + fprintf(stderr, "Unknown parameter '%s', please use -h for help.\n", argv[argi]); + return -EINVAL; + } + break; + case 'E': + early_audio = 1; + break; + case 'a': + audiodev = options_strdup(argv[argi]); + break; + case 's': + samplerate = atoi(argv[argi]); + break; + case 'b': + latency = atoi(argv[argi]); + break; + case 'r': + rt_prio = atoi(argv[argi]); + break; + case 'C': + if (!strcasecmp(argv[argi], "help")) { + osmo_cc_help(); + return 0; + } + if (cc_argc == MAX_CC_ARGS) { + fprintf(stderr, "Too many osmo-cc args!\n"); + break; + } + cc_argv[cc_argc++] = options_strdup(argv[argi]); + break; + default: + return -EINVAL; + } + return 1; +} + +static int quit = 0; +void sighandler(int sigset) +{ + if (sigset == SIGHUP || sigset == SIGPIPE) + return; + + fprintf(stderr, "\nSignal %d received.\n", sigset); + + quit = 1; +} + +static int get_char() +{ + struct timeval tv = {0, 0}; + fd_set fds; + char c = 0; + int __attribute__((__unused__)) rc; + + FD_ZERO(&fds); + FD_SET(0, &fds); + select(0+1, &fds, NULL, NULL, &tv); + if (FD_ISSET(0, &fds)) { + rc = read(0, &c, 1); + return c; + } else + return -1; +} + +int main(int argc, char *argv[]) +{ + int argi, rc; + const char *dialing = ""; + struct termios term, term_orig; + char c; + + g711_init(); + + telephone_ep = telephone_create(); + if (!telephone_ep) + goto error; + + cc_argv[cc_argc++] = options_strdup("remote auto"); + + /* handle options / config file */ + add_options(); + rc = options_config_file(argc, argv, "~/.osmocom/alsa/alsa.conf", handle_options); + if (rc < 0) + return 0; + argi = options_command_line(argc, argv, handle_options); + if (argi <= 0) + return argi; + + if (argi < argc) + dialing = argv[argi]; + + rc = ui_init(dialing, autoalert, autoanswer); + if (rc) { + PDEBUG(DTEL, DEBUG_ERROR, "UI initializing failed!\n"); + goto error; + } + + rc = telephone_init(telephone_ep, name, caller_id, OSMO_CC_LOCATION_USER, early_audio, audiodev, samplerate, samplerate * latency / 1000); + if (rc) { + PDEBUG(DTEL, DEBUG_ERROR, "Endpoint initializing failed!\n"); + goto error; + } + + rc = osmo_cc_new(&telephone_ep->cc_ep, OSMO_CC_VERSION, name, OSMO_CC_LOCATION_USER, cc_message, NULL, telephone_ep, cc_argc, cc_argv); + if (rc < 0) + goto error; + + /* real time priority */ + if (rt_prio > 0) { + struct sched_param schedp; + int rc; + + memset(&schedp, 0, sizeof(schedp)); + schedp.sched_priority = rt_prio; + rc = sched_setscheduler(0, SCHED_RR, &schedp); + if (rc) + fprintf(stderr, "Error setting SCHED_RR with prio %d\n", rt_prio); + } + + /* prepare terminal */ + tcgetattr(0, &term_orig); + term = term_orig; + term.c_lflag &= ~(ISIG|ICANON|ECHO); + term.c_cc[VMIN]=1; + term.c_cc[VTIME]=2; + tcsetattr(0, TCSANOW, &term); + + signal(SIGINT, sighandler); + signal(SIGHUP, sighandler); + signal(SIGTERM, sighandler); + signal(SIGPIPE, sighandler); + + while (!quit) { + int w; + c = get_char(); + if (c == 3) { + /* quit */ + if (clear_console_text) + clear_console_text(); + printf("CTRL+c received, quitting!\n"); + quit = 1; + continue; + } + process_timer(); + alsa_work(telephone_ep); + rtp_work(telephone_ep); + do { + w = 0; + w |= osmo_cc_handle(); + w |= ui_work(telephone_ep, c); + c = 0; + } while (w); + usleep(1000); + } + + signal(SIGINT, SIG_DFL); + signal(SIGTSTP, SIG_DFL); + signal(SIGHUP, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGPIPE, SIG_DFL); + + /* reset terminal */ + tcsetattr(0, TCSANOW, &term_orig); + + /* reset real time prio */ + if (rt_prio > 0) { + struct sched_param schedp; + + memset(&schedp, 0, sizeof(schedp)); + schedp.sched_priority = 0; + sched_setscheduler(0, SCHED_OTHER, &schedp); + } + +error: + if (telephone_ep) { + osmo_cc_delete(&telephone_ep->cc_ep); + telephone_destroy(telephone_ep); + } + + options_free(); + + return 0; +} + |