Current trunk is about to become new release. So lets put it into stable.

This commit is contained in:
MelwareDE 2009-07-23 14:11:08 +00:00
parent 628b685080
commit 28ff6d6cdf
29 changed files with 5421 additions and 424 deletions

85
CHANGES
View File

@ -1,20 +1,45 @@
CHANGES
=======
HEAD
------------------
- fixed buffer length error with internal libcapi debug code.
- performance optimizations, use debug code when needed only.
- added commands for media features supported by Dialogic(R) Diva(R) Media Boards
- added variable CAPI_CIP for full access to all bearer capabilities.
- fixed CAPI 'chat' for using more than 8 controllers.
- fixed CAPI 'chat' for not exceeding maximal size of CAPI message
- add color fax
- add autodetection of fax file format for sendfax command (SFF, CFF JPEG, CFF T.43, TEXT)
- add extension for FAX paper formats and resolutions
- adjust NULL PLCI LI path
- add resource PLCI
- add echocancelpath configuration option
- fixed possible race condition while waiting for DISCONNECT_CONF
- add static half duplex conference
- add dynamic half duplex conference
- add clear channel fax
- add DTMF detection for NULL PLCI
- use direct access to vocoders without RTP framing
- play message to conference and music on hold to caller
- add commands to remove users from chat
- allow to specity the 'ETS 300 102-1' called party number octet 3
chan_capi-1.1.2
------------------
- added config setting 'faxdetecttime' to limit the fax detection for a given amount of seconds.
- added config option for subscriber prefix. Some lines may show local calls without area code
signaled as subscriber-number. Here the complete prefix including area code must be added.
- better counting of active b-channels.
- make capicommand(progress) "early-B3" usable for non NT-mode incoming channels too.
- support early Line-Interconnect (bridge) as soon as both b-channels are up. This bridges b-channels
from beginning of call-establishment, even before calls are connected and the bridge command is received.
Dial() option 'G' is used to activate this feature.
- better counting of active B-channels.
- make capicommand(progress) "early-B3" usable for non NT-mode incoming channels as well.
- support early Line-Interconnect (bridge) as soon as both B-channels are up. This bridges B-channels
from beginning of the call-establishment, even before calls are connected and the bridge command is received.
The dial() option 'G' is used to activate this feature.
- fixed big-endian issue for DATA_B3 messages in internal libcapi code.
- fixed NULL-pointer when no digits are signaled in DID mode.
- adapt to new Asterisk 1.6.1 changes.
- added capicommand to set CAPI application id into an Asterisk dialplan variable.
- added capicommand to set CAPI application ID into an Asterisk dialplan variable.
chan_capi-1.1.1
@ -34,8 +59,8 @@ chan_capi-1.1.0
- adapt to new asterisk 1.6 API
- fixed reading capi profile on big-endian
- increased maximum number of CAPI controllers to 64 (needed for big PBX).
- if immedіate=yes is set in DID mode, accept calls to empty DNID (needed for Austrian lines).
- use own libcapi20 implementation by default (no library for capi is needed any more).
- if immediate=yes is set in DID mode, accept calls to empty DNID (needed for Austrian lines).
- use own libcapi20 implementation by default (no library for CAPI is needed any more).
chan_capi-1.0.2
------------------
@ -43,7 +68,7 @@ chan_capi-1.0.2
- added 'x' option to capicommand(ect) to have real 'explicit call transfer'
(needed by some ISDN lines)
- support CCBS (call completion on busy subscriber)
- added capicommand(chat) for CAPI based MeetMe/Conference using onboard DSPs.
- added capicommand(chat) for CAPI-based MeetMe/Conference using onboard DSPs.
- fixed ton-display in 'show capi channels' on outgoing line.
- fix for 64bit support
- Asterisk 1.4.4 adaptions
@ -55,12 +80,12 @@ chan_capi-1.0.2
chan_capi-1.0.1
------------------
- added qsig caller-name patch by Mario Goegel
- recognise asterisk 1.4.1
- recognize asterisk 1.4.1
- register at CAPI with needed maxLogicalConnections only
- don't send SELECT_B_PROTOCOL more than once
- don't send more DATA_B3 messages than allowed by CAPI_MAX_B3_BLOCKS
- do not send SELECT_B_PROTOCOL more than once
- do not send more DATA_B3 messages than allowed by CAPI_MAX_B3_BLOCKS
- added 'k' option to capi receivefax command for not deleting bad faxes
- added b-channel number to channel name for better identification
- added B-channel number to channel name for better identification
- added variable setting REDIRECTIONNUMBER on outgoing call
- fixed deadlock with ast_async_goto on fax tone detection
- listen to CAPI supplementary information
@ -84,15 +109,15 @@ chan_capi-1.0.0
- Read the channel frames during wait for fax finish.
- Added progress when in faxmode to wakeup asterisk-1.2.
(needed for e.g. auto-hangup on timeout)
- Don't error on invalid controller in capi.conf, just ignore it.
- Do not error on invalid controller in capi.conf, just ignore it.
- Added 3PTY patch by Simon Peter.
- Allow echo-cancel even with old capi configuration bit for
- Allow echo-cancel even with old CAPI configuration bit for
echo-cancel.
- Fix compiler warnings.
- Fixed callerid on incoming call with Asterisk 1.4 (PR#25)
- Remove possible race condition in with hangup and DISCONNECT_IND.
- Rixed gain and echosquelch use according to transfercapability.
- Don't wait for DISCONNECT_B3_CONF in activehangup.
- Do not wait for DISCONNECT_B3_CONF in activehangup.
- Reset PLCI on DISCONNECT_IND to avoid race if asterisk is too slow
with hangup command.
- Added Asterisk 1.4 jitterbuffer usage.
@ -126,7 +151,7 @@ chan_capi-cm-0.6.5
chan_capi-cm-0.6.4
------------------
- don't do echo-squelch or gain if transfercapability is non-voice
- do not do echo-squelch or gain if transfercapability is non-voice
- fix deadlock when changing to fax mode
- better capi message handling
- removed double memset to zero
@ -148,15 +173,15 @@ chan_capi-cm-0.6.2
- set some info variables when receiving fax
- added language support
- prepared devicestate(hint) support
- don't change early-B3 setting on conf error for CONNECT_B3
- do not change early-B3 setting on conf error for CONNECT_B3
- small fixes in Makefile targets (thanks to Karsten Keil)
- don't send audio to local exchange when in TE mode.
- do not send audio to local exchange when in TE-mode.
- fix missing CONF messages when no interface is found
- small transfercap and overlapdial fix
- don't forward DTMF if in NT-mode and the line is not connected yet.
- do not forward DTMF if in NT-mode and the line is not yet connected
- fixed line interconnect
- b-channel handling better
- NT mode progress
- B-channel handling better
- NT-mode progress
- removed deadlock in faxreceive.
- initialize variable ocid
- correct use of timeoutms in native bridge
@ -173,26 +198,26 @@ chan_capi-cm-0.6.1
used if dial option 'd' is specified.
- moved ast_softhangup() out of interface lock
- use correct mutex_init call for interface lock
- when 'o' option is used for overlap dialing, don't send any digits
- when 'o' option is used for overlap dialing, do not send any digits
with the CONNECT_REQ. This gives better progress together with 'b'.
- create a pseudo channel for each interface for incoming signalling
without B-channel.
- added channel locks
- fixed capi init order (thanks to Hans Petter Selasky)
- fixed did handling
- fixed CAPI init order (thanks to Hans Petter Selasky)
- fixed DID handling
- set RDNIS if redirecting number was received.
- simplified call to ast_exists_extension()
- when check for valid extension, check the callerid as well
- changed call-waiting and deflect handling in CONNECT_IND
- use 'immediate' config in MSN mode, if pbx shall be started on
- use 'immediate' config in MSN mode, if PBX shall be started on
CONNECT_IND and shall not wait until SETUP/SENDING-COMPLETE was received.
Since info like REDIRECTINGNUMBER will come after CONNECT_IND, this may
be lost then. But for some drivers/telcos/pbx, this setting is needed.
- fix start of line interconnect in old mode.
- start early-b3 on PROCEEDING too.
- don't send audio data, if in fax receive mode
- do not send audio data, if in fax receive mode
- disconnect on finished fax immediately
- don't run through gain list, if gain is 1.0.
- do not run through gain list, if gain is 1.0.
- use correct A-law idle value.
- removed old example from capi.conf
@ -224,12 +249,12 @@ chan_capi-cm-0.6
- receive a fax via CAPI is now done with capicommand(receivefax|...) and added stationid...
- fixed call-deflection and moved this feature from separate application
to capicommand().
- added config option 'immediate' to start pbx if no dnid has been received yet.
- added config option 'immediate' to start PBX if no dnid has been received yet.
- endian fixes
- compile fixes with newer Asterisk
- update channel name on did changes.
- support 'type of number' (numbering-plan).
- U-Law setting is now done in capi.conf instead of Makefile define.
- u-Law setting is now done in capi.conf instead of Makefile define.
- allow using interface name in Dial().
- on hangup, use hangupcause from other channel or from var PRI_CAUSE.
- improved DID handling on PtP connections.

View File

@ -4,12 +4,12 @@ INSTALL
Modify the Makefile to fit your system, especially the path to the Asterisk
include files.
To build the driver you will need an installed Capi system, including header
To build the driver you will need an installed CAPI system, including header
files.
By default an internal version of libcapi20 is used (you don't need libcapi20 to
be installed on your system). If you don't want this and the installed libcapi20
shall be used, add the option
By default, an internal version of libcapi20 is used (you do not need libcapi20 to
be installed on your system). If you do not want this and the installed libcapi20
should be used, add the option
USE_OWN_LIBCAPI=no
to the 'make' command.

View File

@ -97,7 +97,7 @@ INSTALL=install
SHAREDOS=chan_capi.so
OBJECTS=chan_capi.o chan_capi_utils.o chan_capi_rtp.o xlaw.o \
OBJECTS=chan_capi.o chan_capi_utils.o chan_capi_rtp.o chan_capi_command.o xlaw.o dlist.o \
chan_capi_qsig_core.o chan_capi_qsig_ecma.o chan_capi_qsig_asn197ade.o \
chan_capi_qsig_asn197no.o chan_capi_supplementary.o chan_capi_chat.o

142
README
View File

@ -29,7 +29,7 @@ No support for Asterisk 1.0.x any more, you need at least
Asterisk 1.2.x , 1.4.x or 1.6.x.
Note:
Eicon DIVA Server cards are now named Dialogic(R) Diva(R).
Eicon DIVA Server cards are now named Dialogic(R) Diva(R) Media Boards.
This chan_capi version includes:
=====================================================
@ -44,9 +44,9 @@ This chan_capi version includes:
- Overlap sending (dialtone and additional digits)
- E(xplicit) C(all) T(ransfer) (...although it's done implicit-but don't tell!)
- Use asterisks internal DSP functions for DTMF
- Alaw support
- Ulaw support!
- Dialogic DSP echo cancelation (echocancel=1)
- a-Law support
- u-Law support!
- Dialogic(R) Diva(R) software DSP echo cancellation (echocancel=1)
- Reject call waiting (ACO)
- DID for Point to Point mode (a.k.a overlap receiving)
- Rx/Tx gains using positive linar value (rxgain=1.0, txgain=1.0 means no change)
@ -86,26 +86,26 @@ The Dial string
using '-'. The according interface is found by searching a match with
the 'group' specified in the capi.conf for each interface.
The optional <callerid> followed by an ':' can be used to set a callerid
for this dial() command, without changing the original channel's callerid.
The optional <callerid> followed by an ':' can be used to set a caller ID
for this dial() command, without changing the original channel's caller ID.
'params' is an optional part to set special settings for this call.
The string consists of a list of characters with the following meaning:
'b' : early B3 always.
'B' : early B3 on successful calls only.
'd' : use the default caller id which is set by defaultcid= in capi.conf
'd' : use the default caller ID that is set by defaultcid= in capi.conf
'o' : use overlap sending of number.
(Useful if additional digits shall be send afterwards or together
with 'b' to get dialtone and then send the number, e.g. if otherwise
(Useful if additional digits should be send afterwards or together
with 'b' to get the dialtone and then send the number, e.g., if
no progress tones are available)
's' : activate 'stay-online': don't disconnect CAPI connection on Hangup.
This is needed to give additional commands like CCBS after Hangup.
To really hangup the CAPI connection, use either capicommand(hangup)
's' : activate 'stay-online': do not disconnect CAPI connection on hangup.
This is needed to give additional commands like CCBS after hangup.
To really hang up the CAPI connection, use either capicommand(hangup)
or wait for chan_capi/network timeout (about 20 seconds).
'G' : early Line-Interconnect / bridge: Use Line-Interconnect as soon as
both b-channels are up. Both channels must be of type CAPI and
the incoming call may need 'capicommand(progress)' to enable early-B3
on it as well as dial option 'b' for the outgoing channel.
both B-channels are up. Both channels must be of type the CAPI and
the incoming call may need 'capicommand(progress)' to enable Early B3
on it as well as the dial option 'b' for the outgoing channel.
Before Dial(), the capicommand(peerlink) must be used to signal the
dialed channel its peer.
@ -143,7 +143,7 @@ CAPI command application
========================================
chan_capi provides an additional Asterisk application
capicommand()
With this application, special capi commands and features can be used.
With this application, special CAPI commands and features can be used.
Call Deflection:
Forwards an unanswered call to another number.
@ -151,29 +151,29 @@ Call Deflection:
exten => s,1,capicommand(deflect|12345678)
Fax receive:
Receive a fax using CAPI.
Receives a fax using CAPI.
Example:
exten => s,1,capicommand(receivefax|/tmp/${UNIQUEID}|+49 6137 555123|Asterisk|k)
(more see below)
Fax send:
Send a fax using CAPI.
Sends a fax using CAPI.
Example:
exten => s,1,capicommand(sendfax|/path/to/faxfile.sff|+49 6137 555123|Asterisk)
(more see below)
Enable/Disable echosquelch:
Enable or disable a very primitive echo suppressor.
Disable this before you start recording voicemail or your files may get choppy.
Enables or disable a very primitive echo suppressor.
Disable this option before you start recording voicemail or your files may get choppy.
Example:
exten => s,1,capicommand(echosquelch|yes)
or
exten => s,1,capicommand(echosquelch|no)
Enable/Disable echocancel:
Enable or disable echo-cancel provided by CAPI driver/hardware.
You may need to disable echo-cancel when e.g. data/fax transmission handled
by non-CAPI application. After hangup, this setting is restored to value
Enables or disables echo-cancel provided by CAPI driver/hardware.
You might need to disable echo-cancel when the data/fax transmission is handled
by a non-CAPI application. After hangup, this setting is restored to the value
set in capi.conf.
Example:
exten => s,1,capicommand(echocancel|yes)
@ -181,14 +181,14 @@ Enable/Disable echocancel:
exten => s,1,capicommand(echocancel|no)
Malicious Call Identification:
Report a call of malicious nature.
Reports a call of malicious nature.
Example:
exten => s,1,capicommand(malicious)
Hold:
Puts an answered call on hold, this has nothing to do with asterisk's onhold
thingie (music et al).
An optional parameter is the name of the variable which shall be set with
Puts an answered call on hold, this has nothing to do with Asterisk's onhold
(music et al).
An optional parameter is the name of the variable, which should be set with
the reference ID of the call on hold.
Example:
exten => s,1,capicommand(hold)
@ -196,7 +196,7 @@ Hold:
exten => s,1,capicommand(hold|MYHOLDVAR)
Holdtype:
Set the type of 'hold'. When Asterisk wants to put the call on hold, the specified method
Sets the type of 'hold'. When Asterisk wants to put the call on hold, the specified method
will be used.
Example:
exten => s,1,capicommand(holdtype|local) ;no hold, Asterisk can play MOH
@ -216,7 +216,7 @@ Retrieve:
exten => s,1,capicommand(retrieve|${MYHOLDVAR})
ECT:
Explicit call transfer of the call on hold (must put call on hold first!)
Explicit Call Transfer of the call on hold (must put call on hold first!)
Example:
exten => s,1,capicommand(ect|${MYHOLDVAR})
or
@ -232,7 +232,7 @@ ECT:
instead.
3PTY:
Initiate a Three-Party Conference (must have one call on hold and one active call!).
Initiates a Three-Party Conference (must have one call on hold and one active call!).
Example:
exten => s,1,capicommand(3pty_begin|${MYHOLDVAR})
or
@ -243,23 +243,23 @@ ECT:
exten => s,2,Dial(CAPI/contr1/1234,,M(capi3pty))
Peer link creation:
Create a reference for chan_capi to know who is the calling channel on Dial().
Creates a reference for chan_capi to know who is the calling channel on Dial().
This is needed if you want to use CCBS/CCNR afterwards.
Example:
exten => s,1,capicommand(peerlink)
Hangup in mode 'stay-online':
After hangup in 'stay-online' mode, the line isn't really disconnected
After hangup in 'stay-online' mode, the line is not really disconnected
until timeout or command:
exten => s,1,capicommand(hangup)
This works after capicommand(peerlink) only.
Set local party to 'busy' or 'free':
Set the local phone to status to 'busy' or 'free' when
Sets the local phone to the status 'busy' or 'free' when
awaiting a callback for CCBS/CCNR. If the network wants to
call you back for CCBS/CCNR, chan_capi normaly doesn't know
call you back for CCBS/CCNR, chan_capi normaly does not know
about the status of the extension who started the callback.
By default chan_capi assumes 'free', but you can change that
By default, chan_capi assumes 'free', but you can change that
with:
exten => s,1,capicommand(ccpartybusy|${CCLINKAGEID}|yes)
or
@ -275,7 +275,7 @@ Call completion on subscriber busy (CCBS):
;here you can ask the caller if CCBS shall be activated...
exten => s,4,capicommand(ccbs|${CCLINKAGEID}|<context>|<exten>|<priority>)
exten => s,5,NoOp(${CCBSSTATUS}) ;if CCBS was successfully enabled, it is set to "ACTIVATED".
If the remote party becomes 'non-busy', the network initiates the callback which will be
If the remote party becomes 'non-busy', the network initiates the callback that will be
sent to the provided context/exten/priority. Of course, this only happens if your local
phone is set to 'free' with capicommand(ccpartybusy), which is the default.
In this context/exten/priority you should just setup a callfile to initiate an outgoing
@ -283,27 +283,29 @@ Call completion on subscriber busy (CCBS):
exten => s,1,Dial(CAPI/ccbs/${CCLINKAGEID}/)
Deactivate CCBS:
To deactivate a previously activated CCBS, use following command:
To deactivate a previously activated CCBS, use the following command:
Example:
exten => s,1,capicommand(ccbsstop|${CCLINKAGEID})
Chat (MeetMe/Conference):
If the CAPI card/driver supports it, the caller can be put into a chat-room:
(This uses the DSPs onboard a Dialogic Diva Rev.2 card.)
(This uses the DSPs onboard a Dialogic(R) Diva(R) Rev.2 Media Board.)
exten => s,1,capicommand(chat|<roomname>|<options>|controller)
Example:
exten => s,1,capicommand(chat|salesmeeting|m|1,3-6)
Possible options:
'm' = The first caller will get music-on-hold until second caller arrives.
'o' = The caller is operator
'l' = The caller is listener
Progress / early-B3 on incoming calls:
Activate early-B3 on incoming channels to signal progress tones
Progress / Early-B3 on incoming calls:
Activate Early-B3 on incoming channels to signal progress tones
when in NT-mode or if the Telco-line supports this.
Example:
exten => s,1,capicommand(progress)
Get CAPI application ID:
To store the CAPI application ID in an asterisk dialplan variable, use:
To store the CAPI application ID in an Asterisk dialplan variable, use:
Example:
exten => s,1,capicommand(getid,CAPI_ID)
exten => s,2,NoOp(CAPI appl-id is ${CAPI_ID})
@ -315,7 +317,7 @@ Use the SetCallerPres() application before you dial:
exten => _X.,2,Dial(CAPI/contr1/${EXTEN})
Enjoying early B3 connects (inband call progress, tones and announcements)
Enjoying Early B3 connects (inband call progress, tones and announcements)
==========================================================================
Early B3 is configurable in the dialstring parameters.
If you set a 'b', early B3 will always be used, also if the call fails,
@ -323,7 +325,7 @@ because the number is unprovisioned, etc ...
If you set a 'B', early B3 will only be used on successful calls,
giving you ring indication,etc...
Don't use indications in the Dial command, your local exchange will do that for
Do not use indications in the Dial command, your local exchange will do that for
you:
exten => _X.,1,Dial(CAPI/contr1/${EXTEN}/B,30)
(early B3 on success)
@ -342,14 +344,14 @@ you:
(early B3 on success, fake indicatons if the exchange does not give us
indications)
For normal PBX usage you would use the "b" option, always early B3.
For normal PBX usage, you would use the "b" option, always Early B3.
Overlap sending (a.k.a. real dialtone)
======================================
When you dial an empty number, and have early B3 enabled, with:
When you dial an empty number and have early B3 enabled, with:
Dial(CAPI/g1//b)
The channel will come up at once and give you the dialtone it gets from the
the channel will come up at once and give you the dialtone it gets from the
local exchange.
At this point the channel is like a legacy phone, now you can send DTMF digits
to dial.
@ -365,15 +367,15 @@ exten => 12345678,2,Hangup
Short HOWTO of capicommand(receivefax...) and capicommand(sendfax...):
========================================================================================
For those of you who have a CAPI card with an on-board DSP (like Dialogic Diva),
For those of you who have a CAPI card with an on-board DSP (like Dialogic(R) Diva(R) Media Boards),
this allows you to receive/send faxes.
capicommand(receivefax|<filename>[|<stationid>|<headline>|<options>]):
-------------------------------------------------------------------------
If you want to answer a channel in fax mode, use capicommand(receivefax|...)
instead of Answer()
If you use Answer(), you will be in voice mode. If the hardware DSP detects
fax tone, you can switch from voice to fax mode by calling capicommand(receivefax|...).
instead of Answer(). If you use Answer(), you will be in voice mode.
If the hardware DSP detects fax tone, you can switch from voice to fax mode
by calling capicommand(receivefax|...).
The parameter <filename> is mandatory and the parameters <stationid>,
<headline> and <options> are optional.
By default, if fax reception was not successful, the file is deleted. If you want even
@ -401,7 +403,7 @@ exten => h,1,deadagi,fax.php // Run sfftobmp and mail it.
The output of capicommand(receivefax|...) is a SFF file.
Use sfftobmp to convert it.
With a Dialogic Diva, following features are provided:
With a Dialogic(R) Diva(R) Media Board, the following features are provided:
- fax up to 33600
- high resolution
- Color Fax
@ -434,46 +436,57 @@ CLI command "capi show channels"
This CLI command shows detailed info on all CAPI channels.
Column description:
Line-Name : the name of the interface as defined in capi.conf
NTmode : is the line in NT mode instead fo TE mode
NTmode : is the line in NT-mode instead fo TE-mode
state : the state of the channel, like 'Conn', 'Disc', 'Dial', ...
i/o : incoming or outgoing line
bproto : protocol on CAPI ('fax', 'trans' or 'rtp')
isdnstate : a string which may consists of the following characters
* = PBX is active
G = Line-Interconnect (CAPI bridge) active
B = b-channel is up
b = b-channel is requested
B = B-channel is up
b = B-channel is requested
P = Progress was signaled
H = this line is on hold
T = this line is in transfer (ECT) mode
S = SETUP[_ACK] was signaled
ton : type of number value
number : the caller-number and destination-number
number : the caller number and destination number
Asterisk variables used/set by chan_capi
==========================================================
BCHANNELINFO
On incomming call, this variable is set with the B-channel information value:
On incomming calls, this variable is set with the B-channel information value:
'0' : B-channel is used (default)
'1' : D-channel is used (not implemented yet)
'2' : neither B nor D channel is used (e.g. call waiting)
'2' : neither B nor D-channel is used (e.g., call waiting)
Call-Waiting: an incoming call with BCHANNELINFO not '0' cannot be accepted.
Another connection must be dropped before accepting or use
capicommand(deflect|<number>) to initiate call deflection to another destination.
CALLEDTON
The 'type of number' value of the called number is saved in this variable on
Incoming calls: 'type of number' value of the called number is saved in this variable on
incomming call.
Outgoing calls: Allows to specity the 'ETS 300 102-1' called party number octet 3
(0x80 is used by default)
exten => _X.,1,Answer
exten => _X.,n,Set(_CALLEDTON=${CALLEDTON}) ; Use value of incoming call for outgoing call
exten => _X.,n,Dial(CAPI/ISDN3/100,10)
exten => _X.,1,Answer
exten => _X.,n,Set(_CALLEDTON=1) ; Use new value
exten => _X.,n,Dial(CAPI/ISDN3/100,10)
CALLERTON
The 'type of number' value to overwrite for the caller number on outgoing call.
_CALLERHOLDID
If a call is put on hold (ISDN-HOLD), the reference id is saved in this variable.
If a call is put on hold (ISDN-HOLD), the reference ID is saved in this variable.
This variable is inherited as CALLERHOLDID to the dialed channel and will be used
if e.g. capicommand(ect) is used to transfer the held call.
if e.g., capicommand(ect) is used to transfer the held call.
CALLINGSUBADDRESS
If set on dial(), the calling subaddress will be set to the content.
@ -481,12 +494,17 @@ CALLINGSUBADDRESS
CALLEDSUBADDRESS
If set on dial(), the called subaddress will be set to the content.
CAPI_CIP
The real CIP value, not the transformed 'transfercapability'.
Set on incoming call automatically. If set on outgoing call, it is used
instead of transfercapability.
CCBSSTATUS
When using capicommand(ccbs|....), this variable is set to either "ERROR" or
"ACTIVATED".
CCLINKAGEID
If a Call-Linkage-Id is received for CCBS/CCNR, this variable contains this Id.
If a Call-Linkage-Id is received for CCBS/CCNR, this variable contains this ID.
But you need to use capicommand(peerlink) before dialing a CAPI channel, because
of a design problem in Asterisk, chan_capi is not able to set channel variables
of the calling channel.
@ -503,7 +521,7 @@ PRI_CAUSE
If set, this value will be used as hangup cause on hangup.
REDIRECTINGNUMBER
On incoming call, if the call was redirected to you by someone, the
On incoming calls, if the call was redirected to you by someone, the
number of the redirecting party is saved in this variable.
RDNIS is set as well.

350
README.Diva.fax Normal file
View File

@ -0,0 +1,350 @@
+===================================================================+
| Diva fax support |
+-------------------------------------------------------------------+
| |
| Intelligent fax processing |
| FoIP/VoIP (Fax/Voice over IP) T.38 fax support |
| FoIP/VoIP clear channel fax support |
| Color fax |
| High resolution fax, non standard paper size |
| Use of fax with chan_capi |
| |
+===================================================================+
+-------------------------------------------------------------------+
| INTELLIGENT FAX PROCESSING |
+-------------------------------------------------------------------+
The fax chan_capi command set provides an easy way to access fax-related functionality.
If you use fax document processing, you need to be aware of the following problems,
that might occur:
* It is necessary to maintain a constant data stream between the application and the fax device.
Any interruption in this data stream will affect the quality of the fax document.
* It is necessary to deal with various low-level T.30 protocol settings like scan line time,
compression, error correction, etc.
* Not every application or device supports the command-set features provided by T.30 fax protocol.
This limits the functionality and may require modification of the existing application.
* The usage of fax document compression forces you to deal with compressed data (reception),
or to be able to generate compressed data stream on demand, or to provide documents in different
compression formats (transmission).
* The "classic" fax application is unable to deal with transmission speeds higher than 14400 bps.
To be able use V.34 fax transmission speeds of up to 33600 bps, the application needs to be modified.
This section explains how the Dialogic(R) Diva(R) Media Board can overcome these drawbacks and
allows you to use the chan_capi to process fax documents with a comparable level of reliability and
flexibility as a sophisticated high-level fax API.
Reliable data transfer between application and Dialogic(R) Diva(R) Media Board
------------------------------------------------------------------------------
Dialogic(R) Diva(R) Media Boards provide a high-performance block-oriented IDI (ISDN Direct Interface)
between the board hardware and the host CPU. The data transfer is performed via a BUS master DMA.
This enables a reliable data transfer between the host CPU and the Diva Media Board memory that is not
affected by the host CPU load. At the same time, using the BUS master DMA reduces the host CPU load.
The Dialogic(R) Diva(R) chan_capi/CAPI interface/drivers does not perform data processing. It is only
used to forward the data stream between the application and the IDI interface.
The entire data processing is performed on the RISC CPU of the Diva Media Board.
The reliability of the data stream is ensured by the board hardware through buffering
(up to 64 Kbytes for every channel) and block-oriented data transfer (blocks of up to 2 Kbytes)
via the BUS master DMA.
Automatic T.30 protocol parameter adjustment
--------------------------------------------
The chan_capi can ignore low-level T.30 protocol settings. The T.30 protocol stack that runs on the RISC CPU
of the Dialogic(R) Diva(R) Media Board is able to perform the required adjustment of transmission parameters
to provide reliable and fast document transmission without requiring application intervention.
You can overrule the automatic T.30 protocol parameter adjustment with global fax
configuration options in the Dialogic(R) Diva(R) WEB configuration interface.
ECM (Error Correction Mode) support
-----------------------------------
You can control ECM support via global fax configuration options in the Dialogic(R) Diva(R) WEB configuration interface.
If you use global Diva configuration options to enable ECM support, the Dialogic(R) Diva(R) Media Board will use
ECM mode for document transfer, if supported by the opposite side.
Diva Media Boards use their internal memory to store document data. They retrieve data for ECM re-transmissions
from this internal buffer (up to 64 Kbytes for every channel). This reduces the host CPU load and increases
the reliability of the fax transmission.
Document compression support
----------------------------
Dialogic(R) Diva(R) Media Boards use MR, MMR, T.6 fax document compression. In order to reduce transmission time,
Diva Media Boards select the best compression algorithm supported by the opposite side. The Diva Media Board's
RISC CPU is used to re-compress 1D-coded page data from the application to the format requested by the opposite
side (transmission) and to convert received data to 1D-coded page data that is sent to the application (reception).
The re-compression process is handled internally by the board's RISC CPU and happens fully transparent to the
application that deals only with 1D (MH) coded data.
You can adjust the compression-related T.30 protocol settings via Global fax configuration options.
Automatic detection of document format
--------------------------------------
chan_capi uses the context of the file to determine the format of the document and to apply
all necessary for transmission of the document settings.
Following media formats are detected:
SFF, CFF (Color Fax in JPEG or T.43 format), text file
Diva supports media stream consisting from pages with different media types.
V.34 (33600 bps) fax support
----------------------------
The V.34 fax support can be controlled via global fax configuration options in the Dialogic(R) Diva(R) Configuration
web interface. If the Dialogic(R) Diva(R) Media Board is able to establish a connection with a transmission speed
higher than 14400 bps (V.34), it handles this transparent to the application.
You can use the "divalogd" accounting utility that uses the Diva Media Board Management interface to get
information on the transmission speed and the used compression algorithm.
+-------------------------------------------------------------------+
| FoIP/VoIP (Fax/Voice over IP) T.38 FAX SUPPORT |
+-------------------------------------------------------------------+
You can use the Dialogic(R) Diva(R) softIP software to access T.38 functionality.
There is no need to change your chan_capi configuration. The Dialogic(R) Diva(R) softIP software exposes the
CAPI interface towards chan_capi and the SIP interface towards the IP network.
All T.38 and SIP-related configurations are handled using Diva WEB configuration interface.
This is no limitation of the voice and supplementary services functionality of chan_capi.
You can change the call flow between voice and fax or invoke the supplementary services at the CAPI interface
and the Diva softIP software handles all necessary media and SIP negotiation.
You can use the Diva hardware and the Diva softIP software in parallel on one system.
It is possible to use line interconnect (conferencing) features between the Diva hardware and
The Diva softIP software without any limitations.
You can use the Diva softIP software in virtual environments (VMWare, XEN, ...).
+-------------------------------------------------------------------+
| FoIP/VoIP CLEAR CHANNEL FAX SUPPORT |
+-------------------------------------------------------------------+
Together with the Diva(R) Dialogic(R) hardware you can use the Dialogic(R) Diva(R) softIP software or chan_capi to
access T.38 (only Diva softIP software) and Clear Channel Fax functionality.
If you use the Diva softIP software there is no need to change your chan_capi configuration.
The Dialogic(R) Diva(R) softIP software exposes the CAPI interface towards chan_capi and the SIP interface towards
the IP network. All T.38 and SIP related configurations are handled using the Diva WEB configuration interface.
To activate Clear Channel Fax support, the Diva hardware should be switched in Resource Board mode.
This is no limitation of the voice and supplementory services functionality of chan_capi.
You can change the call flow between voice and fax or invoke the supplementary services at the CAPI interface
and the Diva softIP software will handle all necessary media and SIP negotiation.
You can use the Diva hardware in TDM (E.1/T.1/S0), in Resource Board mode and the Diva softIP software in
parallel on one system. It is possible to use the line interconnect (conferencing) features between the Diva hardware and
the Diva softIP software without any limitations.
If you use chan_capi, then you can use 'resource' command to assign DSP resources to connected
by IP users. Resource PLCI allows to send and to receive fax documents over IP using
Clear Channel fax and to use the DSP resources for processing of IP media and for conferencing.
It is possible to use the line interconnect (conferencing) features between E.1/T.1/S0/PSTN and
IP peers without any limitations.
Both the Diva softIP software and chan_capi allow to use G.729, G.723, iLBC, GSM, and other codecs
supported by the Diva hardware.
You can use the Diva hardware, chan_capi, and Diva softIP software in virtual environments if access by software is supported (XEN).
+-------------------------------------------------------------------+
| COLOR FAX |
+-------------------------------------------------------------------+
The Dialogic (R) Diva(R) hardware and the Dialogic (R) Diva(R) softIP software support color fax and allow to send/receive
fax document using
Continuous tone color and gray-scale mode according to T.4 Annex E using JPEG coding
Lossless color and gray-scale mode according to T.43 using JBIG coding
Color fax documents are processed using CFF.
Each of these data formats starts with a unique pattern:
0x53 0x66 - SFF - First bytes of magic number in SFF document header, CAPI 2.0 Annex B
0xFF 0xD8 - T.4 - Annex E SOI marker
0xFF 0xA8 0 T.43 - Start marker 0xFFA8
It is possible to change between different media types in the time of fax transmission. This
allows to change media between black and white and color for every page.
After completion of transmission or reception of fax CFF (color/greyscale image format)
variable FAXFORMAT is set to 8 (native format, CFF image) and variable FAXCFFFORMAT
provides information about the image format.
+-------------------------------------------------------------------+
| High resolution fax, non standard paper size |
+-------------------------------------------------------------------+
The Dialogic (R) Diva(R) hardware and the Dialogic (R) Diva(R) softIP software provide access to following T.30 features:
Ultra/Super fine resolution
Non standard paper formats
The current COMMON-ISDN-API specification defines paper formats ISO A4, ISO B4, and ISO A3
at standard resolution (R8 x 3.85) and high resolution (R8 x 7.7).
Support for B4 and A3 is optional.
The Dialogic (R) Diva(R) software supports a COMMON-ISDN-API extension that enables FAX document transmission and
reception with paper formats ISO A4, ISO B4, and ISO A3 and the following resolutions as specified in T.30:
R8 x 3.85
R8 x 7.7
R8 x 15.4
R16 x 15.4
200 x 200 dpi
300 x 300 dpi
400 x 400 dpi
300 x 600 dpi
400 x 800 dpi
600 x 1200 dpi
600 x 600 dpi
1200 x 1200 dpi
The page format and resolution information is passed via appropriate fields in the SFF page header.
The Dialogic(R) Diva(R) SFF2TIFF utility provides conversion from SFF to TIFF format for all basic and
extended resolutions and paper formats.
+-------------------------------------------------------------------+
| Use of fax with chan_capi |
+-------------------------------------------------------------------+
Based on information from README
Reception of fax documents
--------------------------
You can use the Dialogic (R) Diva(R) chan_capi configuration to activate fax support ("Fax detection" and "Fax detection time").
The reception of the fax message is started using 'receivefax' capi command:
capicommand(receivefax|<filename>[|<stationid>|<headline>|<options>])
Parameters:
'filename' - Contains the full path and file name for the resulting fax file, mandatory
'stationid' - station ID, optional
'headline' - head line, optional
'options' - fax options, optional
'k' - keep fax document in case of errors (by default document is removed
if fax transmission was not completed with success).
'f' - allow Fine resolution
'u' - activate support for Super/Ultra fine resolutions and paper formats
'j' - enable JPEG coding
'b' - enable T.43 coding
't' - do not use T.85
'e' - do not use ECM
'm' - do not use MMR (T.6) coding
'd' - do not use MR (2D) coding
It is possible to answer the incomming call using 'receivefax' command and start reception of
the fax document directly.
It is possible to answer a call using 'Answer' in voice mode and change to reception (transmission) of the fax by
'receivefax' later, for example after the detection of the fax calling tone or after the user entered a password
using DTMF digits.
Using resource ('resource' command) PLCI allows to receive fax documents over IP using Clear Channel fax.
The 'resource' command allocates one resource PLCI for IP connections only and does not perform any actions for
E.1/T.1/S0/PSTN connections. This allows for safe use of 'resource' command in any context.
Example:
[isdn-in]
exten => _X.,1,Answer() ; Answer in voice mode
exten => _X.,n,Set(TIMEOUT(digit)=5) ; Set Digit Timeout to 5 seconds
exten => _X.,n,Set(TIMEOUT(response)=10) ; Set Response Timeout to 10 seconds
exten => _X.,n,BackGround(jpop) ; Play message and wait until detection of fax calling tone
exten => 124,1,Goto(handle_fax,s,1) ; Extension 124 is dedicated to fax, answer in fax mode
exten => fax,1,Goto(handle_fax,s,1) ; Fax calling tone detected, change to fax mode
exten => i,1,Hangup() ; Received unexpected event
[handle_fax]
exten => s,1,capicommand(receivefax|/tmp/${UNIQUEID}[|<stationid>|<headline>|<options>])
exten => s,2,Hangup()
exten => h,1,deadagi,fax.php ; Run sfftobmp and mail it
Example with Clear Channel fax support:
[handle_fax]
exten => s,1,capicommand(resource|1-4) ; Assign resource PLCI
exten => s,1,capicommand(receivefax|/tmp/${UNIQUEID}[|<stationid>|<headline>|<options>])
exten => s,2,Hangup()
exten => h,1,deadagi,fax.php ; Run sfftobmp and mail it
Transmission of fax documents
-----------------------------
The transmission of the fax message is started using 'sendfax' capi command:
capicommand(sendfax|<filename>[|<stationid>|<headline>|<options>])
Parameters:
'filename' - Contains the full path and file name to be sent, mandatory
sendfax command automatically detects the type of file
using the context of file.
Supported formats:
.sff - SFF file
.txt - text file
.cff - JPEG/T.43 (color/gray tone) coded file
'stationid' - station ID, optional
'headline' - head line, optional
'options' - fax options, optional
'f' - use Fine resolution
'u' - activate support for Super/Ultra fine resolutions and paper formats
't' - do not use T.85
'e' - do not use ECM
'm' - do not use MMR (T.6) coding
'd' - do not use MR (2D) coding
You need to start the call using the 'Dial' command in voice mode and change to transmission (reception)
of the fax by 'sendfax'. Optionally, you can wait until the user entered a password using DTMF digits.
Using resource ('resource' command) PLCI allows to transmit fax documents over IP using Clear Channel fax.
The 'resource' command allocates one resource PLCI for IP connections only and does not perform any actions for
E.1/T.1/S0/PSTN connections. This allows for safe use of 'resource' command in any context.
Example:
[dial_fax]
exten => 1,1,Dial(capi/ISDN1/1234512345,20,G(handle_sendfax,s,1))
[handle_sendfax]
exten => s,1,capicommand(sendfax|/tmp/sendfax001.sff|1234 1234 1234|Outgoing Fax)
exten => s,n,deadagi,faxlog.php ; Log result and schedule restart if necessary
exten => s,n,Hangup
Example with Clear Channel fax support:
[handle_sendfax]
exten => s,1,capicommand(resource|1-4) ; Assign resource PLCI
exten => s,n,capicommand(sendfax|/tmp/sendfax001.sff|1234 1234 1234|Outgoing Fax)
exten => s,n,deadagi,faxlog.php ; Log result and schedule restart if necessary
exten => s,n,Hangup
Results of fax transmission
---------------------------
After chan_capi completed the processing of the 'receivefax' or 'sendfax' commands, following variables are set:
FAXSTATUS - Status of fax transmission
0 - OK
1 - Error
FAXREASON - Value of B3 disconnect reason
FAXREASONTEXT - Decoded text of FAXREASON value
FAXRATE - The baud rate of the fax connection
FAXRESOLUTION - Resolution of received fax message
0 - standard
1 - high
FAXFORMAT - Format of received fax document
0 - SFF (default, description in Annex B)
1 - Plain fax format (modified Huffman coding)
2 - PCX
3 - DCX
4 - TIFF
5 - ASCII
6 - Extended ANSI
7 - Binary-File transfer
8 - Native (CFF
continuous-tone color and gray-scale T.4 Annex E using JPEG coding
lossless color and gray-scale mode according to T.43)
FAXCFFFORMAT - Valid if FAXFORMAT is set to 8 (native)
1 - continuous tone color and gray-scale mode according to T.4 Annex E using JPEG coding
2 - lossless color and gray-scale mode according to T.43 [7] using JBIG coding
FAXPAGES - Number of pages received
FAXID - The ID of the remote fax maschine

172
README.Diva.qsig Normal file
View File

@ -0,0 +1,172 @@
+===================================================================+
| QSIG Abstraction |
+===================================================================+
+-------------------------------------------------------------------+
| QSIG supplementary services |
+-------------------------------------------------------------------+
The QSIG network differentiates between four different types of call transfers,
two unassisted and two assisted.
The type of invoked unassisted call transfer depends on the call state.
The type of assisted call transfers depends on the type of the switching
equipment Dialogic(R) Diva(R) interfaces as well.
The coding of the messages and the type of the transfer invoked, depends
on the QSIG dialect and on the vendor-specific implementation of QSIG dialect.
+-------------------------------------------------------------------+
| QSIG abstraction |
+-------------------------------------------------------------------+
Dialogic(R) Diva(R) System Release Software abstraction allows to write
QSIG applications independent of the used QSIG dialect.
Unassisted call transfer:
The application can use CAPI call deflection. The Diva System Release software
will automatically translate the call deflection request in the appropriate
QSIG primitives. The translation depends on the Diva System Release software
configuration and on the call state.
You can invoke this feature in any call state, but the request may fail in
case the used switching equipment does not support the required service.
Assisted call transfer:
The application can use CAPI Explicit Call Transfer (ECT). The Diva System Release
software will automatically translate ECT in the appropriate QSIG primitive.
The translation depends on the Diva System Release configuration.
+-------------------------------------------------------------------+
| Conclusion |
+-------------------------------------------------------------------+
If reviewed in short form, you can use any ETSI application with QSIG and without
the need to change any code to access QSIG call transfers. There is no need to deal
with details of the underlying network.
The same is true not only for QSIG but for all supported signaling protocols.
The same interface can be used to access basic and supplementary services for
ETSI, QSIG, SS7 ISUP, 5ESS, R2, RBS/CAS, ...
+-------------------------------------------------------------------+
| QSIG path replacement |
+-------------------------------------------------------------------+
There are three parties involved in the path replacement procedure;
The party that initiated the call (party A), the party that initially received and
transferred the call (party B) and the party that finally received the
call after the call transfer (party C).
The goal of the call replacement procedure is to free switching equipment resources
by the replacement of the chain A->B->C with chain A->C.
To achieve this, party B will short cut the D-channel link between A and C and
let A and C exchange D-channel messages. In most cases, party B will short
cut the B-channel between A and C as well and preserve this connection until the path
replacement is complete. If the path replacement will not proceed (not supported, ...),
party B will preserve the D-channel and B-channel interconnections for the entire
duration of the call.
After party B completes the call transfer procedure, one transfer complete message
will be sent (Diva System Release softwre configuration option) and will invoke the path
replacement procedure (Diva System Release configuration option). As part of this procedure,
party A will prepare an alternative resource and send information about this resource over
the D-channel to C through B.
After the information about the alternative resource is received, C will establish a new call
directly from C to A and replace A->B->C by C->A (A->B->C still running in parallel).
After the new connection is established, A and C will establish a new B-channel connection
and will exchange D-channel messages over B and release connections A->B and B->C.
After the release is complete, C->A is preserved during the duration of the call.
The Diva System Release software supports all three parties A, B, and C in the above mentioned
path replacement procedure.
+-------------------------------------------------------------------+
| Support at party A and C endpoints |
+-------------------------------------------------------------------+
The support at A and C endpoints is transparent to the applications.
The Diva System Release software will replace one connection with another in
a fully transparent way to the application.
The data streaming between the application and the bearer resource will not be interrupted
during this operation. Only one notification about the change of the B-channel and
about the completion of the path replacement procedure is provided to the application but
does not require any action from the application (in certain environments
applications will use this notification to issue RESET_B3 REQ and restart the voice
message if any. PBX applications do not need to perform any action).
Please note that party C responds to the call replacement procedure only if the change of the
connection is supported by the underlying protocol. This change is not possible if the fax or
modem session is already in progress. In this case, C will ignore the path replacement and
the chain A->B->C will be preserved for the entire duration of the call.
The same is true if the path replacement procedure fails for any reason.
The M-Board is required to provide the path replacement operation at A and B and it is
responsible for moving the call between different connections transparently for application.
The path replacement can be performed only between Dialogic(R) Diva(R) interfaces
that belong to the same M-Board.
+-------------------------------------------------------------------+
| Support at the party B endpoint |
+-------------------------------------------------------------------+
Party B is the party that uses ECT to perform the assisted QSIG call transfer.
The type of call transfer and the messages sent after the call transfer is completed
are specified by the Diva System Release software configuration. The software detects if
compatible QSIG dialects are used for both parties of ECT and will automatically
establish the D-channel bridge.
The application is responsible to establish the B-channel bridge. The best practice is to
establish the B-channel bridge (using CAPI line interconnect command) before issuing
the CAPI ECT command. The Dialogic(R) Diva(R) CAPI will atomatically maintain the D-channel bridge.
If the M-Board is used at the party B endpoint, it is possible to activate "ECT Emulation".
If active, the M-Board will automatically establish and maintain the B-channel and D-channel bridge
once the ECT command is sent by the application. In this case, there is no need to maintain the B-channel
bridge by the application. The M-Board will maintain all necessary resources until the path
replacement procedure is completed or for the entire duration of the call.
This option is available only for calls that belong to the same M-Board.
+-------------------------------------------------------------------+
| Call state of involved in the ECT calls |
+-------------------------------------------------------------------+
In case of QSIG, it is not necessary to put one of the calls, involved in the ECT, on hold.
Moreover, it is possible to invoke the ECT if the consultation call is in alerted state
(if supported by the switching equipment).
To achieve this, independent from the state of the primary and of the consultation call operation
of the ECT, it is necessary to set the CAPIECTPLCI variable to PLCI (getplci commang provides it in
CAPIPLCI variable) of the primary call before invoking the ECT.
Example: The application accepts one call, creates the consultation call and once the alert is
received, the consultation call starts the playback of message on the first call. After an
additional command is received, the application proceeds with ECT, independent from the state
of the consultation call.
It is even possible to play the message to the first call until the path replacement is completed
and parties A and C are connected directly.
ECT Example:
/////////////////////////////////////////////////////////////////////
[macro-capiect]
; Activate suppressor of ambient noise for consultation call
exten => s,1,capicommand(noisesuppressor|yes)
; Invoke ECT command
exten => s,n,capicommand(ect)
[isdn-in]
; Send progress message on incoming call
exten => 12345,1,Progress()
exten => 12345,n,Set(TIMEOUT(digit)=1) ; Set Digit Timeout to 5 seconds
exten => 12345,n,Set(TIMEOUT(response)=5) ; Set Response Timeout to 10 seconds
; Play message to incoming call using early media mode
exten => 12345,n,Playback(demo-enterkeywords,noanswer,us)
; Accept incoming call
exten => 12345,n,Answer
; Activate suppressor of ambient noises for incoming call
exten => 12345,n,capicommand(noisesuppressor|yes)
; Save PLCI of incoming call to CAPIPLCI variable
exten => 12345,n,capicommand(getplci)
; Set CAPIECTPLCI variable to PLCI of incoming call
; and allow to export this variable to consultation call
exten => 12345,n,Set(_CAPIECTPLCI=${CAPIPLCI})
; Create consultation call and invoke ECT
; ECT procedure will detect CAPIECTPLCI is set and use saved in this variable value
; to identify the ECT party and invoke ECT independent from the state of the primary call
exten => 12345,n,Dial(CAPI/ISDN1/100,10,M(capiect))
exten => 12345,n,Hangup()
/////////////////////////////////////////////////////////////////////

1294
README.media Normal file

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@ QSIG Extension for chan_capi
This program is free software and may be modified and distributed under
the terms of the GNU Public License. There is _NO_ warranty for this!
Thanks go to the debuggers, bugfixers and contributors :)
Thanks go to the debuggers, bugfixers, and contributors :)
===========================================================================
None yet - you will be welcome here :-)
@ -23,22 +23,22 @@ Asterisk 1.2.x , 1.4.x or 1.6.x.
What is Q.SIG
=============
Q.SIG is an protocoll extension for ISDN.
Q.SIG is a protocol extension for ISDN.
It is mainly used on connecting PBXs of different PBX vendors, which allows
better interoperability.
As example there can be a name of an extension transferred between different
PBXs, which is with standard ISDN not possible.
PBXs, which is not possibile with standard ISDN.
These extensions will be transmitted as encoded facility information elements.
To use Q.SIG with asterisk, you'll need a card like Dialogic Diva
(BRI like PRI), which supports QSIG. Maybe others do also work, let me now.
To use Q.SIG with Asterisk, you willll need a card such as a Dialogic(R) Diva(R)
Media Board (BRI like PRI) that supports QSIG. Maybe others do also work, if so, let me now.
The QSIG support includes:
The Q.SIG support includes:
==========================
- Name presentation on Call SETUP incoming like outgoing
- ISDN LEG INFO2 field - a message which delivers informations about call diversions on incoming call to asterisk
- ISDN LEG INFO2 field - a message that delivers information about call diversions on incoming calls to Asterisk
Data is stored in Asterisk variables:
QSIG_LI2_DIVREASON Reason of divertion: 0 - unknown, 1 - unconditional, 2 - user busy, 3 - user no reply
QSIG_LI2_ODIVREASON Reason of original divertion (like above)
@ -50,45 +50,45 @@ The QSIG support includes:
at the moment only incoming handling is supported
- Possibility to inform QSIG switch about call from public network
If you set variable QSIG_SETUP=X then the QSIG switch on the other side will know,
this call source is public network - you will get different ring tone, etc.
- Possibility to inform Q.SIG switch about a call from the public network
If you set the variable QSIG_SETUP=X, then the QSIG switch on the other side will know,
that this call source is the public network - you will get a different ring tone, etc.
In dialplan use: Set(__QSIG_SETUP=X) command.
The leading "__" tells asterisk, to export this variable to the outgoing channel and
The leading "__" tells Asterisk, to export this variable to the outgoing channel and
its subchannels
- Simple Call Transfer
With capicommand(qsig_ct|src-id|dst-id) you can transfer an inbound call back to the qsig switch.
The B-Channel of this call will be relased, so that the line is free for a next call.
Unfortunately the call will be completely released by the switch, if the target is busy.
If you want need to know, if your target is busy, you can use the call transfer feature below.
With capicommand(qsig_ct|src-id|dst-id), you can transfer an inbound call back to the qsig switch.
The B-channel of this call will be relased, so that the line is free for a next call.
Unfortunately, the call will be completely released by the switch if the target is busy.
If you need to know whether your target is busy, you can use the call transfer feature below.
- Call Transfer (outgoing)
You can do an outbound call transfer.
First you need the PLCI (logical channel id) of your first channel. You'll get it with capicommand(qsig_getplci). This
command returns the channel id in the variable QSIG_PLCI. Now you can enable the call transfer feature.
Simply add "Ct<PLCI>" to QSIG_SETUP (i.e. QSIG_SETUP="X/Ct${QSIG_PLCI}" ). On the next dial command the call will
be automatically transferred. The transfer occurs after the CONNECT. If you want an transfer early on ringing you
can use "Ctr<PLCI>". Then the target user will get the infos about the originating user, while his phone is ringing.
First, you need the PLCI (logical channel ID) of your first channel. You can obtain it with capicommand(qsig_getplci). This
command returns the channel ID in the variable QSIG_PLCI. Now, you can enable the call transfer feature.
Simply add "Ct<PLCI>" to QSIG_SETUP (i.e., QSIG_SETUP="X/Ct${QSIG_PLCI}" ). On the next dial command the call will
be automatically transferred. The transfer occurs after the CONNECT. If you want a transfer early on ringing, you
may use "Ctr<PLCI>". Then the target user will get the information about the originating user, while his phone is ringing.
If the external switch offers an path replacement propose, it will be taken automatically in account.
The B-Channels will be cleared by the switch after call connection. Your channels stay free.
The B-channels will be cleared by the switch after the call is conneced. Your channels stay free.
- Automatic Call Transfer and Path Replacement (if allowed/possible) on bridge/line interconnect
If an line interconnect is set up from asterisk, chan_capi sends an Call Transfer facility out and waits for an
If a line interconnect is set up from Asterisk, chan_capi sends an Call Transfer facility out and waits for an
Path Replacement Propose message - if no Path Replacement is received, the line interconnect will proceed.
The Call Transfer allows your connected extensions in every case (if the switch supports the Call Transfer feature)
to see the name and number of his connected peer.
to see the name and number of its connected peer.
This should be configurable in the next release.
- decoding of incoming Call Transfer feature
Enables inbound Path Replacement. If received, an automatic Path Replacement with asterisk internal bridging will be fired.
Enables inbound Path Replacement. If received, an automatic Path Replacement with Asterisk internal bridging will be fired.
- Support for sending CalledName
If in dialplan a variable CALLEDNAME was set, it will be sent out to the switch, while the asterisk extension is ringing.
If in the dialplan a variable CALLEDNAME was set, it will be sent out to the switch, while the Asterisk extension is ringing.
- Support for sending ConnectedName
If in dialplan a variable CONNECTEDNAME was set, it will be sent out to the switch AFTER connection is answered by asterisk
If in the dialplan a variable CONNECTEDNAME was set, it will be sent out to the switch AFTER connection is answered by asterisk
Future Targets:
@ -98,7 +98,7 @@ Future Targets:
- Call Rerouting feature [ECMA-174]
- CCBS
- AOC
- sendtext implementation (e.g. display instructions on the connected set)
- sendtext implementation (e.g., display instructions on the connected set)
- ...
How to use:
@ -110,11 +110,11 @@ Please visit: http://www.melware.org/ChanCapiConf
simply enable Q.SIG with following line in your capi.conf interface:
Simply enable Q.SIG with the following line in your capi.conf interface:
Here we go with new configuration
Set qsig to one of the following values, which corresponds to your configuration.
Set Q.SIG to one of the following values, which corresponds to your configuration.
0 QSIG turned off
1 Alcatel (4400 & Enterprise - Maybe OXO/4200) ECMA (wrongly named ECMA - it is ETSI) variant

