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
|
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
|
chan_capi-1.1.2
|
||||||
------------------
|
------------------
|
||||||
- added config setting 'faxdetecttime' to limit the fax detection for a given amount of seconds.
|
- 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
|
- 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.
|
signaled as subscriber-number. Here the complete prefix including area code must be added.
|
||||||
- better counting of active b-channels.
|
- better counting of active B-channels.
|
||||||
- make capicommand(progress) "early-B3" usable for non NT-mode incoming channels too.
|
- 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
|
- 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.
|
from beginning of the call-establishment, even before calls are connected and the bridge command is received.
|
||||||
Dial() option 'G' is used to activate this feature.
|
The dial() option 'G' is used to activate this feature.
|
||||||
- fixed big-endian issue for DATA_B3 messages in internal libcapi code.
|
- fixed big-endian issue for DATA_B3 messages in internal libcapi code.
|
||||||
- fixed NULL-pointer when no digits are signaled in DID mode.
|
- fixed NULL-pointer when no digits are signaled in DID mode.
|
||||||
- adapt to new Asterisk 1.6.1 changes.
|
- 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
|
chan_capi-1.1.1
|
||||||
|
@ -34,8 +59,8 @@ chan_capi-1.1.0
|
||||||
- adapt to new asterisk 1.6 API
|
- adapt to new asterisk 1.6 API
|
||||||
- fixed reading capi profile on big-endian
|
- fixed reading capi profile on big-endian
|
||||||
- increased maximum number of CAPI controllers to 64 (needed for big PBX).
|
- 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).
|
- 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).
|
- use own libcapi20 implementation by default (no library for CAPI is needed any more).
|
||||||
|
|
||||||
chan_capi-1.0.2
|
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'
|
- added 'x' option to capicommand(ect) to have real 'explicit call transfer'
|
||||||
(needed by some ISDN lines)
|
(needed by some ISDN lines)
|
||||||
- support CCBS (call completion on busy subscriber)
|
- 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.
|
- fixed ton-display in 'show capi channels' on outgoing line.
|
||||||
- fix for 64bit support
|
- fix for 64bit support
|
||||||
- Asterisk 1.4.4 adaptions
|
- Asterisk 1.4.4 adaptions
|
||||||
|
@ -55,12 +80,12 @@ chan_capi-1.0.2
|
||||||
chan_capi-1.0.1
|
chan_capi-1.0.1
|
||||||
------------------
|
------------------
|
||||||
- added qsig caller-name patch by Mario Goegel
|
- 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
|
- register at CAPI with needed maxLogicalConnections only
|
||||||
- don't send SELECT_B_PROTOCOL more than once
|
- do not send SELECT_B_PROTOCOL more than once
|
||||||
- don't send more DATA_B3 messages than allowed by CAPI_MAX_B3_BLOCKS
|
- 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 '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
|
- added variable setting REDIRECTIONNUMBER on outgoing call
|
||||||
- fixed deadlock with ast_async_goto on fax tone detection
|
- fixed deadlock with ast_async_goto on fax tone detection
|
||||||
- listen to CAPI supplementary information
|
- listen to CAPI supplementary information
|
||||||
|
@ -84,15 +109,15 @@ chan_capi-1.0.0
|
||||||
- Read the channel frames during wait for fax finish.
|
- Read the channel frames during wait for fax finish.
|
||||||
- Added progress when in faxmode to wakeup asterisk-1.2.
|
- Added progress when in faxmode to wakeup asterisk-1.2.
|
||||||
(needed for e.g. auto-hangup on timeout)
|
(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.
|
- 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.
|
echo-cancel.
|
||||||
- Fix compiler warnings.
|
- Fix compiler warnings.
|
||||||
- Fixed callerid on incoming call with Asterisk 1.4 (PR#25)
|
- Fixed callerid on incoming call with Asterisk 1.4 (PR#25)
|
||||||
- Remove possible race condition in with hangup and DISCONNECT_IND.
|
- Remove possible race condition in with hangup and DISCONNECT_IND.
|
||||||
- Rixed gain and echosquelch use according to transfercapability.
|
- 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
|
- Reset PLCI on DISCONNECT_IND to avoid race if asterisk is too slow
|
||||||
with hangup command.
|
with hangup command.
|
||||||
- Added Asterisk 1.4 jitterbuffer usage.
|
- Added Asterisk 1.4 jitterbuffer usage.
|
||||||
|
@ -126,7 +151,7 @@ chan_capi-cm-0.6.5
|
||||||
|
|
||||||
chan_capi-cm-0.6.4
|
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
|
- fix deadlock when changing to fax mode
|
||||||
- better capi message handling
|
- better capi message handling
|
||||||
- removed double memset to zero
|
- removed double memset to zero
|
||||||
|
@ -148,15 +173,15 @@ chan_capi-cm-0.6.2
|
||||||
- set some info variables when receiving fax
|
- set some info variables when receiving fax
|
||||||
- added language support
|
- added language support
|
||||||
- prepared devicestate(hint) 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)
|
- 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
|
- fix missing CONF messages when no interface is found
|
||||||
- small transfercap and overlapdial fix
|
- 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
|
- fixed line interconnect
|
||||||
- b-channel handling better
|
- B-channel handling better
|
||||||
- NT mode progress
|
- NT-mode progress
|
||||||
- removed deadlock in faxreceive.
|
- removed deadlock in faxreceive.
|
||||||
- initialize variable ocid
|
- initialize variable ocid
|
||||||
- correct use of timeoutms in native bridge
|
- correct use of timeoutms in native bridge
|
||||||
|
@ -173,26 +198,26 @@ chan_capi-cm-0.6.1
|
||||||
used if dial option 'd' is specified.
|
used if dial option 'd' is specified.
|
||||||
- moved ast_softhangup() out of interface lock
|
- moved ast_softhangup() out of interface lock
|
||||||
- use correct mutex_init call for 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'.
|
with the CONNECT_REQ. This gives better progress together with 'b'.
|
||||||
- create a pseudo channel for each interface for incoming signalling
|
- create a pseudo channel for each interface for incoming signalling
|
||||||
without B-channel.
|
without B-channel.
|
||||||
- added channel locks
|
- added channel locks
|
||||||
- fixed capi init order (thanks to Hans Petter Selasky)
|
- fixed CAPI init order (thanks to Hans Petter Selasky)
|
||||||
- fixed did handling
|
- fixed DID handling
|
||||||
- set RDNIS if redirecting number was received.
|
- set RDNIS if redirecting number was received.
|
||||||
- simplified call to ast_exists_extension()
|
- simplified call to ast_exists_extension()
|
||||||
- when check for valid extension, check the callerid as well
|
- when check for valid extension, check the callerid as well
|
||||||
- changed call-waiting and deflect handling in CONNECT_IND
|
- 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.
|
CONNECT_IND and shall not wait until SETUP/SENDING-COMPLETE was received.
|
||||||
Since info like REDIRECTINGNUMBER will come after CONNECT_IND, this may
|
Since info like REDIRECTINGNUMBER will come after CONNECT_IND, this may
|
||||||
be lost then. But for some drivers/telcos/pbx, this setting is needed.
|
be lost then. But for some drivers/telcos/pbx, this setting is needed.
|
||||||
- fix start of line interconnect in old mode.
|
- fix start of line interconnect in old mode.
|
||||||
- start early-b3 on PROCEEDING too.
|
- 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
|
- 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.
|
- use correct A-law idle value.
|
||||||
- removed old example from capi.conf
|
- 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...
|
- receive a fax via CAPI is now done with capicommand(receivefax|...) and added stationid...
|
||||||
- fixed call-deflection and moved this feature from separate application
|
- fixed call-deflection and moved this feature from separate application
|
||||||
to capicommand().
|
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
|
- endian fixes
|
||||||
- compile fixes with newer Asterisk
|
- compile fixes with newer Asterisk
|
||||||
- update channel name on did changes.
|
- update channel name on did changes.
|
||||||
- support 'type of number' (numbering-plan).
|
- 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().
|
- allow using interface name in Dial().
|
||||||
- on hangup, use hangupcause from other channel or from var PRI_CAUSE.
|
- on hangup, use hangupcause from other channel or from var PRI_CAUSE.
|
||||||
- improved DID handling on PtP connections.
|
- 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
|
Modify the Makefile to fit your system, especially the path to the Asterisk
|
||||||
include files.
|
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.
|
files.
|
||||||
|
|
||||||
By default an internal version of libcapi20 is used (you don't need libcapi20 to
|
By default, an internal version of libcapi20 is used (you do not need libcapi20 to
|
||||||
be installed on your system). If you don't want this and the installed libcapi20
|
be installed on your system). If you do not want this and the installed libcapi20
|
||||||
shall be used, add the option
|
should be used, add the option
|
||||||
USE_OWN_LIBCAPI=no
|
USE_OWN_LIBCAPI=no
|
||||||
to the 'make' command.
|
to the 'make' command.
|
||||||
|
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -97,7 +97,7 @@ INSTALL=install
|
||||||
|
|
||||||
SHAREDOS=chan_capi.so
|
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_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
|
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.
|
Asterisk 1.2.x , 1.4.x or 1.6.x.
|
||||||
|
|
||||||
Note:
|
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:
|
This chan_capi version includes:
|
||||||
=====================================================
|
=====================================================
|
||||||
|
@ -44,9 +44,9 @@ This chan_capi version includes:
|
||||||
- Overlap sending (dialtone and additional digits)
|
- Overlap sending (dialtone and additional digits)
|
||||||
- E(xplicit) C(all) T(ransfer) (...although it's done implicit-but don't tell!)
|
- E(xplicit) C(all) T(ransfer) (...although it's done implicit-but don't tell!)
|
||||||
- Use asterisks internal DSP functions for DTMF
|
- Use asterisks internal DSP functions for DTMF
|
||||||
- Alaw support
|
- a-Law support
|
||||||
- Ulaw support!
|
- u-Law support!
|
||||||
- Dialogic DSP echo cancelation (echocancel=1)
|
- Dialogic(R) Diva(R) software DSP echo cancellation (echocancel=1)
|
||||||
- Reject call waiting (ACO)
|
- Reject call waiting (ACO)
|
||||||
- DID for Point to Point mode (a.k.a overlap receiving)
|
- 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)
|
- 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
|
using '-'. The according interface is found by searching a match with
|
||||||
the 'group' specified in the capi.conf for each interface.
|
the 'group' specified in the capi.conf for each interface.
|
||||||
|
|
||||||
The optional <callerid> followed by an ':' can be used to set a 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 callerid.
|
for this dial() command, without changing the original channel's caller ID.
|
||||||
|
|
||||||
'params' is an optional part to set special settings for this call.
|
'params' is an optional part to set special settings for this call.
|
||||||
The string consists of a list of characters with the following meaning:
|
The string consists of a list of characters with the following meaning:
|
||||||
'b' : early B3 always.
|
'b' : early B3 always.
|
||||||
'B' : early B3 on successful calls only.
|
'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.
|
'o' : use overlap sending of number.
|
||||||
(Useful if additional digits shall be send afterwards or together
|
(Useful if additional digits should be send afterwards or together
|
||||||
with 'b' to get dialtone and then send the number, e.g. if otherwise
|
with 'b' to get the dialtone and then send the number, e.g., if
|
||||||
no progress tones are available)
|
no progress tones are available)
|
||||||
's' : activate 'stay-online': don't disconnect CAPI connection on Hangup.
|
's' : activate 'stay-online': do not disconnect CAPI connection on hangup.
|
||||||
This is needed to give additional commands like CCBS after Hangup.
|
This is needed to give additional commands like CCBS after hangup.
|
||||||
To really hangup the CAPI connection, use either capicommand(hangup)
|
To really hang up the CAPI connection, use either capicommand(hangup)
|
||||||
or wait for chan_capi/network timeout (about 20 seconds).
|
or wait for chan_capi/network timeout (about 20 seconds).
|
||||||
'G' : early Line-Interconnect / bridge: Use Line-Interconnect as soon as
|
'G' : early Line-Interconnect / bridge: Use Line-Interconnect as soon as
|
||||||
both b-channels are up. Both channels must be of type CAPI and
|
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
|
the incoming call may need 'capicommand(progress)' to enable Early B3
|
||||||
on it as well as dial option 'b' for the outgoing channel.
|
on it as well as the dial option 'b' for the outgoing channel.
|
||||||
Before Dial(), the capicommand(peerlink) must be used to signal the
|
Before Dial(), the capicommand(peerlink) must be used to signal the
|
||||||
dialed channel its peer.
|
dialed channel its peer.
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ CAPI command application
|
||||||
========================================
|
========================================
|
||||||
chan_capi provides an additional Asterisk application
|
chan_capi provides an additional Asterisk application
|
||||||
capicommand()
|
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:
|
Call Deflection:
|
||||||
Forwards an unanswered call to another number.
|
Forwards an unanswered call to another number.
|
||||||
|
@ -151,29 +151,29 @@ Call Deflection:
|
||||||
exten => s,1,capicommand(deflect|12345678)
|
exten => s,1,capicommand(deflect|12345678)
|
||||||
|
|
||||||
Fax receive:
|
Fax receive:
|
||||||
Receive a fax using CAPI.
|
Receives a fax using CAPI.
|
||||||
Example:
|
Example:
|
||||||
exten => s,1,capicommand(receivefax|/tmp/${UNIQUEID}|+49 6137 555123|Asterisk|k)
|
exten => s,1,capicommand(receivefax|/tmp/${UNIQUEID}|+49 6137 555123|Asterisk|k)
|
||||||
(more see below)
|
(more see below)
|
||||||
|
|
||||||
Fax send:
|
Fax send:
|
||||||
Send a fax using CAPI.
|
Sends a fax using CAPI.
|
||||||
Example:
|
Example:
|
||||||
exten => s,1,capicommand(sendfax|/path/to/faxfile.sff|+49 6137 555123|Asterisk)
|
exten => s,1,capicommand(sendfax|/path/to/faxfile.sff|+49 6137 555123|Asterisk)
|
||||||
(more see below)
|
(more see below)
|
||||||
|
|
||||||
Enable/Disable echosquelch:
|
Enable/Disable echosquelch:
|
||||||
Enable or disable a very primitive echo suppressor.
|
Enables or disable a very primitive echo suppressor.
|
||||||
Disable this before you start recording voicemail or your files may get choppy.
|
Disable this option before you start recording voicemail or your files may get choppy.
|
||||||
Example:
|
Example:
|
||||||
exten => s,1,capicommand(echosquelch|yes)
|
exten => s,1,capicommand(echosquelch|yes)
|
||||||
or
|
or
|
||||||
exten => s,1,capicommand(echosquelch|no)
|
exten => s,1,capicommand(echosquelch|no)
|
||||||
|
|
||||||
Enable/Disable echocancel:
|
Enable/Disable echocancel:
|
||||||
Enable or disable echo-cancel provided by CAPI driver/hardware.
|
Enables or disables echo-cancel provided by CAPI driver/hardware.
|
||||||
You may need to disable echo-cancel when e.g. data/fax transmission handled
|
You might need to disable echo-cancel when the data/fax transmission is handled
|
||||||
by non-CAPI application. After hangup, this setting is restored to value
|
by a non-CAPI application. After hangup, this setting is restored to the value
|
||||||
set in capi.conf.
|
set in capi.conf.
|
||||||
Example:
|
Example:
|
||||||
exten => s,1,capicommand(echocancel|yes)
|
exten => s,1,capicommand(echocancel|yes)
|
||||||
|
@ -181,14 +181,14 @@ Enable/Disable echocancel:
|
||||||
exten => s,1,capicommand(echocancel|no)
|
exten => s,1,capicommand(echocancel|no)
|
||||||
|
|
||||||
Malicious Call Identification:
|
Malicious Call Identification:
|
||||||
Report a call of malicious nature.
|
Reports a call of malicious nature.
|
||||||
Example:
|
Example:
|
||||||
exten => s,1,capicommand(malicious)
|
exten => s,1,capicommand(malicious)
|
||||||
|
|
||||||
Hold:
|
Hold:
|
||||||
Puts an answered call on hold, this has nothing to do with asterisk's onhold
|
Puts an answered call on hold, this has nothing to do with Asterisk's onhold
|
||||||
thingie (music et al).
|
(music et al).
|
||||||
An optional parameter is the name of the variable which shall be set with
|
An optional parameter is the name of the variable, which should be set with
|
||||||
the reference ID of the call on hold.
|
the reference ID of the call on hold.
|
||||||
Example:
|
Example:
|
||||||
exten => s,1,capicommand(hold)
|
exten => s,1,capicommand(hold)
|
||||||
|
@ -196,7 +196,7 @@ Hold:
|
||||||
exten => s,1,capicommand(hold|MYHOLDVAR)
|
exten => s,1,capicommand(hold|MYHOLDVAR)
|
||||||
|
|
||||||
Holdtype:
|
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.
|
will be used.
|
||||||
Example:
|
Example:
|
||||||
exten => s,1,capicommand(holdtype|local) ;no hold, Asterisk can play MOH
|
exten => s,1,capicommand(holdtype|local) ;no hold, Asterisk can play MOH
|
||||||
|
@ -216,7 +216,7 @@ Retrieve:
|
||||||
exten => s,1,capicommand(retrieve|${MYHOLDVAR})
|
exten => s,1,capicommand(retrieve|${MYHOLDVAR})
|
||||||
|
|
||||||
ECT:
|
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:
|
Example:
|
||||||
exten => s,1,capicommand(ect|${MYHOLDVAR})
|
exten => s,1,capicommand(ect|${MYHOLDVAR})
|
||||||
or
|
or
|
||||||
|
@ -232,7 +232,7 @@ ECT:
|
||||||
instead.
|
instead.
|
||||||
|
|
||||||
3PTY:
|
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:
|
Example:
|
||||||
exten => s,1,capicommand(3pty_begin|${MYHOLDVAR})
|
exten => s,1,capicommand(3pty_begin|${MYHOLDVAR})
|
||||||
or
|
or
|
||||||
|
@ -243,23 +243,23 @@ ECT:
|
||||||
exten => s,2,Dial(CAPI/contr1/1234,,M(capi3pty))
|
exten => s,2,Dial(CAPI/contr1/1234,,M(capi3pty))
|
||||||
|
|
||||||
Peer link creation:
|
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.
|
This is needed if you want to use CCBS/CCNR afterwards.
|
||||||
Example:
|
Example:
|
||||||
exten => s,1,capicommand(peerlink)
|
exten => s,1,capicommand(peerlink)
|
||||||
|
|
||||||
Hangup in mode 'stay-online':
|
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:
|
until timeout or command:
|
||||||
exten => s,1,capicommand(hangup)
|
exten => s,1,capicommand(hangup)
|
||||||
This works after capicommand(peerlink) only.
|
This works after capicommand(peerlink) only.
|
||||||
|
|
||||||
Set local party to 'busy' or 'free':
|
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
|
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.
|
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:
|
with:
|
||||||
exten => s,1,capicommand(ccpartybusy|${CCLINKAGEID}|yes)
|
exten => s,1,capicommand(ccpartybusy|${CCLINKAGEID}|yes)
|
||||||
or
|
or
|
||||||
|
@ -275,7 +275,7 @@ Call completion on subscriber busy (CCBS):
|
||||||
;here you can ask the caller if CCBS shall be activated...
|
;here you can ask the caller if CCBS shall be activated...
|
||||||
exten => s,4,capicommand(ccbs|${CCLINKAGEID}|<context>|<exten>|<priority>)
|
exten => s,4,capicommand(ccbs|${CCLINKAGEID}|<context>|<exten>|<priority>)
|
||||||
exten => s,5,NoOp(${CCBSSTATUS}) ;if CCBS was successfully enabled, it is set to "ACTIVATED".
|
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
|
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.
|
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
|
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}/)
|
exten => s,1,Dial(CAPI/ccbs/${CCLINKAGEID}/)
|
||||||
|
|
||||||
Deactivate CCBS:
|
Deactivate CCBS:
|
||||||
To deactivate a previously activated CCBS, use following command:
|
To deactivate a previously activated CCBS, use the following command:
|
||||||
Example:
|
Example:
|
||||||
exten => s,1,capicommand(ccbsstop|${CCLINKAGEID})
|
exten => s,1,capicommand(ccbsstop|${CCLINKAGEID})
|
||||||
|
|
||||||
Chat (MeetMe/Conference):
|
Chat (MeetMe/Conference):
|
||||||
If the CAPI card/driver supports it, the caller can be put into a chat-room:
|
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)
|
exten => s,1,capicommand(chat|<roomname>|<options>|controller)
|
||||||
Example:
|
Example:
|
||||||
exten => s,1,capicommand(chat|salesmeeting|m|1,3-6)
|
exten => s,1,capicommand(chat|salesmeeting|m|1,3-6)
|
||||||
Possible options:
|
Possible options:
|
||||||
'm' = The first caller will get music-on-hold until second caller arrives.
|
'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:
|
Progress / Early-B3 on incoming calls:
|
||||||
Activate early-B3 on incoming channels to signal progress tones
|
Activate Early-B3 on incoming channels to signal progress tones
|
||||||
when in NT-mode or if the Telco-line supports this.
|
when in NT-mode or if the Telco-line supports this.
|
||||||
Example:
|
Example:
|
||||||
exten => s,1,capicommand(progress)
|
exten => s,1,capicommand(progress)
|
||||||
|
|
||||||
Get CAPI application ID:
|
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:
|
Example:
|
||||||
exten => s,1,capicommand(getid,CAPI_ID)
|
exten => s,1,capicommand(getid,CAPI_ID)
|
||||||
exten => s,2,NoOp(CAPI appl-id is ${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})
|
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.
|
Early B3 is configurable in the dialstring parameters.
|
||||||
If you set a 'b', early B3 will always be used, also if the call fails,
|
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,
|
If you set a 'B', early B3 will only be used on successful calls,
|
||||||
giving you ring indication,etc...
|
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:
|
you:
|
||||||
exten => _X.,1,Dial(CAPI/contr1/${EXTEN}/B,30)
|
exten => _X.,1,Dial(CAPI/contr1/${EXTEN}/B,30)
|
||||||
(early B3 on success)
|
(early B3 on success)
|
||||||
|
@ -342,14 +344,14 @@ you:
|
||||||
(early B3 on success, fake indicatons if the exchange does not give us
|
(early B3 on success, fake indicatons if the exchange does not give us
|
||||||
indications)
|
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)
|
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)
|
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.
|
local exchange.
|
||||||
At this point the channel is like a legacy phone, now you can send DTMF digits
|
At this point the channel is like a legacy phone, now you can send DTMF digits
|
||||||
to dial.
|
to dial.
|
||||||
|
@ -365,15 +367,15 @@ exten => 12345678,2,Hangup
|
||||||
|
|
||||||
Short HOWTO of capicommand(receivefax...) and capicommand(sendfax...):
|
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.
|
this allows you to receive/send faxes.
|
||||||
|
|
||||||
capicommand(receivefax|<filename>[|<stationid>|<headline>|<options>]):
|
capicommand(receivefax|<filename>[|<stationid>|<headline>|<options>]):
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
If you want to answer a channel in fax mode, use capicommand(receivefax|...)
|
If you want to answer a channel in fax mode, use capicommand(receivefax|...)
|
||||||
instead of Answer()
|
instead of Answer(). If you use Answer(), you will be in voice mode.
|
||||||
If you use Answer(), you will be in voice mode. If the hardware DSP detects
|
If the hardware DSP detects fax tone, you can switch from voice to fax mode
|
||||||
fax tone, you can switch from voice to fax mode by calling capicommand(receivefax|...).
|
by calling capicommand(receivefax|...).
|
||||||
The parameter <filename> is mandatory and the parameters <stationid>,
|
The parameter <filename> is mandatory and the parameters <stationid>,
|
||||||
<headline> and <options> are optional.
|
<headline> and <options> are optional.
|
||||||
By default, if fax reception was not successful, the file is deleted. If you want even
|
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.
|
The output of capicommand(receivefax|...) is a SFF file.
|
||||||
Use sfftobmp to convert it.
|
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
|
- fax up to 33600
|
||||||
- high resolution
|
- high resolution
|
||||||
- Color Fax
|
- Color Fax
|
||||||
|
@ -434,46 +436,57 @@ CLI command "capi show channels"
|
||||||
This CLI command shows detailed info on all CAPI channels.
|
This CLI command shows detailed info on all CAPI channels.
|
||||||
Column description:
|
Column description:
|
||||||
Line-Name : the name of the interface as defined in capi.conf
|
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', ...
|
state : the state of the channel, like 'Conn', 'Disc', 'Dial', ...
|
||||||
i/o : incoming or outgoing line
|
i/o : incoming or outgoing line
|
||||||
bproto : protocol on CAPI ('fax', 'trans' or 'rtp')
|
bproto : protocol on CAPI ('fax', 'trans' or 'rtp')
|
||||||
isdnstate : a string which may consists of the following characters
|
isdnstate : a string which may consists of the following characters
|
||||||
* = PBX is active
|
* = PBX is active
|
||||||
G = Line-Interconnect (CAPI bridge) active
|
G = Line-Interconnect (CAPI bridge) active
|
||||||
B = b-channel is up
|
B = B-channel is up
|
||||||
b = b-channel is requested
|
b = B-channel is requested
|
||||||
P = Progress was signaled
|
P = Progress was signaled
|
||||||
H = this line is on hold
|
H = this line is on hold
|
||||||
T = this line is in transfer (ECT) mode
|
T = this line is in transfer (ECT) mode
|
||||||
S = SETUP[_ACK] was signaled
|
S = SETUP[_ACK] was signaled
|
||||||
ton : type of number value
|
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
|
Asterisk variables used/set by chan_capi
|
||||||
==========================================================
|
==========================================================
|
||||||
|
|
||||||
BCHANNELINFO
|
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)
|
'0' : B-channel is used (default)
|
||||||
'1' : D-channel is used (not implemented yet)
|
'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.
|
Call-Waiting: an incoming call with BCHANNELINFO not '0' cannot be accepted.
|
||||||
Another connection must be dropped before accepting or use
|
Another connection must be dropped before accepting or use
|
||||||
capicommand(deflect|<number>) to initiate call deflection to another destination.
|
capicommand(deflect|<number>) to initiate call deflection to another destination.
|
||||||
|
|
||||||
CALLEDTON
|
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.
|
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
|
CALLERTON
|
||||||
The 'type of number' value to overwrite for the caller number on outgoing call.
|
The 'type of number' value to overwrite for the caller number on outgoing call.
|
||||||
|
|
||||||
_CALLERHOLDID
|
_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
|
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
|
CALLINGSUBADDRESS
|
||||||
If set on dial(), the calling subaddress will be set to the content.
|
If set on dial(), the calling subaddress will be set to the content.
|
||||||
|
@ -481,12 +494,17 @@ CALLINGSUBADDRESS
|
||||||
CALLEDSUBADDRESS
|
CALLEDSUBADDRESS
|
||||||
If set on dial(), the called subaddress will be set to the content.
|
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
|
CCBSSTATUS
|
||||||
When using capicommand(ccbs|....), this variable is set to either "ERROR" or
|
When using capicommand(ccbs|....), this variable is set to either "ERROR" or
|
||||||
"ACTIVATED".
|
"ACTIVATED".
|
||||||
|
|
||||||
CCLINKAGEID
|
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
|
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 a design problem in Asterisk, chan_capi is not able to set channel variables
|
||||||
of the calling channel.
|
of the calling channel.
|
||||||
|
@ -503,7 +521,7 @@ PRI_CAUSE
|
||||||
If set, this value will be used as hangup cause on hangup.
|
If set, this value will be used as hangup cause on hangup.
|
||||||
|
|
||||||
REDIRECTINGNUMBER
|
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.
|
number of the redirecting party is saved in this variable.
|
||||||
RDNIS is set as well.
|
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
|
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!
|
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 :-)
|
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
|
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
|
It is mainly used on connecting PBXs of different PBX vendors, which allows
|
||||||
better interoperability.
|
better interoperability.
|
||||||
As example there can be a name of an extension transferred between different
|
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.
|
These extensions will be transmitted as encoded facility information elements.
|
||||||
To use Q.SIG with asterisk, you'll need a card like Dialogic Diva
|
To use Q.SIG with Asterisk, you willll need a card such as a Dialogic(R) Diva(R)
|
||||||
(BRI like PRI), which supports QSIG. Maybe others do also work, let me now.
|
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
|
- 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:
|
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_DIVREASON Reason of divertion: 0 - unknown, 1 - unconditional, 2 - user busy, 3 - user no reply
|
||||||
QSIG_LI2_ODIVREASON Reason of original divertion (like above)
|
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
|
at the moment only incoming handling is supported
|
||||||
|
|
||||||
- Possibility to inform QSIG switch about call from public network
|
- Possibility to inform Q.SIG switch about a call from the public network
|
||||||
If you set variable QSIG_SETUP=X then the QSIG switch on the other side will know,
|
If you set the 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.
|
that this call source is the public network - you will get a different ring tone, etc.
|
||||||
In dialplan use: Set(__QSIG_SETUP=X) command.
|
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
|
its subchannels
|
||||||
|
|
||||||
- Simple Call Transfer
|
- Simple Call Transfer
|
||||||
With capicommand(qsig_ct|src-id|dst-id) you can transfer an inbound call back to the qsig switch.
|
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.
|
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.
|
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.
|
If you need to know whether your target is busy, you can use the call transfer feature below.
|
||||||
|
|
||||||
- Call Transfer (outgoing)
|
- Call Transfer (outgoing)
|
||||||
You can do an outbound call transfer.
|
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
|
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.
|
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
|
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
|
be automatically transferred. The transfer occurs after the CONNECT. If you want a 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.
|
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.
|
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
|
- 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.
|
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)
|
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.
|
This should be configurable in the next release.
|
||||||
|
|
||||||
- decoding of incoming Call Transfer feature
|
- 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
|
- 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
|
- 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:
|
Future Targets:
|
||||||
|
@ -98,7 +98,7 @@ Future Targets:
|
||||||
- Call Rerouting feature [ECMA-174]
|
- Call Rerouting feature [ECMA-174]
|
||||||
- CCBS
|
- CCBS
|
||||||
- AOC
|
- AOC
|
||||||
- sendtext implementation (e.g. display instructions on the connected set)
|
- sendtext implementation (e.g., display instructions on the connected set)
|
||||||
- ...
|
- ...
|
||||||
|
|
||||||
How to use:
|
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
|
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
|
0 QSIG turned off
|
||||||
1 Alcatel (4400 & Enterprise - Maybe OXO/4200) ECMA (wrongly named ECMA - it is ETSI) variant
|
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
|
[ISDN1] ;this example interface gets name 'ISDN1' and may be any
|
||||||
;name not starting with 'g' or 'contr'.
|
;name not starting with 'g' or 'contr'.
|
||||||
;Use one interface section for each isdn port!
|
;Use one interface section for each ISDN port!
|
||||||
;ntmode=yes ;if isdn card operates in nt mode, set this to yes
|
;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)
|
isdnmode=msn ;'MSN' (point-to-multipoint) or 'DID' (direct inward dial)
|
||||||
;when using NT-mode, 'DID' should be set in any case
|
;when using NT-mode, 'DID' should be set in any case
|
||||||
incomingmsn=* ;allow incoming calls to this list of MSNs/DIDs, * = any
|
incomingmsn=* ;allow incoming calls to this list of MSNs/DIDs, * = any
|
||||||
;defaultcid=123 ;set a default caller id to that interface for dial-out,
|
;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.
|
;this caller ID will be used when the dial option 'd' is set.
|
||||||
;controller=0 ;ISDN4BSD default
|
;controller=0 ;ISDN4BSD default
|
||||||
;controller=7 ;ISDN4BSD USB 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
|
group=1 ;dialout group
|
||||||
;prefix=0 ;set a prefix to calling number on incoming calls
|
;prefix=0 ;set a prefix to the calling number on incoming calls
|
||||||
softdtmf=on ;enable/disable software dtmf detection, recommended for AVM cards
|
softdtmf=on ;enable/disable software DTMF detection, recommended for AVM cards
|
||||||
relaxdtmf=on ;in addition to softdtmf, you can use relaxed dtmf detection
|
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
|
faxdetect=off ;enable faxdetection and redirection to EXTEN 'fax' for incoming and/or
|
||||||
;outgoing calls. (default='off', possible values: 'incoming','outgoing','both')
|
;outgoing calls. (default='off', possible values: 'incoming','outgoing','both')
|
||||||
faxdetecttime=0 ;Only detect faxes during the first 'n' seconds of the call.
|
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
|
;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
|
;set to 'local' (default value), no hold is done and the PBX may
|
||||||
;play MOH.
|
;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)
|
; 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
|
; info like REDIRECTINGNUMBER may be lost, but this is necessary for
|
||||||
; drivers/pbx/telco which does not send SETUP or SENDING-COMPLETE.
|
; 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)
|
;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')
|
;(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)
|
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)
|
;echotail=64 ;echo cancel tail setting (default=0 for maximum)
|
||||||
;echocancelnlp=1 ;activate non-linear-processing; this improves echo cancel ratio, but might
|
;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)
|
;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.
|
;transfergroup=1 ;Controller(s) where a transfer on native bridge is allowed to.
|
||||||
;language=de ;set language for this device (overwrites default language)
|
;language=de ;set language for this device (overwrites default language)
|
||||||
;disallow=all ;RTP codec selection (valid with Dialogic Diva only)
|
;disallow=all ;RTP codec selection (valid with Dialogic(R) Diva(R) Media Boards only)
|
||||||
;allow=all ;RTP codec selection (valid with Dialogic Diva 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
|
devices=2 ;number of concurrent calls (B-Channels) on this controller
|
||||||
;(2 makes sense for single BRI, 30/23 for PRI/T1)
|
;(2 makes sense for single BRI, 30/23 for PRI/T1)
|
||||||
;jb..... ;with Asterisk 1.4 you can configure jitterbuffer,
|
;jb..... ;with Asterisk 1.4 you can configure jitterbuffer,
|
||||||
;see Asterisk documentation for all jb* setting available.
|
;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"
|
#include "asterisk/abstract_jb.h"
|
||||||
#endif
|
#endif
|
||||||
#include "asterisk/musiconhold.h"
|
#include "asterisk/musiconhold.h"
|
||||||
|
#include "dlist.h"
|
||||||
|
|
||||||
#ifndef _PBX_CAPI_H
|
#ifndef _PBX_CAPI_H
|
||||||
#define _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_TRANSPARENT 0
|
||||||
#define CC_BPROTO_FAXG3 1
|
#define CC_BPROTO_FAXG3 1
|
||||||
#define CC_BPROTO_RTP 2
|
#define CC_BPROTO_RTP 2
|
||||||
|
#define CC_BPROTO_VOCODER 3
|
||||||
|
|
||||||
/* FAX Resolutions */
|
/* FAX Resolutions */
|
||||||
#define FAX_STANDARD_RESOLUTION 0
|
#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_ASCII_FORMAT 5
|
||||||
#define FAX_EXTENDED_ASCII_FORMAT 6
|
#define FAX_EXTENDED_ASCII_FORMAT 6
|
||||||
#define FAX_BINARY_FILE_TRANSFER_FORMAT 7
|
#define FAX_BINARY_FILE_TRANSFER_FORMAT 7
|
||||||
|
#define FAX_NATIVE_FILE_TRANSFER_FORMAT 8
|
||||||
|
|
||||||
/* Fax struct */
|
/* Fax struct */
|
||||||
struct fax3proto3 {
|
struct fax3proto3 {
|
||||||
|
@ -178,6 +181,7 @@ typedef struct fax3proto3 B3_PROTO_FAXG3;
|
||||||
#define FACILITYSELECTOR_SUPPLEMENTARY 0x0003
|
#define FACILITYSELECTOR_SUPPLEMENTARY 0x0003
|
||||||
#define FACILITYSELECTOR_LINE_INTERCONNECT 0x0005
|
#define FACILITYSELECTOR_LINE_INTERCONNECT 0x0005
|
||||||
#define FACILITYSELECTOR_ECHO_CANCEL 0x0008
|
#define FACILITYSELECTOR_ECHO_CANCEL 0x0008
|
||||||
|
#define PRIV_SELECTOR_DTMF_ONDATA 0x00fa
|
||||||
#define FACILITYSELECTOR_FAX_OVER_IP 0x00fd
|
#define FACILITYSELECTOR_FAX_OVER_IP 0x00fd
|
||||||
#define FACILITYSELECTOR_VOICE_OVER_IP 0x00fe
|
#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_OPTION_DISABLE_G164_OR_G165 (1<<1 | 1<<2)
|
||||||
#define EC_DEFAULT_TAIL 0 /* maximum */
|
#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_LOCAL 0
|
||||||
#define CC_HOLDTYPE_HOLD 1
|
#define CC_HOLDTYPE_HOLD 1
|
||||||
#define CC_HOLDTYPE_NOTIFY 2
|
#define CC_HOLDTYPE_NOTIFY 2
|
||||||
|
@ -261,6 +272,10 @@ struct cc_capi_gains {
|
||||||
#define CAPI_CHANNELTYPE_D 1
|
#define CAPI_CHANNELTYPE_D 1
|
||||||
#define CAPI_CHANNELTYPE_NULL 2
|
#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 */
|
/* the lower word is reserved for capi commands */
|
||||||
#define CAPI_WAITEVENT_B3_UP 0x00010000
|
#define CAPI_WAITEVENT_B3_UP 0x00010000
|
||||||
#define CAPI_WAITEVENT_B3_DOWN 0x00020000
|
#define CAPI_WAITEVENT_B3_DOWN 0x00020000
|
||||||
|
@ -437,6 +452,21 @@ struct capi_pvt {
|
||||||
float rxmin;
|
float rxmin;
|
||||||
float txmin;
|
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
|
#ifdef CC_AST_HAS_VERSION_1_4
|
||||||
struct ast_jb_conf jbconf;
|
struct ast_jb_conf jbconf;
|
||||||
char mohinterpret[MAX_MUSICCLASS];
|
char mohinterpret[MAX_MUSICCLASS];
|
||||||
|
@ -466,6 +496,14 @@ struct capi_pvt {
|
||||||
/* Q.SIG features */
|
/* Q.SIG features */
|
||||||
int qsigfeat;
|
int qsigfeat;
|
||||||
struct cc_qsig_data qsig_data;
|
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 */
|
/*! Next channel in list */
|
||||||
struct capi_pvt *next;
|
struct capi_pvt *next;
|
||||||
|
@ -528,6 +566,7 @@ struct cc_capi_conf {
|
||||||
struct ast_jb_conf jbconf;
|
struct ast_jb_conf jbconf;
|
||||||
char mohinterpret[MAX_MUSICCLASS];
|
char mohinterpret[MAX_MUSICCLASS];
|
||||||
#endif
|
#endif
|
||||||
|
int echocancelpath;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cc_capi_controller {
|
struct cc_capi_controller {
|
||||||
|
@ -559,6 +598,9 @@ struct cc_capi_controller {
|
||||||
int CONF;
|
int CONF;
|
||||||
/* RTP */
|
/* RTP */
|
||||||
int rtpcodec;
|
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[];
|
extern char chatinfo_usage[];
|
||||||
#endif
|
#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
|
#endif
|
||||||
|
|
722
chan_capi_chat.c
722
chan_capi_chat.c
|
@ -12,67 +12,136 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/signal.h>
|
#include <sys/signal.h>
|
||||||
|
|
||||||
|
#include "chan_capi_platform.h"
|
||||||
#include "chan_capi20.h"
|
#include "chan_capi20.h"
|
||||||
#include "chan_capi.h"
|
#include "chan_capi.h"
|
||||||
#include "chan_capi_chat.h"
|
#include "chan_capi_chat.h"
|
||||||
#include "chan_capi_utils.h"
|
#include "chan_capi_utils.h"
|
||||||
|
#include "chan_capi_command.h"
|
||||||
|
|
||||||
#define CHAT_FLAG_MOH 0x0001
|
#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 {
|
struct capichat_s {
|
||||||
char name[16];
|
char name[16];
|
||||||
unsigned int number;
|
unsigned int number;
|
||||||
int active;
|
int active;
|
||||||
|
room_member_type_t room_member_type;
|
||||||
|
room_mode_t room_mode;
|
||||||
struct capi_pvt *i;
|
struct capi_pvt *i;
|
||||||
struct capichat_s *next;
|
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;
|
static struct capichat_s *chat_list = NULL;
|
||||||
AST_MUTEX_DEFINE_STATIC(chat_lock);
|
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;
|
struct capichat_s *room;
|
||||||
unsigned char p_list[360];
|
unsigned char* p_list = &capi_msg->p_list[0];
|
||||||
_cdword dest;
|
_cdword dest;
|
||||||
_cdword datapath;
|
_cdword datapath;
|
||||||
capi_prestruct_t p_struct;
|
capi_prestruct_t* p_struct = &capi_msg->p_struct;
|
||||||
unsigned int found = 0;
|
unsigned int found = 0;
|
||||||
_cword j = 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) {
|
room = chat_start;
|
||||||
cc_verbose(2, 0, VERBOSE_PREFIX_3 CC_MESSAGE_NAME
|
while (room != 0) {
|
||||||
" mixer: %s: PLCI is unset, abort.\n", i->vname);
|
if (room->i == i) {
|
||||||
return;
|
main_member_type = room->room_member_type;
|
||||||
|
room_mode = room->room_mode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
room = room->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
cc_mutex_lock(&chat_lock);
|
if ((room_mode == RoomModeMuted) && (main_member_type == RoomMemberDefault)) {
|
||||||
room = chat_list;
|
main_member_type = RoomMemberListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
room = chat_start;
|
||||||
while (room) {
|
while (room) {
|
||||||
if ((room->number == roomnumber) &&
|
if ((room->number == roomnumber) &&
|
||||||
(room->i != i)) {
|
(room->i != i)) {
|
||||||
found++;
|
if ((found >= PLCI_PER_LX_REQUEST) || ((j + 9) > sizeof(capi_msg->p_list))) {
|
||||||
if (j + 9 > sizeof(p_list)) {
|
|
||||||
/* maybe we need to split capi messages here */
|
/* maybe we need to split capi messages here */
|
||||||
|
new_chat_start = room;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
found++;
|
||||||
ii = room->i;
|
ii = room->i;
|
||||||
|
ii_last = ii;
|
||||||
p_list[j++] = 8;
|
p_list[j++] = 8;
|
||||||
p_list[j++] = (_cbyte)(ii->PLCI);
|
p_list[j++] = (_cbyte)(ii->PLCI);
|
||||||
p_list[j++] = (_cbyte)(ii->PLCI >> 8);
|
p_list[j++] = (_cbyte)(ii->PLCI >> 8);
|
||||||
p_list[j++] = (_cbyte)(ii->PLCI >> 16);
|
p_list[j++] = (_cbyte)(ii->PLCI >> 16);
|
||||||
p_list[j++] = (_cbyte)(ii->PLCI >> 24);
|
p_list[j++] = (_cbyte)(ii->PLCI >> 24);
|
||||||
dest = (remove) ? 0x00000000 : 0x00000003;
|
dest = (remove) ? 0x00000000 : 0x00000003;
|
||||||
if (ii->channeltype == CAPI_CHANNELTYPE_NULL) {
|
if (ii->channeltype == CAPI_CHANNELTYPE_NULL && ii->line_plci == 0) {
|
||||||
dest |= 0x00000030;
|
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);
|
||||||
p_list[j++] = (_cbyte)(dest >> 8);
|
p_list[j++] = (_cbyte)(dest >> 8);
|
||||||
p_list[j++] = (_cbyte)(dest >> 16);
|
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 = 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) {
|
if (found != 0) {
|
||||||
p_struct.wLen = j;
|
p_struct->wLen = j;
|
||||||
p_struct.info = p_list;
|
p_struct->info = p_list;
|
||||||
|
|
||||||
/* don't send DATA_B3 to me */
|
/* don't send DATA_B3 to me */
|
||||||
datapath = 0x00000000;
|
datapath = 0x00000000;
|
||||||
if (remove) {
|
if (remove) {
|
||||||
/* now we need DATA_B3 again */
|
/* now we need DATA_B3 again */
|
||||||
datapath = 0x0000000c;
|
if (i->line_plci == 0) {
|
||||||
if (found == 1) {
|
if (i->channeltype != CAPI_CHANNELTYPE_NULL) {
|
||||||
|
datapath = 0x0000000c;
|
||||||
|
} else {
|
||||||
|
datapath = 0x00000030;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overall_found == 1) {
|
||||||
/* only one left, enable DATA_B3 too */
|
/* 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) {
|
if (!remove) {
|
||||||
datapath |= 0x00000030;
|
datapath |= 0x00000030;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cc_verbose(3, 1, VERBOSE_PREFIX_3 CC_MESSAGE_NAME
|
capi_msg->busy = 1;
|
||||||
" mixer: %s PLCI=0x%04x LI=0x%x\n", i->vname, i->PLCI, datapath);
|
capi_msg->datapath = datapath;
|
||||||
|
}
|
||||||
|
|
||||||
capi_sendf(NULL, 0, CAPI_FACILITY_REQ, i->PLCI, get_capi_MessageNumber(),
|
return (new_chat_start);
|
||||||
"w(w(dc))",
|
}
|
||||||
FACILITYSELECTOR_LINE_INTERCONNECT,
|
|
||||||
0x0001, /* CONNECT */
|
static void update_capi_mixer(int remove, unsigned int roomnumber, struct capi_pvt *i, deffered_chat_capi_message_t* update_segment)
|
||||||
datapath,
|
{
|
||||||
&p_struct
|
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);
|
cc_mutex_unlock(&chat_lock);
|
||||||
|
|
||||||
update_capi_mixer(1, roomnumber, i);
|
update_capi_mixer(1, roomnumber, i, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* add a new chat member
|
* 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 *room = NULL;
|
||||||
struct capichat_s *tmproom;
|
struct capichat_s *tmproom;
|
||||||
unsigned int roomnumber = 1;
|
unsigned int roomnumber = 1;
|
||||||
|
room_mode_t room_mode = RoomModeDefault;
|
||||||
|
|
||||||
room = malloc(sizeof(struct capichat_s));
|
room = malloc(sizeof(struct capichat_s));
|
||||||
if (room == NULL) {
|
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));
|
strncpy(room->name, roomname, sizeof(room->name));
|
||||||
room->name[sizeof(room->name) - 1] = 0;
|
room->name[sizeof(room->name) - 1] = 0;
|
||||||
room->i = i;
|
room->i = i;
|
||||||
|
room->room_member_type = room_member_type;
|
||||||
|
|
||||||
cc_mutex_lock(&chat_lock);
|
cc_mutex_lock(&chat_lock);
|
||||||
|
|
||||||
tmproom = chat_list;
|
tmproom = chat_list;
|
||||||
while (tmproom) {
|
while (tmproom) {
|
||||||
if (!strcmp(tmproom->name, roomname)) {
|
if (!strcmp(tmproom->name, roomname)) {
|
||||||
roomnumber = tmproom->number;
|
roomnumber = tmproom->number;
|
||||||
|
room_mode = tmproom->room_mode;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
if (tmproom->number == roomnumber) {
|
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->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;
|
room->next = chat_list;
|
||||||
chat_list = room;
|
chat_list = room;
|
||||||
|
|
||||||
cc_mutex_unlock(&chat_lock);
|
cc_mutex_unlock(&chat_lock);
|
||||||
|
|
||||||
cc_verbose(3, 0, VERBOSE_PREFIX_3 "%s: added new chat member to room '%s' (%d)\n",
|
cc_verbose(3, 0, VERBOSE_PREFIX_3 "%s: added new chat member to room '%s' %s(%d)\n",
|
||||||
i->vname, roomname, roomnumber);
|
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;
|
return room;
|
||||||
}
|
}
|
||||||
|
@ -209,7 +422,7 @@ static struct capichat_s *add_chat_member(char *roomname, struct capi_pvt *i)
|
||||||
* loop during chat
|
* loop during chat
|
||||||
*/
|
*/
|
||||||
static void chat_handle_events(struct ast_channel *c, struct capi_pvt *i,
|
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;
|
struct ast_frame *f;
|
||||||
int ms;
|
int ms;
|
||||||
|
@ -219,24 +432,33 @@ static void chat_handle_events(struct ast_channel *c, struct capi_pvt *i,
|
||||||
int nfds = 0;
|
int nfds = 0;
|
||||||
struct ast_channel *rchan;
|
struct ast_channel *rchan;
|
||||||
struct ast_channel *chan = c;
|
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;
|
waitfd = i->readerfd;
|
||||||
if (i->channeltype == CAPI_CHANNELTYPE_NULL) {
|
if (i->channeltype == CAPI_CHANNELTYPE_NULL) {
|
||||||
nfds = 1;
|
nfds = 1;
|
||||||
ast_set_read_format(chan, capi_capability);
|
if (voice_message == NULL) {
|
||||||
ast_set_write_format(chan, capi_capability);
|
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)
|
#if defined(CC_AST_HAS_VERSION_1_6) || defined(CC_AST_HAS_VERSION_1_4)
|
||||||
ast_moh_start(chan, NULL, NULL);
|
ast_moh_start(chan, NULL, NULL);
|
||||||
#else
|
#else
|
||||||
ast_moh_start(chan, NULL);
|
ast_moh_start(chan, NULL);
|
||||||
#endif
|
#endif
|
||||||
moh_active = 1;
|
if (voice_message == 0) {
|
||||||
|
moh_active = 1;
|
||||||
|
} else {
|
||||||
|
voice_message_moh_active = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -245,6 +467,10 @@ static void chat_handle_events(struct ast_channel *c, struct capi_pvt *i,
|
||||||
errno = 0;
|
errno = 0;
|
||||||
exception = 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);
|
rchan = ast_waitfor_nandfds(&chan, 1, &waitfd, nfds, &exception, &ready_fd, &ms);
|
||||||
|
|
||||||
if (rchan) {
|
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) {
|
} else if (f->frametype == AST_FRAME_VOICE) {
|
||||||
cc_verbose(5, 1, VERBOSE_PREFIX_3 "%s: chat: voice frame.\n",
|
cc_verbose(5, 1, VERBOSE_PREFIX_3 "%s: chat: voice frame.\n",
|
||||||
i->vname);
|
i->vname);
|
||||||
if (i->channeltype == CAPI_CHANNELTYPE_NULL) {
|
if ((voice_message == 0) && (i->channeltype == CAPI_CHANNELTYPE_NULL)) {
|
||||||
capi_write_frame(i, f);
|
capi_write_frame(i, f);
|
||||||
|
} else if (iline != 0) {
|
||||||
|
capi_write_frame(iline, f);
|
||||||
}
|
}
|
||||||
} else if (f->frametype == AST_FRAME_NULL) {
|
} else if (f->frametype == AST_FRAME_NULL) {
|
||||||
/* ignore NULL frame */
|
/* ignore NULL frame */
|
||||||
cc_verbose(5, 1, VERBOSE_PREFIX_3 "%s: chat: NULL frame, ignoring.\n",
|
cc_verbose(5, 1, VERBOSE_PREFIX_3 "%s: chat: NULL frame, ignoring.\n",
|
||||||
i->vname);
|
i->vname);
|
||||||
|
} else if ((f->frametype == AST_FRAME_DTMF_END) && (voice_message == 0)) {
|
||||||
|
pbx_capi_voicecommand_process_digit (i, c, f->subclass);
|
||||||
} else {
|
} else {
|
||||||
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: chat: unhandled frame %d/%d.\n",
|
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: chat: unhandled frame %d/%d.\n",
|
||||||
i->vname, f->frametype, f->subclass);
|
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);
|
f = capi_read_pipeframe(i);
|
||||||
if (f->frametype == AST_FRAME_VOICE) {
|
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 */
|
/* ignore other nullplci frames */
|
||||||
} else {
|
} else {
|
||||||
|
@ -299,6 +550,9 @@ static void chat_handle_events(struct ast_channel *c, struct capi_pvt *i,
|
||||||
moh_active = 0;
|
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;
|
ast_group_t tmpcntr;
|
||||||
unsigned long long contr = 0;
|
unsigned long long contr = 0;
|
||||||
unsigned int flags = 0;
|
unsigned int flags = 0;
|
||||||
|
room_member_type_t room_member_type = RoomMemberDefault;
|
||||||
|
|
||||||
roomname = strsep(¶m, "|");
|
roomname = strsep(¶m, "|");
|
||||||
options = strsep(¶m, "|");
|
options = strsep(¶m, "|");
|
||||||
|
@ -336,6 +591,13 @@ int pbx_capi_chat(struct ast_channel *c, char *param)
|
||||||
case 'm':
|
case 'm':
|
||||||
flags |= CHAT_FLAG_MOH;
|
flags |= CHAT_FLAG_MOH;
|
||||||
break;
|
break;
|
||||||
|
case 'l':
|
||||||
|
room_member_type = RoomMemberListener;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
room_member_type = RoomMemberOperator;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
cc_log(LOG_WARNING, "Unknown chat option '%c'.\n",
|
cc_log(LOG_WARNING, "Unknown chat option '%c'.\n",
|
||||||
*options);
|
*options);
|
||||||
|
@ -352,8 +614,12 @@ int pbx_capi_chat(struct ast_channel *c, char *param)
|
||||||
i = CC_CHANNEL_PVT(c);
|
i = CC_CHANNEL_PVT(c);
|
||||||
} else {
|
} else {
|
||||||
/* virtual CAPI channel */
|
/* virtual CAPI channel */
|
||||||
i = capi_mknullif(c, contr);
|
i = pbx_check_resource_plci(c);
|
||||||
if (!i) {
|
|
||||||
|
if (i == NULL) {
|
||||||
|
i = capi_mknullif(c, contr);
|
||||||
|
}
|
||||||
|
if (i == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -367,14 +633,15 @@ int pbx_capi_chat(struct ast_channel *c, char *param)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
room = add_chat_member(roomname, i);
|
room = add_chat_member(roomname, i, room_member_type);
|
||||||
if (!room) {
|
if (!room) {
|
||||||
cc_log(LOG_WARNING, "Unable to open " CC_MESSAGE_NAME " chat room.\n");
|
cc_log(LOG_WARNING, "Unable to open " CC_MESSAGE_NAME " chat room.\n");
|
||||||
|
capi_remove_nullif(i);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* main loop */
|
/* main loop */
|
||||||
chat_handle_events(c, i, room, flags);
|
chat_handle_events(c, i, room, flags, 0, 0);
|
||||||
|
|
||||||
del_chat_member(room);
|
del_chat_member(room);
|
||||||
|
|
||||||
|
@ -384,6 +651,278 @@ out:
|
||||||
return 0;
|
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
|
* do command capi chatinfo
|
||||||
*/
|
*/
|
||||||
|
@ -447,3 +986,70 @@ int pbxcli_capi_chatinfo(int fd, int argc, char *argv[])
|
||||||
#endif
|
#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
|
* prototypes
|
||||||
*/
|
*/
|
||||||
extern int pbx_capi_chat(struct ast_channel *c, char *param);
|
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
|
#ifdef CC_AST_HAS_VERSION_1_6
|
||||||
extern char *pbxcli_capi_chatinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
|
extern char *pbxcli_capi_chatinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
|
||||||
#else
|
#else
|
||||||
extern int pbxcli_capi_chatinfo(int fd, int argc, char *argv[]);
|
extern int pbxcli_capi_chatinfo(int fd, int argc, char *argv[]);
|
||||||
#endif
|
#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
|
#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 <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "chan_capi_platform.h"
|
||||||
#include "chan_capi20.h"
|
#include "chan_capi20.h"
|
||||||
#include "chan_capi.h"
|
#include "chan_capi.h"
|
||||||
#include "chan_capi_utils.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];
|
char buf[ASN197ADE_NUMDIGITS_STRSIZE+1];
|
||||||
unsigned int buflen = sizeof(buf);
|
unsigned int buflen = sizeof(buf);
|
||||||
unsigned res;
|
unsigned res;
|
||||||
|
int numtype;
|
||||||
|
|
||||||
ns->partyNumber = NULL;
|
ns->partyNumber = NULL;
|
||||||
ns->screeningInd = userProvidedNotScreened;
|
ns->screeningInd = userProvidedNotScreened;
|
||||||
int numtype;
|
|
||||||
|
|
||||||
numtype = (data[myidx++] & 0x0F); /* defines type of Number */
|
numtype = (data[myidx++] & 0x0F); /* defines type of Number */
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "chan_capi_platform.h"
|
||||||
#include "chan_capi20.h"
|
#include "chan_capi20.h"
|
||||||
#include "chan_capi.h"
|
#include "chan_capi.h"
|
||||||
#include "chan_capi_utils.h"
|
#include "chan_capi_utils.h"
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "chan_capi_platform.h"
|
||||||
#include "chan_capi20.h"
|
#include "chan_capi20.h"
|
||||||
#include "chan_capi.h"
|
#include "chan_capi.h"
|
||||||
#include "chan_capi_utils.h"
|
#include "chan_capi_utils.h"
|
||||||
|
@ -574,13 +575,15 @@ signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protoco
|
||||||
invokedescrtype = 2;
|
invokedescrtype = 2;
|
||||||
datalen = invoke->oid_len;
|
datalen = invoke->oid_len;
|
||||||
|
|
||||||
unsigned char *oidstr = NULL;
|
{
|
||||||
oidstr = cc_qsig_asn1_oid2str(invoke->oid_bin, invoke->oid_len);
|
unsigned char *oidstr = NULL;
|
||||||
if (oidstr) {
|
oidstr = cc_qsig_asn1_oid2str(invoke->oid_bin, invoke->oid_len);
|
||||||
cc_qsig_verbose( 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (%s)\n", oidstr);
|
if (oidstr) {
|
||||||
free(oidstr);
|
cc_qsig_verbose( 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (%s)\n", oidstr);
|
||||||
} else {
|
free(oidstr);
|
||||||
cc_qsig_verbose( 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (unknown - OID not displayable)\n");
|
} else {
|
||||||
|
cc_qsig_verbose( 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (unknown - OID not displayable)\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((datalen) == 4) {
|
if ((datalen) == 4) {
|
||||||
|
@ -606,13 +609,15 @@ signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protoco
|
||||||
invokedescrtype = 2;
|
invokedescrtype = 2;
|
||||||
datalen = invoke->oid_len;
|
datalen = invoke->oid_len;
|
||||||
|
|
||||||
unsigned char *oidstr = NULL;
|
{
|
||||||
oidstr = cc_qsig_asn1_oid2str(invoke->oid_bin, invoke->oid_len);
|
unsigned char *oidstr = NULL;
|
||||||
if (oidstr) {
|
oidstr = cc_qsig_asn1_oid2str(invoke->oid_bin, invoke->oid_len);
|
||||||
cc_qsig_verbose( 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (%s)\n", oidstr);
|
if (oidstr) {
|
||||||
free(oidstr);
|
cc_qsig_verbose( 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (%s)\n", oidstr);
|
||||||
} else {
|
free(oidstr);
|
||||||
cc_qsig_verbose( 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (unknown - OID not displayable)\n");
|
} else {
|
||||||
|
cc_qsig_verbose( 1, VERBOSE_PREFIX_3 "QSIG: INVOKE OP (unknown - OID not displayable)\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((datalen) == 4) {
|
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.calltransfer = 1;
|
||||||
i->qsig_data.partner_plci = atoi(pp);
|
i->qsig_data.partner_plci = atoi(pp);
|
||||||
/* set the other channel as partner to me */
|
/* set the other channel as partner to me */
|
||||||
struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci);
|
{
|
||||||
if (ii)
|
struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci);
|
||||||
ii->qsig_data.partner_plci = i->PLCI;
|
if (ii)
|
||||||
|
ii->qsig_data.partner_plci = i->PLCI;
|
||||||
|
}
|
||||||
|
|
||||||
cc_qsig_verbose( 1, " for plci %#x\n", i->qsig_data.partner_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.calltransfer_onring = 1;
|
||||||
i->qsig_data.partner_plci = atoi(pp);
|
i->qsig_data.partner_plci = atoi(pp);
|
||||||
/* set the other channel as partner to me */
|
/* set the other channel as partner to me */
|
||||||
struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci);
|
{
|
||||||
if (ii)
|
struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci);
|
||||||
ii->qsig_data.partner_plci = i->PLCI;
|
if (ii)
|
||||||
|
ii->qsig_data.partner_plci = i->PLCI;
|
||||||
|
}
|
||||||
|
|
||||||
cc_qsig_verbose( 1, " for plci %#x\n", i->qsig_data.partner_plci);
|
cc_qsig_verbose( 1, " for plci %#x\n", i->qsig_data.partner_plci);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "chan_capi_platform.h"
|
||||||
#include "chan_capi20.h"
|
#include "chan_capi20.h"
|
||||||
#include "chan_capi.h"
|
#include "chan_capi.h"
|
||||||
#include "chan_capi_utils.h"
|
#include "chan_capi_utils.h"
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include "chan_capi_platform.h"
|
||||||
#include "chan_capi20.h"
|
#include "chan_capi20.h"
|
||||||
#include "chan_capi.h"
|
#include "chan_capi.h"
|
||||||
#include "chan_capi_rtp.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;
|
cp->rtpcodec |= AST_FORMAT_G729A;
|
||||||
cc_verbose(3, 0, "G.729");
|
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");
|
cc_verbose(3, 0, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "chan_capi_platform.h"
|
||||||
#include "chan_capi20.h"
|
#include "chan_capi20.h"
|
||||||
#include "chan_capi.h"
|
#include "chan_capi.h"
|
||||||
#include "chan_capi_supplementary.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)
|
static int ccbsnr_tell_activated(void *data)
|
||||||
{
|
{
|
||||||
unsigned int handle = (unsigned int)data;
|
unsigned int handle = (unsigned int)(unsigned long)data;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
unsigned int state;
|
unsigned int state;
|
||||||
|
|
||||||
|
@ -832,7 +833,7 @@ int pbx_capi_ccbs(struct ast_channel *c, char *data)
|
||||||
for (a = 0; a < 7; a++) {
|
for (a = 0; a < 7; a++) {
|
||||||
/* Wait for CCBS request indication */
|
/* Wait for CCBS request indication */
|
||||||
if (ast_safe_sleep_conditional(c, 500, ccbsnr_tell_activated,
|
if (ast_safe_sleep_conditional(c, 500, ccbsnr_tell_activated,
|
||||||
(void *)handle) != 0) {
|
(void *)(unsigned long)handle) != 0) {
|
||||||
/* we got a hangup */
|
/* we got a hangup */
|
||||||
cc_verbose(3, 1,
|
cc_verbose(3, 1,
|
||||||
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " ccbs: hangup.\n");
|
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " ccbs: hangup.\n");
|
||||||
|
|
|
@ -16,7 +16,9 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include "chan_capi_platform.h"
|
||||||
#include "xlaw.h"
|
#include "xlaw.h"
|
||||||
#include "chan_capi20.h"
|
#include "chan_capi20.h"
|
||||||
#include "chan_capi.h"
|
#include "chan_capi.h"
|
||||||
|
@ -45,9 +47,9 @@ static struct peerlink_s {
|
||||||
} peerlinkchannel[CAPI_MAX_PEERLINKCHANNELS];
|
} 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];
|
char line[4096];
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
@ -55,6 +57,7 @@ void cc_verbose(int o_v, int c_d, char *text, ...)
|
||||||
va_start(ap, text);
|
va_start(ap, text);
|
||||||
vsnprintf(line, sizeof(line), text, ap);
|
vsnprintf(line, sizeof(line), text, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
line[sizeof(line)-1]=0;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
{
|
{
|
||||||
|
@ -66,13 +69,9 @@ void cc_verbose(int o_v, int c_d, char *text, ...)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((o_v == 0) || (option_verbose > o_v)) {
|
cc_mutex_lock(&verbose_lock);
|
||||||
if ((!c_d) || ((c_d) && (capidebug))) {
|
cc_pbx_verbose(line);
|
||||||
cc_mutex_lock(&verbose_lock);
|
cc_mutex_unlock(&verbose_lock);
|
||||||
cc_pbx_verbose(line);
|
|
||||||
cc_mutex_unlock(&verbose_lock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -88,10 +87,17 @@ void capi_remove_nullif(struct capi_pvt *i)
|
||||||
return;
|
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 (i->PLCI != 0) {
|
||||||
/* if the interface is in use, hangup first */
|
/* if the interface is in use, hangup first */
|
||||||
cc_mutex_lock(&i->lock);
|
cc_mutex_lock(&i->lock);
|
||||||
|
|
||||||
state = i->state;
|
state = i->state;
|
||||||
i->state = CAPI_STATE_DISCONNECTING;
|
i->state = CAPI_STATE_DISCONNECTING;
|
||||||
capi_activehangup(i, state);
|
capi_activehangup(i, state);
|
||||||
|
@ -126,6 +132,16 @@ void capi_remove_nullif(struct capi_pvt *i)
|
||||||
cc_mutex_unlock(&nullif_lock);
|
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
|
* 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;
|
unsigned int controller = 1;
|
||||||
int contrcount;
|
int contrcount;
|
||||||
int channelcount = 0xffff;
|
int channelcount = 0xffff;
|
||||||
int maxcontr = (CAPI_MAX_CONTROLLERS > sizeof(controllermask)) ?
|
int maxcontr = (CAPI_MAX_CONTROLLERS > (sizeof(controllermask)*8)) ?
|
||||||
sizeof(controllermask) : CAPI_MAX_CONTROLLERS;
|
(sizeof(controllermask)*8) : CAPI_MAX_CONTROLLERS;
|
||||||
|
|
||||||
cc_verbose(3, 1, VERBOSE_PREFIX_4 "capi_mknullif: find controller for mask 0x%lx\n",
|
cc_verbose(3, 1, VERBOSE_PREFIX_4 "capi_mknullif: find controller for mask 0x%lx\n",
|
||||||
controllermask);
|
controllermask);
|
||||||
/* find the next controller of mask with least plcis used */
|
/* find the next controller of mask with least plcis used */
|
||||||
for (contrcount = 0; contrcount < maxcontr; contrcount++) {
|
for (contrcount = 0; contrcount < maxcontr; contrcount++) {
|
||||||
if ((controllermask & (1 << contrcount))) {
|
if ((controllermask & (1ULL << contrcount)) != 0) {
|
||||||
if (controller_nullplcis[contrcount] < channelcount) {
|
if (controller_nullplcis[contrcount] < channelcount) {
|
||||||
channelcount = controller_nullplcis[contrcount];
|
channelcount = controller_nullplcis[contrcount];
|
||||||
controller = contrcount + 1;
|
controller = contrcount + 1;
|
||||||
|
@ -213,6 +229,137 @@ struct capi_pvt *capi_mknullif(struct ast_channel *c, unsigned long long control
|
||||||
return tmp;
|
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
|
* get a new capi message number atomically
|
||||||
*/
|
*/
|
||||||
|
@ -232,7 +379,7 @@ _cword get_capi_MessageNumber(void)
|
||||||
|
|
||||||
cc_mutex_unlock(&messagenumber_lock);
|
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;
|
struct capi_pvt *i;
|
||||||
|
|
||||||
if (plci == 0)
|
if (unlikely(plci == 0))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (i = capi_iflist; i; i = i->next) {
|
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
|
* 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) {
|
if (err) {
|
||||||
|
_cmsg _CMSG, *CMSG = &_CMSG;
|
||||||
|
|
||||||
|
capi_message2cmsg(CMSG, msg);
|
||||||
cc_log(LOG_ERROR, "CAPI error sending %s (NCCI=%#x) (error=%#x %s)\n",
|
cc_log(LOG_ERROR, "CAPI error sending %s (NCCI=%#x) (error=%#x %s)\n",
|
||||||
capi_cmsg2str(CMSG), (unsigned int)HEADER_CID(CMSG),
|
capi_cmsg2str(CMSG), (unsigned int)HEADER_CID(CMSG),
|
||||||
err, capi_info_string((unsigned int)err));
|
err, capi_info_string((unsigned int)err));
|
||||||
|
@ -353,8 +503,10 @@ static MESSAGE_EXCHANGE_ERROR _capi_put_msg(unsigned char *msg)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
capi_message2cmsg(&CMSG, msg);
|
if (cc_verbose_check(4, 1) != 0) {
|
||||||
log_capi_message(&CMSG);
|
capi_message2cmsg(&CMSG, msg);
|
||||||
|
log_capi_message(&CMSG);
|
||||||
|
}
|
||||||
|
|
||||||
error = capi20_put_message(capi_ApplID, msg);
|
error = capi20_put_message(capi_ApplID, msg);
|
||||||
|
|
||||||
|
@ -363,7 +515,7 @@ static MESSAGE_EXCHANGE_ERROR _capi_put_msg(unsigned char *msg)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_capi_error_message(error, &CMSG);
|
log_capi_error_message(error, msg);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -425,8 +577,6 @@ MESSAGE_EXCHANGE_ERROR capi_sendf(
|
||||||
capi_prestruct_t *s;
|
capi_prestruct_t *s;
|
||||||
unsigned char msg[2048];
|
unsigned char msg[2048];
|
||||||
|
|
||||||
memset(msg, 0, sizeof(msg));
|
|
||||||
|
|
||||||
write_capi_word(&msg[2], capi_ApplID);
|
write_capi_word(&msg[2], capi_ApplID);
|
||||||
msg[4] = (unsigned char)((command >> 8) & 0xff);
|
msg[4] = (unsigned char)((command >> 8) & 0xff);
|
||||||
msg[5] = (unsigned char)(command & 0xff);
|
msg[5] = (unsigned char)(command & 0xff);
|
||||||
|
@ -438,9 +588,9 @@ MESSAGE_EXCHANGE_ERROR capi_sendf(
|
||||||
|
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
for (i = 0; format[i]; i++) {
|
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",
|
cc_log(LOG_ERROR, "capi_sendf: message too big (%d)\n",
|
||||||
(p - (&msg[0])));
|
(int)(p - (&msg[0])));
|
||||||
return 0x1004;
|
return 0x1004;
|
||||||
}
|
}
|
||||||
switch(format[i]) {
|
switch(format[i]) {
|
||||||
|
@ -532,7 +682,7 @@ MESSAGE_EXCHANGE_ERROR capi_sendf(
|
||||||
ret = capi_wait_conf(capii, (command & 0xff00) | CAPI_CONF);
|
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",
|
cc_verbose(3, 0, VERBOSE_PREFIX_4 "%s: CAPI INFO 0x%04x: %s\n",
|
||||||
name, info, p);
|
name, info, p);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -931,6 +1080,50 @@ unsigned capi_ListenOnController(unsigned int CIPmask, unsigned controller)
|
||||||
return error;
|
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
|
* 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->frametype == AST_FRAME_VOICE) && (f->datalen > 0)) {
|
||||||
if (f->datalen > sizeof(i->frame_data)) {
|
if (f->datalen > sizeof(i->frame_data)) {
|
||||||
cc_log(LOG_ERROR, "f.datalen(%d) greater than space of frame_data(%d)\n",
|
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);
|
f->datalen = sizeof(i->frame_data);
|
||||||
}
|
}
|
||||||
readsize = read(i->readerfd, i->frame_data + AST_FRIENDLY_OFFSET, f->datalen);
|
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 txavg=0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (!i) {
|
if (unlikely(!i)) {
|
||||||
cc_log(LOG_ERROR, "channel has no interface\n");
|
cc_log(LOG_ERROR, "channel has no interface\n");
|
||||||
return -1;
|
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) ||
|
if (unlikely((!(i->isdnstate & CAPI_ISDN_STATE_B3_UP)) || (!i->NCCI) ||
|
||||||
((i->isdnstate & (CAPI_ISDN_STATE_B3_CHANGE | CAPI_ISDN_STATE_LI)))) {
|
((i->isdnstate & (CAPI_ISDN_STATE_B3_CHANGE | CAPI_ISDN_STATE_LI))))) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1160,41 +1364,62 @@ int capi_write_frame(struct capi_pvt *i, struct ast_frame *f)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f->frametype == AST_FRAME_NULL) {
|
if (unlikely(f->frametype == AST_FRAME_NULL)) {
|
||||||
return 0;
|
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");
|
cc_log(LOG_ERROR, "dtmf frame should be written\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (f->frametype != AST_FRAME_VOICE) {
|
if (unlikely(f->frametype != AST_FRAME_VOICE)) {
|
||||||
cc_log(LOG_ERROR,"not a voice frame\n");
|
cc_log(LOG_ERROR,"not a voice frame\n");
|
||||||
return 0;
|
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",
|
cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: write on fax activity?\n",
|
||||||
i->vname);
|
i->vname);
|
||||||
return 0;
|
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);
|
cc_log(LOG_DEBUG, "No data for FRAME_VOICE %s\n", i->vname);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (i->isdnstate & CAPI_ISDN_STATE_RTP) {
|
if (i->isdnstate & CAPI_ISDN_STATE_RTP) {
|
||||||
if ((!(f->subclass & i->codec)) &&
|
if (unlikely((!(f->subclass & i->codec)) &&
|
||||||
(f->subclass != capi_capability)) {
|
(f->subclass != capi_capability))) {
|
||||||
cc_log(LOG_ERROR, "don't know how to write subclass %s(%d)\n",
|
cc_log(LOG_ERROR, "don't know how to write subclass %s(%d)\n",
|
||||||
ast_getformatname(f->subclass), f->subclass);
|
ast_getformatname(f->subclass), f->subclass);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return capi_write_rtp(i, f);
|
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",
|
cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: B3count is full, dropping packet.\n",
|
||||||
i->vname);
|
i->vname);
|
||||||
return 0;
|
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)) {
|
if ((!i->smoother) || (ast_smoother_feed(i->smoother, f) != 0)) {
|
||||||
cc_log(LOG_ERROR, "%s: failed to fill smoother\n", i->vname);
|
cc_log(LOG_ERROR, "%s: failed to fill smoother\n", i->vname);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1242,7 +1467,7 @@ int capi_write_frame(struct capi_pvt *i, struct ast_frame *f)
|
||||||
i->vname, i->NCCI);
|
i->vname, i->NCCI);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!error) {
|
if (likely(!error)) {
|
||||||
cc_mutex_lock(&i->lock);
|
cc_mutex_lock(&i->lock);
|
||||||
i->B3count++;
|
i->B3count++;
|
||||||
i->B3q -= fsmooth->datalen;
|
i->B3q -= fsmooth->datalen;
|
||||||
|
|
|
@ -18,7 +18,27 @@
|
||||||
extern int capidebug;
|
extern int capidebug;
|
||||||
extern char *emptyid;
|
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 _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_msgnum(unsigned short msgnum);
|
||||||
extern struct capi_pvt *capi_find_interface_by_plci(unsigned int plci);
|
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 char *capi_info_string(unsigned int info);
|
||||||
extern void show_capi_info(struct capi_pvt *i, _cword info);
|
extern void show_capi_info(struct capi_pvt *i, _cword info);
|
||||||
extern unsigned capi_ListenOnController(unsigned int CIPmask, unsigned controller);
|
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 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 char *capi_number_func(unsigned char *data, unsigned int strip, char *buf);
|
||||||
extern int cc_add_peer_link_id(struct ast_channel *c);
|
extern int cc_add_peer_link_id(struct ast_channel *c);
|
||||||
extern struct ast_channel *cc_get_peer_link_id(const char *p);
|
extern struct ast_channel *cc_get_peer_link_id(const char *p);
|
||||||
extern void capi_remove_nullif(struct capi_pvt *i);
|
extern void capi_remove_nullif(struct capi_pvt *i);
|
||||||
extern struct capi_pvt *capi_mknullif(struct ast_channel *c, unsigned long long controllermask);
|
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 int capi_create_reader_writer_pipe(struct capi_pvt *i);
|
||||||
extern struct ast_frame *capi_read_pipeframe(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_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) \
|
#define capi_number(data, strip) \
|
||||||
capi_number_func(data, strip, alloca(AST_MAX_EXTENSION))
|
capi_number_func(data, strip, alloca(AST_MAX_EXTENSION))
|
||||||
|
@ -52,6 +75,6 @@ typedef struct capi_prestruct_s {
|
||||||
*/
|
*/
|
||||||
extern MESSAGE_EXCHANGE_ERROR capi_sendf(
|
extern MESSAGE_EXCHANGE_ERROR capi_sendf(
|
||||||
struct capi_pvt *capii, int waitconf,
|
struct capi_pvt *capii, int waitconf,
|
||||||
_cword command, _cdword Id, _cword Number, char * format, ...);
|
_cword command, _cdword Id, _cword Number, char * format, ...);
|
||||||
|
|
||||||
#endif
|
#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 <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
|
||||||
|
#include "capi20_platform.h"
|
||||||
|
|
||||||
#include "capi20.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;
|
return CapiNoError;
|
||||||
|
|
||||||
/*----- open managment link -----*/
|
/*----- open managment link -----*/
|
||||||
|
@ -696,10 +706,10 @@ capi20_put_message (unsigned ApplID, unsigned char *Msg)
|
||||||
int fd;
|
int fd;
|
||||||
int datareq = 0;
|
int datareq = 0;
|
||||||
|
|
||||||
if (capi20_isinstalled() != CapiNoError)
|
if (capi20_isinstalled_internal() != CapiNoError)
|
||||||
return CapiRegNotInstalled;
|
return CapiRegNotInstalled;
|
||||||
|
|
||||||
if (!validapplid(ApplID))
|
if (unlikely(!validapplid(ApplID)))
|
||||||
return CapiIllAppNr;
|
return CapiIllAppNr;
|
||||||
|
|
||||||
fd = applid2fd(ApplID);
|
fd = applid2fd(ApplID);
|
||||||
|
@ -797,10 +807,10 @@ capi20_get_message (unsigned ApplID, unsigned char **Buf)
|
||||||
size_t bufsiz;
|
size_t bufsiz;
|
||||||
int rc, fd;
|
int rc, fd;
|
||||||
|
|
||||||
if (capi20_isinstalled() != CapiNoError)
|
if (capi20_isinstalled_internal() != CapiNoError)
|
||||||
return CapiRegNotInstalled;
|
return CapiRegNotInstalled;
|
||||||
|
|
||||||
if (!validapplid(ApplID))
|
if (unlikely(!validapplid(ApplID)))
|
||||||
return CapiIllAppNr;
|
return CapiIllAppNr;
|
||||||
|
|
||||||
fd = applid2fd(ApplID);
|
fd = applid2fd(ApplID);
|
||||||
|
@ -823,7 +833,7 @@ capi20_get_message (unsigned ApplID, unsigned char **Buf)
|
||||||
CAPIMSG_U32(rcvbuf, 8));
|
CAPIMSG_U32(rcvbuf, 8));
|
||||||
capimsg_setu16(rcvbuf, 18, offset); /* patch datahandle */
|
capimsg_setu16(rcvbuf, 18, offset); /* patch datahandle */
|
||||||
if (sizeof(void *) == 4) {
|
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[12] = data & 0xff;
|
||||||
rcvbuf[13] = (data >> 8) & 0xff;
|
rcvbuf[13] = (data >> 8) & 0xff;
|
||||||
rcvbuf[14] = (data >> 16) & 0xff;
|
rcvbuf[14] = (data >> 16) & 0xff;
|
||||||
|
@ -1009,10 +1019,10 @@ capi20_waitformessage(unsigned ApplID, struct timeval *TimeOut)
|
||||||
|
|
||||||
FD_ZERO(&rfds);
|
FD_ZERO(&rfds);
|
||||||
|
|
||||||
if (capi20_isinstalled() != CapiNoError)
|
if (capi20_isinstalled_internal() != CapiNoError)
|
||||||
return CapiRegNotInstalled;
|
return CapiRegNotInstalled;
|
||||||
|
|
||||||
if (!validapplid(ApplID))
|
if (unlikely(!validapplid(ApplID)))
|
||||||
return CapiIllAppNr;
|
return CapiIllAppNr;
|
||||||
|
|
||||||
fd = applid2fd(ApplID);
|
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,
|
/*15*/ 0,
|
||||||
/*16 DISCONNECT_CONF*/ (unsigned char*)"\x03\x24\x01",
|
/*16 DISCONNECT_CONF*/ (unsigned char*)"\x03\x24\x01",
|
||||||
/*17 LISTEN_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",
|
/*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,
|
/*19*/ 0,
|
||||||
/*1a INFO_CONF*/ (unsigned char*)"\x03\x24\x01",
|
/*1a INFO_CONF*/ (unsigned char*)"\x03\x24\x01",
|
||||||
/*1b FACILITY_CONF*/ (unsigned char*)"\x03\x24\x20\x1b\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",
|
/*27 CONNECT_ACTIVE_IND*/ (unsigned char*)"\x03\x16\x17\x29\x01",
|
||||||
/*28 DISCONNECT_IND*/ (unsigned char*)"\x03\x2d\x01",
|
/*28 DISCONNECT_IND*/ (unsigned char*)"\x03\x2d\x01",
|
||||||
/*29*/ 0,
|
/*29*/ 0,
|
||||||
|
#if 0
|
||||||
/*2a MANUFACTURER_CONF*/ (unsigned char*)"\x03\x2b\x15\x22\x2a\x01",
|
/*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,
|
/*2b*/ 0,
|
||||||
/*2c INFO_IND*/ (unsigned char*)"\x03\x27\x25\x01",
|
/*2c INFO_IND*/ (unsigned char*)"\x03\x27\x25\x01",
|
||||||
/*2d FACILITY_IND*/ (unsigned char*)"\x03\x20\x1d\x01",
|
/*2d FACILITY_IND*/ (unsigned char*)"\x03\x20\x1d\x01",
|
||||||
|
@ -422,10 +430,18 @@ static unsigned char *cpars[] = {
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
#ifdef __bfin__ /* Blackfin */
|
||||||
|
#define wordTLcpy(x,y) memcpy(x,y,2);
|
||||||
|
#else
|
||||||
#define wordTLcpy(x,y) *(_cword *)(x)=*(_cword *)(y);
|
#define wordTLcpy(x,y) *(_cword *)(x)=*(_cword *)(y);
|
||||||
|
#endif
|
||||||
#define dwordTLcpy(x,y) memcpy(x,y,4);
|
#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);
|
#define wordTRcpy(x,y) *(_cword *)(y)=*(_cword *)(x);
|
||||||
|
#endif
|
||||||
#define dwordTRcpy(x,y) memcpy(y,x,4);
|
#define dwordTRcpy(x,y) memcpy(y,x,4);
|
||||||
|
|
||||||
#define qwordTLcpy(x,y) memcpy(x,y,8);
|
#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
|
if ( cmsg->Command == CAPI_DATA_B3
|
||||||
&& (cmsg->Subcommand == CAPI_REQ || cmsg->Subcommand == CAPI_IND)) {
|
&& (cmsg->Subcommand == CAPI_REQ || cmsg->Subcommand == CAPI_IND)) {
|
||||||
if (sizeof(void *) == 4) {
|
if (sizeof(void *) == 4) {
|
||||||
cmsg->Data32 = (_cdword) cmsg->Data;
|
cmsg->Data32 = (_cdword)(unsigned long)cmsg->Data;
|
||||||
cmsg->Data64 = 0;
|
cmsg->Data64 = 0;
|
||||||
} else {
|
} else {
|
||||||
cmsg->Data32 = 0;
|
cmsg->Data32 = 0;
|
||||||
|
@ -570,7 +586,9 @@ unsigned capi_cmsg2message(_cmsg * cmsg, _cbyte * msg)
|
||||||
/*-------------------------------------------------------*/
|
/*-------------------------------------------------------*/
|
||||||
static void message_2_pars(_cmsg * cmsg)
|
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) {
|
switch (TYP) {
|
||||||
case _CBYTE:
|
case _CBYTE:
|
||||||
|
@ -621,11 +639,15 @@ static void message_2_pars(_cmsg * cmsg)
|
||||||
/*-------------------------------------------------------*/
|
/*-------------------------------------------------------*/
|
||||||
unsigned capi_message2cmsg(_cmsg * cmsg, _cbyte * msg)
|
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->m = msg;
|
||||||
cmsg->l = 8;
|
cmsg->l = 8;
|
||||||
cmsg->p = 0;
|
cmsg->p = 0;
|
||||||
byteTRcpy(cmsg->m + 4, &cmsg->Command);
|
cmsg->Command = Command;
|
||||||
byteTRcpy(cmsg->m + 5, &cmsg->Subcommand);
|
byteTRcpy(cmsg->m + 5, &cmsg->Subcommand);
|
||||||
cmsg->par = cpars[command_2_index(cmsg->Command, 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
|
if ( cmsg->Command == CAPI_DATA_B3
|
||||||
&& (cmsg->Subcommand == CAPI_REQ || cmsg->Subcommand == CAPI_IND)) {
|
&& (cmsg->Subcommand == CAPI_REQ || cmsg->Subcommand == CAPI_IND)) {
|
||||||
if (sizeof(void *) == 4) {
|
if (sizeof(void *) == 4) {
|
||||||
cmsg->Data = (void *) cmsg->Data32;
|
cmsg->Data = (void *)(unsigned long)cmsg->Data32;
|
||||||
} else {
|
} else {
|
||||||
cmsg->Data = (void *)(unsigned long)cmsg->Data64;
|
cmsg->Data = (void *)(unsigned long)cmsg->Data64;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue