Author |
|
ajdiaz Junior
Joined: December 10 2007 Location: United States Posts: 76
|
Posted: January 30 2008 at 3:00pm | IP Logged
|
|
|
I have an application that needs to place 20 outbound phone calls at once. I have 20 different threads being launched at once. How do I determine which phone line is available? I could query every single line for its status, but I was wondering if the MediaEngine handles line management for outbound calls? I do not want all 20 threads to try to make a call in line #0 because all of them querying at the same time will think line 0 is available.
Do you have any suggestions on how to do this so that each thread gets a different available line without clashing?
|
Back to Top |
|
|
support Administrator
Joined: January 26 2005 Location: United States Posts: 1666
|
Posted: January 30 2008 at 5:37pm | IP Logged
|
|
|
Hi Alex,
If your app has many threads and all the threads want to make outgoing calls using either the MakeCall() or MakeCallUri() API procs, the media engine will internally serialize the “make call” requests for each phone line such that no two app threads are able to use the same phone line for outgoing calls.
A very easy way for your threads to make outgoing calls would be to call the following C# procedure:
Code:
//////////////////////////////////////////////////////////// /////////////
//
// This procedure can be called by a managed code thread to make an
// outbound call using any available phone line. If this proc detects
// that the phone line is already in use, it will try the next line.
// Input parameters:
//
// MediaEngine - An instance of your voip media engine.
//
// MaxPhoneLines - The max number of phone lines.
//
// CallUri - The destination of the call.
// Something like "sip:1234@domain.com:5060" or "sip:1234@1.2.3.4:5060"
//
// Return to the caller:
//
// false - Error. call not placed.
//
// true - Success. The call was placed.
//
//////////////////////////////////////////////////////////// /////////////
public static bool BlindMakeCall(
VoipMediaEngine MediaEngine,
int MaxPhoneLines,
String CallUri,
bool UseSipProxy
)
{
bool ret = false;
int CurPhoneLine;
VoipMediaEngine.TELEPHONY_RETURN_VAL UE status;
VoipMediaEngine.LINE_STATE LineState;
int LineBeingUsedCount = 0;
LineState = new VoipMediaEngine.LINE_STATE();
// try to make a phone call using any line.
for (CurPhoneLine = 0; CurPhoneLine < MaxPhoneLines; CurPhoneLine++)
{
// get the current line status.
status = MediaEngine.GetLineStatus(CurPhoneLine, LineState);
if (status == VoipMediaEngine.TELEPHONY_RETURN_VALUE.SipSuccess)
{
// make sure the line is on hook.
if (LineState.State == VoipMediaEngine.TELEPHONY_RETURN_VALUE.SipOnHook)
{
// try to make a call using this line.
status = MediaEngine.MakeCallUri(
CallUri,
UseSipProxy,
CurPhoneLine,
false, // asynchronous call.
0 // call answer timeout Ms not used.
);
if (status == VoipMediaEngine.TELEPHONY_RETURN_VALUE.SipCallAlreadyInProgr ess)
{
// the line is already being used.
LineBeingUsedCount++;
}
else if (status == VoipMediaEngine.TELEPHONY_RETURN_VALUE.SipSuccess)
{
// the call has been made and we are connected.
//
// let the call exist for 2 seconds.
Thread.Sleep(2000);
// terminate the call.
status = MediaEngine.TerminateCall(
CurPhoneLine,
true, // synchronous call terminate.
2000 // call terminate timeout Ms.
);
if (status != VoipMediaEngine.TELEPHONY_RETURN_VALUE.SipSuccess)
{
// handle the error.
}
// the call has been made. return to the
// caller.
ret = true;
break;
}
else
{
// some other error.
}
}
else
{
// the line is already being used.
LineBeingUsedCount++;
}
}
}
return (ret);
}
|
|
|
The code above uses very little logic on the part of the VOIP app and is quick.
Another way would be for your VOIP app to serialize access to the phone lines so you know exactly what lines are being used for outgoing calls. That way your app can only try phone lines it knows is available.
A file named “BlindMakeCall.cs” has been placed into your support FTP account that contains the proc above.
Support
|
Back to Top |
|
|
support Administrator
Joined: January 26 2005 Location: United States Posts: 1666
|
Posted: January 31 2008 at 12:14pm | IP Logged
|
|
|
Alex,
Here is a variation of the above proc that also handles both synchronous and asynch “make calls”.
Check your support FTP account for the “BlindMakeCallSynchronous.cs” module.
Thanks,
Support
Code:
//////////////////////////////////////////////////////////// /////////////
//
// This procedure can be called by a managed code thread to make an
// outbound call using any available phone line. If this proc detects
// that the phone line is already in use, it will try the next line.
// Input parameters:
//
// MediaEngine - An instance of your voip media engine.
//
// MaxPhoneLines - The max number of phone lines.
//
// CallUri - The destination of the call. Something like
// "sip:1234@domain.com:5 060" or "sip:1234@1.2.3.4:5060"
//
// UseSipProxy - true if using a SIP proxy.
//
// Synchronous - true if calling synchronously.
//
// SynchronousTimeoutMs - The amount of time to wait for the call
// to connect if using synchronous mode. if
// not using synchronous mode, this parameter
// is ignored.
//
// Return to the caller:
//
// -1 - Error. call not placed.
//
// 0 to MaxPhoneLines-1 - Success. The call was placed. the return
// value is the phone line used.
//
//////////////////////////////////////////////////////////// /////////////
public static int BlindMakeCall(
VoipMediaEngine MediaEngine,
int MaxPhoneLines,
String CallUri,
bool UseSipProxy,
bool Synchronous,
uint SynchronousTimeoutMs
)
{
int PhoneLineUsedForCall = -1;
int CurPhoneLine;
VoipMediaEngine.TELEPHONY_RETURN_VAL UE status;
VoipMediaEngine.LINE_STATE LineState;
int LineBeingUsedCount = 0;
bool done;
bool WriteToConsole = true;
LineState = new VoipMediaEngine.LINE_STATE();
// try to make a phone call using any line.
for (CurPhoneLine = 0, done = false; !done && (CurPhoneLine < MaxPhoneLines); CurPhoneLine++)
{
// get the current line status.
status = MediaEngine.GetLineStatus(CurPhoneLine, LineState);
if (status == VoipMediaEngine.TELEPHONY_RETURN_VALUE.SipSuccess)
{
// make sure the line is on hook.
//if (LineState.State == VoipMediaEngine.TELEPHONY_RETURN_VALUE.SipOnHook)
if (true)
{
if (WriteToConsole)
{
Console.WriteLine(
"Thread {0} attempting call on line {1}",
Thread.CurrentThread.ManagedThreadId,
CurPhoneLine
);
}
// try to make a call using this line.
status = MediaEngine.MakeCallUri(
CallUri,
UseSipProxy,
CurPhoneLine,
Synchronous,
SynchronousTimeoutMs
);
if (status == VoipMediaEngine.TELEPHONY_RETURN_VALUE.SipCallAlreadyInProgr ess)
{
// the line is already being used.
LineBeingUsedCount++;
if (WriteToConsole)
{
Console.WriteLine(
"Thread {0} call failed. Line {1} already in use.",
Thread.CurrentThread.ManagedThreadId,
CurPhoneLine
);
}
// try another line.
//
}
else
{
if (Synchronous)
{
if ((status == VoipMediaEngine.TELEPHONY_RETURN_VALUE.SipSuccess) ||
(status == VoipMediaEngine.TELEPHONY_RETURN_VALUE.SipFarEndError) ||
(status == VoipMediaEngine.TELEPHONY_RETURN_VALUE.SipFarEndIsBusy))
{
// The phone call initiated without error. if we received the
// SipInCall status, the call actuall connected. if we received
// the SipFarEndIsBusy status, the far end is busy and cannot
// accept the call. if we received the SipFarEndError status,
// the far end of the call returned some kind of error.
//
PhoneLineUsedForCall = CurPhoneLine;
if (WriteToConsole)
{
Console.WriteLine(
"SUCCESS - Thread {0} phone line {1} completed.",
Thread.CurrentThread.ManagedThreadId,
CurPhoneLine
);
}
done = true;
}
else
{
// some other error.
if (WriteToConsole)
{
// some other error.
Console.WriteLine(
"Thread {0} call failed. Trying another line.",
Thread.CurrentThread.ManagedThreadId
);
// try another line.
//
}
}
}
else
{
if (status == VoipMediaEngine.TELEPHONY_RETURN_VALUE.SipSuccess)
{
// the call has been made. wait for the "in call" state, a busy indication
// or a call a far end call error.
//
for (; !done; )
{
// get the current line status.
status = MediaEngine.GetLineStatus(CurPhoneLine, LineState);
if (status != VoipMediaEngine.TELEPHONY_RETURN_VALUE.SipSuccess)
{
// error reading line status
done = true;
if (WriteToConsole)
{
Console.WriteLine(
"Thread {0} call failed. Error reading line status",
Thread.CurrentThread.ManagedThreadId
);
}
}
else
{
if ((LineState.State == VoipMediaEngine.TELEPHONY_RETURN_VALUE.SipInCall) ||
(LineState.State == VoipMediaEngine.TELEPHONY_RETURN_VALUE.SipFarEndError) ||
(LineState.State == VoipMediaEngine.TELEPHONY_RETURN_VALUE.SipFarEndIsBusy))
{
// The phone call initiated without error. if we received the
// SipInCall status, the call actuall connected. if we received
// the SipFarEndIsBusy status, the far end is busy and cannot
// accept the call. if we received the SipFarEndError status,
// the far end of the call returned some kind of error.
//
PhoneLineUsedForCall = CurPhoneLine;
if (WriteToConsole)
{
Console.WriteLine(
"SUCCESS - Thread {0} phone line {1} completed.",
Thread.CurrentThread.ManagedThreadId,
CurPhoneLine
);
}
done = true;
}
else
{
// wait a bit until we poll status again.
Thread.Sleep(20);
}
}
}
}
else
{
if (WriteToConsole)
{
// some other error.
Console.WriteLine(
"Thread {0} call failed. Trying another line.",
Thread.CurrentThread.ManagedThreadId
);
}
// try another line.
//
}
}
}
}
else
{
// the line is already being used.
LineBeingUsedCount++;
if (WriteToConsole)
{
Console.WriteLine(
"Thread {0} call failed. Line {1} already in use.",
Thread.CurrentThread.ManagedThreadId,
CurPhoneLine
);
}
// try another line.
//
}
}
else
{
if (WriteToConsole)
{
// some other error.
Console.WriteLine(
"Thread {0} call failed. Trying another line.",
Thread.CurrentThread.ManagedThreadId
);
// try another line.
//
}
}
}
return (PhoneLineUsedForCall);
}
|
|
|
|
Back to Top |
|
|
|
|