android sip通话实现流程分析
2017-03-29 16:03
956 查看
sip协议的核心是SipManager,我在前篇博客中已经讲述了sip通话的代码建立过程,点击打开链接
会创建一个SipManager实例,它的构造代码如下:
public static SipManager newInstance(Context context) {
return (isApiSupported(context) ? new SipManager(context) : null);
}
private SipManager(Context context) {
mContext = context;
createSipService();
}
private void createSipService() {
IBinder b = ServiceManager.getService(Context.SIP_SERVICE); //获取sip服务的代理类,返回一个BinderProxy对象.
mSipService = ISipService.Stub.asInterface(b);
}
从上面代码可以看出,SipManager的构造过程中会去获取sip服务(实际就是SipService)的代理类对象,SipManager的很多方法最终是调用到这个服务端的相应方法来实现的.
那么下面我们先看看SipService是如何注册到ServiceManager中去的.
它的注册与一般服务的注册不同,绝大多数Service都是直接在SysetmServer进程中进行注册,而SipService是在TeleService apk中注册,也就是在phone进程中注册的(部分phone相关的服务也是在phone进程中注册的),虽然最终都是注册到ServiceManager中,但这个服务是运行在phone进程中的.
具体实现代码在PhoneGlobals.java中.
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
PhoneConstants.State phoneState;
switch (msg.what) {
// Starts the SIP service. It's a no-op if SIP API is not supported
// on the deivce.
// TODO: Having the phone process host the SIP service is only
// temporary. Will move it to a persistent communication process
// later.
case EVENT_START_SIP_SERVICE:
SipService.start(getApplicationContext());
break;
..//
}
在PhoneGlobals的onCreate()中
if (mCM == null) {
....//
mHandler.sendEmptyMessage(EVENT_START_SIP_SERVICE);
}
SipService的start方法如下:
public static void start(Context context) {
if (SipManager.isApiSupported(context)) {
ServiceManager.addService("sip", new SipService(context));
context.sendBroadcast(new Intent(SipManager.ACTION_SIP_SERVICE_UP));
if (DBG) slog("start:");
}
}
这样就将一个SipService注册到ServiceManager中了.
我在前面博客已分析过,拨打一个网络电话是调用SipManager的makeAudioCall()方法实现的.
下面我以拨打一个网络电话为例进行说明具体实现流程:
public SipAudioCall makeAudioCall(SipProfile localProfile,
SipProfile peerProfile, SipAudioCall.Listener listener, int timeout)
throws SipException {
if (!isVoipSupported(mContext)) {
throw new SipException("VOIP API is not supported");
}
SipAudioCall call = new SipAudioCall(mContext, localProfile);
call.setListener(listener);
SipSession s = createSipSession(localProfile, null);
call.makeCall(peerProfile, s, timeout);
return call;
}
该方法中首先创建了一个SipAudioCall对象,然后调用createSipSession()创建一个sip会话SipSession对象.
public SipSession createSipSession(SipProfile localProfile,
SipSession.Listener listener) throws SipException {
try {
ISipSession s = mSipService.createSession(localProfile, null);
if (s == null) {
throw new SipException(
"Failed to create SipSession; network unavailable?");
}
return new SipSession(s, listener);
} catch (RemoteException e) {
throw new SipException("createSipSession()", e);
}
}
mSipService.createSession(localProfile, null);对应实现在SipService中,代码如下:
public synchronized ISipSession createSession(SipProfile localProfile,
ISipSessionListener listener) {
if (DBG) log("createSession: profile" + localProfile);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.USE_SIP, null);
localProfile.setCallingUid(Binder.getCallingUid());
if (mNetworkType == -1) {
if (DBG) log("createSession: mNetworkType==-1 ret=null");
return null;
}
try {
SipSessionGroupExt group = createGroup(localProfile);
return group.createSession(listener);
} catch (SipException e) {
if (DBG) loge("createSession;", e);
return null;
}
}
public ISipSession createSession(ISipSessionListener listener) {
return (isClosed() ? null : new SipSessionImpl(listener));
}
根据上面代码分析,mSipService.createSession()在服务端创建了一个SipSessionImpl对象.
我们再看SipAudioCall的makeCall()方法实现.
public void makeCall(SipProfile peerProfile, SipSession sipSession,
int timeout) throws SipException {
if (DBG) log("makeCall: " + peerProfile + " session=" + sipSession + " timeout=" + timeout);
if (!SipManager.isVoipSupported(mContext)) {
throw new SipException("VOIP API is not supported");
}
synchronized (this) {
mSipSession = sipSession;
try {
mAudioStream = new AudioStream(InetAddress.getByName(
getLocalIp()));
sipSession.setListener(createListener());
sipSession.makeCall(peerProfile, createOffer().encode(),
timeout);
} catch (IOException e) {
loge("makeCall:", e);
throw new SipException("makeCall()", e);
}
}
}
上面代码中创建了一个AudioStream对象(这个类是传输音频流使用的,我会在后面一篇博客中进行分析音频流是如何传输的),并调用sipSession.makeCall()方法,
SipSession类的makeCall()方法如下:
public void makeCall(SipProfile callee, String sessionDescription,
int timeout) {
try {
mSession.makeCall(callee, sessionDescription, timeout);
} catch (RemoteException e) {
loge("makeCall:", e);
}
}
此处的mSession就是我们之前分析的SipSessionImpl在客户端的代理类,参数callee就是目的主机对应的SipProfile,我们直接看它的服务端SipSessionImpl的实现.对应代码在SipSessionGroup.java中.
// process the command in a new thread
private void doCommandAsync(final EventObject command) {
new Thread(new Runnable() {
@Override
public void run() {
try {
processCommand(command);
} catch (Throwable e) {
loge("command error: " + command + ": "
+ mLocalProfile.getUriString(),
getRootCause(e));
onError(e);
}
}
}, "SipSessionAsyncCmdThread").start();
}
@Override
public void makeCall(SipProfile peerProfile, String sessionDescription,
int timeout) {
doCommandAsync(new MakeCallCommand(peerProfile, sessionDescription,
timeout));
}
从上面代码中我们可以看出它是在一个子线程中调用processCommand()来处理命令消息的.
private void processCommand(EventObject command) throws SipException {
if (isLoggable(command)) log("process cmd: " + command);
if (!process(command)) {
onError(SipErrorCode.IN_PROGRESS,
"cannot initiate a new transaction to execute: "
+ command);
}
}
public boolean process(EventObject evt) throws SipException {
if (isLoggable(this, evt)) log(" ~~~~~ " + this + ": "
+ SipSession.State.toString(mState) + ": processing "
+ logEvt(evt));
synchronized (SipSessionGroup.this) {
if (isClosed()) return false;
if (mSipKeepAlive != null) {
// event consumed by keepalive process
if (mSipKeepAlive.process(evt)) return true;
}
Dialog dialog = null;
if (evt instanceof RequestEvent) {
dialog = ((RequestEvent) evt).getDialog();
} else if (evt instanceof ResponseEvent) {
dialog = ((ResponseEvent) evt).getDialog();
extractExternalAddress((ResponseEvent) evt);
}
if (dialog != null) mDialog = dialog;
boolean processed;
switch (mState) {
case SipSession.State.REGISTERING:
case SipSession.State.DEREGISTERING:
processed = registeringToReady(evt);
break;
case SipSession.State.READY_TO_CALL:
processed = readyForCall(evt);
break;
case SipSession.State.INCOMING_CALL:
processed = incomingCall(evt);
break;
case SipSession.State.INCOMING_CALL_ANSWERING:
processed = incomingCallToInCall(evt);
break;
case SipSession.State.OUTGOING_CALL:
case SipSession.State.OUTGOING_CALL_RING_BACK:
processed = outgoingCall(evt);
break;
case SipSession.State.OUTGOING_CALL_CANCELING:
processed = outgoingCallToReady(evt);
break;
case SipSession.State.IN_CALL:
processed = inCall(evt);
break;
case SipSession.State.ENDING_CALL:
processed = endingCall(evt);
break;
default:
processed = false;
}
return (processed || processExceptions(evt));
}
}
从上面方法中可以看出,依据mState的值走不同的分支,我们看打电话时是调用outgoingCall(evt);
private boolean outgoingCall(EventObject evt) throws SipException {
if (expectResponse(Request.INVITE, evt)) {
ResponseEvent event = (ResponseEvent) evt;
Response response = event.getResponse();
int statusCode = response.getStatusCode();
switch (statusCode) {
case Response.RINGING:
case Response.CALL_IS_BEING_FORWARDED:
case Response.QUEUED:
case Response.SESSION_PROGRESS:
// feedback any provisional responses (except TRYING) as
// ring back for better UX
if (mState == SipSession.State.OUTGOING_CALL) {
mState = SipSession.State.OUTGOING_CALL_RING_BACK;
cancelSessionTimer();
mProxy.onRingingBack(this);
}
return true;
case Response.OK:
if (mReferSession != null) {
mSipHelper.sendReferNotify(mReferSession.mDialog,
getResponseString(Response.OK));
// since we don't need to remember the session anymore.
mReferSession = null;
}
mSipHelper.sendInviteAck(event, mDialog);
mPeerSessionDescription = extractContent(response);
establishCall(true);
return true;
case Response.UNAUTHORIZED:
case Response.PROXY_AUTHENTICATION_REQUIRED:
if (handleAuthentication(event)) {
addSipSession(this);
}
return true;
case Response.REQUEST_PENDING:
// TODO: rfc3261#section-14.1; re-schedule invite
return true;
default:
if (mReferSession != null) {
mSipHelper.sendReferNotify(mReferSession.mDialog,
getResponseString(Response.SERVICE_UNAVAILABLE));
}
if (statusCode >= 400) {
// error: an ack is sent automatically by the stack
onError(response);
return true;
} else if (statusCode >= 300) {
// TODO: handle 3xx (redirect)
} else {
return true;
}
}
return false;
} else if (END_CALL == evt) {
// RFC says that UA should not send out cancel when no
// response comes back yet. We are cheating for not checking
// response.
mState = SipSession.State.OUTGOING_CALL_CANCELING;
mSipHelper.sendCancel(mClientTransaction);
startSessionTimer(CANCEL_CALL_TIMER);
return true;
} else if (isRequestEvent(Request.INVITE, evt)) {
// Call self? Send BUSY HERE so server may redirect the call to
// voice mailbox.
RequestEvent event = (RequestEvent) evt;
mSipHelper.sendInviteBusyHere(event,
event.getServerTransaction());
return true;
}
return false;
}
实际上调用了mSipHelper.sendInviteBusyHere(event,event.getServerTransaction());此处的mSipHelper就是一个SipHelper类实例.
SipHelper是一个辅助类,它对sip协议栈操作的相关封装,用于建立sip会话的流程封装.例如发送INVITE消息给目的主机.
整个sip流程的建立,核心类是SipService,SipSessionGroup,这篇文章讲述了sip流程的建立过程.
其实SIP协议规定了会话的发起过程,但没有规定会话的内容及格式。会话内容可以是文本、语音、视频等。因此,SIP协议要结合其它协议,如:用SDP协议描述要传递的内容格式,用RTP,RTSP流媒体协议传输媒体,才能完成整个通信过程。 SIP协议这样做为了简化协议,留下扩展的灵活性。
,那么当一个sip会话建立之后,整个音频数据流是如何从一端传递到另一端的呢,请参考我的下一篇博客.
会创建一个SipManager实例,它的构造代码如下:
public static SipManager newInstance(Context context) {
return (isApiSupported(context) ? new SipManager(context) : null);
}
private SipManager(Context context) {
mContext = context;
createSipService();
}
private void createSipService() {
IBinder b = ServiceManager.getService(Context.SIP_SERVICE); //获取sip服务的代理类,返回一个BinderProxy对象.
mSipService = ISipService.Stub.asInterface(b);
}
从上面代码可以看出,SipManager的构造过程中会去获取sip服务(实际就是SipService)的代理类对象,SipManager的很多方法最终是调用到这个服务端的相应方法来实现的.
那么下面我们先看看SipService是如何注册到ServiceManager中去的.
它的注册与一般服务的注册不同,绝大多数Service都是直接在SysetmServer进程中进行注册,而SipService是在TeleService apk中注册,也就是在phone进程中注册的(部分phone相关的服务也是在phone进程中注册的),虽然最终都是注册到ServiceManager中,但这个服务是运行在phone进程中的.
具体实现代码在PhoneGlobals.java中.
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
PhoneConstants.State phoneState;
switch (msg.what) {
// Starts the SIP service. It's a no-op if SIP API is not supported
// on the deivce.
// TODO: Having the phone process host the SIP service is only
// temporary. Will move it to a persistent communication process
// later.
case EVENT_START_SIP_SERVICE:
SipService.start(getApplicationContext());
break;
..//
}
在PhoneGlobals的onCreate()中
if (mCM == null) {
....//
mHandler.sendEmptyMessage(EVENT_START_SIP_SERVICE);
}
SipService的start方法如下:
public static void start(Context context) {
if (SipManager.isApiSupported(context)) {
ServiceManager.addService("sip", new SipService(context));
context.sendBroadcast(new Intent(SipManager.ACTION_SIP_SERVICE_UP));
if (DBG) slog("start:");
}
}
这样就将一个SipService注册到ServiceManager中了.
我在前面博客已分析过,拨打一个网络电话是调用SipManager的makeAudioCall()方法实现的.
下面我以拨打一个网络电话为例进行说明具体实现流程:
public SipAudioCall makeAudioCall(SipProfile localProfile,
SipProfile peerProfile, SipAudioCall.Listener listener, int timeout)
throws SipException {
if (!isVoipSupported(mContext)) {
throw new SipException("VOIP API is not supported");
}
SipAudioCall call = new SipAudioCall(mContext, localProfile);
call.setListener(listener);
SipSession s = createSipSession(localProfile, null);
call.makeCall(peerProfile, s, timeout);
return call;
}
该方法中首先创建了一个SipAudioCall对象,然后调用createSipSession()创建一个sip会话SipSession对象.
public SipSession createSipSession(SipProfile localProfile,
SipSession.Listener listener) throws SipException {
try {
ISipSession s = mSipService.createSession(localProfile, null);
if (s == null) {
throw new SipException(
"Failed to create SipSession; network unavailable?");
}
return new SipSession(s, listener);
} catch (RemoteException e) {
throw new SipException("createSipSession()", e);
}
}
mSipService.createSession(localProfile, null);对应实现在SipService中,代码如下:
public synchronized ISipSession createSession(SipProfile localProfile,
ISipSessionListener listener) {
if (DBG) log("createSession: profile" + localProfile);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.USE_SIP, null);
localProfile.setCallingUid(Binder.getCallingUid());
if (mNetworkType == -1) {
if (DBG) log("createSession: mNetworkType==-1 ret=null");
return null;
}
try {
SipSessionGroupExt group = createGroup(localProfile);
return group.createSession(listener);
} catch (SipException e) {
if (DBG) loge("createSession;", e);
return null;
}
}
public ISipSession createSession(ISipSessionListener listener) {
return (isClosed() ? null : new SipSessionImpl(listener));
}
根据上面代码分析,mSipService.createSession()在服务端创建了一个SipSessionImpl对象.
我们再看SipAudioCall的makeCall()方法实现.
public void makeCall(SipProfile peerProfile, SipSession sipSession,
int timeout) throws SipException {
if (DBG) log("makeCall: " + peerProfile + " session=" + sipSession + " timeout=" + timeout);
if (!SipManager.isVoipSupported(mContext)) {
throw new SipException("VOIP API is not supported");
}
synchronized (this) {
mSipSession = sipSession;
try {
mAudioStream = new AudioStream(InetAddress.getByName(
getLocalIp()));
sipSession.setListener(createListener());
sipSession.makeCall(peerProfile, createOffer().encode(),
timeout);
} catch (IOException e) {
loge("makeCall:", e);
throw new SipException("makeCall()", e);
}
}
}
上面代码中创建了一个AudioStream对象(这个类是传输音频流使用的,我会在后面一篇博客中进行分析音频流是如何传输的),并调用sipSession.makeCall()方法,
SipSession类的makeCall()方法如下:
public void makeCall(SipProfile callee, String sessionDescription,
int timeout) {
try {
mSession.makeCall(callee, sessionDescription, timeout);
} catch (RemoteException e) {
loge("makeCall:", e);
}
}
此处的mSession就是我们之前分析的SipSessionImpl在客户端的代理类,参数callee就是目的主机对应的SipProfile,我们直接看它的服务端SipSessionImpl的实现.对应代码在SipSessionGroup.java中.
// process the command in a new thread
private void doCommandAsync(final EventObject command) {
new Thread(new Runnable() {
@Override
public void run() {
try {
processCommand(command);
} catch (Throwable e) {
loge("command error: " + command + ": "
+ mLocalProfile.getUriString(),
getRootCause(e));
onError(e);
}
}
}, "SipSessionAsyncCmdThread").start();
}
@Override
public void makeCall(SipProfile peerProfile, String sessionDescription,
int timeout) {
doCommandAsync(new MakeCallCommand(peerProfile, sessionDescription,
timeout));
}
从上面代码中我们可以看出它是在一个子线程中调用processCommand()来处理命令消息的.
private void processCommand(EventObject command) throws SipException {
if (isLoggable(command)) log("process cmd: " + command);
if (!process(command)) {
onError(SipErrorCode.IN_PROGRESS,
"cannot initiate a new transaction to execute: "
+ command);
}
}
public boolean process(EventObject evt) throws SipException {
if (isLoggable(this, evt)) log(" ~~~~~ " + this + ": "
+ SipSession.State.toString(mState) + ": processing "
+ logEvt(evt));
synchronized (SipSessionGroup.this) {
if (isClosed()) return false;
if (mSipKeepAlive != null) {
// event consumed by keepalive process
if (mSipKeepAlive.process(evt)) return true;
}
Dialog dialog = null;
if (evt instanceof RequestEvent) {
dialog = ((RequestEvent) evt).getDialog();
} else if (evt instanceof ResponseEvent) {
dialog = ((ResponseEvent) evt).getDialog();
extractExternalAddress((ResponseEvent) evt);
}
if (dialog != null) mDialog = dialog;
boolean processed;
switch (mState) {
case SipSession.State.REGISTERING:
case SipSession.State.DEREGISTERING:
processed = registeringToReady(evt);
break;
case SipSession.State.READY_TO_CALL:
processed = readyForCall(evt);
break;
case SipSession.State.INCOMING_CALL:
processed = incomingCall(evt);
break;
case SipSession.State.INCOMING_CALL_ANSWERING:
processed = incomingCallToInCall(evt);
break;
case SipSession.State.OUTGOING_CALL:
case SipSession.State.OUTGOING_CALL_RING_BACK:
processed = outgoingCall(evt);
break;
case SipSession.State.OUTGOING_CALL_CANCELING:
processed = outgoingCallToReady(evt);
break;
case SipSession.State.IN_CALL:
processed = inCall(evt);
break;
case SipSession.State.ENDING_CALL:
processed = endingCall(evt);
break;
default:
processed = false;
}
return (processed || processExceptions(evt));
}
}
从上面方法中可以看出,依据mState的值走不同的分支,我们看打电话时是调用outgoingCall(evt);
private boolean outgoingCall(EventObject evt) throws SipException {
if (expectResponse(Request.INVITE, evt)) {
ResponseEvent event = (ResponseEvent) evt;
Response response = event.getResponse();
int statusCode = response.getStatusCode();
switch (statusCode) {
case Response.RINGING:
case Response.CALL_IS_BEING_FORWARDED:
case Response.QUEUED:
case Response.SESSION_PROGRESS:
// feedback any provisional responses (except TRYING) as
// ring back for better UX
if (mState == SipSession.State.OUTGOING_CALL) {
mState = SipSession.State.OUTGOING_CALL_RING_BACK;
cancelSessionTimer();
mProxy.onRingingBack(this);
}
return true;
case Response.OK:
if (mReferSession != null) {
mSipHelper.sendReferNotify(mReferSession.mDialog,
getResponseString(Response.OK));
// since we don't need to remember the session anymore.
mReferSession = null;
}
mSipHelper.sendInviteAck(event, mDialog);
mPeerSessionDescription = extractContent(response);
establishCall(true);
return true;
case Response.UNAUTHORIZED:
case Response.PROXY_AUTHENTICATION_REQUIRED:
if (handleAuthentication(event)) {
addSipSession(this);
}
return true;
case Response.REQUEST_PENDING:
// TODO: rfc3261#section-14.1; re-schedule invite
return true;
default:
if (mReferSession != null) {
mSipHelper.sendReferNotify(mReferSession.mDialog,
getResponseString(Response.SERVICE_UNAVAILABLE));
}
if (statusCode >= 400) {
// error: an ack is sent automatically by the stack
onError(response);
return true;
} else if (statusCode >= 300) {
// TODO: handle 3xx (redirect)
} else {
return true;
}
}
return false;
} else if (END_CALL == evt) {
// RFC says that UA should not send out cancel when no
// response comes back yet. We are cheating for not checking
// response.
mState = SipSession.State.OUTGOING_CALL_CANCELING;
mSipHelper.sendCancel(mClientTransaction);
startSessionTimer(CANCEL_CALL_TIMER);
return true;
} else if (isRequestEvent(Request.INVITE, evt)) {
// Call self? Send BUSY HERE so server may redirect the call to
// voice mailbox.
RequestEvent event = (RequestEvent) evt;
mSipHelper.sendInviteBusyHere(event,
event.getServerTransaction());
return true;
}
return false;
}
实际上调用了mSipHelper.sendInviteBusyHere(event,event.getServerTransaction());此处的mSipHelper就是一个SipHelper类实例.
SipHelper是一个辅助类,它对sip协议栈操作的相关封装,用于建立sip会话的流程封装.例如发送INVITE消息给目的主机.
整个sip流程的建立,核心类是SipService,SipSessionGroup,这篇文章讲述了sip流程的建立过程.
其实SIP协议规定了会话的发起过程,但没有规定会话的内容及格式。会话内容可以是文本、语音、视频等。因此,SIP协议要结合其它协议,如:用SDP协议描述要传递的内容格式,用RTP,RTSP流媒体协议传输媒体,才能完成整个通信过程。 SIP协议这样做为了简化协议,留下扩展的灵活性。
,那么当一个sip会话建立之后,整个音频数据流是如何从一端传递到另一端的呢,请参考我的下一篇博客.
相关文章推荐
- 基于GBT28181:SIP协议组件开发-----------第三篇SIP注册流程分析实现
- Android5.1 Telecomm层通话去电流程两路进程分析之一通话去电流程框架介绍
- sip命令与音视频rtp通话完整流程分析
- Android5.1Telecomm层通话去电流程两路进程分析之二拨号过程显示通话界面过程分析
- Android 语音通话模块介绍(二) SIP流程
- Android BLE学习(二): Android与51822蓝牙模块通信流程的实现与分析
- Android 7.0 虚拟按键(NavigationBar)源码分析 之 点击事件的实现流程
- Linphone android去电增加自定义SIP消息头的流程分析
- android原生热修复流程和原理分析实现
- Android 语音通话模块介绍(二) SIP流程
- android 之 Handler 详解----(一)实现的消息传递基本原理(流程分析)
- 基于GBT28181:SIP协议组件开发-----------第三篇SIP注册流程分析实现
- Android注解AndroidAnnotation的使用及实现流程分析
- Android BLE学习(二): Android与51822蓝牙模块通信流程的实现与分析
- Android GSM驱动模块(rild)详细分析(二)request流程
- Android APN开发流程分析
- Android 实现通话监听
- Android APN开发流程分析
- Android APN开发流程分析
- Android事件处理分析+Android事件处理 +Android输入事件流程