View File

@ -23,20 +23,20 @@ language=de ;set default language
[ISDN1] ;this example interface gets name 'ISDN1' and may be any
;name not starting with 'g' or 'contr'.
;Use one interface section for each isdn port!
;ntmode=yes ;if isdn card operates in nt mode, set this to yes
;Use one interface section for each ISDN port!
;ntmode=yes ;if the ISDN card operates in NT-mode, set this to 'yes'
isdnmode=msn ;'MSN' (point-to-multipoint) or 'DID' (direct inward dial)
;when using NT-mode, 'DID' should be set in any case
incomingmsn=* ;allow incoming calls to this list of MSNs/DIDs, * = any
;defaultcid=123 ;set a default caller id to that interface for dial-out,
;this caller id will be used when dial option 'd' is set.
;defaultcid=123 ;set a default caller ID to that interface for dial-out,
;this caller ID will be used when the dial option 'd' is set.
;controller=0 ;ISDN4BSD default
;controller=7 ;ISDN4BSD USB default
controller=1 ;capi controller number of this interface/port
controller=1 ;CAPI controller number of this interface/port
group=1 ;dialout group
;prefix=0 ;set a prefix to calling number on incoming calls
softdtmf=on ;enable/disable software dtmf detection, recommended for AVM cards
relaxdtmf=on ;in addition to softdtmf, you can use relaxed dtmf detection
;prefix=0 ;set a prefix to the calling number on incoming calls
softdtmf=on ;enable/disable software DTMF detection, recommended for AVM cards
relaxdtmf=on ;in addition to softdtmf, you can use relaxed DTMF detection
faxdetect=off ;enable faxdetection and redirection to EXTEN 'fax' for incoming and/or
;outgoing calls. (default='off', possible values: 'incoming','outgoing','both')
faxdetecttime=0 ;Only detect faxes during the first 'n' seconds of the call.
@ -47,15 +47,17 @@ context=isdn-in ;context for incoming calls
;holdtype=hold ;when the PBX puts the call on hold, ISDN HOLD will be used. If
;set to 'local' (default value), no hold is done and the PBX may
;play MOH.
;immediate=yes ;DID: immediate start of pbx with extension 's' if no digits were
;immediate=yes ;DID: immediate start of PBX with extension 's' if no digits were
; received on incoming call (no destination number yet)
;MSN: start pbx on CONNECT_IND and don't wait for SETUP/SENDING-COMPLETE.
;MSN: start PBX on CONNECT_IND and do not wait for SETUP/SENDING-COMPLETE.
; info like REDIRECTINGNUMBER may be lost, but this is necessary for
; drivers/pbx/telco which does not send SETUP or SENDING-COMPLETE.
;echosquelch=1 ;_VERY_PRIMITIVE_ echo suppression. Disable this before you start recording voicemail
;echosquelch=1 ;_VERY_PRIMITIVE_ echo suppression. Disable it before you start recording voicemail
;or your files may get choppy. (you can use capicommand(echosquelch|no) for this)
;echocancel=yes ;Dialogic Diva (Capi) echo cancelation (yes=g165)
;echocancel=yes ;Dialogic(R) Diva(R) (CAPI) echo cancellation (yes=g165)
;(possible values: 'no', 'yes', 'force', 'g164', 'g165')
;echocancelpath=1;Dialogic(R) Diva(R) (CAPI) echo cancellation path
;(possible values: default '1' - E.1/T.1/S0, '2' - IP, '3' - both)
echocancelold=yes;use facility selector 6 instead of correct 8 (necessary for older eicon drivers)
;echotail=64 ;echo cancel tail setting (default=0 for maximum)
;echocancelnlp=1 ;activate non-linear-processing; this improves echo cancel ratio, but might
@ -65,9 +67,9 @@ echocancelold=yes;use facility selector 6 instead of correct 8 (necessary for ol
;pickupgroup=1 ;PBX pickup group (which call groups are we allowed to pickup)
;transfergroup=1 ;Controller(s) where a transfer on native bridge is allowed to.
;language=de ;set language for this device (overwrites default language)
;disallow=all ;RTP codec selection (valid with Dialogic Diva only)
;allow=all ;RTP codec selection (valid with Dialogic Diva only)
devices=2 ;number of concurrent calls (b-channels) on this controller
;disallow=all ;RTP codec selection (valid with Dialogic(R) Diva(R) Media Boards only)
;allow=all ;RTP codec selection (valid with Dialogic(R) Diva(R) Media Boards only)
devices=2 ;number of concurrent calls (B-Channels) on this controller
;(2 makes sense for single BRI, 30/23 for PRI/T1)
;jb..... ;with Asterisk 1.4 you can configure jitterbuffer,
;see Asterisk documentation for all jb* setting available.

File diff suppressed because it is too large Load Diff

View File

@ -40,6 +40,7 @@
#include "asterisk/abstract_jb.h"
#endif
#include "asterisk/musiconhold.h"
#include "dlist.h"
#ifndef _PBX_CAPI_H
#define _PBX_CAPI_H
@ -138,6 +139,7 @@ static inline unsigned int read_capi_dword(void *m)
#define CC_BPROTO_TRANSPARENT 0
#define CC_BPROTO_FAXG3 1
#define CC_BPROTO_RTP 2
#define CC_BPROTO_VOCODER 3
/* FAX Resolutions */
#define FAX_STANDARD_RESOLUTION 0
@ -152,6 +154,7 @@ static inline unsigned int read_capi_dword(void *m)
#define FAX_ASCII_FORMAT 5
#define FAX_EXTENDED_ASCII_FORMAT 6
#define FAX_BINARY_FILE_TRANSFER_FORMAT 7
#define FAX_NATIVE_FILE_TRANSFER_FORMAT 8
/* Fax struct */
struct fax3proto3 {
@ -178,6 +181,7 @@ typedef struct fax3proto3 B3_PROTO_FAXG3;
#define FACILITYSELECTOR_SUPPLEMENTARY 0x0003
#define FACILITYSELECTOR_LINE_INTERCONNECT 0x0005
#define FACILITYSELECTOR_ECHO_CANCEL 0x0008
#define PRIV_SELECTOR_DTMF_ONDATA 0x00fa
#define FACILITYSELECTOR_FAX_OVER_IP 0x00fd
#define FACILITYSELECTOR_VOICE_OVER_IP 0x00fe
@ -191,6 +195,13 @@ typedef struct fax3proto3 B3_PROTO_FAXG3;
#define EC_OPTION_DISABLE_G164_OR_G165 (1<<1 | 1<<2)
#define EC_DEFAULT_TAIL 0 /* maximum */
/*
EC path mask
*/
#define EC_ECHOCANCEL_PATH_IFC 1 /* Default, activate EC for E.1/T.1/S0 only */
#define EC_ECHOCANCEL_PATH_IP 2 /* Activate EC for IP */
#define EC_ECHOCANCEL_PATH_BITS (EC_ECHOCANCEL_PATH_IFC | EC_ECHOCANCEL_PATH_IP)
#define CC_HOLDTYPE_LOCAL 0
#define CC_HOLDTYPE_HOLD 1
#define CC_HOLDTYPE_NOTIFY 2
@ -261,6 +272,10 @@ struct cc_capi_gains {
#define CAPI_CHANNELTYPE_D 1
#define CAPI_CHANNELTYPE_NULL 2
#define CAPI_RESOURCE_PLCI_NULL 0
#define CAPI_RESOURCE_PLCI_DATA 1
#define CAPI_RESOURCE_PLCI_LINE 2
/* the lower word is reserved for capi commands */
#define CAPI_WAITEVENT_B3_UP 0x00010000
#define CAPI_WAITEVENT_B3_DOWN 0x00020000
@ -437,6 +452,21 @@ struct capi_pvt {
float rxmin;
float txmin;
unsigned short divaAudioFlags;
unsigned short divaDigitalRxGain;
float divaDigitalRxGainDB;
unsigned short divaDigitalTxGain;
float divaDigitalTxGainDB;
unsigned short rxPitch;
unsigned short txPitch;
char special_tone_extension[AST_MAX_EXTENSION+1];
char channel_command_digits[AST_MAX_EXTENSION+1];
time_t channel_command_timestamp;
int channel_command_digit;
int command_pass_digits;
diva_entity_queue_t channel_command_q;
#ifdef CC_AST_HAS_VERSION_1_4
struct ast_jb_conf jbconf;
char mohinterpret[MAX_MUSICCLASS];
@ -466,6 +496,14 @@ struct capi_pvt {
/* Q.SIG features */
int qsigfeat;
struct cc_qsig_data qsig_data;
/* Resource PLCI data */
int resource_plci_type; /* NULL PLCI, DATA, LINE */
/* Resource PLCI line if data */
struct capi_pvt *line_plci;
/* Resource PLCI data data if line */
struct capi_pvt *data_plci;
/*! Next channel in list */
struct capi_pvt *next;
@ -528,6 +566,7 @@ struct cc_capi_conf {
struct ast_jb_conf jbconf;
char mohinterpret[MAX_MUSICCLASS];
#endif
int echocancelpath;
};
struct cc_capi_controller {
@ -559,6 +598,9 @@ struct cc_capi_controller {
int CONF;
/* RTP */
int rtpcodec;
int divaExtendedFeaturesAvailable;
int ecPath;
};
@ -630,4 +672,14 @@ extern void capi_gains(struct cc_capi_gains *g, float rxgain, float txgain);
extern char chatinfo_usage[];
#endif
typedef int (*pbx_capi_command_proc_t)(struct ast_channel *, char *);
pbx_capi_command_proc_t pbx_capi_lockup_command_by_name(const char* name);
/* DIVA specific MANUFACTURER definitions */
#define _DI_MANU_ID 0x44444944
#define _DI_ASSIGN_PLCI 0x0001
#define _DI_DSP_CTRL 0x0003
#define _DI_OPTIONS_REQUEST 0x0009
#endif

View File

@ -12,67 +12,136 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <sys/signal.h>
#include "chan_capi_platform.h"
#include "chan_capi20.h"
#include "chan_capi.h"
#include "chan_capi_chat.h"
#include "chan_capi_utils.h"
#include "chan_capi_command.h"
#define CHAT_FLAG_MOH 0x0001
typedef enum {
RoomMemberDefault = 0, /* Rx/Tx by default, muted by operator */
RoomMemberListener = 1, /* Rx only, always muted */
RoomMemberOperator = 2 /* Rx/Tx, newer muted */
} room_member_type_t;
typedef enum {
RoomModeDefault = 0,
RoomModeMuted = 1
} room_mode_t;
#define PLCI_PER_LX_REQUEST 8
#define PBX_CHAT_MEMBER_INFO_RECENT 0x00000001
#define PBX_CHAT_MEMBER_INFO_REMOVE 0x00000002
struct capichat_s {
char name[16];
unsigned int number;
int active;
room_member_type_t room_member_type;
room_mode_t room_mode;
struct capi_pvt *i;
struct capichat_s *next;
unsigned int info;
time_t time;
};
struct _deffered_chat_capi_message;
typedef struct _deffered_chat_capi_message {
int busy;
_cdword datapath;
capi_prestruct_t p_struct;
unsigned char p_list[254];
} deffered_chat_capi_message_t;
static struct capichat_s *chat_list = NULL;
AST_MUTEX_DEFINE_STATIC(chat_lock);
/*
* update the capi mixer for the given char room
* LOCALS
*/
static void update_capi_mixer(int remove, unsigned int roomnumber, struct capi_pvt *i)
static const char* room_member_type_2_name(room_member_type_t room_member_type);
/*
* partial update the capi mixer for the given char room
*/
static struct capichat_s* update_capi_mixer_part(
struct capichat_s *chat_start,
int overall_found,
deffered_chat_capi_message_t* capi_msg,
int remove,
unsigned int roomnumber,
struct capi_pvt *i)
{
struct capi_pvt *ii;
struct capi_pvt *ii, *ii_last = NULL;
struct capichat_s *room;
unsigned char p_list[360];
unsigned char* p_list = &capi_msg->p_list[0];
_cdword dest;
_cdword datapath;
capi_prestruct_t p_struct;
capi_prestruct_t* p_struct = &capi_msg->p_struct;
unsigned int found = 0;
_cword j = 0;
struct capichat_s *new_chat_start = NULL;
room_member_type_t main_member_type = RoomMemberDefault;
room_mode_t room_mode = RoomModeDefault;
if (i->PLCI == 0) {
cc_verbose(2, 0, VERBOSE_PREFIX_3 CC_MESSAGE_NAME
" mixer: %s: PLCI is unset, abort.\n", i->vname);
return;
room = chat_start;
while (room != 0) {
if (room->i == i) {
main_member_type = room->room_member_type;
room_mode = room->room_mode;
break;
}
room = room->next;
}
cc_mutex_lock(&chat_lock);
room = chat_list;
if ((room_mode == RoomModeMuted) && (main_member_type == RoomMemberDefault)) {
main_member_type = RoomMemberListener;
}
room = chat_start;
while (room) {
if ((room->number == roomnumber) &&
(room->i != i)) {
found++;
if (j + 9 > sizeof(p_list)) {
if ((found >= PLCI_PER_LX_REQUEST) || ((j + 9) > sizeof(capi_msg->p_list))) {
/* maybe we need to split capi messages here */
new_chat_start = room;
break;
}
found++;
ii = room->i;
ii_last = ii;
p_list[j++] = 8;
p_list[j++] = (_cbyte)(ii->PLCI);
p_list[j++] = (_cbyte)(ii->PLCI >> 8);
p_list[j++] = (_cbyte)(ii->PLCI >> 16);
p_list[j++] = (_cbyte)(ii->PLCI >> 24);
dest = (remove) ? 0x00000000 : 0x00000003;
if (ii->channeltype == CAPI_CHANNELTYPE_NULL) {
if (ii->channeltype == CAPI_CHANNELTYPE_NULL && ii->line_plci == 0) {
dest |= 0x00000030;
}
if (remove == 0) {
room_member_type_t room_member_type = room->room_member_type;
if ((room_mode == RoomModeMuted) && (room_member_type == RoomMemberDefault)) {
room_member_type = RoomMemberListener;
}
if ((main_member_type == RoomMemberListener) && (room_member_type == RoomMemberListener)) {
dest &= ~3U; /* Disable data transmission between two listener */
} else if ((main_member_type == RoomMemberListener) && (room_member_type != RoomMemberListener)) {
dest &= ~1U; /* Disable data transmission from main PLCI to member PLCI */
} else if ((main_member_type != RoomMemberListener) && (room_member_type == RoomMemberListener)) {
dest &= ~2U; /* Disable data transmission from member PLCI to main PLCI */
}
}
p_list[j++] = (_cbyte)(dest);
p_list[j++] = (_cbyte)(dest >> 8);
p_list[j++] = (_cbyte)(dest >> 16);
@ -82,45 +151,177 @@ static void update_capi_mixer(int remove, unsigned int roomnumber, struct capi_p
}
room = room->next;
}
room = chat_list;
while (room) {
if (room->number == roomnumber) {
room->active = found + ((remove) ? 0 : 1);
}
room = room->next;
}
cc_mutex_unlock(&chat_lock);
if (found) {
p_struct.wLen = j;
p_struct.info = p_list;
if (found != 0) {
p_struct->wLen = j;
p_struct->info = p_list;
/* don't send DATA_B3 to me */
datapath = 0x00000000;
if (remove) {
/* now we need DATA_B3 again */
datapath = 0x0000000c;
if (found == 1) {
if (i->line_plci == 0) {
if (i->channeltype != CAPI_CHANNELTYPE_NULL) {
datapath = 0x0000000c;
} else {
datapath = 0x00000030;
}
}
if (overall_found == 1) {
/* only one left, enable DATA_B3 too */
p_list[5] |= 0x0c;
if (ii_last->line_plci == 0) {
if (ii_last->channeltype != CAPI_CHANNELTYPE_NULL) {
p_list[5] |= 0x0c;
} else {
p_list[5] |= 0x30;
}
}
}
}
if (i->channeltype == CAPI_CHANNELTYPE_NULL) {
if ((i->channeltype == CAPI_CHANNELTYPE_NULL) && (i->line_plci == 0)) {
if (!remove) {
datapath |= 0x00000030;
}
}
cc_verbose(3, 1, VERBOSE_PREFIX_3 CC_MESSAGE_NAME
" mixer: %s PLCI=0x%04x LI=0x%x\n", i->vname, i->PLCI, datapath);
capi_msg->busy = 1;
capi_msg->datapath = datapath;
}
capi_sendf(NULL, 0, CAPI_FACILITY_REQ, i->PLCI, get_capi_MessageNumber(),
"w(w(dc))",
FACILITYSELECTOR_LINE_INTERCONNECT,
0x0001, /* CONNECT */
datapath,
&p_struct
);
return (new_chat_start);
}
static void update_capi_mixer(int remove, unsigned int roomnumber, struct capi_pvt *i, deffered_chat_capi_message_t* update_segment)
{
struct capichat_s *room;
unsigned int overall_found;
unsigned int nr_segments;
if (i->PLCI == 0) {
cc_verbose(2, 0, VERBOSE_PREFIX_3 CC_MESSAGE_NAME
" mixer: %s: PLCI is unset, abort.\n", i->vname);
return;
}
if (update_segment == 0) {
cc_mutex_lock(&chat_lock);
}
/*
Get overall amount of parties
*/
for (room = chat_list, overall_found = 0; room != 0; room = room->next) {
overall_found += ((room->number == roomnumber) && (room->i != i));
}
room = chat_list;
while (room != 0) {
if (room->number == roomnumber) {
room->active = overall_found + ((remove != 0) ? 0 : 1);
}
room = room->next;
}
nr_segments = overall_found/PLCI_PER_LX_REQUEST + (overall_found%PLCI_PER_LX_REQUEST != 0);
if (nr_segments != 0) {
deffered_chat_capi_message_t __segments[nr_segments];
deffered_chat_capi_message_t* segments = update_segment == 0 ? __segments : update_segment;
struct capichat_s *chat_start;
int segment_nr, nr;
for (segment_nr = 0, chat_start = chat_list; segment_nr < nr_segments && chat_start != 0; segment_nr++) {
segments[segment_nr].busy = 0;
chat_start = update_capi_mixer_part(chat_start, overall_found, &segments[segment_nr], remove, roomnumber, i);
}
if (update_segment == 0) {
cc_mutex_unlock(&chat_lock);
}
if (chat_start != 0) {
cc_log(LOG_ERROR, "%s:%s at %d.\n", __FILE__, __FUNCTION__, __LINE__);
}
if (update_segment == 0) {
for (nr = 0; nr < segment_nr; nr++) {
if (segments[nr].busy != 0) {
cc_verbose(3, 1, VERBOSE_PREFIX_3 CC_MESSAGE_NAME
" mixer: %s PLCI=0x%04x LI=0x%x\n", i->vname, i->PLCI, segments[nr].datapath);
capi_sendf(NULL, 0, CAPI_FACILITY_REQ, i->PLCI, get_capi_MessageNumber(),
"w(w(dc))",
FACILITYSELECTOR_LINE_INTERCONNECT,
0x0001, /* CONNECT */
segments[nr].datapath,
&segments[nr].p_struct);
}
}
}
return;
}
if (update_segment == 0) {
cc_mutex_unlock(&chat_lock);
}
}
static void update_all_capi_mixers(unsigned int roomnumber)
{
struct capichat_s *room;
unsigned int overall_found;
unsigned int nr_segments;
for (room = chat_list, overall_found = 0; room != 0; room = room->next) {
overall_found += (room->number == roomnumber);
}
nr_segments = overall_found/PLCI_PER_LX_REQUEST + (overall_found%PLCI_PER_LX_REQUEST != 0);
{
deffered_chat_capi_message_t *segments, *segment;
unsigned int PLCIS[overall_found];
int i, j, nr;
segments = malloc (sizeof(*segments)*overall_found*nr_segments);
if (segments == 0) {
cc_mutex_unlock(&chat_lock);
return;
}
for (room = chat_list, i = 0; room != 0; room = room->next) {
if (room->number == roomnumber && room->i && room->i->PLCI != 0) {
segment = segments + i*nr_segments;
for (nr = 0; nr < nr_segments; nr++) {
segment[nr].busy = 0;
}
update_capi_mixer(0, roomnumber, room->i, segment);
if (segment[0].busy != 0) {
PLCIS[i++] = room->i->PLCI;
}
}
}
cc_mutex_unlock(&chat_lock);
for (j = 0; j < i; j++) {
segment = segments + j*nr_segments;
for (nr = 0; nr < nr_segments; nr++) {
if (segment[nr].busy != 0) {
cc_verbose(3, 1, VERBOSE_PREFIX_3 CC_MESSAGE_NAME
" mixer: PLCI=0x%04x LI=0x%x\n", PLCIS[j], segment[nr].datapath);
capi_sendf(NULL, 0, CAPI_FACILITY_REQ, PLCIS[j], get_capi_MessageNumber(),
"w(w(dc))",
FACILITYSELECTOR_LINE_INTERCONNECT,
0x0001, /* CONNECT */
segment[nr].datapath,
&segment[nr].p_struct);
}
}
}
free (segments);
}
}
@ -152,17 +353,18 @@ static void del_chat_member(struct capichat_s *room)
}
cc_mutex_unlock(&chat_lock);
update_capi_mixer(1, roomnumber, i);
update_capi_mixer(1, roomnumber, i, 0);
}
/*
* add a new chat member
*/
static struct capichat_s *add_chat_member(char *roomname, struct capi_pvt *i)
static struct capichat_s *add_chat_member(char *roomname, struct capi_pvt *i, room_member_type_t room_member_type)
{
struct capichat_s *room = NULL;
struct capichat_s *tmproom;
unsigned int roomnumber = 1;
room_mode_t room_mode = RoomModeDefault;
room = malloc(sizeof(struct capichat_s));
if (room == NULL) {
@ -174,13 +376,15 @@ static struct capichat_s *add_chat_member(char *roomname, struct capi_pvt *i)
strncpy(room->name, roomname, sizeof(room->name));
room->name[sizeof(room->name) - 1] = 0;
room->i = i;
room->room_member_type = room_member_type;
cc_mutex_lock(&chat_lock);
tmproom = chat_list;
while (tmproom) {
if (!strcmp(tmproom->name, roomname)) {
roomnumber = tmproom->number;
room_mode = tmproom->room_mode;
break;
} else {
if (tmproom->number == roomnumber) {
@ -191,16 +395,25 @@ static struct capichat_s *add_chat_member(char *roomname, struct capi_pvt *i)
}
room->number = roomnumber;
room->room_mode = room_mode;
for (tmproom = chat_list; tmproom != 0; tmproom = tmproom->next) {
if (tmproom->number == roomnumber) {
tmproom->info &= ~PBX_CHAT_MEMBER_INFO_RECENT;
}
}
room->info |= PBX_CHAT_MEMBER_INFO_RECENT;
room->time = time(0);
room->next = chat_list;
chat_list = room;
cc_mutex_unlock(&chat_lock);
cc_verbose(3, 0, VERBOSE_PREFIX_3 "%s: added new chat member to room '%s' (%d)\n",
i->vname, roomname, roomnumber);
cc_verbose(3, 0, VERBOSE_PREFIX_3 "%s: added new chat member to room '%s' %s(%d)\n",
i->vname, roomname, room_member_type_2_name(room_member_type), roomnumber);
update_capi_mixer(0, roomnumber, i);
update_capi_mixer(0, roomnumber, i, 0);
return room;
}
@ -209,7 +422,7 @@ static struct capichat_s *add_chat_member(char *roomname, struct capi_pvt *i)
* loop during chat
*/
static void chat_handle_events(struct ast_channel *c, struct capi_pvt *i,
struct capichat_s *room, unsigned int flags)
struct capichat_s *room, unsigned int flags, struct capi_pvt* iline, FILE* voice_message)
{
struct ast_frame *f;
int ms;
@ -219,24 +432,33 @@ static void chat_handle_events(struct ast_channel *c, struct capi_pvt *i,
int nfds = 0;
struct ast_channel *rchan;
struct ast_channel *chan = c;
int moh_active = 0;
int moh_active = 0, voice_message_moh_active = 0;
int write_block_nr = 2;
ast_indicate(chan, -1);
if (voice_message == NULL) {
ast_indicate(chan, -1);
}
waitfd = i->readerfd;
if (i->channeltype == CAPI_CHANNELTYPE_NULL) {
nfds = 1;
ast_set_read_format(chan, capi_capability);
ast_set_write_format(chan, capi_capability);
if (voice_message == NULL) {
ast_set_read_format(chan, capi_capability);
ast_set_write_format(chan, capi_capability);
}
}
if ((flags & CHAT_FLAG_MOH) && (room->active < 2)) {
if ((flags & CHAT_FLAG_MOH) && ((room->active < 2) || (voice_message != 0))) {
#if defined(CC_AST_HAS_VERSION_1_6) || defined(CC_AST_HAS_VERSION_1_4)
ast_moh_start(chan, NULL, NULL);
#else
ast_moh_start(chan, NULL);
#endif
moh_active = 1;
if (voice_message == 0) {
moh_active = 1;
} else {
voice_message_moh_active = 1;
}
}
while (1) {
@ -245,6 +467,10 @@ static void chat_handle_events(struct ast_channel *c, struct capi_pvt *i,
errno = 0;
exception = 0;
if ((room->info & PBX_CHAT_MEMBER_INFO_REMOVE) != 0) {
break;
}
rchan = ast_waitfor_nandfds(&chan, 1, &waitfd, nfds, &exception, &ready_fd, &ms);
if (rchan) {
@ -262,13 +488,17 @@ static void chat_handle_events(struct ast_channel *c, struct capi_pvt *i,
} else if (f->frametype == AST_FRAME_VOICE) {
cc_verbose(5, 1, VERBOSE_PREFIX_3 "%s: chat: voice frame.\n",
i->vname);
if (i->channeltype == CAPI_CHANNELTYPE_NULL) {
if ((voice_message == 0) && (i->channeltype == CAPI_CHANNELTYPE_NULL)) {
capi_write_frame(i, f);
} else if (iline != 0) {
capi_write_frame(iline, f);
}
} else if (f->frametype == AST_FRAME_NULL) {
/* ignore NULL frame */
cc_verbose(5, 1, VERBOSE_PREFIX_3 "%s: chat: NULL frame, ignoring.\n",
i->vname);
} else if ((f->frametype == AST_FRAME_DTMF_END) && (voice_message == 0)) {
pbx_capi_voicecommand_process_digit (i, c, f->subclass);
} else {
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: chat: unhandled frame %d/%d.\n",
i->vname, f->frametype, f->subclass);
@ -282,7 +512,28 @@ static void chat_handle_events(struct ast_channel *c, struct capi_pvt *i,
}
f = capi_read_pipeframe(i);
if (f->frametype == AST_FRAME_VOICE) {
ast_write(chan, f);
if (voice_message == 0) {
ast_write(chan, f);
} else {
char* p = f->FRAME_DATA_PTR;
int len;
do {
if ((len = fread(p, 1, f->datalen, voice_message)) > 0) {
if (len < f->datalen) {
memset (&p[len], 0x00, f->datalen-len);
len = 0;
}
capi_write_frame(i, f);
}
} while ((write_block_nr-- != 0) && (len > 0));
if (len <= 0) {
break;
}
write_block_nr = 0;
}
}
/* ignore other nullplci frames */
} else {
@ -299,6 +550,9 @@ static void chat_handle_events(struct ast_channel *c, struct capi_pvt *i,
moh_active = 0;
}
}
if (voice_message_moh_active != 0) {
ast_moh_stop(chan);
}
}
/*
@ -313,6 +567,7 @@ int pbx_capi_chat(struct ast_channel *c, char *param)
ast_group_t tmpcntr;
unsigned long long contr = 0;
unsigned int flags = 0;
room_member_type_t room_member_type = RoomMemberDefault;
roomname = strsep(&param, "|");
options = strsep(&param, "|");
@ -336,6 +591,13 @@ int pbx_capi_chat(struct ast_channel *c, char *param)
case 'm':
flags |= CHAT_FLAG_MOH;
break;
case 'l':
room_member_type = RoomMemberListener;
break;
case 'o':
room_member_type = RoomMemberOperator;
break;
default:
cc_log(LOG_WARNING, "Unknown chat option '%c'.\n",
*options);
@ -352,8 +614,12 @@ int pbx_capi_chat(struct ast_channel *c, char *param)
i = CC_CHANNEL_PVT(c);
} else {
/* virtual CAPI channel */
i = capi_mknullif(c, contr);
if (!i) {
i = pbx_check_resource_plci(c);
if (i == NULL) {
i = capi_mknullif(c, contr);
}
if (i == NULL) {
return -1;
}
}
@ -367,14 +633,15 @@ int pbx_capi_chat(struct ast_channel *c, char *param)
goto out;
}
room = add_chat_member(roomname, i);
room = add_chat_member(roomname, i, room_member_type);
if (!room) {
cc_log(LOG_WARNING, "Unable to open " CC_MESSAGE_NAME " chat room.\n");
capi_remove_nullif(i);
return -1;
}
/* main loop */
chat_handle_events(c, i, room, flags);
chat_handle_events(c, i, room, flags, 0, 0);
del_chat_member(room);
@ -384,6 +651,278 @@ out:
return 0;
}
int pbx_capi_chat_play(struct ast_channel *c, char *param)
{
struct capi_pvt *i = NULL;
char *roomname, *options, *file_name, *controller;
char *p;
struct capichat_s *room;
ast_group_t tmpcntr;
unsigned long long contr = 0;
unsigned int flags = 0;
room_member_type_t room_member_type = RoomMemberOperator;
FILE* f;
if (param == 0 || *param == 0) {
cc_log(LOG_WARNING, CC_MESSAGE_NAME " chat_play requires parameters.\n");
return (-1);
}
roomname = strsep(&param, "|");
options = strsep(&param, "|");
file_name = strsep(&param, "|");
controller = param;
if (!roomname) {
cc_log(LOG_WARNING, CC_MESSAGE_NAME " chat_play requires room name.\n");
return -1;
}
if (!file_name || !*file_name) {
cc_log(LOG_WARNING, CC_MESSAGE_NAME " chat_play requires file name.\n");
return -1;
}
{
int chat_members;
cc_mutex_lock(&chat_lock);
for (room = chat_list, chat_members = 0; room != 0 && chat_members == 0; room = room->next) {
chat_members += (strcmp(room->name, roomname) == 0);
}
cc_mutex_unlock(&chat_lock);
if (chat_members == 0) {
return 0;
}
}
while ((options) && (*options)) {
switch (*options) {
case 'm':
flags |= CHAT_FLAG_MOH;
break;
default:
cc_log(LOG_WARNING, "Unknown chat option '%c'.\n",
*options);
break;
}
options++;
}
f = fopen(file_name, "rb");
if (f == NULL) {
cc_log(LOG_WARNING, "can't open voice file (%s)\n", strerror(errno));
return -1;
}
{
unsigned char tmp[2] = { 0, 0 };
if (fread(tmp, 1, 2, f) != 2) {
cc_log(LOG_WARNING, "can't read voice file (%s)\n", strerror(errno));
fclose(f);
return -1;
}
}
rewind(f);
if (controller) {
for (p = controller; p && *p; p++) {
if (*p == '|') *p = ',';
}
tmpcntr = ast_get_group(controller);
contr = (unsigned long long)(tmpcntr >> 1);
}
cc_verbose(3, 1, VERBOSE_PREFIX_3 CC_MESSAGE_NAME " chat_play: %s: roomname=%s "
"message=%s controller=%s (0x%llx)\n",
c->name, roomname, file_name, controller, contr);
i = capi_mknullif(c, contr);
if (i == NULL) {
fclose (f);
cc_log(LOG_WARNING, "Unable to play %s to chat room %s", file_name, roomname);
return (-1);
}
if (c->_state != AST_STATE_UP) {
ast_answer(c);
}
capi_wait_for_answered(i);
if (!(capi_wait_for_b3_up(i))) {
goto out;
}
room = add_chat_member(roomname, i, room_member_type);
if (!room) {
capi_remove_nullif(i);
fclose (f);
cc_log(LOG_WARNING, "Unable to open " CC_MESSAGE_NAME " chat room.\n");
return -1;
}
/* main loop */
chat_handle_events(c, i, room, flags, (c->tech == &capi_tech) ? (CC_CHANNEL_PVT(c)) : 0, f);
del_chat_member(room);
out:
fclose (f);
capi_remove_nullif(i);
return 0;
}
int pbx_capi_chat_command (struct ast_channel *c, char *param)
{
struct capichat_s *room, *tmproom;
struct capi_pvt *i;
unsigned int roomnumber, ret = 0;
const char* options = strsep(&param, "|");
const char* roomname = param;
unsigned int disconnect_command = 0;
if (options == 0 || *options == 0) {
cc_log(LOG_WARNING, CC_MESSAGE_NAME " chat_command requires options.\n");
return -1;
}
if (roomname == 0 && *roomname == 0) {
roomname = 0;
}
while (*options != 0) {
switch (*options) {
case 'r': /* Disconnect recent member */
disconnect_command |= 1U;
break;
case 'l': /* Disconnect all listeners */
disconnect_command |= 2U;
break;
case 'o': /* Disconnect all operators */
disconnect_command |= 4U;
break;
case 'a': /* Disconnect all users */
disconnect_command |= 8U;
break;
default:
cc_log(LOG_WARNING, "Unknown chat_disconnect option '%c'.\n", *options);
break;
}
options++;
}
if (disconnect_command != 0) {
i = pbx_check_resource_plci(c);
cc_mutex_lock(&chat_lock);
for (room = chat_list; room != 0; room = room->next) {
if (((roomname != 0 && strcmp(room->name, roomname) == 0) || (i != 0 && room->i == i)) &&
(room->i != 0 && (room->i->used == c || room->i->peer == c))) {
if (room->room_member_type == RoomMemberOperator) {
struct capichat_s *recent = 0;
time_t t = 0;
roomnumber = room->number;
cc_verbose(3, 0, VERBOSE_PREFIX_3 "%s: command %08x (%d)\n",
room->name, disconnect_command, roomnumber);
for (tmproom = chat_list; tmproom != 0; tmproom = tmproom->next) {
if (tmproom->number == roomnumber && tmproom != room) {
if ((disconnect_command & 8U) != 0) {
tmproom->info |= PBX_CHAT_MEMBER_INFO_REMOVE;
} else if ((disconnect_command & 2U) != 0 && room->room_member_type == RoomMemberListener) {
tmproom->info |= PBX_CHAT_MEMBER_INFO_REMOVE;
} else if ((disconnect_command & 4U) != 0 && room->room_member_type == RoomMemberOperator) {
tmproom->info |= PBX_CHAT_MEMBER_INFO_REMOVE;
} else if ((disconnect_command & 1U) != 0) {
if (t < tmproom->time) {
t = tmproom->time;
recent = tmproom;
}
}
}
}
if (recent != 0) {
recent->info |= PBX_CHAT_MEMBER_INFO_REMOVE;
}
} else {
cc_verbose(3, 0, VERBOSE_PREFIX_3 "%s: no permissions for command command %08x\n",
room->name, disconnect_command);
ret = -1;
}
break;
}
}
cc_mutex_unlock(&chat_lock);
}
return (ret);
}
struct capi_pvt* pbx_check_resource_plci(struct ast_channel *c)
{
struct capi_pvt *i = NULL;
const char* id = pbx_builtin_getvar_helper(c, "RESOURCEPLCI");
if (id != 0) {
i = (struct capi_pvt*)strtoul(id, NULL, 0);
if (i != 0 && capi_verify_resource_plci(i) != 0) {
cc_log(LOG_ERROR, "resource PLCI lost\n");
i = 0;
}
}
return i;
}
int pbx_capi_chat_associate_resource_plci(struct ast_channel *c, char *param)
{
struct capi_pvt *i = NULL;
char *controller;
char *p;
ast_group_t tmpcntr;
unsigned long long contr = 0;
controller = param;
if (controller) {
for (p = controller; p && *p; p++) {
if (*p == '|') *p = ',';
}
tmpcntr = ast_get_group(controller);
contr = (unsigned long long)(tmpcntr >> 1);
}
if (c->tech != &capi_tech) {
i = capi_mkresourceif(c, contr, 0);
if (i != NULL) {
char buffer[24];
snprintf(buffer, sizeof(buffer)-1, "%p", i);
/**
Not sure ast_channel pointer does not change across the
use of resource PLCI. For this reason use variable to provide
the pointer to resource PLCI to resource PLCI user
\todo This is still possible that resource PLCI will be lost.
In case this happens this will be necessary to maintain one
live time stamp on resource PLCI and automatically remove
resource LCI if time stamp exceeds certail limit.
*/
pbx_builtin_setvar_helper(c, "RESOURCEPLCI", buffer);
capi_mkresourceif(c, contr, i);
}
}
return 0; /* Always return success in case c->tech == &capi_tech or to fallback to NULL PLCI */
}
/*
* do command capi chatinfo
*/
@ -447,3 +986,70 @@ int pbxcli_capi_chatinfo(int fd, int argc, char *argv[])
#endif
}
static const char* room_member_type_2_name(room_member_type_t room_member_type)
{
switch (room_member_type) {
case RoomMemberListener:
return "in listener mode ";
case RoomMemberOperator:
return "in operator mode ";
default:
return "";
}
}
int pbx_capi_chat_mute(struct ast_channel *c, char *param)
{
struct capichat_s *room;
unsigned int roomnumber;
room_mode_t room_mode;
const char* roommode = strsep(&param, "|");
const char* roomname = param;
struct capi_pvt *i;
if (roommode == 0 || *roommode == 0) {
cc_log(LOG_WARNING, CC_MESSAGE_NAME " chat_mute requires room mode.\n");
return -1;
}
if (ast_true(roommode)) {
room_mode = RoomModeMuted;
} else if (ast_false(roommode)) {
room_mode = RoomModeDefault;
} else {
cc_log(LOG_WARNING, CC_MESSAGE_NAME " false parameter for chat_mute.\n");
cc_log(LOG_WARNING, "Parameter for chat_mute invalid.\n");
return -1;
}
if (roomname == 0 && *roomname == 0) {
roomname = 0;
}
i = pbx_check_resource_plci(c);
cc_mutex_lock(&chat_lock);
for (room = chat_list; room != 0; room = room->next) {
if ((roomname != 0 && strcmp(room->name, roomname) == 0) ||
(i != 0 && room->i == i) ||
(room->i != 0 && (room->i->used == c || room->i->peer == c))) {
roomnumber = room->number;
cc_verbose(3, 0, VERBOSE_PREFIX_3 "%s: change mode to %s (%d)\n",
room->name, room_mode == RoomModeDefault ? "full duplex" : "half duplex", roomnumber);
for (room = chat_list; room != 0; room = room->next) {
if (room->number == roomnumber) {
room->room_mode = room_mode;
}
}
update_all_capi_mixers(roomnumber);
return 0;
}
}
cc_mutex_unlock(&chat_lock);
return -1;
}

View File

@ -16,10 +16,15 @@
* prototypes
*/
extern int pbx_capi_chat(struct ast_channel *c, char *param);
extern int pbx_capi_chat_associate_resource_plci(struct ast_channel *c, char *param);
extern struct capi_pvt* pbx_check_resource_plci(struct ast_channel *c);
#ifdef CC_AST_HAS_VERSION_1_6
extern char *pbxcli_capi_chatinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
#else
extern int pbxcli_capi_chatinfo(int fd, int argc, char *argv[]);
#endif
extern int pbx_capi_chat_command (struct ast_channel *c, char *param);
extern int pbx_capi_chat_mute(struct ast_channel *c, char *param);
extern int pbx_capi_chat_play(struct ast_channel *c, char *param);
#endif

380
chan_capi_command.c Normal file
View File

@ -0,0 +1,380 @@
/*
*
Copyright (c) Dialogic, 2009.
*
This source file is supplied for the use with
Dialogic range of DIVA Server Adapters.
*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
*
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
*
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <sys/time.h>
#include <sys/signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <math.h>
#include <sys/types.h>
#include <ctype.h>
#include "chan_capi_platform.h"
#include "xlaw.h"
#include "chan_capi20.h"
#include "chan_capi.h"
#include "chan_capi_rtp.h"
#include "chan_capi_qsig.h"
#include "chan_capi_qsig_ecma.h"
#include "chan_capi_qsig_asn197ade.h"
#include "chan_capi_qsig_asn197no.h"
#include "chan_capi_utils.h"
#include "chan_capi_supplementary.h"
#include "chan_capi_chat.h"
#include "chan_capi_command.h"
typedef struct _pbx_capi_voice_command {
diva_entity_link_t link;
pbx_capi_command_proc_t pbx_capi_command;
char channel_command_digits[AST_MAX_EXTENSION+1];
int length; /* channel_command_digits length */
char command_name[64];
char command_parameters[128];
} pbx_capi_voice_command_t;
/*
* LOCALS
*/
static const char* pbx_capi_voicecommand_digits = "1234567890ABCD*#";
static int pbx_capi_command_nop (struct ast_channel *c, char *param);
static pbx_capi_voice_command_t* pbx_capi_find_command (struct capi_pvt *i, const char* name);
static pbx_capi_voice_command_t* pbx_capi_find_command_by_key (struct capi_pvt *i, const char* key);
static pbx_capi_voice_command_t* pbx_capi_voicecommand_find_digit_command (diva_entity_queue_t* q, const char* digits, int length, int* info);
static void pbx_capi_voicecommand_insert_command (diva_entity_queue_t* q, pbx_capi_voice_command_t* cmd);
/*
* voicecommand|key|param1|param2|...
*
*/
int pbx_capi_voicecommand(struct ast_channel *c, char *param)
{
struct capi_pvt *i;
pbx_capi_voice_command_t* cmd;
const char* command[2];
const char* key[2];
size_t length;
if (c->tech == &capi_tech) {
i = CC_CHANNEL_PVT(c);
} else {
i = pbx_check_resource_plci(c);
}
if (i == 0) {
/*
Ignore command silently to ensure same context can be used to process
all types of calls or in case of fallback to NULL PLCI
*/
return 0;
}
if ((param == NULL) || (*param == 0)) { /* Remove all voice commands */
cc_mutex_lock(&i->lock);
pbx_capi_voicecommand_cleanup(i);
cc_mutex_unlock(&i->lock);
return 0;
}
command[0] = param;
command[1] = strchr (command[0], '|');
if (command[1] == 0) {
/*
* Remove command
*/
cc_mutex_lock(&i->lock);
while ((cmd = pbx_capi_find_command (i, command[0])) != 0) {
cc_verbose(2, 0, VERBOSE_PREFIX_4"%s: voicecommand:%s removed\n", i->vname, cmd->command_name);
diva_q_remove (&i->channel_command_q, &cmd->link);
free (cmd);
}
cc_mutex_unlock(&i->lock);
} else {
if ((command[1] - command[0]) < 2 || (command[1] - command[0]) >= sizeof(cmd->command_name) ||
strchr(pbx_capi_voicecommand_digits, command[1][1]) == 0) {
cc_log(LOG_WARNING, CC_MESSAGE_NAME" voicecommand requires an argument im format 'voicecommand[|key[|param1|param2|...]]'\n");
return -1;
}
key[0] = &command[1][1];
key[1] = strchr (key[0], '|');
length = 0;
if ((key[1] == 0 && strlen(key[0]) >= sizeof(cmd->channel_command_digits)) ||
(key[1] != 0 && ((key[1] - key[0]) == 0 || (key[1] - key[0]) >= sizeof(cmd->channel_command_digits) ||
key[1][1] == 0 || (length = strlen (&key[1][1])) >= sizeof(cmd->command_parameters)))) {
cc_log(LOG_WARNING, CC_MESSAGE_NAME
" voicecommand requires an argument im format 'voicecommand[|key[|param1|param2|...]]'\n");
return -1;
}
if (key[1] == 0) {
key[1] = key[0] + strlen(key[0]);
length = 0;
}
{
const char* p = key[0];
for (p = key[0]; p < key[1]; p++) {
if (strchr(pbx_capi_voicecommand_digits, *p) == 0) {
cc_log(LOG_WARNING, CC_MESSAGE_NAME
" voicecommand key can use only '%s'\n", pbx_capi_voicecommand_digits);
return -1;
}
}
}
cmd = malloc(sizeof(*cmd));
if (cmd == NULL) {
cc_log(LOG_WARNING, CC_MESSAGE_NAME " can not allocate memory for voice command\n");
return -1;
}
memcpy (cmd->command_parameters, &key[1][1], length);
cmd->command_parameters[length] = 0;
length = command[1] - command[0];
memcpy (cmd->command_name, command[0], length);
cmd->command_name[length] = 0;
length = key[1] - key[0];
memcpy (cmd->channel_command_digits, key[0], length);
cmd->channel_command_digits[length] = 0;
cmd->length = length;
cmd->pbx_capi_command = pbx_capi_lockup_command_by_name (cmd->command_name);
if ( cmd->pbx_capi_command == 0) {
cmd->pbx_capi_command = pbx_capi_command_nop; /* accept unknown commands for compatibility reason */
}
cc_verbose(2, 0, VERBOSE_PREFIX_4 "%s: %svoicecommand:%s|%s|%s\n",
i->vname, (cmd->pbx_capi_command == pbx_capi_command_nop) ? "dummy " : "",
cmd->command_name, cmd->channel_command_digits, cmd->command_parameters);
{
pbx_capi_voice_command_t* present_cmd;
cc_mutex_lock(&i->lock);
if ((present_cmd = pbx_capi_find_command_by_key (i, cmd->command_name)) != 0) {
diva_q_remove (&i->channel_command_q, &present_cmd->link);
}
pbx_capi_voicecommand_insert_command (&i->channel_command_q, cmd);
cc_mutex_unlock(&i->lock);
if (present_cmd != 0) {
free (present_cmd);
}
}
}
return 0;
}
int pbx_capi_voicecommand_transparency(struct ast_channel *c, char *param)
{
struct capi_pvt *i;
if (c->tech == &capi_tech) {
i = CC_CHANNEL_PVT(c);
} else {
i = pbx_check_resource_plci(c);
}
if (i == 0) {
/*
Ignore command silently to ensure same context can be used to process
all types of calls or in case of fallback to NULL PLCI
*/
return 0;
}
if ((param == NULL) || (*param == 0)) {
cc_log(LOG_WARNING, "Parameter for voicecommand transparency missing.\n");
return -1;
}
if (ast_true(param)) {
i->command_pass_digits = 1;
} else if (ast_false(param)) {
i->command_pass_digits = 0;
} else {
cc_log(LOG_WARNING, "Wrong parameter for voicecommand transparency.\n");
return -1;
}
return 0;
}
int pbx_capi_voicecommand_cleanup(struct capi_pvt *i)
{
diva_entity_link_t* link;
while ((link = diva_q_get_head(&i->channel_command_q)) != NULL) {
diva_q_remove(&i->channel_command_q, link);
free(link);
}
i->channel_command_digit = 0;
i->channel_command_timestamp = 0;
i->command_pass_digits = 0;
return 0;
}
static pbx_capi_voice_command_t* pbx_capi_find_command(struct capi_pvt *i, const char* name)
{
diva_entity_link_t* link;
for (link = diva_q_get_head (&i->channel_command_q); link != 0; link = diva_q_get_next(link)) {
if (strcmp(((pbx_capi_voice_command_t*)link)->command_name, name) == 0) {
return ((pbx_capi_voice_command_t*)link);
}
}
return 0;
}
static pbx_capi_voice_command_t* pbx_capi_find_command_by_key(struct capi_pvt *i, const char* key)
{
diva_entity_link_t* link;
for (link = diva_q_get_head (&i->channel_command_q); link != 0; link = diva_q_get_next(link)) {
if (strcmp (((pbx_capi_voice_command_t*)link)->channel_command_digits, key) == 0) {
return ((pbx_capi_voice_command_t*)link);
}
}
return 0;
}
/*
* Process received DTMF digit
*
* returs zero if digit should be processed as usually
* returns -1 if digit should be discarded
*/
int pbx_capi_voicecommand_process_digit(struct capi_pvt *i, struct ast_channel *owner, char digit)
{
struct ast_channel *c = (owner == 0) ? i->owner : owner;
pbx_capi_voice_command_t* cmd;
int info;
time_t t;
/*
Simple algorithm due to low amount of entries, moreover all sequences will be short, only 1 ... 2 digits
*/
if ((c == NULL) || (diva_q_get_head(&i->channel_command_q) == 0) ||
(strchr(pbx_capi_voicecommand_digits, digit) == 0)) {
i->channel_command_digit = 0;
return 0;
}
t = time(0);
if (((i->channel_command_digit != 0) && (difftime(t, i->channel_command_timestamp) > 2)) ||
(i->channel_command_digit >= (sizeof(i->channel_command_digits) - 1))) {
i->channel_command_digit = 0;
}
i->channel_command_timestamp = t;
i->channel_command_digits[i->channel_command_digit++] = digit;
i->channel_command_digits[i->channel_command_digit] = 0;
cmd = pbx_capi_voicecommand_find_digit_command(
&i->channel_command_q,
i->channel_command_digits,
i->channel_command_digit,
&info);
if (cmd != 0) {
char command_parameters_copy[sizeof( cmd->command_parameters)];
i->channel_command_digit = 0;
cc_verbose(2, 0, VERBOSE_PREFIX_4 "%s: call voicecommand:%s|%s|%s\n",
i->vname, cmd->command_name, cmd->channel_command_digits, cmd->command_parameters);
strcpy (command_parameters_copy, cmd->command_parameters);
info = ((*(cmd->pbx_capi_command))(c, command_parameters_copy));
cc_verbose(2, 0, VERBOSE_PREFIX_4 "%s: voicecommand:%s|%s|%s %s\n",
i->vname, cmd->command_name, cmd->channel_command_digits, cmd->command_parameters, info == 0 ? "OK" : "ERROR");
} else if (info == 0) {
i->channel_command_digit = 0;
return 0;
}
return ((i->command_pass_digits != 0) ? 0 : -1);
}
static pbx_capi_voice_command_t* pbx_capi_voicecommand_find_digit_command(
diva_entity_queue_t* q,
const char* digits,
int length,
int* info)
{
diva_entity_link_t* link;
for (*info = 0, link = diva_q_get_head(q);
link != 0 && length <= ((pbx_capi_voice_command_t*)link)->length;
link = diva_q_get_next (link)) {
pbx_capi_voice_command_t* cmd = (pbx_capi_voice_command_t*)link;
if (memcmp(digits, cmd->channel_command_digits, length) == 0) {
*info = 1;
if (length == cmd->length) {
return cmd;
}
}
}
return 0;
}
static int pbx_capi_command_nop(struct ast_channel *c, char *param)
{
return 0;
}
static void pbx_capi_voicecommand_insert_command(diva_entity_queue_t* q, pbx_capi_voice_command_t* cmd)
{
diva_entity_link_t* link;
for (link = diva_q_get_head (q); link != 0; link = diva_q_get_next (link)) {
if (((pbx_capi_voice_command_t*)link)->length <= cmd->length) {
diva_q_insert_before (q, link, &cmd->link);
return;
}
}
diva_q_add_tail(q, &cmd->link);
}
/*
* vim:ts=2
*/

32
chan_capi_command.h Normal file
View File

@ -0,0 +1,32 @@
/*
*
Copyright (c) Dialogic, 2009.
*
This source file is supplied for the use with
Dialogic range of DIVA Server Adapters.
*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
*
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
*
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef __CHAN_CAPI_COMMAND_H__
#define __CHAN_CAPI_COMMAND_H__
int pbx_capi_voicecommand (struct ast_channel *c, char *param);
int pbx_capi_voicecommand_transparency (struct ast_channel *c, char *param);
int pbx_capi_voicecommand_process_digit (struct capi_pvt *i, struct ast_channel *owner, char digit);
int pbx_capi_voicecommand_cleanup (struct capi_pvt *i);
#endif

25
chan_capi_platform.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef __CHAN_CAPI_PLATFORM_H__
#define __CHAN_CAPI_PLATFORM_H__
#if __GNUC__ >= 3 /* { */
#ifndef likely
#define likely(x) __builtin_expect(!!(x), 1)
#endif
#ifndef unlikely
#define unlikely(x) __builtin_expect(!!(x), 0)
#endif
#else /* } { */
#ifndef likely
#define likely(__x__) (!!(__x__))
#endif
#ifndef unlikely
#define unlikely(__x__) (!!(__x__))
#endif
#endif /* } */
#endif

View File

@ -18,7 +18,8 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "chan_capi_platform.h"
#include "chan_capi20.h"
#include "chan_capi.h"
#include "chan_capi_utils.h"
@ -127,10 +128,10 @@ unsigned int cc_qsig_asn197ade_get_pns(unsigned char *data, int *idx, struct asn
char buf[ASN197ADE_NUMDIGITS_STRSIZE+1];
unsigned int buflen = sizeof(buf);
unsigned res;
int numtype;
ns->partyNumber = NULL;
ns->screeningInd = userProvidedNotScreened;
int numtype;
numtype = (data[myidx++] & 0x0F); /* defines type of Number */

View File

@ -19,6 +19,7 @@
#include <stdio.h>
#include <string.h>
#include "chan_capi_platform.h"
#include "chan_capi20.h"
#include "chan_capi.h"
#include "chan_capi_utils.h"

View File

@ -15,6 +15,7 @@
#include <stdio.h>
#include <string.h>
#include "chan_capi_platform.h"
#include "chan_capi20.h"
#include "chan_capi.h"
#include "chan_capi_utils.h"
@ -574,13 +575,15 @@ signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protoco
invokedescrtype = 2;
datalen = invoke->oid_len;
unsigned char *oidstr = NULL;
oidstr = cc_qsig_asn1_oid2str(invoke->oid_bin, invoke->oid_len);
if (oidstr) {
cc_qsig_verbose( 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (%s)\n", oidstr);
free(oidstr);
} else {
cc_qsig_verbose( 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (unknown - OID not displayable)\n");
{
unsigned char *oidstr = NULL;
oidstr = cc_qsig_asn1_oid2str(invoke->oid_bin, invoke->oid_len);
if (oidstr) {
cc_qsig_verbose( 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (%s)\n", oidstr);
free(oidstr);
} else {
cc_qsig_verbose( 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (unknown - OID not displayable)\n");
}
}
if ((datalen) == 4) {
@ -606,13 +609,15 @@ signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protoco
invokedescrtype = 2;
datalen = invoke->oid_len;
unsigned char *oidstr = NULL;
oidstr = cc_qsig_asn1_oid2str(invoke->oid_bin, invoke->oid_len);
if (oidstr) {
cc_qsig_verbose( 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (%s)\n", oidstr);
free(oidstr);
} else {
cc_qsig_verbose( 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (unknown - OID not displayable)\n");
{
unsigned char *oidstr = NULL;
oidstr = cc_qsig_asn1_oid2str(invoke->oid_bin, invoke->oid_len);
if (oidstr) {
cc_qsig_verbose( 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (%s)\n", oidstr);
free(oidstr);
} else {
cc_qsig_verbose( 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (unknown - OID not displayable)\n");
}
}
if ((datalen) == 4) {
@ -944,9 +949,11 @@ unsigned int cc_qsig_add_call_setup_data(unsigned char *data, struct capi_pvt *i
i->qsig_data.calltransfer = 1;
i->qsig_data.partner_plci = atoi(pp);
/* set the other channel as partner to me */
struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci);
if (ii)
ii->qsig_data.partner_plci = i->PLCI;
{
struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci);
if (ii)
ii->qsig_data.partner_plci = i->PLCI;
}
cc_qsig_verbose( 1, " for plci %#x\n", i->qsig_data.partner_plci);
}
@ -960,9 +967,11 @@ unsigned int cc_qsig_add_call_setup_data(unsigned char *data, struct capi_pvt *i
i->qsig_data.calltransfer_onring = 1;
i->qsig_data.partner_plci = atoi(pp);
/* set the other channel as partner to me */
struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci);
if (ii)
ii->qsig_data.partner_plci = i->PLCI;
{
struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci);
if (ii)
ii->qsig_data.partner_plci = i->PLCI;
}
cc_qsig_verbose( 1, " for plci %#x\n", i->qsig_data.partner_plci);
}

View File

@ -15,6 +15,7 @@
#include <stdio.h>
#include <string.h>
#include "chan_capi_platform.h"
#include "chan_capi20.h"
#include "chan_capi.h"
#include "chan_capi_utils.h"

View File

@ -19,6 +19,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include "chan_capi_platform.h"
#include "chan_capi20.h"
#include "chan_capi.h"
#include "chan_capi_rtp.h"
@ -390,6 +391,10 @@ void voice_over_ip_profile(struct cc_capi_controller *cp)
cp->rtpcodec |= AST_FORMAT_G729A;
cc_verbose(3, 0, "G.729");
}
if (payload1 & (1U << 27)) {
cp->rtpcodec |= AST_FORMAT_ILBC;
cc_verbose(3, 0, "iLBC");
}
cc_verbose(3, 0, "\n");
}

View File

@ -13,6 +13,7 @@
#include <stdlib.h>
#include <unistd.h>
#include "chan_capi_platform.h"
#include "chan_capi20.h"
#include "chan_capi.h"
#include "chan_capi_supplementary.h"
@ -194,7 +195,7 @@ static struct ccbsnr_s *get_ccbsnr_link(char type, unsigned int plci,
*/
static int ccbsnr_tell_activated(void *data)
{
unsigned int handle = (unsigned int)data;
unsigned int handle = (unsigned int)(unsigned long)data;
int ret = 0;
unsigned int state;
@ -832,7 +833,7 @@ int pbx_capi_ccbs(struct ast_channel *c, char *data)
for (a = 0; a < 7; a++) {
/* Wait for CCBS request indication */
if (ast_safe_sleep_conditional(c, 500, ccbsnr_tell_activated,
(void *)handle) != 0) {
(void *)(unsigned long)handle) != 0) {
/* we got a hangup */
cc_verbose(3, 1,
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " ccbs: hangup.\n");

View File

@ -16,7 +16,9 @@
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include "chan_capi_platform.h"
#include "xlaw.h"
#include "chan_capi20.h"
#include "chan_capi.h"
@ -45,9 +47,9 @@ static struct peerlink_s {
} peerlinkchannel[CAPI_MAX_PEERLINKCHANNELS];
/*
* helper for <pbx>_verbose with different verbose settings
* helper for <pbx>_verbose
*/
void cc_verbose(int o_v, int c_d, char *text, ...)
void cc_verbose_internal(char *text, ...)
{
char line[4096];
va_list ap;
@ -55,6 +57,7 @@ void cc_verbose(int o_v, int c_d, char *text, ...)
va_start(ap, text);
vsnprintf(line, sizeof(line), text, ap);
va_end(ap);
line[sizeof(line)-1]=0;
#if 0
{
@ -66,13 +69,9 @@ void cc_verbose(int o_v, int c_d, char *text, ...)
}
#endif
if ((o_v == 0) || (option_verbose > o_v)) {
if ((!c_d) || ((c_d) && (capidebug))) {
cc_mutex_lock(&verbose_lock);
cc_pbx_verbose(line);
cc_mutex_unlock(&verbose_lock);
}
}
cc_mutex_lock(&verbose_lock);
cc_pbx_verbose(line);
cc_mutex_unlock(&verbose_lock);
}
/*
@ -88,10 +87,17 @@ void capi_remove_nullif(struct capi_pvt *i)
return;
}
cc_mutex_lock(&i->lock);
if (i->line_plci != 0) {
ii = i->line_plci;
i->line_plci = 0;
capi_remove_nullif(ii);
}
cc_mutex_unlock(&i->lock);
if (i->PLCI != 0) {
/* if the interface is in use, hangup first */
cc_mutex_lock(&i->lock);
state = i->state;
i->state = CAPI_STATE_DISCONNECTING;
capi_activehangup(i, state);
@ -126,6 +132,16 @@ void capi_remove_nullif(struct capi_pvt *i)
cc_mutex_unlock(&nullif_lock);
}
int capi_verify_resource_plci(const struct capi_pvt *i) {
const struct capi_pvt *ii;
cc_mutex_lock(&nullif_lock);
for (ii = nulliflist; ii != 0 && ii != i; ii = ii->next);
cc_mutex_unlock(&nullif_lock);
return ((ii == i) ? 0 : -1);
}
/*
* create new null-interface
*/
@ -135,14 +151,14 @@ struct capi_pvt *capi_mknullif(struct ast_channel *c, unsigned long long control
unsigned int controller = 1;
int contrcount;
int channelcount = 0xffff;
int maxcontr = (CAPI_MAX_CONTROLLERS > sizeof(controllermask)) ?
sizeof(controllermask) : CAPI_MAX_CONTROLLERS;
int maxcontr = (CAPI_MAX_CONTROLLERS > (sizeof(controllermask)*8)) ?
(sizeof(controllermask)*8) : CAPI_MAX_CONTROLLERS;
cc_verbose(3, 1, VERBOSE_PREFIX_4 "capi_mknullif: find controller for mask 0x%lx\n",
controllermask);
/* find the next controller of mask with least plcis used */
for (contrcount = 0; contrcount < maxcontr; contrcount++) {
if ((controllermask & (1 << contrcount))) {
if ((controllermask & (1ULL << contrcount)) != 0) {
if (controller_nullplcis[contrcount] < channelcount) {
channelcount = controller_nullplcis[contrcount];
controller = contrcount + 1;
@ -213,6 +229,137 @@ struct capi_pvt *capi_mknullif(struct ast_channel *c, unsigned long long control
return tmp;
}
struct capi_pvt *capi_mkresourceif(struct ast_channel *c, unsigned long long controllermask, struct capi_pvt *data_plci_ifc) {
struct capi_pvt *data_ifc /*, *line_ifc */;
unsigned int controller = 1;
if (data_plci_ifc == 0) {
int contrcount;
int channelcount = 0xffff;
int maxcontr = (CAPI_MAX_CONTROLLERS > (sizeof(controllermask)*8)) ?
(sizeof(controllermask)*8) : CAPI_MAX_CONTROLLERS;
cc_verbose(3, 1, VERBOSE_PREFIX_4 "capi_mkresourceif: find controller for mask 0x%lx\n",
controllermask);
/* find the next controller of mask with least plcis used */
for (contrcount = 0; contrcount < maxcontr; contrcount++) {
if ((controllermask & (1ULL << contrcount)) != 0) {
if (controller_nullplcis[contrcount] < channelcount) {
channelcount = controller_nullplcis[contrcount];
controller = contrcount + 1;
}
}
}
} else {
controller = data_plci_ifc->controller;
}
data_ifc = malloc(sizeof(struct capi_pvt));
if (data_ifc == 0) {
return NULL;
}
memset(data_ifc, 0, sizeof(struct capi_pvt));
cc_mutex_init(&data_ifc->lock);
ast_cond_init(&data_ifc->event_trigger, NULL);
snprintf(data_ifc->name, sizeof(data_ifc->name) - 1, "%s-%sPLCI", c->name, (data_plci_ifc == 0) ? "DATA" : "LINE");
snprintf(data_ifc->vname, sizeof(data_ifc->vname) - 1, "%s", data_ifc->name);
data_ifc->channeltype = CAPI_CHANNELTYPE_NULL;
data_ifc->resource_plci_type = (data_plci_ifc == 0) ? CAPI_RESOURCE_PLCI_DATA : CAPI_RESOURCE_PLCI_LINE;
data_ifc->used = c;
data_ifc->peer = c;
data_ifc->cip = CAPI_CIPI_SPEECH;
data_ifc->transfercapability = PRI_TRANS_CAP_SPEECH;
data_ifc->controller = controller;
data_ifc->doEC = 1;
data_ifc->doEC_global = 1;
data_ifc->ecOption = EC_OPTION_DISABLE_NEVER;
data_ifc->ecTail = EC_DEFAULT_TAIL;
data_ifc->isdnmode = CAPI_ISDNMODE_MSN;
data_ifc->ecSelector = FACILITYSELECTOR_ECHO_CANCEL;
data_ifc->capability = capi_capability;
data_ifc->rxgain = 1.0;
data_ifc->txgain = 1.0;
capi_gains(&data_ifc->g, 1.0, 1.0);
if (data_plci_ifc == 0) {
if (!(capi_create_reader_writer_pipe(data_ifc))) {
free(data_ifc);
return NULL;
}
} else {
data_ifc->readerfd = -1;
data_ifc->writerfd = -1;
}
data_ifc->bproto = CC_BPROTO_TRANSPARENT;
data_ifc->doB3 = CAPI_B3_DONT;
data_ifc->smoother = ast_smoother_new(CAPI_MAX_B3_BLOCK_SIZE);
data_ifc->isdnstate |= CAPI_ISDN_STATE_PBX;
cc_mutex_lock(&nullif_lock);
data_ifc->next = nulliflist; /* prepend */
nulliflist = data_ifc;
controller_nullplcis[data_ifc->controller - 1]++;
cc_mutex_unlock(&nullif_lock);
/* connect to driver */
data_ifc->outgoing = 1;
data_ifc->state = CAPI_STATE_CONNECTPENDING;
data_ifc->MessageNumber = get_capi_MessageNumber();
cc_mutex_lock(&data_ifc->lock);
capi_sendf(data_ifc,
1,
CAPI_MANUFACTURER_REQ,
controller,
data_ifc->MessageNumber,
"dw(wbb(www()()()()))",
_DI_MANU_ID,
_DI_ASSIGN_PLCI,
(data_plci_ifc == 0) ? 4 : 5, /* data */
(data_plci_ifc == 0) ? 0 : (unsigned char)(data_plci_ifc->PLCI >> 8), /* bchannel */
1, /* connect */
1, 1, 0);
cc_mutex_unlock(&data_ifc->lock);
if (data_plci_ifc != 0) {
if (data_ifc->PLCI == 0) {
cc_log(LOG_WARNING, "%s: failed to create\n", data_ifc->vname);
capi_remove_nullif(data_ifc);
data_ifc = 0;
} else {
cc_mutex_lock(&data_plci_ifc->lock);
data_plci_ifc->line_plci = data_ifc;
capi_sendf(data_plci_ifc, 1, CAPI_FACILITY_REQ, data_plci_ifc->PLCI, get_capi_MessageNumber(),
"w(w(d()))",
FACILITYSELECTOR_LINE_INTERCONNECT,
0x0001, /* CONNECT */
0x00000000 /* mask */
);
cc_mutex_unlock(&data_plci_ifc->lock);
data_ifc->data_plci = data_plci_ifc;
data_ifc->writerfd = data_plci_ifc->writerfd;
data_plci_ifc->writerfd = -1;
}
}
if (data_ifc != 0) {
cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: created %s-resource-interface on controller %d.\n",
data_ifc->vname, (data_plci_ifc == 0) ? "data" : "line", data_ifc->controller);
}
return data_ifc;
}
/*
* get a new capi message number atomically
*/
@ -232,7 +379,7 @@ _cword get_capi_MessageNumber(void)
cc_mutex_unlock(&messagenumber_lock);
return(mn);
return mn;
}
/*
@ -242,7 +389,7 @@ struct capi_pvt *capi_find_interface_by_plci(unsigned int plci)
{
struct capi_pvt *i;
if (plci == 0)
if (unlikely(plci == 0))
return NULL;
for (i = capi_iflist; i; i = i->next) {
@ -315,9 +462,12 @@ MESSAGE_EXCHANGE_ERROR capi_wait_conf(struct capi_pvt *i, unsigned short wCmd)
/*
* log an error in sending capi message
*/
static void log_capi_error_message(MESSAGE_EXCHANGE_ERROR err, _cmsg *CMSG)
static void log_capi_error_message(MESSAGE_EXCHANGE_ERROR err, unsigned char* msg)
{
if (err) {
_cmsg _CMSG, *CMSG = &_CMSG;
capi_message2cmsg(CMSG, msg);
cc_log(LOG_ERROR, "CAPI error sending %s (NCCI=%#x) (error=%#x %s)\n",
capi_cmsg2str(CMSG), (unsigned int)HEADER_CID(CMSG),
err, capi_info_string((unsigned int)err));
@ -353,8 +503,10 @@ static MESSAGE_EXCHANGE_ERROR _capi_put_msg(unsigned char *msg)
return -1;
}
capi_message2cmsg(&CMSG, msg);
log_capi_message(&CMSG);
if (cc_verbose_check(4, 1) != 0) {
capi_message2cmsg(&CMSG, msg);
log_capi_message(&CMSG);
}
error = capi20_put_message(capi_ApplID, msg);
@ -363,7 +515,7 @@ static MESSAGE_EXCHANGE_ERROR _capi_put_msg(unsigned char *msg)
return -1;
}
log_capi_error_message(error, &CMSG);
log_capi_error_message(error, msg);
return error;
}
@ -425,8 +577,6 @@ MESSAGE_EXCHANGE_ERROR capi_sendf(
capi_prestruct_t *s;
unsigned char msg[2048];
memset(msg, 0, sizeof(msg));
write_capi_word(&msg[2], capi_ApplID);
msg[4] = (unsigned char)((command >> 8) & 0xff);
msg[5] = (unsigned char)(command & 0xff);
@ -438,9 +588,9 @@ MESSAGE_EXCHANGE_ERROR capi_sendf(
va_start(ap, format);
for (i = 0; format[i]; i++) {
if (((p - (&msg[0])) + 12) >= sizeof(msg)) {
if (unlikely(((p - (&msg[0])) + 12) >= sizeof(msg))) {
cc_log(LOG_ERROR, "capi_sendf: message too big (%d)\n",
(p - (&msg[0])));
(int)(p - (&msg[0])));
return 0x1004;
}
switch(format[i]) {
@ -532,7 +682,7 @@ MESSAGE_EXCHANGE_ERROR capi_sendf(
ret = capi_wait_conf(capii, (command & 0xff00) | CAPI_CONF);
}
return (ret);
return ret;
}
/*
@ -891,7 +1041,6 @@ void show_capi_info(struct capi_pvt *i, _cword info)
cc_verbose(3, 0, VERBOSE_PREFIX_4 "%s: CAPI INFO 0x%04x: %s\n",
name, info, p);
return;
}
/*
@ -931,6 +1080,50 @@ unsigned capi_ListenOnController(unsigned int CIPmask, unsigned controller)
return error;
}
/*
* Activate access to vendor specific extensions
*/
unsigned capi_ManufacturerAllowOnController(unsigned controller)
{
MESSAGE_EXCHANGE_ERROR error;
int waitcount = 50;
unsigned char manbuf[CAPI_MANUFACTURER_LEN];
_cmsg CMSG;
if (capi20_get_manufacturer(controller, manbuf) == NULL) {
error = CapiRegOSResourceErr;
goto done;
}
if ((strstr((char *)manbuf, "Eicon") == 0) &&
(strstr((char *)manbuf, "Dialogic") == 0)) {
error = 0x100F;
goto done;
}
error = capi_sendf (NULL, 0, CAPI_MANUFACTURER_REQ, controller, get_capi_MessageNumber(),
"dw(d)", _DI_MANU_ID, _DI_OPTIONS_REQUEST, 0x00000020L);
if (error)
goto done;
while (waitcount) {
error = capidev_check_wait_get_cmsg(&CMSG);
if (IS_MANUFACTURER_CONF(&CMSG) && (CMSG.ManuID == _DI_MANU_ID) &&
((CMSG.Class & 0xffff) == _DI_OPTIONS_REQUEST)) {
error = (MESSAGE_EXCHANGE_ERROR)(CMSG.Class >> 16);
break;
}
usleep(30000);
waitcount--;
}
if (!waitcount)
error = 0x100F;
done:
return error;
}
/*
* convert a number
*/
@ -1122,7 +1315,7 @@ struct ast_frame *capi_read_pipeframe(struct capi_pvt *i)
if ((f->frametype == AST_FRAME_VOICE) && (f->datalen > 0)) {
if (f->datalen > sizeof(i->frame_data)) {
cc_log(LOG_ERROR, "f.datalen(%d) greater than space of frame_data(%d)\n",
f->datalen, sizeof(i->frame_data));
f->datalen, (int)sizeof(i->frame_data));
f->datalen = sizeof(i->frame_data);
}
readsize = read(i->readerfd, i->frame_data + AST_FRIENDLY_OFFSET, f->datalen);
@ -1146,13 +1339,24 @@ int capi_write_frame(struct capi_pvt *i, struct ast_frame *f)
int txavg=0;
int ret = 0;
if (!i) {
if (unlikely(!i)) {
cc_log(LOG_ERROR, "channel has no interface\n");
return -1;
}
{
struct capi_pvt *ii = i;
cc_mutex_lock(&ii->lock);
if (i->line_plci != 0)
i = i->line_plci;
cc_mutex_unlock(&ii->lock);
}
if ((!(i->isdnstate & CAPI_ISDN_STATE_B3_UP)) || (!i->NCCI) ||
((i->isdnstate & (CAPI_ISDN_STATE_B3_CHANGE | CAPI_ISDN_STATE_LI)))) {
if (unlikely((!(i->isdnstate & CAPI_ISDN_STATE_B3_UP)) || (!i->NCCI) ||
((i->isdnstate & (CAPI_ISDN_STATE_B3_CHANGE | CAPI_ISDN_STATE_LI))))) {
return 0;
}
@ -1160,41 +1364,62 @@ int capi_write_frame(struct capi_pvt *i, struct ast_frame *f)
return 0;
}
if (f->frametype == AST_FRAME_NULL) {
if (unlikely(f->frametype == AST_FRAME_NULL)) {
return 0;
}
if (f->frametype == AST_FRAME_DTMF) {
if (unlikely(f->frametype == AST_FRAME_DTMF)) {
cc_log(LOG_ERROR, "dtmf frame should be written\n");
return 0;
}
if (f->frametype != AST_FRAME_VOICE) {
if (unlikely(f->frametype != AST_FRAME_VOICE)) {
cc_log(LOG_ERROR,"not a voice frame\n");
return 0;
}
if (i->FaxState & CAPI_FAX_STATE_ACTIVE) {
if (unlikely(i->FaxState & CAPI_FAX_STATE_ACTIVE)) {
cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: write on fax activity?\n",
i->vname);
return 0;
}
if ((!f->FRAME_DATA_PTR) || (!f->datalen)) {
if (unlikely((!f->FRAME_DATA_PTR) || (!f->datalen))) {
cc_log(LOG_DEBUG, "No data for FRAME_VOICE %s\n", i->vname);
return 0;
}
if (i->isdnstate & CAPI_ISDN_STATE_RTP) {
if ((!(f->subclass & i->codec)) &&
(f->subclass != capi_capability)) {
if (unlikely((!(f->subclass & i->codec)) &&
(f->subclass != capi_capability))) {
cc_log(LOG_ERROR, "don't know how to write subclass %s(%d)\n",
ast_getformatname(f->subclass), f->subclass);
return 0;
}
return capi_write_rtp(i, f);
}
if (i->B3count >= CAPI_MAX_B3_BLOCKS) {
if (unlikely(i->B3count >= CAPI_MAX_B3_BLOCKS)) {
cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: B3count is full, dropping packet.\n",
i->vname);
return 0;
}
if (i->bproto == CC_BPROTO_VOCODER) {
buf = &(i->send_buffer[(i->send_buffer_handle % CAPI_MAX_B3_BLOCKS) *
(CAPI_MAX_B3_BLOCK_SIZE + AST_FRIENDLY_OFFSET)]);
i->send_buffer_handle++;
memcpy (buf, f->FRAME_DATA_PTR, f->datalen);
error = capi_sendf(NULL, 0, CAPI_DATA_B3_REQ, i->NCCI, get_capi_MessageNumber(),
"dwww", buf, f->datalen, i->send_buffer_handle, 0);
if (likely(error == 0)) {
cc_mutex_lock(&i->lock);
i->B3count++;
i->B3q -= f->datalen;
if (i->B3q < 0)
i->B3q = 0;
cc_mutex_unlock(&i->lock);
}
return 0;
}
if ((!i->smoother) || (ast_smoother_feed(i->smoother, f) != 0)) {
cc_log(LOG_ERROR, "%s: failed to fill smoother\n", i->vname);
return 0;
@ -1242,7 +1467,7 @@ int capi_write_frame(struct capi_pvt *i, struct ast_frame *f)
i->vname, i->NCCI);
}
if (!error) {
if (likely(!error)) {
cc_mutex_lock(&i->lock);
i->B3count++;
i->B3q -= fsmooth->datalen;

View File

@ -18,7 +18,27 @@
extern int capidebug;
extern char *emptyid;
extern void cc_verbose(int o_v, int c_d, char *text, ...);
extern void cc_verbose_internal(char *text, ...);
static inline int cc_verbose_check(int o_v, int c_d)
{
if (unlikely(((o_v == 0) || (option_verbose > o_v)) &&
((!c_d) || ((c_d) && (capidebug))))) {
return 1;
}
return 0;
}
/*
* helper for <pbx>_verbose with different verbose settings
*/
#define cc_verbose(o_v,c_d,text, args...) do { \
if (cc_verbose_check(o_v, c_d) != 0) { \
cc_verbose_internal(text , ## args); \
} \
} while(0)
extern _cword get_capi_MessageNumber(void);
extern struct capi_pvt *capi_find_interface_by_msgnum(unsigned short msgnum);
extern struct capi_pvt *capi_find_interface_by_plci(unsigned int plci);
@ -27,15 +47,18 @@ extern MESSAGE_EXCHANGE_ERROR capidev_check_wait_get_cmsg(_cmsg *CMSG);
extern char *capi_info_string(unsigned int info);
extern void show_capi_info(struct capi_pvt *i, _cword info);
extern unsigned capi_ListenOnController(unsigned int CIPmask, unsigned controller);
extern unsigned capi_ManufacturerAllowOnController(unsigned controller);
extern void capi_parse_dialstring(char *buffer, char **interface, char **dest, char **param, char **ocid);
extern char *capi_number_func(unsigned char *data, unsigned int strip, char *buf);
extern int cc_add_peer_link_id(struct ast_channel *c);
extern struct ast_channel *cc_get_peer_link_id(const char *p);
extern void capi_remove_nullif(struct capi_pvt *i);
extern struct capi_pvt *capi_mknullif(struct ast_channel *c, unsigned long long controllermask);
struct capi_pvt *capi_mkresourceif(struct ast_channel *c, unsigned long long controllermask, struct capi_pvt *data_plci_ifc);
extern int capi_create_reader_writer_pipe(struct capi_pvt *i);
extern struct ast_frame *capi_read_pipeframe(struct capi_pvt *i);
extern int capi_write_frame(struct capi_pvt *i, struct ast_frame *f);
extern int capi_verify_resource_plci(const struct capi_pvt *i);
#define capi_number(data, strip) \
capi_number_func(data, strip, alloca(AST_MAX_EXTENSION))
@ -52,6 +75,6 @@ typedef struct capi_prestruct_s {
*/
extern MESSAGE_EXCHANGE_ERROR capi_sendf(
struct capi_pvt *capii, int waitconf,
_cword command, _cdword Id, _cword Number, char * format, ...);
_cword command, _cdword Id, _cword Number, char * format, ...);
#endif

167
dlist.c Normal file
View File

@ -0,0 +1,167 @@
/*
*
Copyright (c) Dialogic, 2009.
*
This source file is supplied for the use with
Dialogic range of DIVA Server Adapters.
*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
*
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
*
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "dlist.h"
/*
** Initialize linked list
*/
void
diva_q_init (diva_entity_queue_t* q)
{
q->head = q->tail = 0;
}
/*
** Remove element from linked list
*/
void
diva_q_remove (diva_entity_queue_t* q, diva_entity_link_t* what)
{
if(!what->prev) {
if ((q->head = what->next)) {
q->head->prev = 0;
} else {
q->tail = 0;
}
} else if (!what->next) {
q->tail = what->prev;
q->tail->next = 0;
} else {
what->prev->next = what->next;
what->next->prev = what->prev;
}
what->prev = what->next = 0;
}
/*
** Add element to the tail of linked list
*/
void
diva_q_add_tail (diva_entity_queue_t* q, diva_entity_link_t* what)
{
what->next = 0;
if (!q->head) {
what->prev = 0;
q->head = q->tail = what;
} else {
what->prev = q->tail;
q->tail->next = what;
q->tail = what;
}
}
/*
** Add element to the linked list after a specified element
*/
void diva_q_insert_after (diva_entity_queue_t* q, diva_entity_link_t* prev, diva_entity_link_t* what)
{
diva_entity_link_t *next;
if((0 == prev) || (0 == (next=diva_q_get_next(prev)))){
diva_q_add_tail(q,what);
return;
}
what->prev = prev;
what->next = next;
prev->next = what;
next->prev = what;
}
/*
** Add element to the linked list before a specified element
*/
void diva_q_insert_before (diva_entity_queue_t* q, diva_entity_link_t* next, diva_entity_link_t* what)
{
diva_entity_link_t *prev;
if(!next){
diva_q_add_tail(q,what);
return;
}
if(0 == (prev=diva_q_get_prev(next))){/*next seems to be the head*/
q->head=what;
what->prev=0;
what->next=next;
next->prev=what;
}else{ /*not the head*/
what->prev = prev;
what->next = next;
prev->next = what;
next->prev = what;
}
}
diva_entity_link_t* diva_q_find (const diva_entity_queue_t* q, const void* what,
diva_q_cmp_fn_t cmp_fn)
{
diva_entity_link_t* diva_q_current = q->head;
while (diva_q_current) {
if (!(*cmp_fn)(what, diva_q_current)) {
break;
}
diva_q_current = diva_q_current->next;
}
return (diva_q_current);
}
diva_entity_link_t*
diva_q_get_head (const diva_entity_queue_t* q)
{
return (q->head);
}
diva_entity_link_t*
diva_q_get_tail (const diva_entity_queue_t* q)
{
return (q->tail);
}
diva_entity_link_t*
diva_q_get_next (const diva_entity_link_t* what)
{
return ((what) ? what->next : 0);
}
diva_entity_link_t*
diva_q_get_prev (const diva_entity_link_t* what)
{
return ((what) ? what->prev : 0);
}
int
diva_q_get_nr_of_entries (const diva_entity_queue_t* q)
{
int i = 0;
const diva_entity_link_t* diva_q_current = q->head;
while (diva_q_current) {
i++;
diva_q_current = diva_q_current->next;
}
return (i);
}

54
dlist.h Normal file
View File

@ -0,0 +1,54 @@
/*
*
Copyright (c) Dialogic, 2009.
*
This source file is supplied for the use with
Dialogic range of DIVA Server Adapters.
*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
*
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
*
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef __DIVA_LINK_H__
#define __DIVA_LINK_H__
struct _diva_entity_link;
typedef struct _diva_entity_link {
struct _diva_entity_link* prev;
struct _diva_entity_link* next;
} diva_entity_link_t;
typedef struct _diva_entity_queue {
diva_entity_link_t* head;
diva_entity_link_t* tail;
} diva_entity_queue_t;
typedef int (*diva_q_cmp_fn_t)(const void* what,
const diva_entity_link_t*);
void diva_q_remove (diva_entity_queue_t* q, diva_entity_link_t* what);
void diva_q_add_tail (diva_entity_queue_t* q, diva_entity_link_t* what);
void diva_q_insert_after (diva_entity_queue_t* q, diva_entity_link_t* prev, diva_entity_link_t* what);
void diva_q_insert_before (diva_entity_queue_t* q, diva_entity_link_t* next, diva_entity_link_t* what);
diva_entity_link_t* diva_q_find (const diva_entity_queue_t* q,
const void* what, diva_q_cmp_fn_t cmp_fn);
diva_entity_link_t* diva_q_get_head (const diva_entity_queue_t* q);
diva_entity_link_t* diva_q_get_tail (const diva_entity_queue_t* q);
diva_entity_link_t* diva_q_get_next (const diva_entity_link_t* what);
diva_entity_link_t* diva_q_get_prev (const diva_entity_link_t* what);
int diva_q_get_nr_of_entries (const diva_entity_queue_t* q);
void diva_q_init (diva_entity_queue_t* q);
#endif

View File

@ -25,6 +25,8 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include "capi20_platform.h"
#include "capi20.h"
@ -311,9 +313,17 @@ static void write_capi_trace(int send, unsigned char *buf, int length, int datam
}
}
unsigned capi20_isinstalled (void)
static inline unsigned capi20_isinstalled_internal(void)
{
if (capi_fd >= 0)
if (likely(capi_fd >= 0))
return CapiNoError;
return (capi20_isinstalled());
}
unsigned capi20_isinstalled(void)
{
if (likely(capi_fd >= 0))
return CapiNoError;
/*----- open managment link -----*/
@ -696,10 +706,10 @@ capi20_put_message (unsigned ApplID, unsigned char *Msg)
int fd;
int datareq = 0;
if (capi20_isinstalled() != CapiNoError)
if (capi20_isinstalled_internal() != CapiNoError)
return CapiRegNotInstalled;
if (!validapplid(ApplID))
if (unlikely(!validapplid(ApplID)))
return CapiIllAppNr;
fd = applid2fd(ApplID);
@ -797,10 +807,10 @@ capi20_get_message (unsigned ApplID, unsigned char **Buf)
size_t bufsiz;
int rc, fd;
if (capi20_isinstalled() != CapiNoError)
if (capi20_isinstalled_internal() != CapiNoError)
return CapiRegNotInstalled;
if (!validapplid(ApplID))
if (unlikely(!validapplid(ApplID)))
return CapiIllAppNr;
fd = applid2fd(ApplID);
@ -823,7 +833,7 @@ capi20_get_message (unsigned ApplID, unsigned char **Buf)
CAPIMSG_U32(rcvbuf, 8));
capimsg_setu16(rcvbuf, 18, offset); /* patch datahandle */
if (sizeof(void *) == 4) {
u_int32_t data = (u_int32_t)rcvbuf + CAPIMSG_LEN(rcvbuf);
u_int32_t data = (u_int32_t)(unsigned long)rcvbuf + CAPIMSG_LEN(rcvbuf);
rcvbuf[12] = data & 0xff;
rcvbuf[13] = (data >> 8) & 0xff;
rcvbuf[14] = (data >> 16) & 0xff;
@ -1009,10 +1019,10 @@ capi20_waitformessage(unsigned ApplID, struct timeval *TimeOut)
FD_ZERO(&rfds);
if (capi20_isinstalled() != CapiNoError)
if (capi20_isinstalled_internal() != CapiNoError)
return CapiRegNotInstalled;
if (!validapplid(ApplID))
if (unlikely(!validapplid(ApplID)))
return CapiIllAppNr;
fd = applid2fd(ApplID);

View File

@ -0,0 +1,24 @@
#ifndef __CAPI20_PLATFORM_H__
#define __CAPI20_PLATFORM_H__
#if __GNUC__ >= 3 /* { */
#ifndef likely
#define likely(x) __builtin_expect(!!(x), 1)
#endif
#ifndef unlikely
#define unlikely(x) __builtin_expect(!!(x), 0)
#endif
#else /* } { */
#ifndef likely
#define likely(__x__) (!!(__x__))
#endif
#ifndef unlikely
#define unlikely(__x__) (!!(__x__))
#endif
#endif /* } */
#endif

View File

@ -343,7 +343,11 @@ static unsigned char *cpars[] = {
/*15*/ 0,
/*16 DISCONNECT_CONF*/ (unsigned char*)"\x03\x24\x01",
/*17 LISTEN_CONF*/ (unsigned char*)"\x03\x24\x01",
#if 0
/*18 MANUFACTURER_REQ*/ (unsigned char*)"\x03\x2b\x15\x22\x2a\x01",
#else /** \todo Need to treate manufacturer specific as plain data */
/*18 MANUFACTURER_REQ dw(...) */ (unsigned char*)"\x03\x2b\x24\x2a\x01",
#endif
/*19*/ 0,
/*1a INFO_CONF*/ (unsigned char*)"\x03\x24\x01",
/*1b FACILITY_CONF*/ (unsigned char*)"\x03\x24\x20\x1b\x01",
@ -365,7 +369,11 @@ static unsigned char *cpars[] = {
/*27 CONNECT_ACTIVE_IND*/ (unsigned char*)"\x03\x16\x17\x29\x01",
/*28 DISCONNECT_IND*/ (unsigned char*)"\x03\x2d\x01",
/*29*/ 0,
#if 0
/*2a MANUFACTURER_CONF*/ (unsigned char*)"\x03\x2b\x15\x22\x2a\x01",
#else /** \todo Need to treate manufacturer specific as plain data */
/*2a MANUFACTURER_CONF*/ (unsigned char*)"\x03\x2b\x15\x01",
#endif
/*2b*/ 0,
/*2c INFO_IND*/ (unsigned char*)"\x03\x27\x25\x01",
/*2d FACILITY_IND*/ (unsigned char*)"\x03\x20\x1d\x01",
@ -422,10 +430,18 @@ static unsigned char *cpars[] = {
#else
#ifdef __bfin__ /* Blackfin */
#define wordTLcpy(x,y) memcpy(x,y,2);
#else
#define wordTLcpy(x,y) *(_cword *)(x)=*(_cword *)(y);
#endif
#define dwordTLcpy(x,y) memcpy(x,y,4);
#ifdef __bfin__ /* Blackfin */
#define wordTRcpy(x,y) memcpy(y,x,2);
#else
#define wordTRcpy(x,y) *(_cword *)(y)=*(_cword *)(x);
#endif
#define dwordTRcpy(x,y) memcpy(y,x,4);
#define qwordTLcpy(x,y) memcpy(x,y,8);
@ -548,7 +564,7 @@ unsigned capi_cmsg2message(_cmsg * cmsg, _cbyte * msg)
if ( cmsg->Command == CAPI_DATA_B3
&& (cmsg->Subcommand == CAPI_REQ || cmsg->Subcommand == CAPI_IND)) {
if (sizeof(void *) == 4) {
cmsg->Data32 = (_cdword) cmsg->Data;
cmsg->Data32 = (_cdword)(unsigned long)cmsg->Data;
cmsg->Data64 = 0;
} else {
cmsg->Data32 = 0;
@ -570,7 +586,9 @@ unsigned capi_cmsg2message(_cmsg * cmsg, _cbyte * msg)
/*-------------------------------------------------------*/
static void message_2_pars(_cmsg * cmsg)
{
for (; TYP != _CEND; cmsg->p++) {
_cword message_length = CAPIMSG_LEN(cmsg->m);
for (; TYP != _CEND && cmsg->l < message_length; cmsg->p++) {
switch (TYP) {
case _CBYTE:
@ -621,11 +639,15 @@ static void message_2_pars(_cmsg * cmsg)
/*-------------------------------------------------------*/
unsigned capi_message2cmsg(_cmsg * cmsg, _cbyte * msg)
{
memset(cmsg, 0, sizeof(_cmsg));
_cbyte Command;
byteTRcpy(msg + 4, &Command);
if (Command != CAPI_DATA_B3)
memset(cmsg, 0, sizeof(_cmsg));
cmsg->m = msg;
cmsg->l = 8;
cmsg->p = 0;
byteTRcpy(cmsg->m + 4, &cmsg->Command);
cmsg->Command = Command;
byteTRcpy(cmsg->m + 5, &cmsg->Subcommand);
cmsg->par = cpars[command_2_index(cmsg->Command, cmsg->Subcommand)];
@ -634,7 +656,7 @@ unsigned capi_message2cmsg(_cmsg * cmsg, _cbyte * msg)
if ( cmsg->Command == CAPI_DATA_B3
&& (cmsg->Subcommand == CAPI_REQ || cmsg->Subcommand == CAPI_IND)) {
if (sizeof(void *) == 4) {
cmsg->Data = (void *) cmsg->Data32;
cmsg->Data = (void *)(unsigned long)cmsg->Data32;
} else {
cmsg->Data = (void *)(unsigned long)cmsg->Data64;
}