summaryrefslogtreecommitdiffstats
path: root/src/ss5/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ss5/main.c')
-rw-r--r--src/ss5/main.c346
1 files changed, 346 insertions, 0 deletions
diff --git a/src/ss5/main.c b/src/ss5/main.c
new file mode 100644
index 0000000..e4ce31a
--- /dev/null
+++ b/src/ss5/main.c
@@ -0,0 +1,346 @@
+/* osmo-cc-ss5-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 "../libdebug/debug.h"
+#include "../liboptions/options.h"
+#include "../libg711/g711.h"
+#include "ss5.h"
+#include "display.h"
+
+ss5_endpoint_t *ss5_ep_sunset = NULL, *ss5_ep_sunrise = NULL;
+int num_kanal = 2;
+
+int endpoints = 1;
+int links = 0;
+int prevent_blueboxing = 0;
+int suppress_disconnect = 1;
+int crosstalk = 1;
+int delay_ms = 300;
+int comfort_noise = 1;
+double sense_db = 5;
+#define MAX_CC_ARGS 1024
+static int cc_argc_sunset, cc_argc_sunrise = 0;
+static const char *cc_argv_sunset[MAX_CC_ARGS], *cc_argv_sunrise[MAX_CC_ARGS];
+
+static void print_usage(const char *app)
+{
+ printf("Usage: %s [--port <misdn port>] [--nt] [<options>]\n", app);
+ printf("This will create pairs of SS5 channels that are bridged together, so that\n");
+ printf("calls from one link to the other can be made using SS5. The a bluebox can be\n");
+ printf("used to play with it.\n");
+ printf("If one endpoint is used (default), its name is 'sunset' and each pair of\n");
+ printf("channels are bridged together. If two endpoints are used, their names are\n");
+ printf("'sunset' and 'sunrise' and same channel index of both endpoints are bridged\n");
+ printf("together.\n");
+}
+
+static void print_help()
+{
+ /* - - */
+ printf(" -h --help\n");
+ printf(" This help\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(" -2 --two\n");
+ printf(" Create two Osmo-CC endpoints instead of one.\n");
+ printf(" -c --channels\n");
+ printf(" Give number of channels per endpoint. If you use a single endpoint,\n");
+ printf(" you must define an even number. By default this is '2' for one\n");
+ printf(" endpoint and '1' for two endpoints.\n");
+ printf(" -s --suppress-disconnect 1 | 0\n");
+ printf(" When a 'busy-flash' or 'release-guard' is received a disconnect is\n");
+ printf(" forwarded towards OsmoCC. Set to 1 to suppress this. (Default is %d.)\n", suppress_disconnect);
+ printf(" -p --prevent-blueboxing 1 | 0\n");
+ printf(" Prevent blueboxing by making 'release-guard' 200 ms minimum length.\n");
+ printf(" -x --crosstalk 1 | 0\n");
+ printf(" Enable or disable some minor crosstalk. This allows you to hear\n");
+ printf(" transmitted tones at a low volume. (Default is %d.).\n", crosstalk);
+ printf(" -d --delay <ms> | 0\n");
+ printf(" Add one-way delay to the connection between two SS5 links. This allows\n");
+ printf(" to hear 'acknowlege' tones delayed. (Default is %d ms.).\n", delay_ms);
+ printf(" -n --comfort-noise 1 | 0\n");
+ printf(" Add comfort noise whenever there is no audio from the remote link\n");
+ printf(" (before or after call). (Default is %d ms.).\n", comfort_noise);
+ printf(" --sense 0 | <db>\n");
+ printf(" Change sensitivity (level) of tone detector. A bluebox must not be\n");
+ printf(" that loud. (Default is %.0f dB.).\n", sense_db);
+ printf(" -C --cc \"<osmo-cc arg>\" [--cc ...]\n");
+ printf(" --cc2 \"<osmo-cc arg>\" [--cc2 ...]\n");
+ printf(" Pass arguments to Osmo-CC endpoint. Use '-cc help' for description.\n");
+ printf(" If you select two endpoints, use '--cc2' to pass arguments to the\n");
+ printf(" second endpoint.\n");
+}
+
+#define OPT_SENSE 256
+#define OPT_CC2 257
+
+static void add_options(void)
+{
+ option_add('h', "help", 0);
+ option_add('v', "verbose", 1);
+ option_add('2', "two", 0);
+ option_add('c', "channels", 1);
+ option_add('s', "suppress-disconnect", 1);
+ option_add('p', "prevent-blueboxing", 1);
+ option_add('x', "crosstalk", 1);
+ option_add('d', "delay", 1);
+ option_add('n', "comfort-noise", 1);
+ option_add(OPT_SENSE, "sense", 1);
+ option_add('C', "cc", 1);
+ option_add(OPT_CC2, "cc2", 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 '2':
+ endpoints = 2;
+ break;
+ case 'c':
+ links = atoi(argv[argi]);
+ break;
+ case 's':
+ suppress_disconnect = atoi(argv[argi]);
+ break;
+ case 'p':
+ prevent_blueboxing = atoi(argv[argi]);
+ break;
+ case 'x':
+ crosstalk = atoi(argv[argi]);
+ break;
+ case 'd':
+ delay_ms = atoi(argv[argi]);
+ break;
+ case 'n':
+ comfort_noise = atoi(argv[argi]);
+ break;
+ case OPT_SENSE:
+ sense_db = (double)atoi(argv[argi]);
+ break;
+ case 'C':
+ if (!strcasecmp(argv[argi], "help")) {
+ osmo_cc_help();
+ return 0;
+ }
+ if (cc_argc_sunset == MAX_CC_ARGS) {
+ fprintf(stderr, "Too many osmo-cc args!\n");
+ break;
+ }
+ cc_argv_sunset[cc_argc_sunset++] = strdup(argv[argi]);
+ break;
+ case OPT_CC2:
+ if (!strcasecmp(argv[argi], "help")) {
+ osmo_cc_help();
+ return 0;
+ }
+ if (cc_argc_sunrise == MAX_CC_ARGS) {
+ fprintf(stderr, "Too many osmo-cc args!\n");
+ break;
+ }
+ cc_argv_sunrise[cc_argc_sunrise++] = 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;
+ struct termios term, term_orig;
+ double now, last_time_call = 0.0;
+ int c;
+
+ /* init MF */
+ mf_init(0);
+
+ /* init codecs (for recording) */
+ g711_init();
+
+ cc_argv_sunset[cc_argc_sunset++] = strdup("remote auto");
+ cc_argv_sunrise[cc_argc_sunrise++] = strdup("remote auto");
+
+ /* handle options / config file */
+ add_options();
+ rc = options_config_file("~/.osmocom/ss5/ss5.conf", handle_options);
+ if (rc < 0)
+ return 0;
+ argi = options_command_line(argc, argv, handle_options);
+ if (argi <= 0)
+ return argi;
+
+ /* check links (per endpoint) */
+ if (!links)
+ links = (endpoints == 2) ? 1 : 2;
+ if (links == 1 && (endpoints % 1)) {
+ PDEBUG(DSS5, DEBUG_ERROR, "You must define an even number of channels on a single endpoint!\n");
+ goto error;
+ }
+
+ /* create sunset and (optionally) sunrise */
+ ss5_ep_sunset = ss5_ep_create("sunset", links, prevent_blueboxing, crosstalk, delay_ms, comfort_noise, suppress_disconnect, sense_db);
+ if (!ss5_ep_sunset)
+ goto error;
+ rc = osmo_cc_new(&ss5_ep_sunset->cc_ep, OSMO_CC_VERSION, "sunset", OSMO_CC_LOCATION_BEYOND_INTERWORKING, cc_message, NULL, ss5_ep_sunset, cc_argc_sunset, cc_argv_sunset);
+ if (rc < 0)
+ goto error;
+ if (endpoints == 2) {
+ ss5_ep_sunrise = ss5_ep_create("sunrise", links, prevent_blueboxing, crosstalk, delay_ms, comfort_noise, suppress_disconnect, sense_db);
+ if (!ss5_ep_sunrise)
+ goto error;
+ rc = osmo_cc_new(&ss5_ep_sunrise->cc_ep, OSMO_CC_VERSION, "sunrise", OSMO_CC_LOCATION_BEYOND_INTERWORKING, cc_message, NULL, ss5_ep_sunrise, cc_argc_sunrise, cc_argv_sunrise);
+ if (rc < 0)
+ goto error;
+ PDEBUG(DSS5, DEBUG_NOTICE, "Created endpoints 'sunset' and 'sunrise' with %d links that connect these endpoints.\n", links);
+ } else
+ PDEBUG(DSS5, DEBUG_NOTICE, "Created endpoint 'sunset' with %d links, each pair connected.\n", links);
+ refresh_status();
+
+ /* 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);
+
+ /* catch signals */
+ signal(SIGINT, sighandler);
+ signal(SIGHUP, sighandler);
+ signal(SIGTERM, sighandler);
+ signal(SIGPIPE, sighandler);
+
+ while (!quit) {
+ int w;
+
+ /* send clock calls to play/record audio files */
+ now = get_time();
+ if (now - last_time_call >= 0.1)
+ last_time_call = now;
+ if (now - last_time_call >= 0.020) {
+ last_time_call += 0.020;
+ /* call clock every 20ms */
+ audio_clock(ss5_ep_sunset, ss5_ep_sunrise, 160);
+ }
+
+ process_timer();
+ do {
+ w = 0;
+ w |= osmo_cc_handle();
+ } while (w);
+ usleep(1000);
+
+ /* process keyboard input */
+next_char:
+ c = get_char();
+ switch (c) {
+ case 3:
+ printf("CTRL+c received, quitting!\n");
+ quit = 1;
+ goto next_char;
+ case 'c':
+ display_status_on(-1);
+ goto next_char;
+ }
+ }
+
+ /* reset signals */
+ 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);
+
+error:
+ /* destroy endpoints */
+ if (ss5_ep_sunset) {
+ osmo_cc_delete(&ss5_ep_sunset->cc_ep);
+ ss5_ep_destroy(ss5_ep_sunset);
+ }
+ if (ss5_ep_sunrise) {
+ osmo_cc_delete(&ss5_ep_sunrise->cc_ep);
+ ss5_ep_destroy(ss5_ep_sunrise);
+ }
+
+ /* exit MF */
+ mf_exit();
+
+ return 0;
+}
+