From 3a8f58ec8946b7f1683208d1cc3b054486f12e6c Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Mon, 13 Dec 2010 09:22:49 +0100 Subject: Adding interface support for remote app (chan_lcr). chan_lcr can be handled as an interface. This way it is possible to (e.g.): - make a SIP phone become an LCR extension with all LCR features. - make conference calls. (untested) - perform parallel ringing. (ISDN phone and SIP phones can ring in parallel.) - do voice recoding. It is still also possible to link chan_lcr directly without interface (as before). Documentation/howto for that will follow. --- remote.cpp | 221 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 remote.cpp (limited to 'remote.cpp') diff --git a/remote.cpp b/remote.cpp new file mode 100644 index 0000000..e14c8e3 --- /dev/null +++ b/remote.cpp @@ -0,0 +1,221 @@ +/*****************************************************************************\ +** ** +** LCR ** +** ** +**---------------------------------------------------------------------------** +** Copyright: Andreas Eversberg ** +** ** +** mISDN remote ** +** ** +\*****************************************************************************/ + +#include "main.h" + +unsigned int new_remote = 0x00000001; + +/* + * constructor + */ +Premote::Premote(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode, int remote_id) : PmISDN(type, mISDNport, portname, settings, channel, exclusive, mode) +{ + union parameter param; + + p_callerinfo.itype = (mISDNport->ifport->interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN; + p_m_r_ref = new_remote++; + SCPY(p_m_r_remote_app, mISDNport->ifport->remote_app); + p_m_r_handle = 0; + + /* send new ref to remote socket */ + memset(¶m, 0, sizeof(union parameter)); + if (type == PORT_TYPE_REMOTE_OUT) + param.newref.direction = 1; /* new ref from lcr */ + p_m_r_remote_id = remote_id; + if (admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_NEWREF, ¶m) < 0) + FATAL("No socket with remote application '%s' found, this shall not happen. because we already created one.\n", mISDNport->ifport->remote_app); + + PDEBUG(DEBUG_GSM, "Created new RemotePort(%s).\n", portname); + +} + +/* + * destructor + */ +Premote::~Premote() +{ + /* need to remote (import) external channel from remote application */ + if (p_m_r_handle) { + message_bchannel_to_remote(p_m_r_remote_id, p_m_r_ref, BCHANNEL_REMOVE, p_m_r_handle, 0, 0, 0, 0, 0, 0, 1); + chan_trace_header(p_m_mISDNport, this, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE); + add_trace("type", NULL, "remove"); + add_trace("channel", NULL, "%d.%d", p_m_r_handle>>8, p_m_r_handle&0xff); + end_trace(); + } + + PDEBUG(DEBUG_GSM, "Destroyed Remote process(%s).\n", p_name); + +} + +/* + * endpoint sends messages to the port + */ +int Premote::message_epoint(unsigned int epoint_id, int message_type, union parameter *param) +{ + struct lcr_msg *message; + int channel; + int ret; + struct epoint_list *epointlist; + + if (PmISDN::message_epoint(epoint_id, message_type, param)) + return 1; + + if (message_type == MESSAGE_SETUP) { + ret = channel = hunt_bchannel(); + if (ret < 0) + goto no_channel; + /* open channel */ + ret = seize_bchannel(channel, 1); + if (ret < 0) { + no_channel: + message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE); + message->param.disconnectinfo.cause = 34; + message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; + message_put(message); + new_state(PORT_STATE_RELEASE); + delete this; + return 0; + } + bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE); + + /* attach only if not already */ + epointlist = p_epointlist; + while(epointlist) { + if (epointlist->epoint_id == epoint_id) + break; + epointlist = epointlist->next; + } + if (!epointlist) + epointlist_new(epoint_id); + + /* set context to pbx */ + SCPY(param->setup.context, "pbx"); + } + + /* look for Remote's interface */ + if (admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, message_type, param)<0) { + PERROR("No socket with remote application '%s' found, this shall not happen. Closing socket shall cause release of all remote ports.\n", p_m_mISDNport->ifport->remote_app); + return 0; + } + + /* enable audio path */ + if (message_type == MESSAGE_SETUP) { + union parameter newparam; + memset(&newparam, 0, sizeof(union parameter)); + admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_PATTERN, &newparam); + newparam.audiopath = 1; + admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_AUDIOPATH, &newparam); + } + + if (message_type == MESSAGE_RELEASE) { + new_state(PORT_STATE_RELEASE); + delete this; + return 0; + } + + return 0; +} + +void Premote::message_remote(int message_type, union parameter *param) +{ + class Endpoint *epoint; + struct lcr_msg *message; + int channel; + int ret; + + if (message_type == MESSAGE_SETUP) { + /* enable audio path */ + union parameter newparam; + memset(&newparam, 0, sizeof(union parameter)); + admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_PATTERN, &newparam); + newparam.audiopath = 1; + admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_AUDIOPATH, &newparam); + + /* set source interface */ + param->setup.callerinfo.itype = p_callerinfo.itype; + param->setup.callerinfo.isdn_port = p_m_portnum; + SCPY(param->setup.callerinfo.interface, p_m_mISDNport->ifport->interface->name); + + ret = channel = hunt_bchannel(); + if (ret < 0) + goto no_channel; + + /* open channel */ + ret = seize_bchannel(channel, 1); + if (ret < 0) { + no_channel: + message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE); + message->param.disconnectinfo.cause = 34; + message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; + message_put(message); + new_state(PORT_STATE_RELEASE); + delete this; + return; + } + bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE); + + /* create endpoint */ + if (p_epointlist) + FATAL("Incoming call but already got an endpoint.\n"); + if (!(epoint = new Endpoint(p_serial, 0))) + FATAL("No memory for Endpoint instance\n"); + if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming + FATAL("No memory for Endpoint Application instance\n"); + + epointlist_new(epoint->ep_serial); + } + + /* set serial on bchannel message + * also ref is given, so we send message with ref */ + if (message_type == MESSAGE_BCHANNEL) { + int i = p_m_b_index; + unsigned int portid = (mISDNloop.port<<8) + i+1+(i>=15); + switch (param->bchannel.type) { + case BCHANNEL_REQUEST: + p_m_r_handle = portid; + message_bchannel_to_remote(p_m_r_remote_id, p_m_r_ref, BCHANNEL_ASSIGN, portid, 0, 0, 0, 0, 0, 0, 1); + chan_trace_header(p_m_mISDNport, this, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE); + add_trace("type", NULL, "assign"); + add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff); + end_trace(); + break; + case BCHANNEL_RELEASE: + p_m_r_handle = 0; + message_bchannel_to_remote(p_m_r_remote_id, p_m_r_ref, BCHANNEL_REMOVE, portid, 0, 0, 0, 0, 0, 0, 1); + chan_trace_header(p_m_mISDNport, this, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE); + add_trace("type", NULL, "remove"); + add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff); + end_trace(); + break; + } + return; + } + + /* cannot just forward, because param is not of container "struct lcr_msg" */ + message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, message_type); + memcpy(&message->param, param, sizeof(message->param)); + message_put(message); + + if (message_type == MESSAGE_RELEASE) { + new_state(PORT_STATE_RELEASE); + delete this; + return; + } +} + +/* select free bchannel from loopback interface */ +int Premote::hunt_bchannel(void) +{ + return loop_hunt_bchannel(this, p_m_mISDNport); +} + + + -- cgit v1.2.3-55-g7522