Einführung in die CAPI-Programmierung

Zurück zur Übersicht ]   [ Aufbau eines Anrufs ]


Um einen Call (Anruf) abzuarbeiten muss der Austausch der Nachrichten (Messages) mit der CAPI wie in der Capi Dokumentation erfolgen, sonst kann das ganze hängen bleiben. (Besonders bei Disconnect_Ind mit Disconnect_Resp antworten).

Beim Messagetausch geht es darum, der Capi auf eine Nachricht (IND=Indication) immer eine Antwort (RESP=Response) zu geben, genauso bekommt man von der Capi auf eine Anfrage (REQ=Request) eine Bestätigung (CONF=Confirmation).

Beispiel: <- Von Capi an Programm
Von Programm an CAPI ->
CAPI_Register ->
Listen_Request ->
<-Connect_Indication
Connect_Response ->
<-Disconnect_Indication
Disconnect_Response ->

Die Deklarationen der verwendeten Funktionen sind im Modul des Anrufmonitor-Beispielprojekts zu finden.

So fängt man z.B. in Form_Load an:

x = CAPI_REGISTER(MessageBuffersize, maxLogicalConnection, _
   maxBDataBlocks, maxBDataLen, Appid)

'Nach dem ListenREQ gibt die CAPI Messages beim Eintreffen
'eines Calls ab.

ListenREQ.length = Len(ListenREQ)
ListenREQ.Appid = Appid
ListenREQ.Command = &H5
ListenREQ.Subcommand = &H80
ListenREQ.Message_Number = 1
ListenREQ.controller = 1
ListenREQ.InfoMask = &H0
ListenREQ.CIPMask = &H1
ListenREQ.CIPMas2 = &H0
ListenREQ.CallingParty = &H0
ListenREQ.CallingPartySub = &H0
x = CAPI_PUT_MESSAGE(ByVal Appid, ListenREQ)


Public Function Get_Capi_Message() 'Hier ein Beispiel um die Message Daten zu laden: 'Es wird eine Message abgerufen und in die Headerstruktur 'kopiert. Ich polle hier mit einem Timer in nachfolgende SUB, da bei 'Verwendung von CAPI_GET_SIGNAL das Programm an der selben Stelle 'stehen bleibt. 'WICHTIG: Dieser Code ist nur ein Ausschnitt aus dem Programm, es fehlen die Antworten ' an die CAPI, ohne die das ganze vermutlich abstürzen würde. ' In meinem Beispielprojekt (siehe oben) ist aber der komplette Code enthalten. ' Wenn Du nicht VB5 hast, kannst Du die Dateien trotzdem im Editor öffnen ' und Dir den Code dort ansehen. x = CAPI_GET_MESSAGE(ByVal Appid, lpCapiBuffer) if x <> 0 Then Exit Function Call RtlMoveMemory(MessageHeader, ByVal lpCapiBuffer, ByVal HeaderLength) 'anhand von MessageHeader.Command und MessageHeader.Subcommand kann man nun 'erkennen, welche Message die Capi geschickt hat. 'Nehmen wir an es ist Command CAPI_CONNECT und Subcommand CAPI_IND, 'dann kann hier die Message wie nachfolgend gelesen werden: Select Case MessageHeader.Command Case CAPI_CONNECT Select Case MessageHeader.Subcommand Case CAPI_IND Call RtlMoveMemory(ConnectInd, ByVal (lpCapiBuffer + HeaderLength), _ ByVal (MessageHeader.length - HeaderLength)) 'In dem ConnectInd.Buffer befinden sich jetzt die Nummern entsprechend 'der Capi Dokumentation strukturiert. Beispiel angerufene Nummer: l1 = Asc(Mid$(ConnectInd.buffer, 1, 1)) 'length of called number If l1 > 0 Then GerufeneNummer$ = Mid$(ConnectInd.buffer, 3, l1 - 1) 'Die anrufende Nummer ist irgendwo (I1+2) dahinter und hat noch ein 'paar zusätzliche Infos: (A$ ist hier die anrufende Nummer) l2 = Asc(Mid$(ConnectInd.buffer, l1 + 2, 1)) If l2 > 0 Then If l2 > 2 Then A$ = Mid$(ConnectInd.buffer, l1 + 5, l2 - 2) Else N = Asc(Mid$(ConnectInd.buffer, l1 + 4,1)) c = Asc(Mid$(ConnectInd.buffer, l1 + 3,1)) If ((N And 32) = 32) And ((N And 64) = 0) Then If ((c And 1) = 1) And ((c And 2) = 0) And _ ((c And 4) = 0) And ((c And 8) = 0) Then A$ = "ISDN Hidden" ElseIf c = 0 Then A$ = "Unknown" Else A$ = "HideCode " + Str$(c) End If End If End If Else A$ = "Error" End If End Select End Select End Sub

