c# - 大关注册总是失败
问题描述
我想用 SIP 呼叫系统构建一个应用程序,我使用Ozeki'SDK。
在这里,我对 SIP 的理解是(大致):客户端 -> SIP 服务器 -> 客户端或客户端 -> SIP 服务器 1 -> SIP 服务器 2 -> 客户端
所以我在我的电脑上安装了 Ozeki Phone System EX 作为 SIP 服务器,下面我添加了两个电话: 图片在这里
下一步,我创建了一个 Visual Studio 项目并安装ozeki.voip.sip.client,它自动建立了两个文件:CallHandlerSample.cs、TestCall.cs
CallHandlerSample.cs:
using Ozeki.Media.MediaHandlers;
using Ozeki.VoIP;
using Ozeki.VoIP.SDK;
namespace OzekiTestApplication
{
//These classes is just an example how to use OZEKI VoIP SIP SDK, what dll is added to the References in Solution Explorer
//Feel free to use the other components of this SDK
//For More information please visit : http://www.voip-sip-sdk.com and http://www.ozekiphone.com/ozeki-voip-sip-client-997.html
class CallHandlerSample
{
private ISoftPhone softPhone;
private IPhoneLine phoneLine;
private RegState phoneLineInformation;
private IPhoneCall call;
private readonly Microphone microphone;
private readonly Speaker speaker;
private readonly MediaConnector connector;
private readonly PhoneCallAudioSender mediaSender;
private readonly PhoneCallAudioReceiver mediaReceiver;
/// <summary>
/// Event triggered when the registered softphone has called
/// </summary>
public event EventHandler<VoIPEventArgs<IPhoneCall>> IncomingCallReceived;
/// <summary>
/// Event the softphone has successfully registered
/// </summary>
public event EventHandler RegistrationSucceded;
/// <summary>
/// Handler of making call and receiving call
/// </summary>
/// <param name="registerName">The SIP ID what will registered into your PBX</param>
/// <param name="domainHost">The address of your PBX</param>
public CallHandlerSample(string registerName, string domainHost)
{
microphone = Microphone.GetDefaultDevice();
speaker = Speaker.GetDefaultDevice();
connector = new MediaConnector();
mediaSender = new PhoneCallAudioSender();
mediaReceiver = new PhoneCallAudioReceiver();
InitializeSoftPhone(registerName, domainHost);
}
/// <summary>
///It initializes a softphone object with a SIP PBX, and it is for requisiting a SIP account that is nedded for a SIP PBX service. It registers this SIP
///account to the SIP PBX through an ’IphoneLine’ object which represents the telephoneline.
///If the telephone registration is successful we have a call ready softphone. In this example the softphone can be reached by dialing the registername.
/// </summary>
/// <param name="registerName">The SIP ID what will registered into your PBX</param>
/// <param name="domainHost">The address of your PBX</param>
private void InitializeSoftPhone(string registerName, string domainHost)
{
try
{
softPhone = SoftPhoneFactory.CreateSoftPhone(SoftPhoneFactory.GetLocalIP(), 5000, 10000);
softPhone.IncomingCall += softPhone_IncomingCall;
var sp = new SIPAccount(true, registerName, registerName, registerName, registerName, domainHost, 5060);
phoneLine = softPhone.CreatePhoneLine(sp);
phoneLine.RegistrationStateChanged += phoneLine_PhoneLineInformation;
softPhone.RegisterPhoneLine(phoneLine);
}
catch (Exception ex)
{
Console.WriteLine("You didn't give your local IP adress, so the program won't run properly.\n {0}", ex.Message);
}
}
/// <summary>
/// Create and start the call to the dialed number
/// </summary>
/// <param name="dialedNumber"></param>
public void Call(string dialedNumber)
{
if (phoneLineInformation != RegState.RegistrationSucceeded)
{
Console.WriteLine("Phone line state is not valid!");
return;
}
if (string.IsNullOrEmpty(dialedNumber))
return;
if (call != null)
return;
call = softPhone.CreateCallObject(phoneLine, dialedNumber);
WireUpCallEvents();
call.Start();
}
/// <summary>
/// Occurs when phone line state has changed.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void phoneLine_PhoneLineInformation(object sender, RegistrationStateChangedArgs e)
{
phoneLineInformation = e.State;
Console.WriteLine("Register name:" + ((IPhoneLine)sender).SIPAccount.RegisterName);
if (e.State == RegState.RegistrationSucceeded)
{
Console.WriteLine("Registration succeeded. Online.");
OnRegistrationSucceded();
}
else
{
Console.WriteLine("Current state:" + e.State);
}
}
/// <summary>
/// Occurs when an incoming call request has received.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void softPhone_IncomingCall(object sender, VoIPEventArgs<IPhoneCall> e)
{
Console.WriteLine("Incoming call from {0}", e.Item.DialInfo);
call = e.Item;
WireUpCallEvents();
OnIncomingCallReceived(e.Item);
}
/// <summary>
/// Occurs when the phone call state has changed.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void call_CallStateChanged(object sender, CallStateChangedArgs e)
{
Console.WriteLine("Call state changed: " + e.State);
switch (e.State)
{
case CallState.InCall:
ConnectDevicesToCall();
break;
case CallState.Completed:
DisconnectDevicesFromCall();
WireDownCallEvents();
call = null;
break;
case CallState.Cancelled:
WireDownCallEvents();
call = null;
break;
}
}
private void OnRegistrationSucceded()
{
var handler = RegistrationSucceded;
if (handler != null)
handler(this, EventArgs.Empty);
}
private void OnIncomingCallReceived(IPhoneCall item)
{
var handler = IncomingCallReceived;
if (handler != null)
handler(this, new VoIPEventArgs<IPhoneCall>(item));
}
/// <summary>
/// Connecting the microphone and speaker to the call
/// </summary>
private void ConnectDevicesToCall()
{
if (microphone != null)
microphone.Start();
connector.Connect(microphone, mediaSender);
if (speaker != null)
speaker.Start();
connector.Connect(mediaReceiver, speaker);
mediaSender.AttachToCall(call);
mediaReceiver.AttachToCall(call);
}
/// <summary>
/// Disconnecting the microphone and speaker from the call
/// </summary>
private void DisconnectDevicesFromCall()
{
if (microphone != null)
microphone.Stop();
connector.Disconnect(microphone, mediaSender);
if (speaker != null)
speaker.Stop();
connector.Disconnect(mediaReceiver, speaker);
mediaSender.Detach();
mediaReceiver.Detach();
}
/// <summary>
/// It signs up to the necessary events of a call transact.
/// </summary>
private void WireUpCallEvents()
{
if (call != null)
{
call.CallStateChanged += ( call_CallStateChanged );
}
}
/// <summary>
/// It signs down from the necessary events of a call transact.
/// </summary>
private void WireDownCallEvents()
{
if (call != null)
{
call.CallStateChanged -= (call_CallStateChanged);
}
}
~CallHandlerSample()
{
if (softPhone != null)
softPhone.Close();
WireDownCallEvents();
}
}
}
测试调用.cs:
using Ozeki.VoIP;
namespace OzekiTestApplication
{
//These classes is just an example how to use OZEKI VoIP SIP SDK, what dll is added to the References in Solution Explorer
//Feel free to use the other components of this SDK
//For More information please visit : http://www.voip-sip-sdk.com and http://www.ozekiphone.com/ozeki-voip-sip-client-997.html
class TestCall
{
private static CallHandlerSample _callHandlerSample;
public TestCall()
{
_callHandlerSample = new CallHandlerSample("888", "192.168.2.69");
SubscribeCallHandlerSampleEvents();
UnsubscribeCallHandlerSampleEvents();
}
static void callHandlerSample_IncomingCallReceived(object sender, VoIPEventArgs<IPhoneCall> incomingCall)
{
incomingCall.Item.Answer();
}
private static void callHandlerSample_RegistrationSucceded(object sender, EventArgs e)
{
_callHandlerSample.Call("1000");
}
private static void SubscribeCallHandlerSampleEvents()
{
_callHandlerSample.RegistrationSucceded += callHandlerSample_RegistrationSucceded;
_callHandlerSample.IncomingCallReceived += callHandlerSample_IncomingCallReceived;
}
private static void UnsubscribeCallHandlerSampleEvents()
{
_callHandlerSample.RegistrationSucceded -= callHandlerSample_RegistrationSucceded;
_callHandlerSample.IncomingCallReceived -= callHandlerSample_IncomingCallReceived;
}
}
}
问题是,每次我打电话softPhone.RegisterPhoneLine(phoneLine)
,一段时间后,事件phoneLine_PhoneLineInformation
总是返回Error
。我错过了什么?我误解了 SIP 结构吗?
解决方案
我不知道这是否是您提供的有限信息的问题。但我只是在调试类似的代码,问题是GetLocalIP()
只能获取计算机上的第一个 IP 地址,并且在计算机上有软件 VPN 的情况下,软件电话将注册请求发送到错误的接口。
尝试改变:
SoftPhoneFactory.CreateSoftPhone(SoftPhoneFactory.GetLocalIP(), 5000, 10000);
至:
SoftPhoneFactory.CreateSoftPhone(5000, 10000);
Ozeki 文档相当乏味,但这是我所知道的文档:http ://www.voip-sip-sdk.com/doc/html/118347ff-efa9-1054-7747-9154f85380a2.htm和http:// voip-sip-sdk.com/p_7333-voip-sdk-softphone-development-voip.html
我只是通过我的网络知识和使用 WireShark 进行测试才弄清楚这一点。
如果您绝对必须设置源 IP 地址,我建议检查此答案:https ://stackoverflow.com/a/27376368/5815327
推荐阅读
- jquery - 如何返回 jQuery 提示内容的值
- javascript - 在 Sanctum 中使用代币进行授权
- mysql - 复杂关系 TypeORM / MySQL
- python - 尝试使用 csv 模块时出现“AttributeError:部分初始化模块‘csv’”
- python - 在 tkinter 中清除以前的标签
- javascript - 元素在数组中被放置了两次,即使我只是在 Nextjs/React App 中添加了一次
- java - 找到结果后 Java 跳出 for 循环
- python - 当只能通过遍历发现数据结构时,如何使用 Python 枚举有向无环图结构中的所有路径?
- java - 如何显示共享相同属性的对象列表?
- blazor-webassembly - 如何在 ABP Blazor UI 中用其他组件库完全替换 Blazorize