Can't Dispose Calls leading to TSP driver crash

Jan 19, 2014 at 9:36 AM
Hi All,

I am using the ATAPI wrapper in a Visual Basic .Net program targeting Net Framework 4.0. The TSP on the server crashes periodically every ~4 hours. I found using the following code that all the calls were being retained by the TSP:

myTAPI.GetLineByName("EXTENSION 204 Keyset", True).GetCalls.Count

When I start my program, the CallStateChanged event fires for all these retained calls and I can console.writeline, for example, the callerid property of these retained calls.

How can I dispose of the calls ? This is driving me crazy.

The minimal code I am using is shown below.

I have tried:
oCall.Dispose
oCall.CallHandle.Close
Calling lineDeallocateCall directly from Tapi32.dll.

Your help would be much appreciated.

Code:

Private WithEvents myTAPI As JulMar.Atapi.TapiManager

Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
myTAPI = New TapiManager("Phone.Net")

myTAPI.Initialize()

Dim oLine As TapiLine = myTAPI.GetLineByName("EXTENSION 204 Keyset", True)

AddHandler oLine.CallStateChanged, AddressOf onCallStateChanged

oLine.Monitor()

Console.WriteLine("Monitoring EXTENSION 204 Keyset")
End Sub


Private Sub onCallStateChanged(sender As Object, e As CallStateEventArgs)
Dim oCall As TapiCall = e.Call

Dim strCallState As String
Dim strLineName As String
Dim strCallerID As String
Dim strCalledId As String
Dim strAddress As String

strCallState = oCall.CallState.ToString()
strLineName = oCall.Line.Name
strCallerID = oCall.CallerId
strCalledId = oCall.CalledId
strAddress = oCall.Address.ToString()

Console.WriteLine(strCallState & " | " & Format(TimeOfDay, "hh:mm:ss tt") & " | " & strLineName & " | " & strCallerID & " | " & strCalledId & " | " & strAddress)

If strCallState = "Idle" Then
    oCall.Dispose()
End If
End Sub


Private Sub frmMain_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed
myTAPI.Shutdown()
End Sub
Coordinator
Jan 19, 2014 at 7:07 PM
Sounds like a bug in the TSP to me. The call object and handle the TSP uses isn't the same as the one the app uses - TAPISRV and TAPI32.DLL maintains the bridge between them as they are held in completely different processes.. If you are closing/disposing the call then that's all you can do - the TSP should get a TSPI_lineCloseCall in response and that's the end of the call - if it's holding onto the call after that, it's a bug.
Oct 2, 2014 at 9:13 AM
To follow up on this, I've encountered similar behaviour. The bug is definitely in ATAPI, in the TapiCall.Dispose method to be exact.

When a new call is created, the numeric value of the call handle and TapiCall instance are put in a static dictionary "CallsMap". When the Idle event is raised by the TAPI driver, or when a LINE_REPLY is indicating LINEERR_INVALCALLHANDLE, the TapiCall.Deallocate method is called.
The Deallocate method:
  • Removes the TapiCall from the associated addresses
  • Removes the call handle from the static dictionary "CallsMap"
  • Closes the call handle
However! If you call TapiCall.Dispose, all this method does is a Dispose on the call handle. It does not remove the TapiCall from associated addresses, nor its numeric value from the static dictionary. After some time (in my experience around 256 calls), the Operating System decides to re-use call handles that are considered free again (and the handles are free because they were disposed). Since the numeric value of the call handle was never removed from the static dictionary, the new call will fail with a message saying that the key already exists. This will cause no events to be raised for the new call.

In addition, if you decide to Dispose the TapiCall in the CallStateChanged event when the new call state is Idle, ATAPI wil generate a ObjectDisposedException. This is because the CallStateChanged event is raised synchronously and before the call to TapiCall.Deallocate (in TapiCall.OnCallStateChange), causing the call handle to be disposed and thus is not accessible anymore in Deallocate.

Not disposing the TapiCall in the CallStateChanged when the state is Idle sovled the issue for me, though it is an error in the Dispose implementation.
Jun 7 at 9:04 PM
Hi, I think I am experiencing a similar issue here. I am just monitoring all lines for the callstatechanged event. I am just forwarding the events to another part of my code and don't dispose anything. I have noticed that the handle count of my service increases and stumbled across your finding. Unfortunately I stumbled across the issue with disposing when in IDLE state.

Have you been able to fix the issue you have discovered in your code and would you mind sharing?

I am just conscious of the fact that my (supposed to be) long running serice will quickly stop working...
Any tipps are greatly appreciated.

Thanks in advance