Bezüglich der Handshakes mit der Capi hier noch ein paar Erläuterungen:

Es gilt prinzipiell: Du kannst nur REQ's und RESP's an die Capi schicken. Die Capi kann nur IND's und CONF's an Dich schicken. Du bist in diesem Fall Dein Programm. Das sind die sogenannten Subcommands. Es gibt aber noch Commands. Die Commands entsprechen den Klassen und die Subcommands den Properties in der Bill Gates Terminologie. Jede Klasse hat mindestens zwei Properties die einen Handshake ermöglichen.

Eine Klasse ist z.b. LISTEN.
LISTEN hat zwei Properties nämlich Request (REQ) und Confirmation (CONF). Du machst also LISTEN_REQ und die CAPI gibt, wenn alles o.k. ist ein LISTEN_CONF zurück. Sobald dann ein Call reinkommmt, stellt die CAPI ein CONNECT_IND zur Verfügung.

Die CONNECT ist eine weitere Klasse die aber alle 4 Properties (oder Subcommands) hat. Auf die CONNECT_IND musst Du dann mit CONNECT_RESP antworten. In der CONNECT_RESP Struktur ist dann auch vermerkt, was Du mit dem Call anstellen willst.
Nimmst Du den Ruf nicht an, dann schließt der Call nach einiger Zeit und die CAPI meldet DISCONNECT_IND. Darauf hin musst Du zwingend mit DISCONNECT_RESP antworten, da sich nach weiteren versuchen das System aufhängt.

Es gibt noch die Möglichkeit mit ALERT das Beenden des Anrufes zu verhindern, ohne das Gespräch anzunehmen (weiter klingeln lassen), bis jemand anderes am BUS das Gespräch übernimmt oder die Telecom auslöst. Das verwende ich um die weiteren Infos zusätzlich zu der Nummer zu erhalten.

Dies geschieht nach CONNECT_IND mit ALERT_REQ. Die weiteren Infos schickt die Capi dann mit INFO_IND.

Hier nochmals der Ablauf
<------CAPI an Programm
Programm an CAPI

LISTEN_REQ ----->Du willst wissen was auf dem Bus abgeht
<------LISTEN_CONFDie CAPI hat's kapiert und bestätigt
<------CONNECT_INDDie CAPI weiß was und stellt Infos bereit
ALERT_REQ-------->Du hältst die Telekom (und den Anrufer) hin
CONNECT_RESP----->Willst aber nicht abheben
<------ALERT_CONFDie CAPI ist damit einverstanden
<------INFO_INDUnd teilt mit, auf welchen Kanal Du denn abnehmen könntest
INFO_RESP------>Du hast das mitgekriegt und teilst dies der CAPI mit. Und wenn dann jemand abnimmt oder der Anrufer auflegt dann
<-------DISCONNECT_INDmeint die CAPI, du hast die Telekom lange genug hingehalten und gibt Dir noch den Grund des Abbruches mit
DISCONNECT_RESP---->das musst Du unbedingt machen, das ist soviel wie "Auf Wiedersehen"

und danach ist Schluss, die CAPI gibt zu diesem Call leider keinen Mucks mehr von sich.
Und deshalb findest Du auch keine auf CAPI basierenden Monitore, die die Dauer des eingegangenen Anrufes feststellen können.
Auch den Versuch den D-Kanal auf ausgehende Anrufe zu überwachen kannst Du Dir sparen. Es sei denn Du hast die ISDN-Chip Dokumentation und willst im Treiber Level operieren.
Du solltest Dir auf jeden Fall die CAPI Dokumentation von der http://www.capi.org/document.htm herunterladen. Man muss ja nicht alles lesen. Aber einige Teile der Codierung sind nur zu verstehen, wenn man die Tabellen vor Augen hat.