aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2012-11-29 21:41:01 +0100
committerHolger Hans Peter Freyther <zecke@selfish.org>2012-12-16 11:33:27 +0100
commitd74ac335748ad2fe4971fd7dcca653284b9bbc17 (patch)
tree68c9ae77ca34bc413bed5e8f6e0bba6e6a6241e3 /src
parent9b2474490a738665247ea3a04648f96411a78d6d (diff)
dtmf: Schedule DTMF tones for the MTN hardware
Create a simple queue for pending DTMF tones, play them using the MTN API, and then send the next tones once the playback is complete. The callback and scheduling is done from the same context so no locking needs to be done.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/dtmf_scheduler.c59
-rw-r--r--src/mgcp_ss7.c72
3 files changed, 133 insertions, 1 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 4ef3edf..e681537 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,7 +6,8 @@ AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOSCCP_CFLAGS) $(LIBOSMOVTY_CFLAGS)
sbin_PROGRAMS = cellmgr_ng osmo_stp mgcp_mgw
mgcp_mgw_SOURCES = mgcp_ss7.c mgcp_ss7_vty.c mgcp_hw.c thread.c debug.c \
- mgcp/mgcp_protocol.c mgcp/mgcp_network.c mgcp/mgcp_vty.c
+ mgcp/mgcp_protocol.c mgcp/mgcp_network.c mgcp/mgcp_vty.c \
+ dtmf_scheduler.c
mgcp_mgw_LDADD = $(LAFORGE_LIBS) $(NEXUSWARE_C7_LIBS) $(NEXUSWARE_UNIPORTE_LIBS) \
$(LIBOSMOVTY_LIBS) $(LIBOSMOCORE_LIBS) -lpthread -lcrypto
diff --git a/src/dtmf_scheduler.c b/src/dtmf_scheduler.c
new file mode 100644
index 0000000..26dc090
--- /dev/null
+++ b/src/dtmf_scheduler.c
@@ -0,0 +1,59 @@
+/*
+ * (C) 2012 by Holger Hans Peter Freyther
+ * (C) 2012 by On-Waves
+ * All Rights Reserved
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "dtmf_scheduler.h"
+#include <string.h>
+#include <stdio.h>
+
+void dtmf_state_init(struct dtmf_state *state)
+{
+ memset(state, 0, sizeof(*state));
+}
+
+int dtmf_state_add(struct dtmf_state *state, char tone)
+{
+ /* we would override the head */
+ if (state->size == sizeof(state->tones))
+ return -1;
+
+ state->tones[state->size++] = tone;
+ return 0;
+}
+
+void dtmf_state_get_pending(struct dtmf_state *state, char *tones)
+{
+ int pos;
+
+ for (pos = 0; pos < state->size; ++pos)
+ tones[pos] = state->tones[pos];
+
+ /* consume everything up to the tail */
+ state->size = 0;
+
+ /* remember that we play things */
+ if (pos > 0)
+ state->playing = 1;
+ tones[pos] = '\0';
+}
+
+void dtmf_state_played(struct dtmf_state *state)
+{
+ state->playing = 0;
+}
diff --git a/src/mgcp_ss7.c b/src/mgcp_ss7.c
index 47c162b..c9e9b4f 100644
--- a/src/mgcp_ss7.c
+++ b/src/mgcp_ss7.c
@@ -70,6 +70,44 @@ static void mgcp_ss7_do_exec(struct mgcp_ss7 *mgcp, uint8_t type, struct mgcp_en
/* Contains a mapping from UniPorte to the MGCP side of things */
static struct mgcp_endpoint *s_endpoints[240];
+static void play_pending_tones(struct mgcp_endpoint *endp)
+{
+ ToneGenerationT toneGeneration;
+ char tones[25];
+
+ /* Check if we need to play anything? */
+ dtmf_state_get_pending(&endp->dtmf_state, tones);
+
+ /* nothing to play? */
+ if (strlen(tones) == 0)
+ return;
+
+ /* fill out the data now */
+ osmo_static_assert(sizeof(tones) <= sizeof(toneGeneration.list), Enough_space_for_tones);
+ memset(&toneGeneration, 0, sizeof(toneGeneration));
+ toneGeneration.count = strlen(tones);
+ strcpy(toneGeneration.list, tones);
+ MtnSaSetMOB(endp->audio_port, ChannelType_PORT,
+ PredefMob_C_TONE_GENERATION, (char *) &toneGeneration,
+ sizeof(toneGeneration), 1);
+}
+
+static void send_dtmf(struct mgcp_endpoint *mgw_endp, int ascii_tone)
+{
+ int rc;
+ rc = dtmf_state_add(&mgw_endp->dtmf_state, ascii_tone);
+ if (rc != 0) {
+ fprintf(stderr, "DTMF queue too long on 0x%x\n",
+ ENDPOINT_NUMBER(mgw_endp));
+ syslog(LOG_ERR, "DTMF queue too long on 0x%x\n",
+ ENDPOINT_NUMBER(mgw_endp));
+ return;
+ }
+
+ if (!mgw_endp->dtmf_state.playing)
+ play_pending_tones(mgw_endp);
+}
+
static int select_voice_port(struct mgcp_endpoint *endp)
{
int mgw_port;
@@ -200,6 +238,24 @@ static int uniporte_events(unsigned long port, EventTypeT event,
fprintf(stderr, "State change on a non blocked port. ERROR.\n");
}
endp->block_processing = 0;
+ } else if (info->trapId == Trap_TONE_GENERATION_COMPLETE) {
+ sprintf(text, "DTMF complete on #%ld", port);
+ puts(text);
+
+ /* update the mgcp state */
+ if (port >= ARRAY_SIZE(s_endpoints)) {
+ syslog(LOG_ERR, "The port is bigger than we can manage.\n");
+ fprintf(stderr, "The port is bigger than we can manage.\n");
+ return 0;
+ }
+
+ endp = s_endpoints[port];
+ if (!endp) {
+ syslog(LOG_ERR, "Unexpected event on port %d\n", port);
+ fprintf(stderr, "Unexpected event on port %d\n", port);
+ return 0;
+ }
+ play_pending_tones(endp);
}
}
else if ( event == Event_MANAGED_OBJECT_SET_COMPLETE ) {
@@ -356,6 +412,9 @@ static void allocate_endp(struct mgcp_ss7 *ss7, struct mgcp_endpoint *endp)
int mgw_port;
unsigned long mgw_address, loc_address;
+ /* reset the DTMF state */
+ dtmf_state_init(&endp->dtmf_state);
+
/* now find the voice processor we want to use */
mgw_port = select_voice_port(endp);
if (mgw_port < 0)
@@ -471,6 +530,10 @@ static void mgcp_ss7_do_exec(struct mgcp_ss7 *mgcp, uint8_t type,
if (mgw_endp->audio_port != UINT_MAX)
update_mute_status(mgw_endp->audio_port, param);
break;
+ case MGCP_SS7_DTMF:
+ if (mgw_endp->audio_port != UINT_MAX)
+ send_dtmf(mgw_endp, param);
+ break;
case MGCP_SS7_DELETE:
if (mgw_endp->audio_port != UINT_MAX) {
rc = MtnSaDisconnect(mgw_endp->audio_port);
@@ -487,6 +550,7 @@ static void mgcp_ss7_do_exec(struct mgcp_ss7 *mgcp, uint8_t type,
mgw_endp->audio_port = UINT_MAX;
mgw_endp->block_processing = 1;
}
+ dtmf_state_init(&mgw_endp->dtmf_state);
hw_maybe_loop_endp(mgw_endp);
break;
case MGCP_SS7_ALLOCATE:
@@ -579,6 +643,12 @@ static int mgcp_ss7_policy(struct mgcp_trunk_config *tcfg, int endp_no, int stat
return rc;
}
+static int mgcp_dtmf_cb(struct mgcp_endpoint *endp, char tone, const char *data)
+{
+ mgcp_ss7_exec(endp, MGCP_SS7_DTMF, tone);
+ return 0;
+}
+
static void enqueue_msg(struct osmo_wqueue *queue, struct sockaddr_in *addr, struct msgb *msg)
{
struct sockaddr_in *data;
@@ -905,6 +975,8 @@ int main(int argc, char **argv)
return -1;
}
+ g_cfg->rqnt_cb = mgcp_dtmf_cb;
+
if (mgcp_parse_config(config_file, g_cfg) != 0) {
LOGP(DMGCP, LOGL_ERROR,
"Failed to parse the config file: '%s'\n", config_file);