Current trunk is about to become new release. So lets put it into stable.
This commit is contained in:
parent
628b685080
commit
28ff6d6cdf
85
CHANGES
85
CHANGES
|
@ -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.
|
||||
|
|
8
INSTALL
8
INSTALL
|
@ -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.
|
||||
|
||||
|
|
2
Makefile
2
Makefile
|
@ -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
142
README
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
File diff suppressed because it is too large
Load Diff
58
README.qsig
58
README.qsig
|
@ -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
|
||||
|
|
32
capi.conf
32
capi.conf
|
@ -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.
|
||||
|
|
1787
chan_capi.c
1787
chan_capi.c
File diff suppressed because it is too large
Load Diff
52
chan_capi.h
52
chan_capi.h
|
@ -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
|
||||
|
|
722
chan_capi_chat.c
722
chan_capi_chat.c
|
@ -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(¶m, "|");
|
||||
options = strsep(¶m, "|");
|
||||
|
@ -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(¶m, "|");
|
||||
options = strsep(¶m, "|");
|
||||
file_name = strsep(¶m, "|");
|
||||
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(¶m, "|");
|
||||
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(¶m, "|");
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
*/
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue