美文网首页webrtc
Xmpp作为WebRTC信令的音视频通话03-实现PeerCon

Xmpp作为WebRTC信令的音视频通话03-实现PeerCon

作者: 张俊峰0613 | 来源:发表于2018-12-19 14:42 被阅读0次

    创建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对象中也添加了两遍

    相关文章

      网友评论

        本文标题:Xmpp作为WebRTC信令的音视频通话03-实现PeerCon

        本文链接:https://www.haomeiwen.com/subject/cbcjkqtx.html