创建PeerConnection对象之后,我们就要实现几个方法
1、首先实现SdpObserver接口
private class SDPObserver implements SdpObserver {
@Override
public void onCreateSuccess(SessionDescription sessionDescription) {//创建offer/answer成功之后触发
Log.d(TAG,"SDPObserver onCreateSuccess!");
if (localSdp != null) {
reportError("Multiple SDP create.");
return;
}
localSdp = getLocalSdp(sessionDescription.type,sessionDescription.description);
executor.execute(new Runnable() {
@Override
public void run() {
if (peerConnection != null && !isError) {
Log.d(TAG, "Set local SDP from " + localSdp.type);
peerConnection.setLocalDescription(sdpObserver, localSdp);
}
}
});
}
@Override
public void onSetSuccess() {//setLocalDescription/setRemoteDescription成功之后触发
Log.d(TAG,"SDPObserver onSetSuccess!");
executor.execute(new Runnable() {
@Override
public void run() {
if (peerConnection == null || isError) {
return;
}
if (isCallout) {//呼叫方
if (peerConnection.getRemoteDescription() == null) {//还没有收到接听方的sdp,所以调用events.onLocalDescription(localSdp)把本地的sdp发送给接听方
Log.d(TAG, "Local SDP set succesfully");
events.onLocalDescription(localSdp);//将保存的本地sdp发送给对方
} else {//已经接受到接听方的sdp和IceCandidate
Log.d(TAG, "Remote SDP set succesfully");
drainCandidates();//将接听方的IceCandidate添加到本地peerConnection对象中
}
} else {//接听方
if (peerConnection.getLocalDescription() != null) {
Log.d(TAG, "Local SDP set succesfully");
events.onLocalDescription(localSdp);//将保存的本地sdp发送给对方
drainCandidates();//将呼叫方的IceCandidate添加到本地peerConnection对象中
} else {
Log.d(TAG, "Remote SDP set succesfully");
}
}
}
});
}
@Override
public void onCreateFailure(String s) {
Log.d(TAG,"SDPObserver onCreateFailure!");
reportError("createSDP error: " + s);
}
@Override
public void onSetFailure(String s) {
Log.d(TAG,"SDPObserver onSetFailure!");
reportError("setSDP error: " + s);
}
}
保存接收端的IceCandidate
private void drainCandidates() {
linkedRemoteCandidates = getQueuedRemoteCandidates().get(peerName);
if (linkedRemoteCandidates != null) {
Log.d(TAG, "Add " + linkedRemoteCandidates.size() + " remote candidates");
for (IceCandidate candidate : linkedRemoteCandidates) {
peerConnection.addIceCandidate(candidate);
}
linkedRemoteCandidates.clear();
linkedRemoteCandidates = null;
}
}
2、呼叫方创建用于offer的sdp
1、呼叫方创建sdp成功后,会调用sdpObserver.onCreateSuccess(SessionDescription sessionDescription),将创建的sdp作为参数传进去;
2、 然后调用peerConnection.setLocalDescription(sdpObserver, localSdp)保存在本地;
3、 保存成功后再调用adpObserver.onSetSuccess()中的events.onLocalDescription(localSdp),将本地的sdp发送给接听方;
/**
* 创建peerOffer
* @param peerName
*/
public void createOffer(final String peerName) {
executor.execute(new Runnable() {
@Override
public void run() {
if (peerConnections == null)
return;
PeerConnection peerConnection = peerConnections.get(peerName);
Log.e(TAG,"pc ==== " + peerConnection);
if (peerConnection != null) {
Log.d(TAG, "PC Create OFFER");
peerConnection.createOffer(sdpObserver,sdpMediaConstraints);
}
}
});
}
3、接听方创建用于answer的sdp
1、接听方要接收到呼叫方发送来的sdp并且调用setRemoteDescription将该sdp保存起来后才会创建sdp,创建成功后,也会调用sdpObserver.onCreateSuccess(SessionDescription sessionDescription),将创建的sdp作为参数传进去;
2、 然后调用peerConnection.setLocalDescription(sdpObserver, localSdp)保存在本地;
3、 保存成功后再调用adpObserver.onSetSuccess()中的events.onLocalDescription(localSdp),将本地的sdp发送给呼叫方;
然后双方sdp交换就结束了
/**
*创建peerAnswer
* @param peerName
*/
public void createAnswer(final String peerName) {
executor.execute(new Runnable() {
@Override
public void run() {
if (peerConnections == null)
return;
PeerConnection peerConnection = peerConnections.get(peerName);
if (peerConnection != null ) {
Log.d(TAG, "PC create ANSWER");
peerConnection.createAnswer(sdpObserver,sdpMediaConstraints);
}
}
});
}
4、保存远端的sdp
我们前面一直提到保存远端的sdp,实现的方法就在这里,最后调用的是PeerConnection的方法,pc.setRemoteDescription(sdpObserver,sdpRemote),保存成功后会触发sdpObserver.onSetSuccess()。
对于接听方来说,此时还没有创建本地的sdp,所以直接打印这句话 Log.d(TAG, "Remote SDP set succesfully");
对于呼叫方来说,要drainCandidates(),即将接受到的IceCandidate添加到peerConnection。
/**
* 保存远端的sdp
* @param peerName 接收端,对于呼叫方来说就是接听方,对于接听方来说就是呼叫方
* @param sdp 接收端的sdp
*/
public void setRemoteDescription(final String peerName, final SessionDescription sdp) {
executor.execute(new Runnable() {
@Override
public void run() {
if (peerConnections == null)
return;
PeerConnection pc = peerConnections.get(peerName);
if (pc == null) {
return;
}
String sdpDescription = sdp.description;
if (preferIsac) {
sdpDescription = preferCodec(sdpDescription, AUDIO_CODEC_ISAC, true);
}
if (videoCallEnabled) {
sdpDescription = preferCodec(sdpDescription, preferredVideoCodec, false);
}
if (videoCallEnabled && peerConnectionParameters.videoMaxBitrate > 0) {
sdpDescription = setStartBitrate(VIDEO_CODEC_VP8, true,
sdpDescription, peerConnectionParameters.videoMaxBitrate);
sdpDescription = setStartBitrate(VIDEO_CODEC_VP9, true,
sdpDescription, peerConnectionParameters.videoMaxBitrate);
sdpDescription = setStartBitrate(VIDEO_CODEC_H264, true,
sdpDescription, peerConnectionParameters.videoMaxBitrate);
}
if (peerConnectionParameters.audioStartBitrate > 0) {
sdpDescription = setStartBitrate(AUDIO_CODEC_OPUS, false,
sdpDescription, peerConnectionParameters.audioStartBitrate);
}
Log.d(TAG, "Set remote SDP.");
SessionDescription sdpRemote = new SessionDescription(
sdp.type, sdpDescription);
pc.setRemoteDescription(sdpObserver,sdpRemote);
}
});
}
5、添加远端的IceCandidate
/**
* 添加远端的IceCandidate
* @param peerName 接收端,对于呼叫方来说就是接听方,对于接听方来说就是呼叫方
* @param candidate 接收到的对方的IceCandidate
*/
public void addRemoteIceCandidate(final String peerName, final IceCandidate candidate) {
executor.execute(new Runnable() {
@Override
public void run() {
if (peerConnections == null)
return;
if(toBeClosePeerNames!=null&&toBeClosePeerNames.size()>0){
for(String l:toBeClosePeerNames){
if(l == peerName){
return;
}
}
}
PeerConnection pc = peerConnections.get(peerName);
if (pc != null) {
Log.d(TAG, "Add Candidate");
pc.addIceCandidate(candidate);
}
else{
if(queuedRemoteCandidates.get(peerName)==null) {
queuedRemoteCandidates.put(peerName,new LinkedList<IceCandidate>());
}
queuedRemoteCandidates.get(peerName).add(candidate);
}
}
});
}
总结
自此,以Xmpp作为WebRTC信令的音视频通话所要实现的东西基本完成!
IceCandidate总感觉接收了两遍,向peerConnection对象中也添加了两遍
网友评论