SIP消息的重要性很高,因为它们经常用于各种目的。 它们用于建立电话,采取补充行动等。今天,当我们生活在一个瞬息万变的世界中时,快速高效的沟通比以往任何时候都更为重要。 SMS技术提供了相互之间发送信息的最快方法之一。 这样,您绝对可以确定收件人会收到您的消息,因为大多数人都将手机放在附近。
开发此示例程序旨在为此类问题提供有效的解决方案。 在开发过程中,我使用了Ozeki提供的SDK和Microsoft Windows Forms演示技术。
我开发了一种电话,可以转发和接收电话,并且还可以发送和接收DTMF信号以在IVR系统中导航。
程序运行运行该程序后,电话将使用给定的SIP帐户自动注册到给定的SIP PBX。 如果在显示屏上成功完成注册过程,则可以看到成功的注册。 从现在开始,softpohne准备拨打,接听电话,并且可以在通话期间发送,接收DTMF信号以在IVR系统中导航。 (示例程序的源代码包含取决于环境的设置,因此下载后不要忘记对其进行自定义)。 通话结束后,会收到有关关键字的通知。
码文件后面的PhoneMain.cs代码记下与界面相关的启动事件,并将逻辑连接到GUI。 该示例程序缺少设计示例和其他专有属性,并且由于其仅用于演示,因此侧重于简单性。 这意味着PhoneMain.cs文件包含示例程序的完整逻辑。 打开文件时,您会看到使用Ozeki VoIP SIP SDK所需的几行声明。
public partial class PhoneMain : Form
{
ISoftPhone softPhone;
IPhoneLine phoneLine;
PhoneLineInformation phoneLineInformation;
IPhoneCall call;
OzPipeStream speakerStream;
ozWavePlayer wavePlayer;
ozWaveRecorder waveRecorder;
bool inComingCall;
Stream ReceivedStream;
Stream SentStream;
软电话
它代表电话,其电话线由IphoneLine代表。 电话线可能更多,这意味着我们可以开发多线电话。
Iphoneline它代表可以注册到SIP PBX(例如Asterisk,3CX)或SIP提供商提供的其他PBX的电话线。 注册通过SIP帐户进行。
电话线信息这是一个枚举类型,表示PBX上电话线的状态。 例如,已注册,未注册,成功/失败注册。
手机通话它代表一个呼叫:呼叫的状态,呼叫的方向,在哪条电话线上创建的,被叫的人等等。
OzPipeStream这是一个可选设备,它有助于处理来自另一方的传入声音数据。
ozWavePlayer它在扬声器上播放接收到的声音数据。
ozWavRecorder它处理来自操作系统默认输入设备(麦克风)的声音数据。
接收流流是保存接收到的流的流。
发送流流将保存发送的流。
从而将其分配给Windows窗体窗口的“已加载”事件,并在加载“ PhoneMain”窗口后,可以启动Ozeki SDK软电话的初始化和注册。
private void InitializeSoftPhone()
{
softPhone = SoftPhoneFactory.CreateSoftPhone("192.168.91.42", 5700, 5750, 5780);
softPhone.IncommingCall += new EventHandler<VoIPEventArgs<IPhoneCall>>(softPhone_IncommingCall);
phoneLine = softPhone.CreatePhoneLine(new SIPAccount(true, "oz891", "oz891", "oz891", "oz891", "192.168.91.212", 5060));
phoneLine.PhoneLineInformation += new EventHandler<VoIPEventArgs<PhoneLineInformation>>(phoneLine_PhoneLineInformation);
softPhone.RegisterPhoneLine(phoneLine);
}
SDK表示通过IpPhoneCall接口的传入和传出呼叫。
此界面包含给定呼叫的状态,在哪条线路上被创建以及谁是被呼叫者。
在此对象上,您可以接听或挂断电话。
让我们看看示例程序的事件。
对于拨出电话,我们提供要拨打的号码。 然后按代答按钮,通话开始。 界面按钮是针对触发器的,因此在“ Pick Up”按钮的情况下让我们看一下。
private void buttonPickUp_Click(object sender, EventArgs e)
{
if (inComingCall)
{
inComingCall = false;
call.Accept();
return;
}
if (call != null)
return;
if (string.IsNullOrWhiteSpace(labelDialingNumber.Text))
return;
if (phoneLineInformation != PhoneLineInformation.RegistrationSucceeded && phoneLineInformation != PhoneLineInformation.NoRegNeeded)
{
MessageBox.Show("Phone line state is not valid!");
return;
}
call = softPhone.Call(phoneLine, labelDialingNumber.Text);
WireUpCallEvents();
call.Start();
}
在下面,您可以看到我是如何接线的。
private void WireUpCallEvents()
{
call.CallStateChanged += new EventHandler<VoIPEventArgs<CallState>>(call_CallStateChanged);
call.MediaDataReceived += new EventHandler<VoIPEventArgs<VoIPMediaData>>(call_MediaDataReceived);
call.DtmfReceived += new EventHandler<VoIPEventArgs<Tuple<VoIPMediaType, DtmfSignal>>>(call_DtmfReceived);
call.CallErrorOccured += new EventHandler<VoIPEventArgs<CallError>>(call_CallErrorOccured);
}
通过CallErrorOccured事件,接收有关未创建的原因的信息。 它们可以是:呼叫被拒绝,被叫方正忙,被叫号码不可用或该号码不存在。
为了解决这些重要事件,请启动一个真正的电话。 您可以使用调用对象的“启动”功能来实现。 在示例中是“ call.Start()”行。
Ozeki VoIP SIP SDK通过“ ISoftphone” InComingCall事件公开传入的呼叫。
private void softPhone_IncommingCall(object sender, VoIPEventArgs<IPhoneCall> e)
{
InvokeGUIThread(()=>
{
labelCallStateInfo.Text = "Incoming call";
labelDialingNumber.Text = String.Format("from {0}", e.Item.DialInfo);
call = e.Item;
WireUpCallEvents();
inComingCall = true;
});
}
上面显示的代码示例对此进行了处理,如果有来电,它将在显示屏上发出呼叫信号。
然后注册来电的必要事件。
如果是呼出电话或呼入电话,则呼入电话变量会发出“ Pick Up”按钮的信号。
“挂断”按钮也连接到事件处理程序,类似于“拾取”按钮。 如下所示的事件处理程序将结束通话,您只需按“挂断”按钮即可。
private void buttonHangUp_Click(object sender, EventArgs e)
{
if (call != null)
{
inComingCall = false;
call.HangUp();
call = null;
}
labelDialingNumber.Text = string.Empty;
}
Ozeki VoIP SIP SDK提供有关呼叫状态的信息。 它们可以是:InCall,完成,拒绝,响铃等。通过CallStateChange事件,将显示这些呼叫状态。 该示例程序无法处理所有可能性,因为我只专注于重要的可能性。 根据这些重要程序,可以轻松创建其他程序。
private void call_CallStateChanged(object sender, VoIPEventArgs<CallState> e)
{
InvokeGUIThread(() => { labelCallStateInfo.Text = e.Item.ToString(); });
switch (e.Item)
{
ozWaveFormat waveFormat = new ozWaveFormat(8000, 16, 1);
ReceivedStream = new ozWaveFileWriter(waveFormat, receivedFilePath);
SentStream = new ozWaveFileWriter(waveFormat, sentFilePath);
waveRecorder = new ozWaveRecorder();
waveRecorder.DataArrived += waveRecorder_DataArrived;
waveRecorder.StartRecording();
speakerStream = new OzPipeStream();
wavePlayer = new ozWavePlayer(speakerStream);
wavePlayer.Play();
break;
case CallState.Completed:
waveRecorder.Dispose();
speakerStream.Dispose();
speakerStream = null;
wavePlayer.Dispose();
call = null;
InvokeGUIThread(() => { labelDialingNumber.Text = string.Empty; });
break;
case CallState.Cancelled:
call = null;
break;
} }
由于在“呼叫” MediaDataReceived的输出/传入线路上,传入的PCM声音数据仅需要转发到声音系统,如下所示。
private void call_MediaDataReceived(object sender, VoIPEventArgs<VoIPMediaData> e)
{
if (speakerStream != null)
speakerStream.Write(e.Item.PCMData, 0, e.Item.PCMData.Length);
if (ReceivedStream.CanWrite)
{
((ozWaveFileWriter)ReceivedStream).Save(e.Item.PCMData);
}
}
将源自麦克风的PCM声音数据传递到代表实际呼叫的呼叫对象。
这是通过SendMediaData的过程发生的,声音将根据构建的通信通道发送。
声音数据将在正确的声音编解码器的帮助下进行压缩,然后将其转发给接收者。
private void waveRecorder_DataArrived(object sender, ozDataArrivedEventArgs e)
{
if (call != null)
call.SendMediaData(VoIPMediaType.Audio, e.Data);
if (SentStream.CanWrite)
{
((ozWaveFileWriter)SentStream).Save(e.Data);
}
}
建立呼叫后,就有机会发送DTMF信号。 您可以在被叫客户服务的IVR系统中导航。 Ozeki VoIP SIP SDK以一种简单的方式发送DTMF信号。 在表示当前调用的对象上调用“ StartDTMFSignal”方法,如下所示。
private void buttonKeyPadButton_MouseDown(object sender, MouseEventArgs e)
{
if (call != null && call.CallState == CallState.InCall)
{
var btn = sender as Button;
if (btn != null)
{
int id;
if (btn.Tag != null && int.TryParse(btn.Tag.ToString(), out id))
{
call.StartDTMFSignal(VoIPMediaType.Audio, id);
}
}
}
}
结束DTMF信号类似于开始。
在表示当前调用的对象上,邀请“ StopDTMFSignal”方法。
在此下方可以看到,其中id是参考编号类型DTMF信号,并且与按下的按钮有关。
call.StopDTMFSignal(VoIPMediaType.Audio, id);
Ozeki VoIP SIP SDK以一种简单的方式通知SIP消息的内容。 为此,将事件分配给如下所示的事件。
OzSIP.Log.SIPMessageLogger.NewSIPMessage += SIPMessageLogger_NewSIPMessage;
现在检查消息内容
void SIPMessageLogger_NewSIPMessage(object sender, VoIPEventArgs<string> e)
{
if (e.Item.Contains(txb_SIPText.Text))
{
SendSMS();
}
}
如果搜索到的SIP文本片段匹配,则只需要发送一条SMS。 可以通过发送到SMS服务器的http API的请求来实现
private void SendSMS()
{
string url =
string.Format(@"http://{0}/api?action=sendmessage&username={1}&password={2}&recipient={3}&messagetype=SMS:TEXT&messagedata={4}",Txb_IpAddress.Text, txb_UserName.Text, Txb_Password.Text, Txb_recipient.Text, Txb_SmsText.Text);
WebRequest request = WebRequest.Create(url);
request.GetResponse();
}
摘要
短信发送已成为我们生活的一部分,就像手机,电视或互联网一样。 这是一种非常有效且快速的通讯方式。 实现很简单,因此很容易创建自己的C#SIP SMS示例。 可以在网页上找到更多特定信息。 我只能向所有人推荐此解决方案。
From: https://bytes.com/topic/c-sharp/insights/913600-how-build-c-sip-sms-example