summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bridges/bridge_softmix.c3
-rw-r--r--channels/Makefile15
-rw-r--r--channels/chan_dahdi.c1147
-rw-r--r--channels/chan_dahdi.h808
-rw-r--r--channels/dahdi/bridge_native_dahdi.c928
-rw-r--r--channels/dahdi/bridge_native_dahdi.h47
-rw-r--r--main/bridging.c13
7 files changed, 1829 insertions, 1132 deletions
diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c
index cf891c668..b2d321815 100644
--- a/bridges/bridge_softmix.c
+++ b/bridges/bridge_softmix.c
@@ -623,6 +623,9 @@ static int softmix_bridge_write(struct ast_bridge *bridge, struct ast_bridge_cha
}
switch (frame->frametype) {
+ case AST_FRAME_NULL:
+ /* "Accept" the frame and discard it. */
+ break;
case AST_FRAME_DTMF_BEGIN:
case AST_FRAME_DTMF_END:
res = ast_bridge_queue_everyone_else(bridge, bridge_channel, frame);
diff --git a/channels/Makefile b/channels/Makefile
index 10d487cfb..154d52e53 100644
--- a/channels/Makefile
+++ b/channels/Makefile
@@ -1,6 +1,6 @@
#
# Asterisk -- An open source telephony toolkit.
-#
+#
# Makefile for channel drivers
#
# Copyright (C) 1999-2006, Digium, Inc.
@@ -72,10 +72,19 @@ dist-clean::
$(if $(filter chan_iax2,$(EMBEDDED_MODS)),modules.link,chan_iax2.so): $(subst .c,.o,$(wildcard iax2/*.c))
$(subst .c,.o,$(wildcard iax2/*.c)): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,chan_iax2)
+
$(if $(filter chan_sip,$(EMBEDDED_MODS)),modules.link,chan_sip.so): $(subst .c,.o,$(wildcard sip/*.c))
$(subst .c,.o,$(wildcard sip/*.c)): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,chan_sip)
-$(if $(filter chan_dahdi,$(EMBEDDED_MODS)),modules.link,chan_dahdi.so): sig_analog.o sig_pri.o sig_ss7.o
-sig_analog.o sig_pri.o sig_ss7.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,chan_dahdi)
+
+# Additional objects to combine with chan_dahdi.so
+CHAN_DAHDI_OBJS= \
+ $(subst .c,.o,$(wildcard dahdi/*.c)) \
+ sig_analog.o \
+ sig_pri.o \
+ sig_ss7.o \
+
+$(if $(filter chan_dahdi,$(EMBEDDED_MODS)),modules.link,chan_dahdi.so): $(CHAN_DAHDI_OBJS)
+$(CHAN_DAHDI_OBJS): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,chan_dahdi)
ifneq ($(filter chan_h323,$(EMBEDDED_MODS)),)
modules.link: h323/libchanh323.a
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index ac8695369..0806ca570 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -62,13 +62,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#else
#include <sys/signal.h>
#endif
-#include <sys/ioctl.h>
-#include <sys/stat.h>
#include <math.h>
-#include <ctype.h>
-#include <dahdi/user.h>
-#include <dahdi/tonezone.h>
#include "sig_analog.h"
/* Analog signaling is currently still present in chan_dahdi for use with
* radio. Sig_analog does not currently handle any radio operations. If
@@ -90,11 +85,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#endif
#endif /* defined(HAVE_SS7) */
-#ifdef HAVE_OPENR2
+#if defined(HAVE_OPENR2)
/* put this here until sig_mfcr2 comes along */
#define SIG_MFCR2_MAX_CHANNELS 672 /*!< No more than a DS3 per trunk group */
-#include <openr2.h>
-#endif
+#endif /* defined(HAVE_OPENR2) */
#include "asterisk/lock.h"
#include "asterisk/channel.h"
@@ -131,6 +125,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/features_config.h"
#include "asterisk/bridging.h"
#include "asterisk/stasis_channels.h"
+#include "chan_dahdi.h"
+#include "dahdi/bridge_native_dahdi.h"
/*** DOCUMENTATION
<application name="DAHDISendKeypadFacility" language="en_US">
@@ -422,7 +418,7 @@ static struct ast_jb_conf global_jbconf;
/*! \brief Signaling types that need to use MF detection should be placed in this macro */
#define NEED_MFDETECT(p) (((p)->sig == SIG_FEATDMF) || ((p)->sig == SIG_FEATDMF_TA) || ((p)->sig == SIG_E911) || ((p)->sig == SIG_FGC_CAMA) || ((p)->sig == SIG_FGC_CAMAMF) || ((p)->sig == SIG_FEATB))
-static const char tdesc[] = "DAHDI Telephony Driver"
+static const char tdesc[] = "DAHDI Telephony"
#if defined(HAVE_PRI) || defined(HAVE_SS7) || defined(HAVE_OPENR2)
" w/"
#if defined(HAVE_PRI)
@@ -445,33 +441,6 @@ static const char tdesc[] = "DAHDI Telephony Driver"
static const char config[] = "chan_dahdi.conf";
-#define SIG_EM DAHDI_SIG_EM
-#define SIG_EMWINK (0x0100000 | DAHDI_SIG_EM)
-#define SIG_FEATD (0x0200000 | DAHDI_SIG_EM)
-#define SIG_FEATDMF (0x0400000 | DAHDI_SIG_EM)
-#define SIG_FEATB (0x0800000 | DAHDI_SIG_EM)
-#define SIG_E911 (0x1000000 | DAHDI_SIG_EM)
-#define SIG_FEATDMF_TA (0x2000000 | DAHDI_SIG_EM)
-#define SIG_FGC_CAMA (0x4000000 | DAHDI_SIG_EM)
-#define SIG_FGC_CAMAMF (0x8000000 | DAHDI_SIG_EM)
-#define SIG_FXSLS DAHDI_SIG_FXSLS
-#define SIG_FXSGS DAHDI_SIG_FXSGS
-#define SIG_FXSKS DAHDI_SIG_FXSKS
-#define SIG_FXOLS DAHDI_SIG_FXOLS
-#define SIG_FXOGS DAHDI_SIG_FXOGS
-#define SIG_FXOKS DAHDI_SIG_FXOKS
-#define SIG_PRI DAHDI_SIG_CLEAR
-#define SIG_BRI (0x2000000 | DAHDI_SIG_CLEAR)
-#define SIG_BRI_PTMP (0X4000000 | DAHDI_SIG_CLEAR)
-#define SIG_SS7 (0x1000000 | DAHDI_SIG_CLEAR)
-#define SIG_MFCR2 DAHDI_SIG_CAS
-#define SIG_SF DAHDI_SIG_SF
-#define SIG_SFWINK (0x0100000 | DAHDI_SIG_SF)
-#define SIG_SF_FEATD (0x0200000 | DAHDI_SIG_SF)
-#define SIG_SF_FEATDMF (0x0400000 | DAHDI_SIG_SF)
-#define SIG_SF_FEATB (0x0800000 | DAHDI_SIG_SF)
-#define SIG_EM_E1 DAHDI_SIG_EM_E1
-
#ifdef LOTS_OF_SPANS
#define NUM_SPANS DAHDI_MAX_SPANS
#else
@@ -578,8 +547,6 @@ static int num_restart_pending = 0;
static int restart_monitor(void);
-static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
-
static int dahdi_sendtext(struct ast_channel *c, const char *text);
static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_topic *topic, struct stasis_message *msg)
@@ -625,8 +592,6 @@ static inline int dahdi_wait_event(int fd)
#define DEFAULT_RINGT ((8000 * 8) / READ_SIZE) /*!< 8,000 ms */
#define DEFAULT_DIALTONE_DETECT_TIMEOUT ((10000 * 8) / READ_SIZE) /*!< 10,000 ms */
-struct dahdi_pvt;
-
/*!
* \brief Configured ring timeout base.
* \note Value computed from "ringtimeout" read in from chan_dahdi.conf if it exists.
@@ -722,644 +687,16 @@ static const char dahdi_pri_cc_type[] = "DAHDI/PRI";
struct dahdi_pri;
#endif
-#define SUB_REAL 0 /*!< Active call */
-#define SUB_CALLWAIT 1 /*!< Call-Waiting call on hold */
-#define SUB_THREEWAY 2 /*!< Three-way call */
-
/* Polarity states */
#define POLARITY_IDLE 0
#define POLARITY_REV 1
-
-struct distRingData {
- int ring[3];
- int range;
-};
-struct ringContextData {
- char contextData[AST_MAX_CONTEXT];
-};
-struct dahdi_distRings {
- struct distRingData ringnum[3];
- struct ringContextData ringContext[3];
-};
-
-static const char * const subnames[] = {
+const char * const subnames[] = {
"Real",
"Callwait",
"Threeway"
};
-struct dahdi_subchannel {
- int dfd;
- struct ast_channel *owner;
- int chan;
- short buffer[AST_FRIENDLY_OFFSET/2 + READ_SIZE];
- struct ast_frame f; /*!< One frame for each channel. How did this ever work before? */
- unsigned int needringing:1;
- unsigned int needbusy:1;
- unsigned int needcongestion:1;
- unsigned int needanswer:1;
- unsigned int needflash:1;
- unsigned int needhold:1;
- unsigned int needunhold:1;
- unsigned int linear:1;
- unsigned int inthreeway:1;
- struct dahdi_confinfo curconf;
-};
-
-#define CONF_USER_REAL (1 << 0)
-#define CONF_USER_THIRDCALL (1 << 1)
-
-#define MAX_SLAVES 4
-
-/* States for sending MWI message
- * First three states are required for send Ring Pulse Alert Signal
- */
-typedef enum {
- MWI_SEND_NULL = 0,
- MWI_SEND_SA,
- MWI_SEND_SA_WAIT,
- MWI_SEND_PAUSE,
- MWI_SEND_SPILL,
- MWI_SEND_CLEANUP,
- MWI_SEND_DONE,
-} mwisend_states;
-
-struct mwisend_info {
- struct timeval pause;
- mwisend_states mwisend_current;
-};
-
-/*! Specify the lists dahdi_pvt can be put in. */
-enum DAHDI_IFLIST {
- DAHDI_IFLIST_NONE, /*!< The dahdi_pvt is not in any list. */
- DAHDI_IFLIST_MAIN, /*!< The dahdi_pvt is in the main interface list */
-#if defined(HAVE_PRI)
- DAHDI_IFLIST_NO_B_CHAN, /*!< The dahdi_pvt is in a no B channel interface list */
-#endif /* defined(HAVE_PRI) */
-};
-
-struct dahdi_pvt {
- ast_mutex_t lock; /*!< Channel private lock. */
- struct callerid_state *cs;
- struct ast_channel *owner; /*!< Our current active owner (if applicable) */
- /*!< Up to three channels can be associated with this call */
-
- struct dahdi_subchannel sub_unused; /*!< Just a safety precaution */
- struct dahdi_subchannel subs[3]; /*!< Sub-channels */
- struct dahdi_confinfo saveconf; /*!< Saved conference info */
-
- struct dahdi_pvt *slaves[MAX_SLAVES]; /*!< Slave to us (follows our conferencing) */
- struct dahdi_pvt *master; /*!< Master to us (we follow their conferencing) */
- int inconference; /*!< If our real should be in the conference */
-
- int bufsize; /*!< Size of the buffers */
- int buf_no; /*!< Number of buffers */
- int buf_policy; /*!< Buffer policy */
- int faxbuf_no; /*!< Number of Fax buffers */
- int faxbuf_policy; /*!< Fax buffer policy */
- int sig; /*!< Signalling style */
- /*!
- * \brief Nonzero if the signaling type is sent over a radio.
- * \note Set to a couple of nonzero values but it is only tested like a boolean.
- */
- int radio;
- int outsigmod; /*!< Outbound Signalling style (modifier) */
- int oprmode; /*!< "Operator Services" mode */
- struct dahdi_pvt *oprpeer; /*!< "Operator Services" peer tech_pvt ptr */
- /*! \brief Amount of gain to increase during caller id */
- float cid_rxgain;
- /*! \brief Rx gain set by chan_dahdi.conf */
- float rxgain;
- /*! \brief Tx gain set by chan_dahdi.conf */
- float txgain;
-
- float txdrc; /*!< Dynamic Range Compression factor. a number between 1 and 6ish */
- float rxdrc;
-
- int tonezone; /*!< tone zone for this chan, or -1 for default */
- enum DAHDI_IFLIST which_iflist; /*!< Which interface list is this structure listed? */
- struct dahdi_pvt *next; /*!< Next channel in list */
- struct dahdi_pvt *prev; /*!< Prev channel in list */
-
- /* flags */
-
- /*!
- * \brief TRUE if ADSI (Analog Display Services Interface) available
- * \note Set from the "adsi" value read in from chan_dahdi.conf
- */
- unsigned int adsi:1;
- /*!
- * \brief TRUE if we can use a polarity reversal to mark when an outgoing
- * call is answered by the remote party.
- * \note Set from the "answeronpolarityswitch" value read in from chan_dahdi.conf
- */
- unsigned int answeronpolarityswitch:1;
- /*!
- * \brief TRUE if busy detection is enabled.
- * (Listens for the beep-beep busy pattern.)
- * \note Set from the "busydetect" value read in from chan_dahdi.conf
- */
- unsigned int busydetect:1;
- /*!
- * \brief TRUE if call return is enabled.
- * (*69, if your dialplan doesn't catch this first)
- * \note Set from the "callreturn" value read in from chan_dahdi.conf
- */
- unsigned int callreturn:1;
- /*!
- * \brief TRUE if busy extensions will hear the call-waiting tone
- * and can use hook-flash to switch between callers.
- * \note Can be disabled by dialing *70.
- * \note Initialized with the "callwaiting" value read in from chan_dahdi.conf
- */
- unsigned int callwaiting:1;
- /*!
- * \brief TRUE if send caller ID for Call Waiting
- * \note Set from the "callwaitingcallerid" value read in from chan_dahdi.conf
- */
- unsigned int callwaitingcallerid:1;
- /*!
- * \brief TRUE if support for call forwarding enabled.
- * Dial *72 to enable call forwarding.
- * Dial *73 to disable call forwarding.
- * \note Set from the "cancallforward" value read in from chan_dahdi.conf
- */
- unsigned int cancallforward:1;
- /*!
- * \brief TRUE if support for call parking is enabled.
- * \note Set from the "canpark" value read in from chan_dahdi.conf
- */
- unsigned int canpark:1;
- /*! \brief TRUE if to wait for a DTMF digit to confirm answer */
- unsigned int confirmanswer:1;
- /*!
- * \brief TRUE if the channel is to be destroyed on hangup.
- * (Used by pseudo channels.)
- */
- unsigned int destroy:1;
- unsigned int didtdd:1; /*!< flag to say its done it once */
- /*! \brief TRUE if analog type line dialed no digits in Dial() */
- unsigned int dialednone:1;
- /*!
- * \brief TRUE if in the process of dialing digits or sending something.
- * \note This is used as a receive squelch for ISDN until connected.
- */
- unsigned int dialing:1;
- /*! \brief TRUE if the transfer capability of the call is digital. */
- unsigned int digital:1;
- /*! \brief TRUE if Do-Not-Disturb is enabled, present only for non sig_analog */
- unsigned int dnd:1;
- /*! \brief XXX BOOLEAN Purpose??? */
- unsigned int echobreak:1;
- /*!
- * \brief TRUE if echo cancellation enabled when bridged.
- * \note Initialized with the "echocancelwhenbridged" value read in from chan_dahdi.conf
- * \note Disabled if the echo canceller is not setup.
- */
- unsigned int echocanbridged:1;
- /*! \brief TRUE if echo cancellation is turned on. */
- unsigned int echocanon:1;
- /*! \brief TRUE if a fax tone has already been handled. */
- unsigned int faxhandled:1;
- /*! TRUE if dynamic faxbuffers are configured for use, default is OFF */
- unsigned int usefaxbuffers:1;
- /*! TRUE while buffer configuration override is in use */
- unsigned int bufferoverrideinuse:1;
- /*! \brief TRUE if over a radio and dahdi_read() has been called. */
- unsigned int firstradio:1;
- /*!
- * \brief TRUE if the call will be considered "hung up" on a polarity reversal.
- * \note Set from the "hanguponpolarityswitch" value read in from chan_dahdi.conf
- */
- unsigned int hanguponpolarityswitch:1;
- /*! \brief TRUE if DTMF detection needs to be done by hardware. */
- unsigned int hardwaredtmf:1;
- /*!
- * \brief TRUE if the outgoing caller ID is blocked/hidden.
- * \note Caller ID can be disabled by dialing *67.
- * \note Caller ID can be enabled by dialing *82.
- * \note Initialized with the "hidecallerid" value read in from chan_dahdi.conf
- */
- unsigned int hidecallerid:1;
- /*!
- * \brief TRUE if hide just the name not the number for legacy PBX use.
- * \note Only applies to PRI channels.
- * \note Set from the "hidecalleridname" value read in from chan_dahdi.conf
- */
- unsigned int hidecalleridname:1;
- /*! \brief TRUE if DTMF detection is disabled. */
- unsigned int ignoredtmf:1;
- /*!
- * \brief TRUE if the channel should be answered immediately
- * without attempting to gather any digits.
- * \note Set from the "immediate" value read in from chan_dahdi.conf
- */
- unsigned int immediate:1;
- /*! \brief TRUE if in an alarm condition. */
- unsigned int inalarm:1;
- /*! \brief TRUE if TDD in MATE mode */
- unsigned int mate:1;
- /*! \brief TRUE if we originated the call leg. */
- unsigned int outgoing:1;
- /* unsigned int overlapdial:1; unused and potentially confusing */
- /*!
- * \brief TRUE if busy extensions will hear the call-waiting tone
- * and can use hook-flash to switch between callers.
- * \note Set from the "callwaiting" value read in from chan_dahdi.conf
- */
- unsigned int permcallwaiting:1;
- /*!
- * \brief TRUE if the outgoing caller ID is blocked/restricted/hidden.
- * \note Set from the "hidecallerid" value read in from chan_dahdi.conf
- */
- unsigned int permhidecallerid:1;
- /*!
- * \brief TRUE if PRI congestion/busy indications are sent out-of-band.
- * \note Set from the "priindication" value read in from chan_dahdi.conf
- */
- unsigned int priindication_oob:1;
- /*!
- * \brief TRUE if PRI B channels are always exclusively selected.
- * \note Set from the "priexclusive" value read in from chan_dahdi.conf
- */
- unsigned int priexclusive:1;
- /*!
- * \brief TRUE if we will pulse dial.
- * \note Set from the "pulsedial" value read in from chan_dahdi.conf
- */
- unsigned int pulse:1;
- /*! \brief TRUE if a pulsed digit was detected. (Pulse dial phone detected) */
- unsigned int pulsedial:1;
- unsigned int restartpending:1; /*!< flag to ensure counted only once for restart */
- /*!
- * \brief TRUE if caller ID is restricted.
- * \note Set but not used. Should be deleted. Redundant with permhidecallerid.
- * \note Set from the "restrictcid" value read in from chan_dahdi.conf
- */
- unsigned int restrictcid:1;
- /*!
- * \brief TRUE if three way calling is enabled
- * \note Set from the "threewaycalling" value read in from chan_dahdi.conf
- */
- unsigned int threewaycalling:1;
- /*!
- * \brief TRUE if call transfer is enabled
- * \note For FXS ports (either direct analog or over T1/E1):
- * Support flash-hook call transfer
- * \note For digital ports using ISDN PRI protocols:
- * Support switch-side transfer (called 2BCT, RLT or other names)
- * \note Set from the "transfer" value read in from chan_dahdi.conf
- */
- unsigned int transfer:1;
- /*!
- * \brief TRUE if caller ID is used on this channel.
- * \note PRI and SS7 spans will save caller ID from the networking peer.
- * \note FXS ports will generate the caller ID spill.
- * \note FXO ports will listen for the caller ID spill.
- * \note Set from the "usecallerid" value read in from chan_dahdi.conf
- */
- unsigned int use_callerid:1;
- /*!
- * \brief TRUE if we will use the calling presentation setting
- * from the Asterisk channel for outgoing calls.
- * \note Only applies to PRI and SS7 channels.
- * \note Set from the "usecallingpres" value read in from chan_dahdi.conf
- */
- unsigned int use_callingpres:1;
- /*!
- * \brief TRUE if distinctive rings are to be detected.
- * \note For FXO lines
- * \note Set indirectly from the "usedistinctiveringdetection" value read in from chan_dahdi.conf
- */
- unsigned int usedistinctiveringdetection:1;
- /*!
- * \brief TRUE if we should use the callerid from incoming call on dahdi transfer.
- * \note Set from the "useincomingcalleridondahditransfer" value read in from chan_dahdi.conf
- */
- unsigned int dahditrcallerid:1;
- /*!
- * \brief TRUE if allowed to flash-transfer to busy channels.
- * \note Set from the "transfertobusy" value read in from chan_dahdi.conf
- */
- unsigned int transfertobusy:1;
- /*!
- * \brief TRUE if the FXO port monitors for neon type MWI indications from the other end.
- * \note Set if the "mwimonitor" value read in contains "neon" from chan_dahdi.conf
- */
- unsigned int mwimonitor_neon:1;
- /*!
- * \brief TRUE if the FXO port monitors for fsk type MWI indications from the other end.
- * \note Set if the "mwimonitor" value read in contains "fsk" from chan_dahdi.conf
- */
- unsigned int mwimonitor_fsk:1;
- /*!
- * \brief TRUE if the FXO port monitors for rpas precursor to fsk MWI indications from the other end.
- * \note RPAS - Ring Pulse Alert Signal
- * \note Set if the "mwimonitor" value read in contains "rpas" from chan_dahdi.conf
- */
- unsigned int mwimonitor_rpas:1;
- /*! \brief TRUE if an MWI monitor thread is currently active */
- unsigned int mwimonitoractive:1;
- /*! \brief TRUE if a MWI message sending thread is active */
- unsigned int mwisendactive:1;
- /*!
- * \brief TRUE if channel is out of reset and ready
- * \note Set but not used.
- */
- unsigned int inservice:1;
- /*!
- * \brief TRUE if the channel is locally blocked.
- * \note Applies to SS7 and MFCR2 channels.
- */
- unsigned int locallyblocked:1;
- /*!
- * \brief TRUE if the channel is remotely blocked.
- * \note Applies to SS7 and MFCR2 channels.
- */
- unsigned int remotelyblocked:1;
- /*!
- * \brief TRUE if the channel alarms will be managed also as Span ones
- * \note Applies to all channels
- */
- unsigned int manages_span_alarms:1;
-
-#if defined(HAVE_PRI)
- struct sig_pri_span *pri;
- int logicalspan;
-#endif
- /*!
- * \brief TRUE if SMDI (Simplified Message Desk Interface) is enabled
- * \note Set from the "usesmdi" value read in from chan_dahdi.conf
- */
- unsigned int use_smdi:1;
- struct mwisend_info mwisend_data;
- /*! \brief The SMDI interface to get SMDI messages from. */
- struct ast_smdi_interface *smdi_iface;
-
- /*! \brief Distinctive Ring data */
- struct dahdi_distRings drings;
-
- /*!
- * \brief The configured context for incoming calls.
- * \note The "context" string read in from chan_dahdi.conf
- */
- char context[AST_MAX_CONTEXT];
- /*!
- * \brief A description for the channel configuration
- * \note The "description" string read in from chan_dahdi.conf
- */
- char description[32];
- /*!
- * \brief Saved context string.
- */
- char defcontext[AST_MAX_CONTEXT];
- /*! \brief Extension to use in the dialplan. */
- char exten[AST_MAX_EXTENSION];
- /*!
- * \brief Language configured for calls.
- * \note The "language" string read in from chan_dahdi.conf
- */
- char language[MAX_LANGUAGE];
- /*!
- * \brief The configured music-on-hold class to use for calls.
- * \note The "musicclass" or "mohinterpret" or "musiconhold" string read in from chan_dahdi.conf
- */
- char mohinterpret[MAX_MUSICCLASS];
- /*!
- * \brief Suggested music-on-hold class for peer channel to use for calls.
- * \note The "mohsuggest" string read in from chan_dahdi.conf
- */
- char mohsuggest[MAX_MUSICCLASS];
- char parkinglot[AST_MAX_EXTENSION]; /*!< Parking lot for this channel */
-#if defined(HAVE_PRI) || defined(HAVE_SS7)
- /*! \brief Automatic Number Identification number (Alternate PRI caller ID number) */
- char cid_ani[AST_MAX_EXTENSION];
-#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
- /*! \brief Automatic Number Identification code from PRI */
- int cid_ani2;
- /*! \brief Caller ID number from an incoming call. */
- char cid_num[AST_MAX_EXTENSION];
- /*!
- * \brief Caller ID tag from incoming call
- * \note the "cid_tag" string read in from chan_dahdi.conf
- */
- char cid_tag[AST_MAX_EXTENSION];
- /*! \brief Caller ID Q.931 TON/NPI field values. Set by PRI. Zero otherwise. */
- int cid_ton;
- /*! \brief Caller ID name from an incoming call. */
- char cid_name[AST_MAX_EXTENSION];
- /*! \brief Caller ID subaddress from an incoming call. */
- char cid_subaddr[AST_MAX_EXTENSION];
- char *origcid_num; /*!< malloced original callerid */
- char *origcid_name; /*!< malloced original callerid */
- /*! \brief Call waiting number. */
- char callwait_num[AST_MAX_EXTENSION];
- /*! \brief Call waiting name. */
- char callwait_name[AST_MAX_EXTENSION];
- /*! \brief Redirecting Directory Number Information Service (RDNIS) number */
- char rdnis[AST_MAX_EXTENSION];
- /*! \brief Dialed Number Identifier */
- char dnid[AST_MAX_EXTENSION];
- /*!
- * \brief Bitmapped groups this belongs to.
- * \note The "group" bitmapped group string read in from chan_dahdi.conf
- */
- ast_group_t group;
- /*! \brief Default call PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW. */
- int law_default;
- /*! \brief Active PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW */
- int law;
- int confno; /*!< Our conference */
- int confusers; /*!< Who is using our conference */
- int propconfno; /*!< Propagated conference number */
- /*!
- * \brief Bitmapped call groups this belongs to.
- * \note The "callgroup" bitmapped group string read in from chan_dahdi.conf
- */
- ast_group_t callgroup;
- /*!
- * \brief Bitmapped pickup groups this belongs to.
- * \note The "pickupgroup" bitmapped group string read in from chan_dahdi.conf
- */
- ast_group_t pickupgroup;
- /*!
- * \brief Named call groups this belongs to.
- * \note The "namedcallgroup" string read in from chan_dahdi.conf
- */
- struct ast_namedgroups *named_callgroups;
- /*!
- * \brief Named pickup groups this belongs to.
- * \note The "namedpickupgroup" string read in from chan_dahdi.conf
- */
- struct ast_namedgroups *named_pickupgroups;
- /*!
- * \brief Channel variable list with associated values to set when a channel is created.
- * \note The "setvar" strings read in from chan_dahdi.conf
- */
- struct ast_variable *vars;
- int channel; /*!< Channel Number */
- int span; /*!< Span number */
- time_t guardtime; /*!< Must wait this much time before using for new call */
- int cid_signalling; /*!< CID signalling type bell202 or v23 */
- int cid_start; /*!< CID start indicator, polarity or ring or DTMF without warning event */
- int dtmfcid_holdoff_state; /*!< State indicator that allows for line to settle before checking for dtmf energy */
- struct timeval dtmfcid_delay; /*!< Time value used for allow line to settle */
- int callingpres; /*!< The value of calling presentation that we're going to use when placing a PRI call */
- int callwaitingrepeat; /*!< How many samples to wait before repeating call waiting */
- int cidcwexpire; /*!< When to stop waiting for CID/CW CAS response (In samples) */
- int cid_suppress_expire; /*!< How many samples to suppress after a CID spill. */
- /*! \brief Analog caller ID waveform sample buffer */
- unsigned char *cidspill;
- /*! \brief Position in the cidspill buffer to send out next. */
- int cidpos;
- /*! \brief Length of the cidspill buffer containing samples. */
- int cidlen;
- /*! \brief Ring timeout timer?? */
- int ringt;
- /*!
- * \brief Ring timeout base.
- * \note Value computed indirectly from "ringtimeout" read in from chan_dahdi.conf
- */
- int ringt_base;
- /*!
- * \brief Number of most significant digits/characters to strip from the dialed number.
- * \note Feature is deprecated. Use dialplan logic.
- * \note The characters are stripped before the PRI TON/NPI prefix
- * characters are processed.
- */
- int stripmsd;
- /*!
- * \brief TRUE if Call Waiting (CW) CPE Alert Signal (CAS) is being sent.
- * \note
- * After CAS is sent, the call waiting caller id will be sent if the phone
- * gives a positive reply.
- */
- int callwaitcas;
- /*! \brief Number of call waiting rings. */
- int callwaitrings;
- /*! \brief Echo cancel parameters. */
- struct {
- struct dahdi_echocanparams head;
- struct dahdi_echocanparam params[DAHDI_MAX_ECHOCANPARAMS];
- } echocancel;
- /*!
- * \brief Echo training time. 0 = disabled
- * \note Set from the "echotraining" value read in from chan_dahdi.conf
- */
- int echotraining;
- /*! \brief Filled with 'w'. XXX Purpose?? */
- char echorest[20];
- /*!
- * \brief Number of times to see "busy" tone before hanging up.
- * \note Set from the "busycount" value read in from chan_dahdi.conf
- */
- int busycount;
- /*!
- * \brief Busy cadence pattern description.
- * \note Set from the "busypattern" value read from chan_dahdi.conf
- */
- struct ast_dsp_busy_pattern busy_cadence;
- /*!
- * \brief Bitmapped call progress detection flags. CALLPROGRESS_xxx values.
- * \note Bits set from the "callprogress" and "faxdetect" values read in from chan_dahdi.conf
- */
- int callprogress;
- /*!
- * \brief Number of milliseconds to wait for dialtone.
- * \note Set from the "waitfordialtone" value read in from chan_dahdi.conf
- */
- int waitfordialtone;
- /*!
- * \brief Number of frames to watch for dialtone in incoming calls
- * \note Set from the "dialtone_detect" value read in from chan_dahdi.conf
- */
- int dialtone_detect;
- int dialtone_scanning_time_elapsed; /*!< Amount of audio scanned for dialtone, in frames */
- struct timeval waitingfordt; /*!< Time we started waiting for dialtone */
- struct timeval flashtime; /*!< Last flash-hook time */
- /*! \brief Opaque DSP configuration structure. */
- struct ast_dsp *dsp;
- /*! \brief DAHDI dial operation command struct for ioctl() call. */
- struct dahdi_dialoperation dop;
- int whichwink; /*!< SIG_FEATDMF_TA Which wink are we on? */
- /*! \brief Second part of SIG_FEATDMF_TA wink operation. */
- char finaldial[64];
- char accountcode[AST_MAX_ACCOUNT_CODE]; /*!< Account code */
- int amaflags; /*!< AMA Flags */
- struct tdd_state *tdd; /*!< TDD flag */
- /*! \brief Accumulated call forwarding number. */
- char call_forward[AST_MAX_EXTENSION];
- /*!
- * \brief Voice mailbox location.
- * \note Set from the "mailbox" string read in from chan_dahdi.conf
- */
- char mailbox[AST_MAX_EXTENSION];
- /*! \brief Opaque event subscription parameters for message waiting indication support. */
- struct stasis_subscription *mwi_event_sub;
- /*! \brief Delayed dialing for E911. Overlap digits for ISDN. */
- char dialdest[256];
-#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
- struct dahdi_vmwi_info mwisend_setting; /*!< Which VMWI methods to use */
- unsigned int mwisend_fsk: 1; /*! Variable for enabling FSK MWI handling in chan_dahdi */
- unsigned int mwisend_rpas:1; /*! Variable for enabling Ring Pulse Alert before MWI FSK Spill */
-#endif
- int distinctivering; /*!< Which distinctivering to use */
- int dtmfrelax; /*!< whether to run in relaxed DTMF mode */
- /*! \brief Holding place for event injected from outside normal operation. */
- int fake_event;
- /*!
- * \brief Minimal time period (ms) between the answer polarity
- * switch and hangup polarity switch.
- */
- int polarityonanswerdelay;
- /*! \brief Start delay time if polarityonanswerdelay is nonzero. */
- struct timeval polaritydelaytv;
- /*!
- * \brief Send caller ID on FXS after this many rings. Set to 1 for US.
- * \note Set from the "sendcalleridafter" value read in from chan_dahdi.conf
- */
- int sendcalleridafter;
- /*! \brief Current line interface polarity. POLARITY_IDLE, POLARITY_REV */
- int polarity;
- /*! \brief DSP feature flags: DSP_FEATURE_xxx */
- int dsp_features;
-#if defined(HAVE_SS7)
- /*! \brief SS7 control parameters */
- struct sig_ss7_linkset *ss7;
-#endif /* defined(HAVE_SS7) */
-#ifdef HAVE_OPENR2
- struct dahdi_mfcr2 *mfcr2;
- openr2_chan_t *r2chan;
- openr2_calling_party_category_t mfcr2_recvd_category;
- openr2_calling_party_category_t mfcr2_category;
- int mfcr2_dnis_index;
- int mfcr2_ani_index;
- int mfcr2call:1;
- int mfcr2_answer_pending:1;
- int mfcr2_charge_calls:1;
- int mfcr2_allow_collect_calls:1;
- int mfcr2_forced_release:1;
- int mfcr2_dnis_matched:1;
- int mfcr2_call_accepted:1;
- int mfcr2_accept_on_offer:1;
- int mfcr2_progress_sent:1;
-#endif
- /*! \brief DTMF digit in progress. 0 when no digit in progress. */
- char begindigit;
- /*! \brief TRUE if confrence is muted. */
- int muting;
- void *sig_pvt;
- struct ast_cc_config_params *cc_params;
- /* DAHDI channel names may differ greatly from the
- * string that was provided to an app such as Dial. We
- * need to save the original string passed to dahdi_request
- * for call completion purposes. This way, we can replicate
- * the original dialed string later.
- */
- char dialstring[AST_CHANNEL_NAME];
-};
-
#define DATA_EXPORT_DAHDI_PVT(MEMBER) \
MEMBER(dahdi_pvt, cid_rxgain, AST_DATA_DOUBLE) \
MEMBER(dahdi_pvt, rxgain, AST_DATA_DOUBLE) \
@@ -1634,8 +971,6 @@ static int dahdi_func_write(struct ast_channel *chan, const char *function, char
static int dahdi_devicestate(const char *data);
static int dahdi_cc_callback(struct ast_channel *inbound, const char *dest, ast_cc_callback_fn callback);
-/* BUGBUG The DAHDI channel driver needs its own native bridge technology. */
-/* BUGBUG The transfer=yes option is broken for ISDN to push tromboned calls to the peer. */
static struct ast_channel_tech dahdi_tech = {
.type = "DAHDI",
.description = tdesc,
@@ -1648,7 +983,6 @@ static struct ast_channel_tech dahdi_tech = {
.answer = dahdi_answer,
.read = dahdi_read,
.write = dahdi_write,
- .bridge = dahdi_bridge,
.exception = dahdi_exception,
.indicate = dahdi_indicate,
.fixup = dahdi_fixup,
@@ -1662,77 +996,6 @@ static struct ast_channel_tech dahdi_tech = {
#define GET_CHANNEL(p) ((p)->channel)
-#define SIG_PRI_LIB_HANDLE_CASES \
- SIG_PRI: \
- case SIG_BRI: \
- case SIG_BRI_PTMP
-
-/*!
- * \internal
- * \brief Determine if sig_pri handles the signaling.
- * \since 1.8
- *
- * \param signaling Signaling to determine if is for sig_pri.
- *
- * \return TRUE if the signaling is for sig_pri.
- */
-static inline int dahdi_sig_pri_lib_handles(int signaling)
-{
- int handles;
-
- switch (signaling) {
- case SIG_PRI_LIB_HANDLE_CASES:
- handles = 1;
- break;
- default:
- handles = 0;
- break;
- }
-
- return handles;
-}
-
-static int analog_lib_handles(int signalling, int radio, int oprmode)
-{
- switch (signalling) {
- case SIG_FXOLS:
- case SIG_FXOGS:
- case SIG_FXOKS:
- case SIG_FXSLS:
- case SIG_FXSGS:
- case SIG_FXSKS:
- case SIG_EMWINK:
- case SIG_EM:
- case SIG_EM_E1:
- case SIG_FEATD:
- case SIG_FEATDMF:
- case SIG_E911:
- case SIG_FGC_CAMA:
- case SIG_FGC_CAMAMF:
- case SIG_FEATB:
- case SIG_SFWINK:
- case SIG_SF:
- case SIG_SF_FEATD:
- case SIG_SF_FEATDMF:
- case SIG_FEATDMF_TA:
- case SIG_SF_FEATB:
- break;
- default:
- /* The rest of the function should cover the remainder of signalling types */
- return 0;
- }
-
- if (radio) {
- return 0;
- }
-
- if (oprmode) {
- return 0;
- }
-
- return 1;
-}
-
static enum analog_sigtype dahdisig_to_analogsig(int sig)
{
switch (sig) {
@@ -3161,9 +2424,6 @@ static int my_is_off_hook(void *pvt)
return par.rxisoffhook;
}
-static void dahdi_enable_ec(struct dahdi_pvt *p);
-static void dahdi_disable_ec(struct dahdi_pvt *p);
-
static int my_set_echocanceller(void *pvt, int enable)
{
struct dahdi_pvt *p = pvt;
@@ -3996,8 +3256,7 @@ struct analog_callback analog_callbacks =
/*! Round robin search locations. */
static struct dahdi_pvt *round_robin[32];
-#define dahdi_get_index(ast, p, nullok) _dahdi_get_index(ast, p, nullok, __PRETTY_FUNCTION__, __LINE__)
-static int _dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok, const char *fname, unsigned long line)
+int _dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok, const char *fname, unsigned long line)
{
int res;
if (p->subs[SUB_REAL].owner == ast)
@@ -4312,7 +3571,6 @@ static void dahdi_r2_on_call_end(openr2_chan_t *r2chan)
ast_mutex_unlock(&p->lock);
}
-static void dahdi_enable_ec(struct dahdi_pvt *p);
static void dahdi_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
{
struct dahdi_pvt *p = NULL;
@@ -5106,7 +4364,7 @@ static int reset_conf(struct dahdi_pvt *p)
return 0;
}
-static int update_conf(struct dahdi_pvt *p)
+void update_conf(struct dahdi_pvt *p)
{
int needconf = 0;
int x;
@@ -5159,10 +4417,9 @@ static int update_conf(struct dahdi_pvt *p)
p->confno = -1;
}
ast_debug(1, "Updated conferencing on %d, with %d conference users\n", p->channel, needconf);
- return 0;
}
-static void dahdi_enable_ec(struct dahdi_pvt *p)
+void dahdi_enable_ec(struct dahdi_pvt *p)
{
int res;
if (!p)
@@ -5234,7 +4491,7 @@ static void dahdi_train_ec(struct dahdi_pvt *p)
}
}
-static void dahdi_disable_ec(struct dahdi_pvt *p)
+void dahdi_disable_ec(struct dahdi_pvt *p)
{
int res;
@@ -6954,7 +6211,7 @@ static int dahdi_answer(struct ast_channel *ast)
return res;
}
-static void disable_dtmf_detect(struct dahdi_pvt *p)
+void disable_dtmf_detect(struct dahdi_pvt *p)
{
int val = 0;
@@ -6968,7 +6225,7 @@ static void disable_dtmf_detect(struct dahdi_pvt *p)
}
}
-static void enable_dtmf_detect(struct dahdi_pvt *p)
+void enable_dtmf_detect(struct dahdi_pvt *p)
{
int val = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
@@ -7458,7 +6715,7 @@ static int dahdi_func_write(struct ast_channel *chan, const char *function, char
return res;
}
-static void dahdi_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
+void dahdi_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
{
/* Unlink a specific slave or all slaves/masters from a given master */
int x;
@@ -7514,7 +6771,8 @@ static void dahdi_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int
}
}
-static void dahdi_link(struct dahdi_pvt *slave, struct dahdi_pvt *master) {
+void dahdi_link(struct dahdi_pvt *slave, struct dahdi_pvt *master)
+{
int x;
if (!slave || !master) {
ast_log(LOG_WARNING, "Tried to link to/from NULL??\n");
@@ -7537,373 +6795,6 @@ static void dahdi_link(struct dahdi_pvt *slave, struct dahdi_pvt *master) {
ast_debug(1, "Making %d slave to master %d at %d\n", slave->channel, master->channel, x);
}
-static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
-{
- struct ast_channel *who;
- struct dahdi_pvt *p0, *p1, *op0, *op1;
- struct dahdi_pvt *master = NULL, *slave = NULL;
- struct ast_frame *f;
- int inconf = 0;
- int nothingok = 1;
- int ofd0, ofd1;
- int oi0, oi1, i0 = -1, i1 = -1, t0, t1;
- int os0 = -1, os1 = -1;
- int priority = 0;
- struct ast_channel *oc0, *oc1;
- enum ast_bridge_result res;
- struct timeval start = ast_tvnow();
-#ifdef PRI_2BCT
- int triedtopribridge = 0;
- q931_call *q931c0;
- q931_call *q931c1;
-#endif
-
- /* For now, don't attempt to native bridge if either channel needs DTMF detection.
- There is code below to handle it properly until DTMF is actually seen,
- but due to currently unresolved issues it's ignored...
- */
-
- if (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))
- return AST_BRIDGE_FAILED_NOWARN;
-
- ast_channel_lock_both(c0, c1);
-
- p0 = ast_channel_tech_pvt(c0);
- p1 = ast_channel_tech_pvt(c1);
- /* cant do pseudo-channels here */
- if (!p0 || (!p0->sig) || !p1 || (!p1->sig)) {
- ast_channel_unlock(c0);
- ast_channel_unlock(c1);
- return AST_BRIDGE_FAILED_NOWARN;
- }
-
- oi0 = dahdi_get_index(c0, p0, 0);
- oi1 = dahdi_get_index(c1, p1, 0);
- if ((oi0 < 0) || (oi1 < 0)) {
- ast_channel_unlock(c0);
- ast_channel_unlock(c1);
- return AST_BRIDGE_FAILED;
- }
-
- op0 = p0 = ast_channel_tech_pvt(c0);
- op1 = p1 = ast_channel_tech_pvt(c1);
- ofd0 = ast_channel_fd(c0, 0);
- ofd1 = ast_channel_fd(c1, 0);
- oc0 = p0->owner;
- oc1 = p1->owner;
-
- if (ast_mutex_trylock(&p0->lock)) {
- /* Don't block, due to potential for deadlock */
- ast_channel_unlock(c0);
- ast_channel_unlock(c1);
- ast_log(LOG_NOTICE, "Avoiding deadlock...\n");
- return AST_BRIDGE_RETRY;
- }
- if (ast_mutex_trylock(&p1->lock)) {
- /* Don't block, due to potential for deadlock */
- ast_mutex_unlock(&p0->lock);
- ast_channel_unlock(c0);
- ast_channel_unlock(c1);
- ast_log(LOG_NOTICE, "Avoiding deadlock...\n");
- return AST_BRIDGE_RETRY;
- }
-
- if ((p0->callwaiting && p0->callwaitingcallerid)
- || (p1->callwaiting && p1->callwaitingcallerid)) {
- /*
- * Call Waiting Caller ID requires DTMF detection to know if it
- * can send the CID spill.
- *
- * For now, don't attempt to native bridge if either channel
- * needs DTMF detection. There is code below to handle it
- * properly until DTMF is actually seen, but due to currently
- * unresolved issues it's ignored...
- */
- ast_mutex_unlock(&p0->lock);
- ast_mutex_unlock(&p1->lock);
- ast_channel_unlock(c0);
- ast_channel_unlock(c1);
- return AST_BRIDGE_FAILED_NOWARN;
- }
-
-#if defined(HAVE_PRI)
- if ((dahdi_sig_pri_lib_handles(p0->sig)
- && ((struct sig_pri_chan *) p0->sig_pvt)->no_b_channel)
- || (dahdi_sig_pri_lib_handles(p1->sig)
- && ((struct sig_pri_chan *) p1->sig_pvt)->no_b_channel)) {
- /*
- * PRI nobch channels (hold and call waiting) are equivalent to
- * pseudo channels and cannot be done here.
- */
- ast_mutex_unlock(&p0->lock);
- ast_mutex_unlock(&p1->lock);
- ast_channel_unlock(c0);
- ast_channel_unlock(c1);
- return AST_BRIDGE_FAILED_NOWARN;
- }
-#endif /* defined(HAVE_PRI) */
-
- if ((oi0 == SUB_REAL) && (oi1 == SUB_REAL)) {
- if (p0->owner && p1->owner) {
- /* If we don't have a call-wait in a 3-way, and we aren't in a 3-way, we can be master */
- if (!p0->subs[SUB_CALLWAIT].inthreeway && !p1->subs[SUB_REAL].inthreeway) {
- master = p0;
- slave = p1;
- inconf = 1;
- } else if (!p1->subs[SUB_CALLWAIT].inthreeway && !p0->subs[SUB_REAL].inthreeway) {
- master = p1;
- slave = p0;
- inconf = 1;
- } else {
- ast_log(LOG_WARNING, "Huh? Both calls are callwaits or 3-ways? That's clever...?\n");
- ast_log(LOG_WARNING, "p0: chan %d/%d/CW%d/3W%d, p1: chan %d/%d/CW%d/3W%d\n",
- p0->channel,
- oi0, (p0->subs[SUB_CALLWAIT].dfd > -1) ? 1 : 0,
- p0->subs[SUB_REAL].inthreeway, p0->channel,
- oi0, (p1->subs[SUB_CALLWAIT].dfd > -1) ? 1 : 0,
- p1->subs[SUB_REAL].inthreeway);
- }
- nothingok = 0;
- }
- } else if ((oi0 == SUB_REAL) && (oi1 == SUB_THREEWAY)) {
- if (p1->subs[SUB_THREEWAY].inthreeway) {
- master = p1;
- slave = p0;
- nothingok = 0;
- }
- } else if ((oi0 == SUB_THREEWAY) && (oi1 == SUB_REAL)) {
- if (p0->subs[SUB_THREEWAY].inthreeway) {
- master = p0;
- slave = p1;
- nothingok = 0;
- }
- } else if ((oi0 == SUB_REAL) && (oi1 == SUB_CALLWAIT)) {
- /* We have a real and a call wait. If we're in a three way call, put us in it, otherwise,
- don't put us in anything */
- if (p1->subs[SUB_CALLWAIT].inthreeway) {
- master = p1;
- slave = p0;
- nothingok = 0;
- }
- } else if ((oi0 == SUB_CALLWAIT) && (oi1 == SUB_REAL)) {
- /* Same as previous */
- if (p0->subs[SUB_CALLWAIT].inthreeway) {
- master = p0;
- slave = p1;
- nothingok = 0;
- }
- }
- ast_debug(1, "master: %d, slave: %d, nothingok: %d\n",
- master ? master->channel : 0, slave ? slave->channel : 0, nothingok);
- if (master && slave) {
- /* Stop any tones, or play ringtone as appropriate. If they're bridged
- in an active threeway call with a channel that is ringing, we should
- indicate ringing. */
- if ((oi1 == SUB_THREEWAY) &&
- p1->subs[SUB_THREEWAY].inthreeway &&
- p1->subs[SUB_REAL].owner &&
- p1->subs[SUB_REAL].inthreeway &&
- (ast_channel_state(p1->subs[SUB_REAL].owner) == AST_STATE_RINGING)) {
- ast_debug(1,
- "Playing ringback on %d/%d(%s) since %d/%d(%s) is in a ringing three-way\n",
- p0->channel, oi0, ast_channel_name(c0), p1->channel, oi1, ast_channel_name(c1));
- tone_zone_play_tone(p0->subs[oi0].dfd, DAHDI_TONE_RINGTONE);
- os1 = ast_channel_state(p1->subs[SUB_REAL].owner);
- } else {
- ast_debug(1, "Stopping tones on %d/%d(%s) talking to %d/%d(%s)\n",
- p0->channel, oi0, ast_channel_name(c0), p1->channel, oi1, ast_channel_name(c1));
- tone_zone_play_tone(p0->subs[oi0].dfd, -1);
- }
- if ((oi0 == SUB_THREEWAY) &&
- p0->subs[SUB_THREEWAY].inthreeway &&
- p0->subs[SUB_REAL].owner &&
- p0->subs[SUB_REAL].inthreeway &&
- (ast_channel_state(p0->subs[SUB_REAL].owner) == AST_STATE_RINGING)) {
- ast_debug(1,
- "Playing ringback on %d/%d(%s) since %d/%d(%s) is in a ringing three-way\n",
- p1->channel, oi1, ast_channel_name(c1), p0->channel, oi0, ast_channel_name(c0));
- tone_zone_play_tone(p1->subs[oi1].dfd, DAHDI_TONE_RINGTONE);
- os0 = ast_channel_state(p0->subs[SUB_REAL].owner);
- } else {
- ast_debug(1, "Stopping tones on %d/%d(%s) talking to %d/%d(%s)\n",
- p1->channel, oi1, ast_channel_name(c1), p0->channel, oi0, ast_channel_name(c0));
- tone_zone_play_tone(p1->subs[oi1].dfd, -1);
- }
- if ((oi0 == SUB_REAL) && (oi1 == SUB_REAL)) {
- if (!p0->echocanbridged || !p1->echocanbridged) {
- /* Disable echo cancellation if appropriate */
- dahdi_disable_ec(p0);
- dahdi_disable_ec(p1);
- }
- }
- dahdi_link(slave, master);
- master->inconference = inconf;
- } else if (!nothingok)
- ast_log(LOG_WARNING, "Can't link %d/%s with %d/%s\n", p0->channel, subnames[oi0], p1->channel, subnames[oi1]);
-
- update_conf(p0);
- update_conf(p1);
- t0 = p0->subs[SUB_REAL].inthreeway;
- t1 = p1->subs[SUB_REAL].inthreeway;
-
- ast_mutex_unlock(&p0->lock);
- ast_mutex_unlock(&p1->lock);
-
- ast_channel_unlock(c0);
- ast_channel_unlock(c1);
-
- /* Native bridge failed */
- if ((!master || !slave) && !nothingok) {
- dahdi_enable_ec(p0);
- dahdi_enable_ec(p1);
- return AST_BRIDGE_FAILED;
- }
-
- ast_verb(3, "Native bridging %s and %s\n", ast_channel_name(c0), ast_channel_name(c1));
-
- if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0) && (oi0 == SUB_REAL))
- disable_dtmf_detect(op0);
-
- if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1) && (oi1 == SUB_REAL))
- disable_dtmf_detect(op1);
-
- for (;;) {
- struct ast_channel *c0_priority[2] = {c0, c1};
- struct ast_channel *c1_priority[2] = {c1, c0};
- int ms;
-
- /* Here's our main loop... Start by locking things, looking for private parts,
- and then balking if anything is wrong */
-
- ast_channel_lock_both(c0, c1);
-
- p0 = ast_channel_tech_pvt(c0);
- p1 = ast_channel_tech_pvt(c1);
-
- if (op0 == p0)
- i0 = dahdi_get_index(c0, p0, 1);
- if (op1 == p1)
- i1 = dahdi_get_index(c1, p1, 1);
-
- ast_channel_unlock(c0);
- ast_channel_unlock(c1);
- ms = ast_remaining_ms(start, timeoutms);
- if (!ms ||
- (op0 != p0) ||
- (op1 != p1) ||
- (ofd0 != ast_channel_fd(c0, 0)) ||
- (ofd1 != ast_channel_fd(c1, 0)) ||
- (p0->subs[SUB_REAL].owner && (os0 > -1) && (os0 != ast_channel_state(p0->subs[SUB_REAL].owner))) ||
- (p1->subs[SUB_REAL].owner && (os1 > -1) && (os1 != ast_channel_state(p1->subs[SUB_REAL].owner))) ||
- (oc0 != p0->owner) ||
- (oc1 != p1->owner) ||
- (t0 != p0->subs[SUB_REAL].inthreeway) ||
- (t1 != p1->subs[SUB_REAL].inthreeway) ||
- (oi0 != i0) ||
- (oi1 != i1)) {
- ast_debug(1, "Something changed out on %d/%d to %d/%d, returning -3 to restart\n",
- op0->channel, oi0, op1->channel, oi1);
- res = AST_BRIDGE_RETRY;
- goto return_from_bridge;
- }
-
-#ifdef PRI_2BCT
- if (!triedtopribridge) {
- triedtopribridge = 1;
- if (p0->pri && p0->pri == p1->pri && p0->pri->transfer) {
- ast_mutex_lock(&p0->pri->lock);
- switch (p0->sig) {
- case SIG_PRI_LIB_HANDLE_CASES:
- q931c0 = ((struct sig_pri_chan *) (p0->sig_pvt))->call;
- break;
- default:
- q931c0 = NULL;
- break;
- }
- switch (p1->sig) {
- case SIG_PRI_LIB_HANDLE_CASES:
- q931c1 = ((struct sig_pri_chan *) (p1->sig_pvt))->call;
- break;
- default:
- q931c1 = NULL;
- break;
- }
- if (q931c0 && q931c1) {
- pri_channel_bridge(q931c0, q931c1);
- }
- ast_mutex_unlock(&p0->pri->lock);
- }
- }
-#endif
-
- who = ast_waitfor_n(priority ? c0_priority : c1_priority, 2, &ms);
- if (!who) {
- ast_debug(1, "Ooh, empty read...\n");
- continue;
- }
- f = ast_read(who);
- switch (f ? f->frametype : AST_FRAME_CONTROL) {
- case AST_FRAME_CONTROL:
- if (f && f->subclass.integer == AST_CONTROL_PVT_CAUSE_CODE) {
- ast_channel_hangupcause_hash_set((who == c0) ? c1 : c0, f->data.ptr, f->datalen);
- break;
- }
- *fo = f;
- *rc = who;
- res = AST_BRIDGE_COMPLETE;
- goto return_from_bridge;
- case AST_FRAME_DTMF_END:
- if ((who == c0) && p0->pulsedial) {
- ast_write(c1, f);
- } else if ((who == c1) && p1->pulsedial) {
- ast_write(c0, f);
- } else {
- *fo = f;
- *rc = who;
- res = AST_BRIDGE_COMPLETE;
- goto return_from_bridge;
- }
- break;
- case AST_FRAME_TEXT:
- if (who == c0) {
- ast_write(c1, f);
- } else {
- ast_write(c0, f);
- }
- break;
- case AST_FRAME_VOICE:
- /* Native bridge handles voice frames in hardware. */
- case AST_FRAME_NULL:
- break;
- default:
- ast_debug(1, "Chan '%s' is discarding frame of frametype:%d\n",
- ast_channel_name(who), f->frametype);
- break;
- }
- ast_frfree(f);
-
- /* Swap who gets priority */
- priority = !priority;
- }
-
-return_from_bridge:
- if (op0 == p0)
- dahdi_enable_ec(p0);
-
- if (op1 == p1)
- dahdi_enable_ec(p1);
-
- if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0) && (oi0 == SUB_REAL))
- enable_dtmf_detect(op0);
-
- if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1) && (oi1 == SUB_REAL))
- enable_dtmf_detect(op1);
-
- dahdi_unlink(slave, master, 1);
-
- return res;
-}
-
static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
{
struct dahdi_pvt *p = ast_channel_tech_pvt(newchan);
@@ -17407,6 +16298,8 @@ static int __unload_module(void)
#endif /* defined(HAVE_SS7) */
ast_cond_destroy(&ss_thread_complete);
+ dahdi_native_unload();
+
dahdi_tech.capabilities = ast_format_cap_destroy(dahdi_tech.capabilities);
STASIS_MESSAGE_TYPE_CLEANUP(dahdichannel_type);
return 0;
@@ -19420,6 +18313,10 @@ static int load_module(void)
ast_format_cap_add(dahdi_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
ast_format_cap_add(dahdi_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0));
+ if (dahdi_native_load(ast_module_info->self, &dahdi_tech)) {
+ return AST_MODULE_LOAD_FAILURE;
+ }
+
#ifdef HAVE_PRI
memset(pris, 0, sizeof(pris));
for (y = 0; y < NUM_SPANS; y++) {
@@ -19640,5 +18537,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, tdesc,
.unload = unload_module,
.reload = reload,
.load_pri = AST_MODPRI_CHANNEL_DRIVER,
- .nonoptreq = "res_smdi",
+ .nonoptreq = "res_smdi",
);
diff --git a/channels/chan_dahdi.h b/channels/chan_dahdi.h
new file mode 100644
index 000000000..69c20db2c
--- /dev/null
+++ b/channels/chan_dahdi.h
@@ -0,0 +1,808 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013 Digium, Inc.
+ *
+ * Richard Mudgett <rmudgett@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief DAHDI internal API definitions.
+ *
+ * \author Richard Mudgett <rmudgett@digium.com>
+ *
+ * See Also:
+ * \arg \ref AstCREDITS
+ */
+
+#ifndef _ASTERISK_CHAN_DAHDI_H
+#define _ASTERISK_CHAN_DAHDI_H
+
+#if defined(HAVE_OPENR2)
+#include <openr2.h>
+#endif /* defined(HAVE_OPENR2) */
+
+#include <dahdi/user.h>
+#include <dahdi/tonezone.h>
+
+#include "asterisk/channel.h"
+#include "asterisk/dsp.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* ------------------------------------------------------------------- */
+
+#if defined(HAVE_PRI)
+struct sig_pri_span;
+#endif /* defined(HAVE_PRI) */
+#if defined(HAVE_SS7)
+struct sig_ss7_linkset;
+#endif /* defined(HAVE_SS7) */
+
+#define SUB_REAL 0 /*!< Active call */
+#define SUB_CALLWAIT 1 /*!< Call-Waiting call on hold */
+#define SUB_THREEWAY 2 /*!< Three-way call */
+
+
+struct distRingData {
+ int ring[3];
+ int range;
+};
+struct ringContextData {
+ char contextData[AST_MAX_CONTEXT];
+};
+struct dahdi_distRings {
+ struct distRingData ringnum[3];
+ struct ringContextData ringContext[3];
+};
+
+
+extern const char * const subnames[];
+
+struct dahdi_subchannel {
+ int dfd;
+ struct ast_channel *owner;
+ int chan;
+ short buffer[AST_FRIENDLY_OFFSET/2 + READ_SIZE];
+ struct ast_frame f; /*!< One frame for each channel. How did this ever work before? */
+ unsigned int needringing:1;
+ unsigned int needbusy:1;
+ unsigned int needcongestion:1;
+ unsigned int needanswer:1;
+ unsigned int needflash:1;
+ unsigned int needhold:1;
+ unsigned int needunhold:1;
+ unsigned int linear:1;
+ unsigned int inthreeway:1;
+ struct dahdi_confinfo curconf;
+};
+
+#define MAX_SLAVES 4
+
+/* States for sending MWI message
+ * First three states are required for send Ring Pulse Alert Signal
+ */
+typedef enum {
+ MWI_SEND_NULL = 0,
+ MWI_SEND_SA,
+ MWI_SEND_SA_WAIT,
+ MWI_SEND_PAUSE,
+ MWI_SEND_SPILL,
+ MWI_SEND_CLEANUP,
+ MWI_SEND_DONE,
+} mwisend_states;
+
+struct mwisend_info {
+ struct timeval pause;
+ mwisend_states mwisend_current;
+};
+
+/*! Specify the lists dahdi_pvt can be put in. */
+enum DAHDI_IFLIST {
+ DAHDI_IFLIST_NONE, /*!< The dahdi_pvt is not in any list. */
+ DAHDI_IFLIST_MAIN, /*!< The dahdi_pvt is in the main interface list */
+#if defined(HAVE_PRI)
+ DAHDI_IFLIST_NO_B_CHAN, /*!< The dahdi_pvt is in a no B channel interface list */
+#endif /* defined(HAVE_PRI) */
+};
+
+struct dahdi_pvt {
+ ast_mutex_t lock; /*!< Channel private lock. */
+ struct callerid_state *cs;
+ struct ast_channel *owner; /*!< Our current active owner (if applicable) */
+ /*!< Up to three channels can be associated with this call */
+
+ struct dahdi_subchannel sub_unused; /*!< Just a safety precaution */
+ struct dahdi_subchannel subs[3]; /*!< Sub-channels */
+ struct dahdi_confinfo saveconf; /*!< Saved conference info */
+
+ struct dahdi_pvt *slaves[MAX_SLAVES]; /*!< Slave to us (follows our conferencing) */
+ struct dahdi_pvt *master; /*!< Master to us (we follow their conferencing) */
+ int inconference; /*!< If our real should be in the conference */
+
+ int bufsize; /*!< Size of the buffers */
+ int buf_no; /*!< Number of buffers */
+ int buf_policy; /*!< Buffer policy */
+ int faxbuf_no; /*!< Number of Fax buffers */
+ int faxbuf_policy; /*!< Fax buffer policy */
+ int sig; /*!< Signalling style */
+ /*!
+ * \brief Nonzero if the signaling type is sent over a radio.
+ * \note Set to a couple of nonzero values but it is only tested like a boolean.
+ */
+ int radio;
+ int outsigmod; /*!< Outbound Signalling style (modifier) */
+ int oprmode; /*!< "Operator Services" mode */
+ struct dahdi_pvt *oprpeer; /*!< "Operator Services" peer tech_pvt ptr */
+ /*! \brief Amount of gain to increase during caller id */
+ float cid_rxgain;
+ /*! \brief Rx gain set by chan_dahdi.conf */
+ float rxgain;
+ /*! \brief Tx gain set by chan_dahdi.conf */
+ float txgain;
+
+ float txdrc; /*!< Dynamic Range Compression factor. a number between 1 and 6ish */
+ float rxdrc;
+
+ int tonezone; /*!< tone zone for this chan, or -1 for default */
+ enum DAHDI_IFLIST which_iflist; /*!< Which interface list is this structure listed? */
+ struct dahdi_pvt *next; /*!< Next channel in list */
+ struct dahdi_pvt *prev; /*!< Prev channel in list */
+
+ /* flags */
+
+ /*!
+ * \brief TRUE if ADSI (Analog Display Services Interface) available
+ * \note Set from the "adsi" value read in from chan_dahdi.conf
+ */
+ unsigned int adsi:1;
+ /*!
+ * \brief TRUE if we can use a polarity reversal to mark when an outgoing
+ * call is answered by the remote party.
+ * \note Set from the "answeronpolarityswitch" value read in from chan_dahdi.conf
+ */
+ unsigned int answeronpolarityswitch:1;
+ /*!
+ * \brief TRUE if busy detection is enabled.
+ * (Listens for the beep-beep busy pattern.)
+ * \note Set from the "busydetect" value read in from chan_dahdi.conf
+ */
+ unsigned int busydetect:1;
+ /*!
+ * \brief TRUE if call return is enabled.
+ * (*69, if your dialplan doesn't catch this first)
+ * \note Set from the "callreturn" value read in from chan_dahdi.conf
+ */
+ unsigned int callreturn:1;
+ /*!
+ * \brief TRUE if busy extensions will hear the call-waiting tone
+ * and can use hook-flash to switch between callers.
+ * \note Can be disabled by dialing *70.
+ * \note Initialized with the "callwaiting" value read in from chan_dahdi.conf
+ */
+ unsigned int callwaiting:1;
+ /*!
+ * \brief TRUE if send caller ID for Call Waiting
+ * \note Set from the "callwaitingcallerid" value read in from chan_dahdi.conf
+ */
+ unsigned int callwaitingcallerid:1;
+ /*!
+ * \brief TRUE if support for call forwarding enabled.
+ * Dial *72 to enable call forwarding.
+ * Dial *73 to disable call forwarding.
+ * \note Set from the "cancallforward" value read in from chan_dahdi.conf
+ */
+ unsigned int cancallforward:1;
+ /*!
+ * \brief TRUE if support for call parking is enabled.
+ * \note Set from the "canpark" value read in from chan_dahdi.conf
+ */
+ unsigned int canpark:1;
+ /*! \brief TRUE if to wait for a DTMF digit to confirm answer */
+ unsigned int confirmanswer:1;
+ /*!
+ * \brief TRUE if the channel is to be destroyed on hangup.
+ * (Used by pseudo channels.)
+ */
+ unsigned int destroy:1;
+ unsigned int didtdd:1; /*!< flag to say its done it once */
+ /*! \brief TRUE if analog type line dialed no digits in Dial() */
+ unsigned int dialednone:1;
+ /*!
+ * \brief TRUE if in the process of dialing digits or sending something.
+ * \note This is used as a receive squelch for ISDN until connected.
+ */
+ unsigned int dialing:1;
+ /*! \brief TRUE if the transfer capability of the call is digital. */
+ unsigned int digital:1;
+ /*! \brief TRUE if Do-Not-Disturb is enabled, present only for non sig_analog */
+ unsigned int dnd:1;
+ /*! \brief XXX BOOLEAN Purpose??? */
+ unsigned int echobreak:1;
+ /*!
+ * \brief TRUE if echo cancellation enabled when bridged.
+ * \note Initialized with the "echocancelwhenbridged" value read in from chan_dahdi.conf
+ * \note Disabled if the echo canceller is not setup.
+ */
+ unsigned int echocanbridged:1;
+ /*! \brief TRUE if echo cancellation is turned on. */
+ unsigned int echocanon:1;
+ /*! \brief TRUE if a fax tone has already been handled. */
+ unsigned int faxhandled:1;
+ /*! TRUE if dynamic faxbuffers are configured for use, default is OFF */
+ unsigned int usefaxbuffers:1;
+ /*! TRUE while buffer configuration override is in use */
+ unsigned int bufferoverrideinuse:1;
+ /*! \brief TRUE if over a radio and dahdi_read() has been called. */
+ unsigned int firstradio:1;
+ /*!
+ * \brief TRUE if the call will be considered "hung up" on a polarity reversal.
+ * \note Set from the "hanguponpolarityswitch" value read in from chan_dahdi.conf
+ */
+ unsigned int hanguponpolarityswitch:1;
+ /*! \brief TRUE if DTMF detection needs to be done by hardware. */
+ unsigned int hardwaredtmf:1;
+ /*!
+ * \brief TRUE if the outgoing caller ID is blocked/hidden.
+ * \note Caller ID can be disabled by dialing *67.
+ * \note Caller ID can be enabled by dialing *82.
+ * \note Initialized with the "hidecallerid" value read in from chan_dahdi.conf
+ */
+ unsigned int hidecallerid:1;
+ /*!
+ * \brief TRUE if hide just the name not the number for legacy PBX use.
+ * \note Only applies to PRI channels.
+ * \note Set from the "hidecalleridname" value read in from chan_dahdi.conf
+ */
+ unsigned int hidecalleridname:1;
+ /*! \brief TRUE if DTMF detection is disabled. */
+ unsigned int ignoredtmf:1;
+ /*!
+ * \brief TRUE if the channel should be answered immediately
+ * without attempting to gather any digits.
+ * \note Set from the "immediate" value read in from chan_dahdi.conf
+ */
+ unsigned int immediate:1;
+ /*! \brief TRUE if in an alarm condition. */
+ unsigned int inalarm:1;
+ /*! \brief TRUE if TDD in MATE mode */
+ unsigned int mate:1;
+ /*! \brief TRUE if we originated the call leg. */
+ unsigned int outgoing:1;
+ /*!
+ * \brief TRUE if busy extensions will hear the call-waiting tone
+ * and can use hook-flash to switch between callers.
+ * \note Set from the "callwaiting" value read in from chan_dahdi.conf
+ */
+ unsigned int permcallwaiting:1;
+ /*!
+ * \brief TRUE if the outgoing caller ID is blocked/restricted/hidden.
+ * \note Set from the "hidecallerid" value read in from chan_dahdi.conf
+ */
+ unsigned int permhidecallerid:1;
+ /*!
+ * \brief TRUE if PRI congestion/busy indications are sent out-of-band.
+ * \note Set from the "priindication" value read in from chan_dahdi.conf
+ */
+ unsigned int priindication_oob:1;
+ /*!
+ * \brief TRUE if PRI B channels are always exclusively selected.
+ * \note Set from the "priexclusive" value read in from chan_dahdi.conf
+ */
+ unsigned int priexclusive:1;
+ /*!
+ * \brief TRUE if we will pulse dial.
+ * \note Set from the "pulsedial" value read in from chan_dahdi.conf
+ */
+ unsigned int pulse:1;
+ /*! \brief TRUE if a pulsed digit was detected. (Pulse dial phone detected) */
+ unsigned int pulsedial:1;
+ unsigned int restartpending:1; /*!< flag to ensure counted only once for restart */
+ /*!
+ * \brief TRUE if caller ID is restricted.
+ * \note Set but not used. Should be deleted. Redundant with permhidecallerid.
+ * \note Set from the "restrictcid" value read in from chan_dahdi.conf
+ */
+ unsigned int restrictcid:1;
+ /*!
+ * \brief TRUE if three way calling is enabled
+ * \note Set from the "threewaycalling" value read in from chan_dahdi.conf
+ */
+ unsigned int threewaycalling:1;
+ /*!
+ * \brief TRUE if call transfer is enabled
+ * \note For FXS ports (either direct analog or over T1/E1):
+ * Support flash-hook call transfer
+ * \note For digital ports using ISDN PRI protocols:
+ * Support switch-side transfer (called 2BCT, RLT or other names)
+ * \note Set from the "transfer" value read in from chan_dahdi.conf
+ */
+ unsigned int transfer:1;
+ /*!
+ * \brief TRUE if caller ID is used on this channel.
+ * \note PRI and SS7 spans will save caller ID from the networking peer.
+ * \note FXS ports will generate the caller ID spill.
+ * \note FXO ports will listen for the caller ID spill.
+ * \note Set from the "usecallerid" value read in from chan_dahdi.conf
+ */
+ unsigned int use_callerid:1;
+ /*!
+ * \brief TRUE if we will use the calling presentation setting
+ * from the Asterisk channel for outgoing calls.
+ * \note Only applies to PRI and SS7 channels.
+ * \note Set from the "usecallingpres" value read in from chan_dahdi.conf
+ */
+ unsigned int use_callingpres:1;
+ /*!
+ * \brief TRUE if distinctive rings are to be detected.
+ * \note For FXO lines
+ * \note Set indirectly from the "usedistinctiveringdetection" value read in from chan_dahdi.conf
+ */
+ unsigned int usedistinctiveringdetection:1;
+ /*!
+ * \brief TRUE if we should use the callerid from incoming call on dahdi transfer.
+ * \note Set from the "useincomingcalleridondahditransfer" value read in from chan_dahdi.conf
+ */
+ unsigned int dahditrcallerid:1;
+ /*!
+ * \brief TRUE if allowed to flash-transfer to busy channels.
+ * \note Set from the "transfertobusy" value read in from chan_dahdi.conf
+ */
+ unsigned int transfertobusy:1;
+ /*!
+ * \brief TRUE if the FXO port monitors for neon type MWI indications from the other end.
+ * \note Set if the "mwimonitor" value read in contains "neon" from chan_dahdi.conf
+ */
+ unsigned int mwimonitor_neon:1;
+ /*!
+ * \brief TRUE if the FXO port monitors for fsk type MWI indications from the other end.
+ * \note Set if the "mwimonitor" value read in contains "fsk" from chan_dahdi.conf
+ */
+ unsigned int mwimonitor_fsk:1;
+ /*!
+ * \brief TRUE if the FXO port monitors for rpas precursor to fsk MWI indications from the other end.
+ * \note RPAS - Ring Pulse Alert Signal
+ * \note Set if the "mwimonitor" value read in contains "rpas" from chan_dahdi.conf
+ */
+ unsigned int mwimonitor_rpas:1;
+ /*! \brief TRUE if an MWI monitor thread is currently active */
+ unsigned int mwimonitoractive:1;
+ /*! \brief TRUE if a MWI message sending thread is active */
+ unsigned int mwisendactive:1;
+ /*!
+ * \brief TRUE if channel is out of reset and ready
+ * \note Set but not used.
+ */
+ unsigned int inservice:1;
+ /*!
+ * \brief TRUE if the channel is locally blocked.
+ * \note Applies to SS7 and MFCR2 channels.
+ */
+ unsigned int locallyblocked:1;
+ /*!
+ * \brief TRUE if the channel is remotely blocked.
+ * \note Applies to SS7 and MFCR2 channels.
+ */
+ unsigned int remotelyblocked:1;
+ /*!
+ * \brief TRUE if the channel alarms will be managed also as Span ones
+ * \note Applies to all channels
+ */
+ unsigned int manages_span_alarms:1;
+
+#if defined(HAVE_PRI)
+ struct sig_pri_span *pri;
+ int logicalspan;
+#endif /* defined(HAVE_PRI) */
+ /*!
+ * \brief TRUE if SMDI (Simplified Message Desk Interface) is enabled
+ * \note Set from the "usesmdi" value read in from chan_dahdi.conf
+ */
+ unsigned int use_smdi:1;
+ struct mwisend_info mwisend_data;
+ /*! \brief The SMDI interface to get SMDI messages from. */
+ struct ast_smdi_interface *smdi_iface;
+
+ /*! \brief Distinctive Ring data */
+ struct dahdi_distRings drings;
+
+ /*!
+ * \brief The configured context for incoming calls.
+ * \note The "context" string read in from chan_dahdi.conf
+ */
+ char context[AST_MAX_CONTEXT];
+ /*!
+ * \brief A description for the channel configuration
+ * \note The "description" string read in from chan_dahdi.conf
+ */
+ char description[32];
+ /*!
+ * \brief Saved context string.
+ */
+ char defcontext[AST_MAX_CONTEXT];
+ /*! \brief Extension to use in the dialplan. */
+ char exten[AST_MAX_EXTENSION];
+ /*!
+ * \brief Language configured for calls.
+ * \note The "language" string read in from chan_dahdi.conf
+ */
+ char language[MAX_LANGUAGE];
+ /*!
+ * \brief The configured music-on-hold class to use for calls.
+ * \note The "musicclass" or "mohinterpret" or "musiconhold" string read in from chan_dahdi.conf
+ */
+ char mohinterpret[MAX_MUSICCLASS];
+ /*!
+ * \brief Suggested music-on-hold class for peer channel to use for calls.
+ * \note The "mohsuggest" string read in from chan_dahdi.conf
+ */
+ char mohsuggest[MAX_MUSICCLASS];
+ char parkinglot[AST_MAX_EXTENSION]; /*!< Parking lot for this channel */
+#if defined(HAVE_PRI) || defined(HAVE_SS7)
+ /*! \brief Automatic Number Identification number (Alternate PRI caller ID number) */
+ char cid_ani[AST_MAX_EXTENSION];
+#endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */
+ /*! \brief Automatic Number Identification code from PRI */
+ int cid_ani2;
+ /*! \brief Caller ID number from an incoming call. */
+ char cid_num[AST_MAX_EXTENSION];
+ /*!
+ * \brief Caller ID tag from incoming call
+ * \note the "cid_tag" string read in from chan_dahdi.conf
+ */
+ char cid_tag[AST_MAX_EXTENSION];
+ /*! \brief Caller ID Q.931 TON/NPI field values. Set by PRI. Zero otherwise. */
+ int cid_ton;
+ /*! \brief Caller ID name from an incoming call. */
+ char cid_name[AST_MAX_EXTENSION];
+ /*! \brief Caller ID subaddress from an incoming call. */
+ char cid_subaddr[AST_MAX_EXTENSION];
+ char *origcid_num; /*!< malloced original callerid */
+ char *origcid_name; /*!< malloced original callerid */
+ /*! \brief Call waiting number. */
+ char callwait_num[AST_MAX_EXTENSION];
+ /*! \brief Call waiting name. */
+ char callwait_name[AST_MAX_EXTENSION];
+ /*! \brief Redirecting Directory Number Information Service (RDNIS) number */
+ char rdnis[AST_MAX_EXTENSION];
+ /*! \brief Dialed Number Identifier */
+ char dnid[AST_MAX_EXTENSION];
+ /*!
+ * \brief Bitmapped groups this belongs to.
+ * \note The "group" bitmapped group string read in from chan_dahdi.conf
+ */
+ ast_group_t group;
+ /*! \brief Default call PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW. */
+ int law_default;
+ /*! \brief Active PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW */
+ int law;
+ int confno; /*!< Our conference */
+ int confusers; /*!< Who is using our conference */
+ int propconfno; /*!< Propagated conference number */
+ /*!
+ * \brief Bitmapped call groups this belongs to.
+ * \note The "callgroup" bitmapped group string read in from chan_dahdi.conf
+ */
+ ast_group_t callgroup;
+ /*!
+ * \brief Bitmapped pickup groups this belongs to.
+ * \note The "pickupgroup" bitmapped group string read in from chan_dahdi.conf
+ */
+ ast_group_t pickupgroup;
+ /*!
+ * \brief Named call groups this belongs to.
+ * \note The "namedcallgroup" string read in from chan_dahdi.conf
+ */
+ struct ast_namedgroups *named_callgroups;
+ /*!
+ * \brief Named pickup groups this belongs to.
+ * \note The "namedpickupgroup" string read in from chan_dahdi.conf
+ */
+ struct ast_namedgroups *named_pickupgroups;
+ /*!
+ * \brief Channel variable list with associated values to set when a channel is created.
+ * \note The "setvar" strings read in from chan_dahdi.conf
+ */
+ struct ast_variable *vars;
+ int channel; /*!< Channel Number */
+ int span; /*!< Span number */
+ time_t guardtime; /*!< Must wait this much time before using for new call */
+ int cid_signalling; /*!< CID signalling type bell202 or v23 */
+ int cid_start; /*!< CID start indicator, polarity or ring or DTMF without warning event */
+ int dtmfcid_holdoff_state; /*!< State indicator that allows for line to settle before checking for dtmf energy */
+ struct timeval dtmfcid_delay; /*!< Time value used for allow line to settle */
+ int callingpres; /*!< The value of calling presentation that we're going to use when placing a PRI call */
+ int callwaitingrepeat; /*!< How many samples to wait before repeating call waiting */
+ int cidcwexpire; /*!< When to stop waiting for CID/CW CAS response (In samples) */
+ int cid_suppress_expire; /*!< How many samples to suppress after a CID spill. */
+ /*! \brief Analog caller ID waveform sample buffer */
+ unsigned char *cidspill;
+ /*! \brief Position in the cidspill buffer to send out next. */
+ int cidpos;
+ /*! \brief Length of the cidspill buffer containing samples. */
+ int cidlen;
+ /*! \brief Ring timeout timer?? */
+ int ringt;
+ /*!
+ * \brief Ring timeout base.
+ * \note Value computed indirectly from "ringtimeout" read in from chan_dahdi.conf
+ */
+ int ringt_base;
+ /*!
+ * \brief Number of most significant digits/characters to strip from the dialed number.
+ * \note Feature is deprecated. Use dialplan logic.
+ * \note The characters are stripped before the PRI TON/NPI prefix
+ * characters are processed.
+ */
+ int stripmsd;
+ /*!
+ * \brief TRUE if Call Waiting (CW) CPE Alert Signal (CAS) is being sent.
+ * \note
+ * After CAS is sent, the call waiting caller id will be sent if the phone
+ * gives a positive reply.
+ */
+ int callwaitcas;
+ /*! \brief Number of call waiting rings. */
+ int callwaitrings;
+ /*! \brief Echo cancel parameters. */
+ struct {
+ struct dahdi_echocanparams head;
+ struct dahdi_echocanparam params[DAHDI_MAX_ECHOCANPARAMS];
+ } echocancel;
+ /*!
+ * \brief Echo training time. 0 = disabled
+ * \note Set from the "echotraining" value read in from chan_dahdi.conf
+ */
+ int echotraining;
+ /*! \brief Filled with 'w'. XXX Purpose?? */
+ char echorest[20];
+ /*!
+ * \brief Number of times to see "busy" tone before hanging up.
+ * \note Set from the "busycount" value read in from chan_dahdi.conf
+ */
+ int busycount;
+ /*!
+ * \brief Busy cadence pattern description.
+ * \note Set from the "busypattern" value read from chan_dahdi.conf
+ */
+ struct ast_dsp_busy_pattern busy_cadence;
+ /*!
+ * \brief Bitmapped call progress detection flags. CALLPROGRESS_xxx values.
+ * \note Bits set from the "callprogress" and "faxdetect" values read in from chan_dahdi.conf
+ */
+ int callprogress;
+ /*!
+ * \brief Number of milliseconds to wait for dialtone.
+ * \note Set from the "waitfordialtone" value read in from chan_dahdi.conf
+ */
+ int waitfordialtone;
+ /*!
+ * \brief Number of frames to watch for dialtone in incoming calls
+ * \note Set from the "dialtone_detect" value read in from chan_dahdi.conf
+ */
+ int dialtone_detect;
+ int dialtone_scanning_time_elapsed; /*!< Amount of audio scanned for dialtone, in frames */
+ struct timeval waitingfordt; /*!< Time we started waiting for dialtone */
+ struct timeval flashtime; /*!< Last flash-hook time */
+ /*! \brief Opaque DSP configuration structure. */
+ struct ast_dsp *dsp;
+ /*! \brief DAHDI dial operation command struct for ioctl() call. */
+ struct dahdi_dialoperation dop;
+ int whichwink; /*!< SIG_FEATDMF_TA Which wink are we on? */
+ /*! \brief Second part of SIG_FEATDMF_TA wink operation. */
+ char finaldial[64];
+ char accountcode[AST_MAX_ACCOUNT_CODE]; /*!< Account code */
+ int amaflags; /*!< AMA Flags */
+ struct tdd_state *tdd; /*!< TDD flag */
+ /*! \brief Accumulated call forwarding number. */
+ char call_forward[AST_MAX_EXTENSION];
+ /*!
+ * \brief Voice mailbox location.
+ * \note Set from the "mailbox" string read in from chan_dahdi.conf
+ */
+ char mailbox[AST_MAX_EXTENSION];
+ /*! \brief Opaque event subscription parameters for message waiting indication support. */
+ struct stasis_subscription *mwi_event_sub;
+ /*! \brief Delayed dialing for E911. Overlap digits for ISDN. */
+ char dialdest[256];
+#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
+ struct dahdi_vmwi_info mwisend_setting; /*!< Which VMWI methods to use */
+ unsigned int mwisend_fsk: 1; /*! Variable for enabling FSK MWI handling in chan_dahdi */
+ unsigned int mwisend_rpas:1; /*! Variable for enabling Ring Pulse Alert before MWI FSK Spill */
+#endif
+ int distinctivering; /*!< Which distinctivering to use */
+ int dtmfrelax; /*!< whether to run in relaxed DTMF mode */
+ /*! \brief Holding place for event injected from outside normal operation. */
+ int fake_event;
+ /*!
+ * \brief Minimal time period (ms) between the answer polarity
+ * switch and hangup polarity switch.
+ */
+ int polarityonanswerdelay;
+ /*! \brief Start delay time if polarityonanswerdelay is nonzero. */
+ struct timeval polaritydelaytv;
+ /*!
+ * \brief Send caller ID on FXS after this many rings. Set to 1 for US.
+ * \note Set from the "sendcalleridafter" value read in from chan_dahdi.conf
+ */
+ int sendcalleridafter;
+ /*! \brief Current line interface polarity. POLARITY_IDLE, POLARITY_REV */
+ int polarity;
+ /*! \brief DSP feature flags: DSP_FEATURE_xxx */
+ int dsp_features;
+#if defined(HAVE_SS7)
+ /*! \brief SS7 control parameters */
+ struct sig_ss7_linkset *ss7;
+#endif /* defined(HAVE_SS7) */
+#if defined(HAVE_OPENR2)
+ struct dahdi_mfcr2 *mfcr2;
+ openr2_chan_t *r2chan;
+ openr2_calling_party_category_t mfcr2_recvd_category;
+ openr2_calling_party_category_t mfcr2_category;
+ int mfcr2_dnis_index;
+ int mfcr2_ani_index;
+ int mfcr2call:1;
+ int mfcr2_answer_pending:1;
+ int mfcr2_charge_calls:1;
+ int mfcr2_allow_collect_calls:1;
+ int mfcr2_forced_release:1;
+ int mfcr2_dnis_matched:1;
+ int mfcr2_call_accepted:1;
+ int mfcr2_accept_on_offer:1;
+ int mfcr2_progress_sent:1;
+#endif /* defined(HAVE_OPENR2) */
+ /*! \brief DTMF digit in progress. 0 when no digit in progress. */
+ char begindigit;
+ /*! \brief TRUE if confrence is muted. */
+ int muting;
+ void *sig_pvt;
+ struct ast_cc_config_params *cc_params;
+ /* DAHDI channel names may differ greatly from the
+ * string that was provided to an app such as Dial. We
+ * need to save the original string passed to dahdi_request
+ * for call completion purposes. This way, we can replicate
+ * the original dialed string later.
+ */
+ char dialstring[AST_CHANNEL_NAME];
+};
+
+
+/* Analog signaling */
+#define SIG_EM DAHDI_SIG_EM
+#define SIG_EMWINK (0x0100000 | DAHDI_SIG_EM)
+#define SIG_FEATD (0x0200000 | DAHDI_SIG_EM)
+#define SIG_FEATDMF (0x0400000 | DAHDI_SIG_EM)
+#define SIG_FEATB (0x0800000 | DAHDI_SIG_EM)
+#define SIG_E911 (0x1000000 | DAHDI_SIG_EM)
+#define SIG_FEATDMF_TA (0x2000000 | DAHDI_SIG_EM)
+#define SIG_FGC_CAMA (0x4000000 | DAHDI_SIG_EM)
+#define SIG_FGC_CAMAMF (0x8000000 | DAHDI_SIG_EM)
+#define SIG_FXSLS DAHDI_SIG_FXSLS
+#define SIG_FXSGS DAHDI_SIG_FXSGS
+#define SIG_FXSKS DAHDI_SIG_FXSKS
+#define SIG_FXOLS DAHDI_SIG_FXOLS
+#define SIG_FXOGS DAHDI_SIG_FXOGS
+#define SIG_FXOKS DAHDI_SIG_FXOKS
+#define SIG_SF DAHDI_SIG_SF
+#define SIG_SFWINK (0x0100000 | DAHDI_SIG_SF)
+#define SIG_SF_FEATD (0x0200000 | DAHDI_SIG_SF)
+#define SIG_SF_FEATDMF (0x0400000 | DAHDI_SIG_SF)
+#define SIG_SF_FEATB (0x0800000 | DAHDI_SIG_SF)
+#define SIG_EM_E1 DAHDI_SIG_EM_E1
+
+/* PRI signaling */
+#define SIG_PRI DAHDI_SIG_CLEAR
+#define SIG_BRI (0x2000000 | DAHDI_SIG_CLEAR)
+#define SIG_BRI_PTMP (0X4000000 | DAHDI_SIG_CLEAR)
+
+/* SS7 signaling */
+#define SIG_SS7 (0x1000000 | DAHDI_SIG_CLEAR)
+
+/* MFC/R2 signaling */
+#define SIG_MFCR2 DAHDI_SIG_CAS
+
+
+#define SIG_PRI_LIB_HANDLE_CASES \
+ SIG_PRI: \
+ case SIG_BRI: \
+ case SIG_BRI_PTMP
+
+/*!
+ * \internal
+ * \brief Determine if sig_pri handles the signaling.
+ * \since 1.8
+ *
+ * \param signaling Signaling to determine if is for sig_pri.
+ *
+ * \return TRUE if the signaling is for sig_pri.
+ */
+static inline int dahdi_sig_pri_lib_handles(int signaling)
+{
+ int handles;
+
+ switch (signaling) {
+ case SIG_PRI_LIB_HANDLE_CASES:
+ handles = 1;
+ break;
+ default:
+ handles = 0;
+ break;
+ }
+
+ return handles;
+}
+
+static inline int analog_lib_handles(int signalling, int radio, int oprmode)
+{
+ switch (signalling) {
+ case SIG_FXOLS:
+ case SIG_FXOGS:
+ case SIG_FXOKS:
+ case SIG_FXSLS:
+ case SIG_FXSGS:
+ case SIG_FXSKS:
+ case SIG_EMWINK:
+ case SIG_EM:
+ case SIG_EM_E1:
+ case SIG_FEATD:
+ case SIG_FEATDMF:
+ case SIG_E911:
+ case SIG_FGC_CAMA:
+ case SIG_FGC_CAMAMF:
+ case SIG_FEATB:
+ case SIG_SFWINK:
+ case SIG_SF:
+ case SIG_SF_FEATD:
+ case SIG_SF_FEATDMF:
+ case SIG_FEATDMF_TA:
+ case SIG_SF_FEATB:
+ break;
+ default:
+ /* The rest of the function should cover the remainder of signalling types */
+ return 0;
+ }
+
+ if (radio) {
+ return 0;
+ }
+
+ if (oprmode) {
+ return 0;
+ }
+
+ return 1;
+}
+
+#define dahdi_get_index(ast, p, nullok) _dahdi_get_index(ast, p, nullok, __PRETTY_FUNCTION__, __LINE__)
+int _dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok, const char *fname, unsigned long line);
+
+void disable_dtmf_detect(struct dahdi_pvt *p);
+void enable_dtmf_detect(struct dahdi_pvt *p);
+
+void dahdi_enable_ec(struct dahdi_pvt *p);
+void dahdi_disable_ec(struct dahdi_pvt *p);
+
+void update_conf(struct dahdi_pvt *p);
+void dahdi_link(struct dahdi_pvt *slave, struct dahdi_pvt *master);
+void dahdi_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock);
+
+/* ------------------------------------------------------------------- */
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* _ASTERISK_CHAN_DAHDI_H */
diff --git a/channels/dahdi/bridge_native_dahdi.c b/channels/dahdi/bridge_native_dahdi.c
new file mode 100644
index 000000000..611994f5e
--- /dev/null
+++ b/channels/dahdi/bridge_native_dahdi.c
@@ -0,0 +1,928 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013 Digium, Inc.
+ *
+ * Richard Mudgett <rmudgett@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief Native DAHDI bridging support.
+ *
+ * \author Richard Mudgett <rmudgett@digium.com>
+ *
+ * See Also:
+ * \arg \ref AstCREDITS
+ */
+
+/*** MODULEINFO
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "../sig_analog.h"
+#if defined(HAVE_PRI)
+#include "../sig_pri.h"
+#endif /* defined(HAVE_PRI) */
+#include "../chan_dahdi.h"
+
+#include "asterisk/astobj.h"
+#include "bridge_native_dahdi.h"
+#include "asterisk/bridging.h"
+#include "asterisk/bridging_technology.h"
+#include "asterisk/frame.h"
+
+/* ------------------------------------------------------------------- */
+
+static const struct ast_channel_tech *dahdi_tech;
+
+struct native_pvt_chan {
+ /*! Original private. */
+ struct dahdi_pvt *pvt;
+ /*! Original private owner. */
+ struct ast_channel *owner;
+ /*! Original owner index. */
+ int index;
+ /*! Original file descriptor 0. */
+ int fd0;
+ /*! Original channel state. */
+ int state;
+ /*! Original inthreeway. */
+ unsigned int inthreeway:1;
+};
+
+struct native_pvt_bridge {
+ /*! Master channel in the native bridge. */
+ struct dahdi_pvt *master;
+ /*! Slave channel in the native bridge. */
+ struct dahdi_pvt *slave;
+ /*! TRUE if the bridge can start when ready. */
+ unsigned int saw_start:1;
+ /*! TRUE if the channels are connected in a conference. */
+ unsigned int connected:1;
+#if defined(HAVE_PRI) && defined(PRI_2BCT)
+ /*!
+ * \brief TRUE if tried to eliminate possible PRI tromboned call.
+ *
+ * \note A tromboned call uses two B channels of the same ISDN
+ * span. One leg comes into Asterisk, the other leg goes out of
+ * Asterisk, and Asterisk is natively bridging the two legs.
+ */
+ unsigned int tried_trombone_removal:1;
+#endif /* defined(HAVE_PRI) && defined(PRI_2BCT) */
+};
+
+/*!
+ * \internal
+ * \brief Create a bridge technology instance for a bridge.
+ * \since 12.0.0
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * \note On entry, bridge may or may not already be locked.
+ * However, it can be accessed as if it were locked.
+ */
+static int native_bridge_create(struct ast_bridge *bridge)
+{
+ struct native_pvt_bridge *tech_pvt;
+
+ ast_assert(!bridge->tech_pvt);
+
+ tech_pvt = ast_calloc(1, sizeof(*tech_pvt));
+ if (!tech_pvt) {
+ return -1;
+ }
+
+ bridge->tech_pvt = tech_pvt;
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Destroy a bridging technology instance for a bridge.
+ * \since 12.0.0
+ *
+ * \note On entry, bridge must NOT be locked.
+ */
+static void native_bridge_destroy(struct ast_bridge *bridge)
+{
+ struct native_pvt_bridge *tech_pvt;
+
+ tech_pvt = bridge->tech_pvt;
+ bridge->tech_pvt = NULL;
+ ast_free(tech_pvt);
+}
+
+/*!
+ * \internal
+ * \brief Stop native bridging activity.
+ * \since 12.0.0
+ *
+ * \param bridge What to operate upon.
+ *
+ * \return Nothing
+ *
+ * \note On entry, bridge is already locked.
+ */
+static void native_stop(struct ast_bridge *bridge)
+{
+ struct native_pvt_bridge *bridge_tech_pvt;
+ struct ast_bridge_channel *cur;
+
+ ast_assert(bridge->tech_pvt != NULL);
+
+ AST_LIST_TRAVERSE(&bridge->channels, cur, entry) {
+ struct native_pvt_chan *chan_tech_pvt;
+
+ chan_tech_pvt = cur->tech_pvt;
+ if (!chan_tech_pvt) {
+ continue;
+ }
+
+ ast_mutex_lock(&chan_tech_pvt->pvt->lock);
+ if (chan_tech_pvt->pvt == ast_channel_tech_pvt(cur->chan)) {
+ dahdi_enable_ec(chan_tech_pvt->pvt);
+ }
+ if (chan_tech_pvt->index == SUB_REAL) {
+ enable_dtmf_detect(chan_tech_pvt->pvt);
+ }
+ ast_mutex_unlock(&chan_tech_pvt->pvt->lock);
+ }
+
+ bridge_tech_pvt = bridge->tech_pvt;
+ dahdi_unlink(bridge_tech_pvt->slave, bridge_tech_pvt->master, 1);
+
+ ast_debug(2, "Stop native bridging %s and %s\n",
+ ast_channel_name(AST_LIST_FIRST(&bridge->channels)->chan),
+ ast_channel_name(AST_LIST_LAST(&bridge->channels)->chan));
+}
+
+/*!
+ * \internal
+ * \brief Request to stop native bridging activity.
+ * \since 12.0.0
+ *
+ * \param bridge What to operate upon.
+ *
+ * \return Nothing
+ *
+ * \note On entry, bridge is already locked.
+ */
+static void native_request_stop(struct ast_bridge *bridge)
+{
+ struct native_pvt_bridge *tech_pvt;
+
+ ast_assert(bridge->tech_pvt != NULL);
+
+ tech_pvt = bridge->tech_pvt;
+ if (!tech_pvt->connected) {
+ return;
+ }
+ tech_pvt->connected = 0;
+
+ /* Now to actually stop the bridge. */
+ native_stop(bridge);
+}
+
+/*!
+ * \internal
+ * \brief Start native bridging activity.
+ * \since 12.0.0
+ *
+ * \param bridge What to operate upon.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error. Could not start the bridge.
+ *
+ * \note On entry, bridge may or may not already be locked.
+ * However, it can be accessed as if it were locked.
+ */
+static int native_start(struct ast_bridge *bridge)
+{
+ struct native_pvt_bridge *tech_pvt;
+ struct ast_bridge_channel *bc0;
+ struct ast_bridge_channel *bc1;
+ struct native_pvt_chan *npc0;
+ struct native_pvt_chan *npc1;
+ struct ast_channel *c0;
+ struct ast_channel *c1;
+ struct dahdi_pvt *p0;
+ struct dahdi_pvt *p1;
+ struct dahdi_pvt *master;
+ struct dahdi_pvt *slave;
+ int inconf;
+ int nothing_ok;
+
+ ast_assert(bridge->tech_pvt != NULL);
+
+ bc0 = AST_LIST_FIRST(&bridge->channels);
+ bc1 = AST_LIST_LAST(&bridge->channels);
+ c0 = bc0->chan;
+ c1 = bc1->chan;
+
+ /* Lock channels and privates */
+ for (;;) {
+ ast_channel_lock(c0);
+ if (!ast_channel_trylock(c1)) {
+ p0 = ast_channel_tech_pvt(c0);
+ if (!ast_mutex_trylock(&p0->lock)) {
+ p1 = ast_channel_tech_pvt(c1);
+ if (!ast_mutex_trylock(&p1->lock)) {
+ /* Got all locks */
+ break;
+ }
+ ast_mutex_unlock(&p0->lock);
+ }
+ ast_channel_unlock(c1);
+ }
+ ast_channel_unlock(c0);
+ sched_yield();
+ }
+
+ npc0 = bc0->tech_pvt;
+ ast_assert(npc0 != NULL);
+ npc0->pvt = p0;
+ npc0->owner = p0->owner;
+ npc0->index = dahdi_get_index(c0, p0, 0);
+ npc0->fd0 = ast_channel_fd(c0, 0);
+ npc0->state = -1;
+ npc0->inthreeway = p0->subs[SUB_REAL].inthreeway;
+
+ npc1 = bc1->tech_pvt;
+ ast_assert(npc1 != NULL);
+ npc1->pvt = p1;
+ npc1->owner = p1->owner;
+ npc1->index = dahdi_get_index(c1, p1, 0);
+ npc1->fd0 = ast_channel_fd(c1, 0);
+ npc1->state = -1;
+ npc1->inthreeway = p1->subs[SUB_REAL].inthreeway;
+
+ /*
+ * Check things that can change on the privates while in native
+ * bridging and cause native to not activate.
+ */
+ if (npc0->index < 0 || npc1->index < 0
+#if defined(HAVE_PRI)
+ /*
+ * PRI nobch channels (hold and call waiting) are equivalent to
+ * pseudo channels and cannot be nativly bridged.
+ */
+ || (dahdi_sig_pri_lib_handles(p0->sig)
+ && ((struct sig_pri_chan *) p0->sig_pvt)->no_b_channel)
+ || (dahdi_sig_pri_lib_handles(p1->sig)
+ && ((struct sig_pri_chan *) p1->sig_pvt)->no_b_channel)
+#endif /* defined(HAVE_PRI) */
+ ) {
+ ast_mutex_unlock(&p0->lock);
+ ast_mutex_unlock(&p1->lock);
+ ast_channel_unlock(c0);
+ ast_channel_unlock(c1);
+ return -1;
+ }
+
+ inconf = 0;
+ nothing_ok = 1;
+ master = NULL;
+ slave = NULL;
+ if (npc0->index == SUB_REAL && npc1->index == SUB_REAL) {
+ if (p0->owner && p1->owner) {
+ /*
+ * If we don't have a call-wait in a 3-way, and we aren't in a
+ * 3-way, we can be master.
+ */
+ if (!p0->subs[SUB_CALLWAIT].inthreeway && !p1->subs[SUB_REAL].inthreeway) {
+ master = p0;
+ slave = p1;
+ inconf = 1;
+ } else if (!p1->subs[SUB_CALLWAIT].inthreeway && !p0->subs[SUB_REAL].inthreeway) {
+ master = p1;
+ slave = p0;
+ inconf = 1;
+ } else {
+ ast_log(LOG_WARNING, "Huh? Both calls are callwaits or 3-ways? That's clever...?\n");
+ ast_log(LOG_WARNING, "p0: chan %d/%d/CW%d/3W%d, p1: chan %d/%d/CW%d/3W%d\n",
+ p0->channel,
+ npc0->index, (p0->subs[SUB_CALLWAIT].dfd > -1) ? 1 : 0,
+ p0->subs[SUB_REAL].inthreeway,
+ p0->channel,
+ npc0->index, (p1->subs[SUB_CALLWAIT].dfd > -1) ? 1 : 0,
+ p1->subs[SUB_REAL].inthreeway);
+ }
+ nothing_ok = 0;
+ }
+ } else if (npc0->index == SUB_REAL && npc1->index == SUB_THREEWAY) {
+ if (p1->subs[SUB_THREEWAY].inthreeway) {
+ master = p1;
+ slave = p0;
+ nothing_ok = 0;
+ }
+ } else if (npc0->index == SUB_THREEWAY && npc1->index == SUB_REAL) {
+ if (p0->subs[SUB_THREEWAY].inthreeway) {
+ master = p0;
+ slave = p1;
+ nothing_ok = 0;
+ }
+ } else if (npc0->index == SUB_REAL && npc1->index == SUB_CALLWAIT) {
+ /*
+ * We have a real and a call wait. If we're in a three way
+ * call, put us in it, otherwise, don't put us in anything.
+ */
+ if (p1->subs[SUB_CALLWAIT].inthreeway) {
+ master = p1;
+ slave = p0;
+ nothing_ok = 0;
+ }
+ } else if (npc0->index == SUB_CALLWAIT && npc1->index == SUB_REAL) {
+ /* Same as previous */
+ if (p0->subs[SUB_CALLWAIT].inthreeway) {
+ master = p0;
+ slave = p1;
+ nothing_ok = 0;
+ }
+ }
+ ast_debug(3, "master: %d, slave: %d, nothing_ok: %d\n",
+ master ? master->channel : 0,
+ slave ? slave->channel : 0,
+ nothing_ok);
+ if (master && slave) {
+ /*
+ * Stop any tones, or play ringtone as appropriate. If they are
+ * bridged in an active threeway call with a channel that is
+ * ringing, we should indicate ringing.
+ */
+ if (npc1->index == SUB_THREEWAY
+ && p1->subs[SUB_THREEWAY].inthreeway
+ && p1->subs[SUB_REAL].owner
+ && p1->subs[SUB_REAL].inthreeway
+ && ast_channel_state(p1->subs[SUB_REAL].owner) == AST_STATE_RINGING) {
+ ast_debug(2,
+ "Playing ringback on %d/%d(%s) since %d/%d(%s) is in a ringing three-way\n",
+ p0->channel, npc0->index, ast_channel_name(c0),
+ p1->channel, npc1->index, ast_channel_name(c1));
+ tone_zone_play_tone(p0->subs[npc0->index].dfd, DAHDI_TONE_RINGTONE);
+ npc1->state = ast_channel_state(p1->subs[SUB_REAL].owner);
+ } else {
+ ast_debug(2, "Stopping tones on %d/%d(%s) talking to %d/%d(%s)\n",
+ p0->channel, npc0->index, ast_channel_name(c0),
+ p1->channel, npc1->index, ast_channel_name(c1));
+ tone_zone_play_tone(p0->subs[npc0->index].dfd, -1);
+ }
+
+ if (npc0->index == SUB_THREEWAY
+ && p0->subs[SUB_THREEWAY].inthreeway
+ && p0->subs[SUB_REAL].owner
+ && p0->subs[SUB_REAL].inthreeway
+ && ast_channel_state(p0->subs[SUB_REAL].owner) == AST_STATE_RINGING) {
+ ast_debug(2,
+ "Playing ringback on %d/%d(%s) since %d/%d(%s) is in a ringing three-way\n",
+ p1->channel, npc1->index, ast_channel_name(c1),
+ p0->channel, npc0->index, ast_channel_name(c0));
+ tone_zone_play_tone(p1->subs[npc1->index].dfd, DAHDI_TONE_RINGTONE);
+ npc0->state = ast_channel_state(p0->subs[SUB_REAL].owner);
+ } else {
+ ast_debug(2, "Stopping tones on %d/%d(%s) talking to %d/%d(%s)\n",
+ p1->channel, npc1->index, ast_channel_name(c1),
+ p0->channel, npc0->index, ast_channel_name(c0));
+ tone_zone_play_tone(p1->subs[npc1->index].dfd, -1);
+ }
+
+ if (npc0->index == SUB_REAL && npc1->index == SUB_REAL) {
+ if (!p0->echocanbridged || !p1->echocanbridged) {
+ /* Disable echo cancellation if appropriate */
+ dahdi_disable_ec(p0);
+ dahdi_disable_ec(p1);
+ }
+ }
+ dahdi_link(slave, master);
+ master->inconference = inconf;
+ } else if (!nothing_ok) {
+ ast_log(LOG_WARNING, "Can't link %d/%s with %d/%s\n",
+ p0->channel, subnames[npc0->index],
+ p1->channel, subnames[npc1->index]);
+ }
+ update_conf(p0);
+ update_conf(p1);
+
+ ast_channel_unlock(c0);
+ ast_channel_unlock(c1);
+
+ /* Native bridge failed */
+ if ((!master || !slave) && !nothing_ok) {
+ ast_mutex_unlock(&p0->lock);
+ ast_mutex_unlock(&p1->lock);
+ return -1;
+ }
+
+ if (npc0->index == SUB_REAL) {
+ disable_dtmf_detect(p0);
+ }
+ if (npc1->index == SUB_REAL) {
+ disable_dtmf_detect(p1);
+ }
+
+ ast_mutex_unlock(&p0->lock);
+ ast_mutex_unlock(&p1->lock);
+
+ tech_pvt = bridge->tech_pvt;
+ tech_pvt->master = master;
+ tech_pvt->slave = slave;
+
+ ast_debug(2, "Start native bridging %s and %s\n",
+ ast_channel_name(c0), ast_channel_name(c1));
+
+#if defined(HAVE_PRI) && defined(PRI_2BCT)
+ if (!tech_pvt->tried_trombone_removal) {
+ tech_pvt->tried_trombone_removal = 1;
+
+ if (p0->pri && p0->pri == p1->pri && p0->pri->transfer) {
+ q931_call *q931_c0;
+ q931_call *q931_c1;
+
+ /* Try to eliminate the tromboned call. */
+ ast_mutex_lock(&p0->pri->lock);
+ ast_assert(dahdi_sig_pri_lib_handles(p0->sig));
+ ast_assert(dahdi_sig_pri_lib_handles(p1->sig));
+ q931_c0 = ((struct sig_pri_chan *) (p0->sig_pvt))->call;
+ q931_c1 = ((struct sig_pri_chan *) (p1->sig_pvt))->call;
+ if (q931_c0 && q931_c1) {
+ pri_channel_bridge(q931_c0, q931_c1);
+ ast_debug(2, "Attempt to eliminate tromboned call with %s and %s\n",
+ ast_channel_name(c0), ast_channel_name(c1));
+ }
+ ast_mutex_unlock(&p0->pri->lock);
+ }
+ }
+#endif /* defined(HAVE_PRI) && defined(PRI_2BCT) */
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Request to start native bridging activity.
+ * \since 12.0.0
+ *
+ * \param bridge What to operate upon.
+ *
+ * \return Nothing
+ *
+ * \note On entry, bridge may or may not already be locked.
+ * However, it can be accessed as if it were locked.
+ */
+static void native_request_start(struct ast_bridge *bridge)
+{
+ struct native_pvt_bridge *tech_pvt;
+ struct ast_bridge_channel *cur;
+
+ ast_assert(bridge->tech_pvt != NULL);
+
+ tech_pvt = bridge->tech_pvt;
+
+ if (bridge->num_channels != 2 || !tech_pvt->saw_start || tech_pvt->connected) {
+ return;
+ }
+ AST_LIST_TRAVERSE(&bridge->channels, cur, entry) {
+ if (cur->suspended || !cur->tech_pvt) {
+ return;
+ }
+ }
+
+ /* Actually try starting the native bridge. */
+ if (native_start(bridge)) {
+ return;
+ }
+ tech_pvt->connected = 1;
+}
+
+/*!
+ * \internal
+ * \brief Request a bridge technology instance start operations.
+ * \since 12.0.0
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * \note On entry, bridge may or may not already be locked.
+ * However, it can be accessed as if it were locked.
+ */
+static int native_bridge_start(struct ast_bridge *bridge)
+{
+ struct native_pvt_bridge *tech_pvt;
+
+ ast_assert(bridge->tech_pvt != NULL);
+
+ tech_pvt = bridge->tech_pvt;
+ tech_pvt->saw_start = 1;
+
+ native_request_start(bridge);
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Request a bridge technology instance stop in preparation for being destroyed.
+ * \since 12.0.0
+ *
+ * \note On entry, bridge is already locked.
+ */
+static void native_bridge_stop(struct ast_bridge *bridge)
+{
+ struct native_pvt_bridge *tech_pvt;
+
+ tech_pvt = bridge->tech_pvt;
+ if (!tech_pvt) {
+ return;
+ }
+
+ tech_pvt->saw_start = 0;
+ native_request_stop(bridge);
+}
+
+/*!
+ * \internal
+ * \brief Add a channel to a bridging technology instance for a bridge.
+ * \since 12.0.0
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ *
+ * \note On entry, bridge is already locked.
+ */
+static int native_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+ struct native_pvt_chan *tech_pvt;
+ struct ast_channel *c0;
+ struct ast_channel *c1;
+
+ ast_assert(!bridge_channel->tech_pvt);
+
+ tech_pvt = ast_calloc(1, sizeof(*tech_pvt));
+ if (!tech_pvt) {
+ return -1;
+ }
+
+ bridge_channel->tech_pvt = tech_pvt;
+ native_request_start(bridge);
+
+ c0 = AST_LIST_FIRST(&bridge->channels)->chan;
+ c1 = AST_LIST_LAST(&bridge->channels)->chan;
+ if (c0 != c1) {
+ /*
+ * Make the channels compatible in case the native bridge did
+ * not start for some reason and we need to fallback to 1-1
+ * bridging.
+ */
+ ast_channel_make_compatible(c0, c1);
+ }
+
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Remove a channel from a bridging technology instance for a bridge.
+ * \since 12.0.0
+ *
+ * \note On entry, bridge is already locked.
+ */
+static void native_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+ struct native_pvt_chan *tech_pvt;
+
+ native_request_stop(bridge);
+
+ tech_pvt = bridge_channel->tech_pvt;
+ bridge_channel->tech_pvt = NULL;
+ ast_free(tech_pvt);
+}
+
+/*!
+ * \internal
+ * \brief Suspend a channel on a bridging technology instance for a bridge.
+ * \since 12.0.0
+ *
+ * \note On entry, bridge is already locked.
+ */
+static void native_bridge_suspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+ native_request_stop(bridge);
+}
+
+/*!
+ * \internal
+ * \brief Unsuspend a channel on a bridging technology instance for a bridge.
+ * \since 12.0.0
+ *
+ * \note On entry, bridge is already locked.
+ */
+static void native_bridge_unsuspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
+{
+ native_request_start(bridge);
+}
+
+/*!
+ * \internal
+ * \brief Check if channel is compatible.
+ * \since 12.0.0
+ *
+ * \param bridge_channel Is this channel compatible.
+ *
+ * \retval TRUE if channel is compatible with native DAHDI bridge.
+ */
+static int native_bridge_is_capable(struct ast_bridge_channel *bridge_channel)
+{
+ struct ast_channel *chan = bridge_channel->chan;
+ struct dahdi_pvt *pvt;
+ int is_capable;
+
+ if (ao2_container_count(bridge_channel->features->dtmf_hooks)) {
+ ast_debug(2, "Channel '%s' has DTMF hooks.\n", ast_channel_name(chan));
+ return 0;
+ }
+
+ ast_channel_lock(chan);
+
+ if (dahdi_tech != ast_channel_tech(chan)) {
+ ast_debug(2, "Channel '%s' is not %s.\n",
+ ast_channel_name(chan), dahdi_tech->type);
+ ast_channel_unlock(chan);
+ return 0;
+ }
+ if (ast_channel_has_audio_frame_or_monitor(chan)) {
+ ast_debug(2, "Channel '%s' has an active monitor, audiohook, or framehook.\n",
+ ast_channel_name(chan));
+ ast_channel_unlock(chan);
+ return 0;
+ }
+ pvt = ast_channel_tech_pvt(chan);
+ if (!pvt || !pvt->sig) {
+ /* No private; or signaling is for a pseudo channel. */
+ ast_channel_unlock(chan);
+ return 0;
+ }
+
+ is_capable = 1;
+ ast_mutex_lock(&pvt->lock);
+
+ if (pvt->callwaiting && pvt->callwaitingcallerid) {
+ /*
+ * Call Waiting Caller ID requires DTMF detection to know if it
+ * can send the CID spill.
+ */
+ ast_debug(2, "Channel '%s' has call waiting caller ID enabled.\n",
+ ast_channel_name(chan));
+ is_capable = 0;
+ }
+
+ ast_mutex_unlock(&pvt->lock);
+ ast_channel_unlock(chan);
+
+ return is_capable;
+}
+
+/*!
+ * \internal
+ * \brief Check if a bridge is compatible with the bridging technology.
+ * \since 12.0.0
+ *
+ * \retval 0 if not compatible
+ * \retval non-zero if compatible
+ *
+ * \note On entry, bridge may or may not already be locked.
+ * However, it can be accessed as if it were locked.
+ */
+static int native_bridge_compatible(struct ast_bridge *bridge)
+{
+ struct ast_bridge_channel *cur;
+
+ /* We require two channels before even considering native bridging. */
+ if (bridge->num_channels != 2) {
+ ast_debug(1, "Bridge %s: Cannot use native DAHDI. Must have two channels.\n",
+ bridge->uniqueid);
+ return 0;
+ }
+
+ AST_LIST_TRAVERSE(&bridge->channels, cur, entry) {
+ if (!native_bridge_is_capable(cur)) {
+ ast_debug(1, "Bridge %s: Cannot use native DAHDI. Channel '%s' not compatible.\n",
+ bridge->uniqueid, ast_channel_name(cur->chan));
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+/*!
+ * \internal
+ * \brief Check if something changed on the channel.
+ * \since 12.0.0
+ *
+ * \param bridge_channel What to operate upon.
+ *
+ * \retval 0 Nothing changed.
+ * \retval -1 Something changed.
+ *
+ * \note On entry, bridge_channel->bridge is already locked.
+ */
+static int native_chan_changed(struct ast_bridge_channel *bridge_channel)
+{
+ struct native_pvt_chan *tech_pvt;
+ struct ast_channel *chan;
+ struct dahdi_pvt *pvt;
+ int idx = -1;
+
+ ast_assert(bridge_channel->tech_pvt != NULL);
+
+ tech_pvt = bridge_channel->tech_pvt;
+
+ chan = bridge_channel->chan;
+ ast_channel_lock(chan);
+ pvt = ast_channel_tech_pvt(chan);
+ if (tech_pvt->pvt == pvt) {
+ idx = dahdi_get_index(chan, pvt, 1);
+ }
+ ast_channel_unlock(chan);
+
+ if (/* Did chan get masqueraded or PRI change associated B channel? */
+ tech_pvt->pvt != pvt
+ /* Did the pvt active owner change? */
+ || tech_pvt->owner != pvt->owner
+ /* Did the pvt three way call status change? */
+ || tech_pvt->inthreeway != pvt->subs[SUB_REAL].inthreeway
+ /* Did the owner index change? */
+ || tech_pvt->index != idx
+ /*
+ * Did chan file descriptor change? (This seems redundant with
+ * masquerade and active owner change checks.)
+ */
+ || tech_pvt->fd0 != ast_channel_fd(chan, 0)
+ /* Did chan state change? i.e. Did it stop ringing? */
+ || (pvt->subs[SUB_REAL].owner
+ && tech_pvt->state > -1
+ && tech_pvt->state != ast_channel_state(pvt->subs[SUB_REAL].owner))) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Check if something changed on the bridge channels.
+ * \since 12.0.0
+ *
+ * \param bridge What to operate upon.
+ *
+ * \retval 0 Nothing changed.
+ * \retval -1 Something changed.
+ *
+ * \note On entry, bridge is already locked.
+ */
+static int native_bridge_changed(struct ast_bridge *bridge)
+{
+ struct ast_bridge_channel *cur;
+
+ AST_LIST_TRAVERSE(&bridge->channels, cur, entry) {
+ if (native_chan_changed(cur)) {
+ ast_debug(1, "Bridge %s: Something changed on channel '%s'.\n",
+ bridge->uniqueid, ast_channel_name(cur->chan));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Write a frame into the bridging technology instance for a bridge.
+ * \since 12.0.0
+ *
+ * \note The bridge must be tolerant of bridge_channel being NULL.
+ *
+ * \retval 0 Frame accepted into the bridge.
+ * \retval -1 Frame needs to be deferred.
+ *
+ * \note On entry, bridge is already locked.
+ */
+static int native_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
+{
+ struct native_pvt_bridge *tech_pvt;
+
+ /*
+ * When we are not native bridged by DAHDI, we are like a normal
+ * 1-1 bridge.
+ */
+
+ ast_assert(bridge->tech_pvt != NULL);
+
+ /* Recheck native bridging validity. */
+ tech_pvt = bridge->tech_pvt;
+ switch (frame->frametype) {
+ case AST_FRAME_VOICE:
+ case AST_FRAME_VIDEO:
+ if (!tech_pvt->connected) {
+ /* Don't try to start native mode on media frames. */
+ break;
+ }
+ if (native_bridge_changed(bridge)) {
+ native_request_stop(bridge);
+ native_request_start(bridge);
+ if (!tech_pvt->connected) {
+ break;
+ }
+ }
+
+ /*
+ * Native bridge handles voice frames in hardware. However, it
+ * also passes the frames up to Asterisk anyway. Discard the
+ * media frames.
+ */
+ return 0;
+ default:
+ if (!tech_pvt->connected) {
+ native_request_start(bridge);
+ break;
+ }
+ if (native_bridge_changed(bridge)) {
+ native_request_stop(bridge);
+ native_request_start(bridge);
+ }
+ break;
+ }
+
+ return ast_bridge_queue_everyone_else(bridge, bridge_channel, frame);
+}
+
+static struct ast_bridge_technology native_bridge = {
+ .name = "native_dahdi",
+ .capabilities = AST_BRIDGE_CAPABILITY_NATIVE,
+ .preference = AST_BRIDGE_PREFERENCE_BASE_NATIVE,
+ .create = native_bridge_create,
+ .start = native_bridge_start,
+ .stop = native_bridge_stop,
+ .destroy = native_bridge_destroy,
+ .join = native_bridge_join,
+ .leave = native_bridge_leave,
+ .suspend = native_bridge_suspend,
+ .unsuspend = native_bridge_unsuspend,
+ .compatible = native_bridge_compatible,
+ .write = native_bridge_write,
+};
+
+/*!
+ * \internal
+ * \brief Destroy the DAHDI native bridge support.
+ * \since 12.0.0
+ *
+ * \return Nothing
+ */
+void dahdi_native_unload(void)
+{
+ ast_bridge_technology_unregister(&native_bridge);
+ ast_format_cap_destroy(native_bridge.format_capabilities);
+}
+
+/*!
+ * \internal
+ * \brief Initialize the DAHDI native bridge support.
+ * \since 12.0.0
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int dahdi_native_load(struct ast_module *mod, const struct ast_channel_tech *tech)
+{
+ struct ast_format format;
+
+ dahdi_tech = tech;
+
+ native_bridge.format_capabilities = ast_format_cap_alloc();
+ if (!native_bridge.format_capabilities) {
+ return -1;
+ }
+
+ /*
+ * This is used to make channels compatible with the bridge
+ * itself not with each other.
+ */
+ ast_format_cap_add(native_bridge.format_capabilities, ast_format_set(&format, AST_FORMAT_SLINEAR, 0));
+ ast_format_cap_add(native_bridge.format_capabilities, ast_format_set(&format, AST_FORMAT_ULAW, 0));
+ ast_format_cap_add(native_bridge.format_capabilities, ast_format_set(&format, AST_FORMAT_ALAW, 0));
+
+ return __ast_bridge_technology_register(&native_bridge, mod);
+}
diff --git a/channels/dahdi/bridge_native_dahdi.h b/channels/dahdi/bridge_native_dahdi.h
new file mode 100644
index 000000000..91e8d16b7
--- /dev/null
+++ b/channels/dahdi/bridge_native_dahdi.h
@@ -0,0 +1,47 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013 Digium, Inc.
+ *
+ * Richard Mudgett <rmudgett@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief Native DAHDI bridging support.
+ *
+ * \author Richard Mudgett <rmudgett@digium.com>
+ *
+ * See Also:
+ * \arg \ref AstCREDITS
+ */
+
+#ifndef _ASTERISK_BRIDGE_NATIVE_DAHDI_H
+#define _ASTERISK_BRIDGE_NATIVE_DAHDI_H
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* ------------------------------------------------------------------- */
+
+void dahdi_native_unload(void);
+int dahdi_native_load(struct ast_module *mod, const struct ast_channel_tech *tech);
+
+/* ------------------------------------------------------------------- */
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* _ASTERISK_BRIDGE_NATIVE_DAHDI_H */
diff --git a/main/bridging.c b/main/bridging.c
index 0419ab1a3..132b7d4be 100644
--- a/main/bridging.c
+++ b/main/bridging.c
@@ -375,6 +375,10 @@ int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, st
/* Drop non-deferable frames when suspended. */
return 0;
}
+ if (fr->frametype == AST_FRAME_NULL) {
+ /* "Accept" the frame and discard it. */
+ return 0;
+ }
dup = ast_frdup(fr);
if (!dup) {
@@ -427,6 +431,11 @@ int ast_bridge_queue_everyone_else(struct ast_bridge *bridge, struct ast_bridge_
struct ast_bridge_channel *cur;
int not_written = -1;
+ if (frame->frametype == AST_FRAME_NULL) {
+ /* "Accept" the frame and discard it. */
+ return 0;
+ }
+
AST_LIST_TRAVERSE(&bridge->channels, cur, entry) {
if (cur == bridge_channel) {
continue;
@@ -1243,10 +1252,6 @@ static void bridge_handle_trip(struct ast_bridge_channel *bridge_channel)
return;
}
switch (frame->frametype) {
- case AST_FRAME_NULL:
- /* Just discard it. */
- ast_frfree(frame);
- return;
case AST_FRAME_CONTROL:
switch (frame->subclass.integer) {
case AST_CONTROL_HANGUP: