下一代网络(Next Generation Network),又称为次世代网络。主要思想是在一个统一的网络平台上以统一管理的方式提供多媒体业务,整合现有的市内固定电话、移动电话的基础上(统称FMC),增加多媒体数据服务及其他增值型服务。其中话音的交换将采用软交换技术,而平台的主要实现方式为IP技术,逐步实现统一通信其中voip将是下一代网络中的一个重点。为了强调IP技术的重要性,业界的主要公司之一思科公司(Cisco Systems)主张称为IP-NGN。
NGN引擎
该引擎是一个包含所有服务的一个黑盒子。你必须始终通过引擎检索服务。
你还必须通过NGN引擎启动/停止服务。
下面的代码演示了然后实例化一个引擎
//获取一个引擎实例。这个函数总是服务相同的实例 //这意味着,只要你想你可以从你的代码任何地方调用它 final NgnEngine mEngine = NgnEngine.getInstance();
下面的代码演示如何从引擎得到一些服务:
//获取配置服务 INgnConfigurationService mConfigurationService = mEngine.getConfigurationService(); //获取SIP/IMS服务 INgnSipService mSipService = mEngine.getSipService(); //等等等等
下面的代码演示如何启动/停止引擎。
//启动引擎 mEngine.start(); //停止引擎 mEngine.stop(); //启动/停止所有基础服务引擎 /** 你应该在你的Android扩展类定义应用程序全局对象 */
基础服务(Base Service)
所有的NGN服务都继承这个类
联系服务(Contact Service)
联系服务用于检索来自本地地址薄中的联系人
HTTP/HTTPS服务(HTTP/HTTPS Service)
HTTP/HTTPS服务用于检索发送和接收来自远程服务HTTP/HTTPS协议的数据
网络服务(Network Service)
网络服务用于管理WiFi和3G/4G网络连接
声音服务(Sound Service)
该服务是用来播放(铃声,回铃音,警报,…)。使用它之前你必须启动NGN引擎服务。
//获取和实例化NGN引擎 NgnEngine mEngine = NgnEngine.getInstance(); //播放回铃音 mEngine.getSoundService().startRingBackTone(); //停止回铃音 mEngine.getSoundService().stopRingBackTone();
存储服务(Storage Service)
该服务用于管理存储功能
配置服务(Configuration Service)
配置服务用于存储用户偏好。保存所有喜好该服务是持久的,这意味着你可以在应用程序/设备重启找回它。你不应该自己创建或启动此服务。
这项服务的一个实例可以这样检索的:
final INgnConfigurationService mConfigurationService =NgnEngine.getInstance().getConfigurationService();
历史服务(History Service)
该服务用于存储/检索历史事件(音频/视频,消息,…)。你不应该自己创建或启动此服务。
这项服务的一个实例是这样检索的:
final INgnHistoryService mHistoryService = NgnEngine.getInstance().getHistoryService();
SIP/IMS服务(SIP/IMS Service)
该服务用于管理SIP/IMS栈。你不应该自己创建或启动此服务。
这项服务的一个实例可以这样检索:
final INgnSipService mSipService = NgnEngine.getInstance().getSipService();
音频/视频通话(Audio/Video calls)
音频呼叫(Making audio call)
得到音频/视频通话有关通知状态请看这里
final String remoteUri = "+33600000000"; final String validUri = NgnUriUtils.makeValidSipUri(remoteUri);
// sip:+33600000000"@doubango.org NgnAVSession avSession = NgnAVSession.createOutgoingSession( mSipService.getSipStack(), NgnMediaType.Audio); if (avSession.makeCall(validUri)) {
Log.d("zhsy", "all is ok"); } else { Log.e("zhsy", "Failed to place the call"); }
视频通话(Making video call)
得到音频/视频通话有关通知状态请看这里
final String remoteUri = "+33600000000"; final String validUri = NgnUriUtils.makeValidSipUri(remoteUri); // sip:+33600000000"@doubango.org NgnAVSession avSession = NgnAVSession.createOutgoingSession( mSipService.getSipStack(), NgnMediaType.AudioVideo); if (avSession.makeCall(validUri)) { Log.d(zhsy, "all is ok"); } else { Log.e("zhsy", "Failed to place the call"); }
短信与聊天(SMS and Chat)
3GPP Binary SMS
// 短信中心 final String SMSC = "sip:+3310000000@doubango.org"; // 对方 final String remotePartyUri = "sip:+336000000@doubango.org"; final String textToSend = "hello world!"; final NgnMessagingSession imSession = NgnMessagingSession.createOutgoingSession(mSipService.getSipStack(),remotePartyUri); if(!imSession.SendBinaryMessage(textToSend,SMSC)){ Log.e("zhsy","Failed to send"); }else{ Log.d("zhsy","Message sent"); } //发布会话
NgnMessagingSession.releaseSession(imSession);
寻呼机模式IM(Pager Mode IM)
final String textToSend = "hello world!"; // 对方
final String remotePartyUri = "sip:+336000000@doubango.org"; final NgnMessagingSession imSession = NgnMessagingSession.createOutgoingSession(mSipService.getSipStack(),remotePartyUri); if(!imSession.sendTextMessage(textToSend)){ Log.e("zhsy","Failed to send"); }else{ Log.d("zhsy","Message sent"); } // 发布会话
NgnMessagingSession.releaseSession(imSession);
监听事件(Listening to events)
SIP/IMS服务负责所有任务相关的SIP协议(注册,音频/视频通话,寻呼机模式IM),你可以订阅事件改变当注册状态变化,新的SIP消息被接收,新得到的通知,输入的音频/视频通话,…所有通知通过不止一次异步查询的方式发送给您。
监听状态注册状态改变(Listening for registration state change)
你可以监听得到当你登录/退出时注册状态变化通知
final TextView mTvInfo = (TextView) findViewById(R.id.textViewInfo); final BroadcastReceiver mSipBroadCastRecv = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); // Registration Event if (NgnRegistrationEventArgs.ACTION_REGISTRATION_EVENT.equals(action)) { NgnRegistrationEventArgs args = intent.getParcelableExtra(NgnEventArgs.EXTRA_EMBEDDED); if (args == null) { Log.e("zhsy", "Invalid event args"); return; } switch (args.getEventType()) { case REGISTRATION_NOK: mTvInfo.setText("Failed to register :("); break; case UNREGISTRATION_OK: mTvInfo.setText("You are now unregistered :)"); break; case REGISTRATION_OK: mTvInfo.setText("You are now registered :)"); break; case REGISTRATION_INPROGRESS: mTvInfo.setText("Trying to register..."); break; case UNREGISTRATION_INPROGRESS: mTvInfo.setText("Trying to unregister..."); break; case UNREGISTRATION_NOK: mTvInfo.setText("Failed to unregister :("); break; } } } }; final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(NgnRegistrationEventArgs.ACTION_REGISTRATION_EVENT); registerReceiver(mSipBroadCastRecv, intentFilter);
监听音频/视频通话状态变化(Listening for audio/video call state change)
你可以监听获得音频/视频呼叫状态变更通知,呼叫状态变更(呼入(incoming),正在呼叫(incall),外呼(outgoing),终止(terminated))
final BroadcastReceiver mSipBroadCastRecv = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { InviteState state; final String action = intent.getAction(); if (NgnInviteEventArgs.ACTION_INVITE_EVENT.equals(action)) { NgnInviteEventArgs args = intent.getParcelableExtra(NgnEventArgs.EXTRA_EMBEDDED); if (args == null) { Log.e("zhsy", "Invalid event args"); return; } Log.d(TAG,"This is anevent for session number "+ args.getSessionId()); // Retrieve the sessionfrom the store NgnAVSession avSession = NgnAVSession.getSession(args.getSessionId()); if (avSession == null) { Log.e(TAG, "Cannot find session"); return; } switch ((state = avSession.getState())) { case NONE: default: break; case INCOMING: Log.i("zhsy", "Incoming call"); break; case INPROGRESS: Log.i("zhsy", "Call in progress"); break; case REMOTE_RINGING: Log.i("zhsy", "Remote party is ringing"); break; case EARLY_MEDIA: Log.i("zhsy", "Early media started"); break; case INCALL: Log.i("zhsy", "Call connected"); break; case TERMINATING: Log.i("zhsy", "Call terminating"); break; case TERMINATED: Log.i("zhsy", "Call terminated"); break; } } } };
配置(Configuration)
试图注册到SIP/IMS服务你必须配置你的凭证。配置服务负责这些任务。使用喜好配置服务都是持久的,这意味着应用程序/设备重新启动。配置信息,你必须得到一个实例这样一个引擎服务:
final INgnConfigurationService mConfigurationService
域(Realm)
域是验证域的名称。它应该是一个有效的SIP URI(例如:sip:open-ims.test or sip:10.0.0.1 )。该域是强制性的,栈开始之前应该设置,一旦栈开始时你不能改变它的值。如果Proxy-CSCF的地址找不到,那么栈会自动使用DNS NAPTR+SRV/或用于动态搜索的DHCP机制。域的值将用作于DNS NAPTR查询的域名中。欲了解更多有关于如何设置CSCF IP地址和端口的信息,请参见第22.1.8
final String myRealm = "sip:doubango.org"; final boolean bSaveNow = true; mConfigurationService(ConfigurationEntry.NETWORK_REALM, myRealm, bSaveNow);
IMS 私有标识(IMPI)(IMS Private Identity (IMPI))
IMS私有标识(又名IMPI)是分配给一个家庭网络用户(或UE)的唯一标识符。它可以是一个SIP URI(例如:sip:bob@open-ims.test),一个电话URI(例如,电话:+33100000)或者如何字母数字字符串(例如:bob@open-ims.test 或 bob)它被用来验证UE(SIP授权/Proxy-Authorization用户名字段)。在现实世界中,应该存储在UICC(通用集成电路卡)。对于那些使用该IMS协议栈作为基本(IETF)的SIP协议栈,该IMPU验证名称应与他们一致。该IMPI是强制性的,栈开始之前,应该设置。你不应该在栈被启动去改变IMPI。
IMPI被栈启动
final String myIMPI = "33446677887"; final boolean bSaveNow = true; mConfigurationService(ConfigurationEntry.IDENTITY_IMPI, myIMPI, bSaveNow);
IMS公共标识(IMPU)(IMS Public Identity (IMPU))
正如它的名字一样,它是你的公共可见的标识符,你愿意接听电话或者任何需求。一个IMPU可以是一个SIP或者URI(比如电话:tel:+33100000 或 sip:bob@openims.test)。在IMS中,用户可具有相关联的独特的IMPI个数的IMPU。对于那些使用该IMS栈基本的SIP协议栈,该IMPU应该与他们的SIP URI一直。该IMPU是强制性的,栈开始前,一个进行设置。你不应该在栈被启动去改变IMPU。
如果你想在栈开始改变IMPU(而不是,改变P-Preferred-Identity默认的公共标识符)
final boolean bSaveNow = true; final String myIMPU = "sip:33446677887@doubango.org"; mConfigurationService(ConfigurationEntry.IDENTITY_IMPU, myIMPU, bSaveNow);
首选身份(Preferred Identity)
作为一个用户有多个IMPU,它可以为呼出每个请求,定义IMPU被使用设置首选身份。用户检查该IPMU没有禁止。一个是IMPU如果它没有出现在返回200和相关联的URL被禁止。缺省情况下,首选的身份是在相关联的标识列表中第一个URL。如果IMPU用于注册的用户被禁止,那么栈将使用URI返回默认SCSCF。
你不应该手动设置此SIP(P-Preferred-Identity)它是由栈
Proxy-CSCF 主机地址(Proxy-CSCF Host address)
Proxy-CSCF 主机是SIP的IP地址(192.168.0.1)或FQDN(doubango.org)注册商。你应该在必要时设置代理CSCF地址和IP。动态机制(DNS NAPTR/或DHCPv4/v6)应该被使用。
下面的代码演示了如何设置ProxyCSCF IP地址和端口。如果端口找不到,那么它的默认值是5060
// Sets IP address final String proxyHost = "192.168.0.1"; mConfigurationService(ConfigurationEntry.NETWORK_PCSCF_HOST, proxyHost); // Sets port final int proxyPort = 5060; mConfigurationService.putInt(ConfigurationEntry.NETWORK_PCSCF_PORT, proxyPort); Save changes mConfigurationService.commit();