美文网首页
webrtc android端和网页端 P2P 通信

webrtc android端和网页端 P2P 通信

作者: lesliefang | 来源:发表于2020-11-18 19:18 被阅读0次

有了上篇的 https://www.jianshu.com/p/d0d74c40dccb 两个 android 手机 P2P 通信, android 和网页P2P通信就更简单了。 android 端的代码我不用动, 只需要添加一个网页版实现就行了。

android-web.png
<body>

    <div>webrtc demo</div>

    <div>当前用户:bbbb 对端用户:aaaa </div>
    <div><button onclick="makeCall()">拨打</button></div> 

    <div>本地流 <video id="localVideo" autoplay playsinline controls="false" style="width: 100%;height: 280px;"/></div>

    <div>远端流 <video id="remoteVideo" autoplay playsinline controls="false" style="width: 100%;height: 280px;"/></div>

    <script>

        // 官网 https://webrtc.org/getting-started/peer-connections
    
        const LOCAL_USER_ID = 'bbbb';
        const RECEIVER_USER_ID = 'aaaa';
    
        var webSocket = new WebSocket('ws://192.168.0.112:5520/websocket');
        webSocket.onerror = function(event) {
            console.log('onerror');
        };
        webSocket.onopen = function(event) {
            console.log("onopen");
            // 注册自己到服务端
            webSocket.send(JSON.stringify({
                'event':'register',
                'userId': LOCAL_USER_ID
            }));
        };
        webSocket.onclose = function(event) {
            console.log('websocket closed');
        };
        webSocket.onmessage = function(event) {
            console.log('onmessage '+event.data);
            // 回调
            onReceiveSocketMessage(JSON.parse(event.data));
        };

        const configuration = {'iceServers': [{'urls': 'stun:stun.l.google.com:19302'}]}
        var peerConnection = new RTCPeerConnection(configuration); // 全局 PeerConnection
        // Listen for local ICE candidates on the local RTCPeerConnection
        peerConnection.addEventListener('icecandidate', event => {
            console.log('local trickle  '+event);
            if (event.candidate) {
                const trickle = {
                    event:'trickle',
                    sender:LOCAL_USER_ID,
                    receiver: RECEIVER_USER_ID,
                    candidate:{
                        sdpMid:event.candidate.sdpMid,
                        sdpMLineIndex:event.candidate.sdpMLineIndex,
                        sdp:event.candidate.candidate
                    }
                };
    
                webSocket.send(JSON.stringify(trickle));
                // 发送本地 ICE candidate 到远端
                console.log('send local ice candidate to remote '+RECEIVER_USER_ID);
            }
        });
        // Listen for connectionstatechange on the local RTCPeerConnection
        peerConnection.addEventListener('connectionstatechange', event => {
            if (peerConnection.connectionState === 'connected') {
                // Peers connected!
                console.log('p2p connected');
            }
        });
    
        // 处理 signaling 消息
        async function onReceiveSocketMessage(message) {
            if ('sdp'===message.event) {
                if('offer'==message.type.toLowerCase()) {
                    // 收到 offer
                    console.log('收到 offer');
                    let offerSdp = {type:'offer', sdp: message.description};
                    peerConnection.setRemoteDescription(new RTCSessionDescription(offerSdp));
                    // 创建 answer
                    const answer = await peerConnection.createAnswer();
                    await peerConnection.setLocalDescription(answer);
                    console.log('create answer and setLocalDescription');
                    // 发送 answer 到对端
                    webSocket.send(JSON.stringify({
                        "event": "sdp",
                        "type": 'answer',
                        "description":answer.sdp,
                        "sender":LOCAL_USER_ID,
                        "receiver":message.sender
                    }));
                    console.log('send answer to remote '+message.receiver);
                } else if ('answer'==message.type.toLowerCase()) {
                    // 收到 answer
                    console.log('收到 answer from '+message.sender);
                    let answerSdp = {type:'answer', sdp: message.description};
                    const remoteDesc = new RTCSessionDescription(answerSdp);
                    await peerConnection.setRemoteDescription(remoteDesc);
                    console.log('setRemoteDescription after reveiver answer');
                }
            } else if('trickle'===message.event) {
                let candidate = message.candidate;
                await peerConnection.addIceCandidate(new RTCIceCandidate({
                    sdpMid:candidate.sdpMid,
                    sdpMLineIndex:candidate.sdpMLineIndex,
                    candidate:candidate.candidate
                }))
                console.log('add remote candidate');
            }
        };

        async function addStreams() {
            try {
                const localStream = await navigator.mediaDevices.getUserMedia({'video':true,'audio':true}); 
                // 添加本地流
                localStream.getTracks().forEach(track => {
                    peerConnection.addTrack(track, localStream);
                });

                const videoElement = document.querySelector('video#localVideo');
                videoElement.srcObject = localStream;
                console.log('Got MediaStream:', localStream);
            } catch(error){
                console.error('Error accessing media devices.', error);
            }

            const remoteStream = new MediaStream();
            const remoteVideo = document.querySelector('video#remoteVideo');
            remoteVideo.srcObject = remoteStream;
            // 监听远程流
            peerConnection.addEventListener('track', async (event) => {
                remoteStream.addTrack(event.track, remoteStream);
            });
        }
    
        // 添加流
        addStreams();

        // 拨打
        async function makeCall() {
            // create offer
            const offer = await peerConnection.createOffer();
            console.log('create offer');
            console.log(offer);
            await peerConnection.setLocalDescription(offer);
            console.log('set setLocalDescription offer');
    
            // 发送 offer 到对端
            webSocket.send(JSON.stringify({
                "event": "sdp",
                "type": 'offer',
                "description":offer.sdp,
                "sender":LOCAL_USER_ID,
                "receiver":RECEIVER_USER_ID
            }));
            console.log('send offer to remote '+RECEIVER_USER_ID);
    
        }   
    
    </script>

</body>

android 端我装 aaaa 用户,网页充当 bbbb 用户。SignalServer 也不用改动。跟 android 一样两端谁先发起通信都是一样的。SignalServer 部署到公网理论上两个公网用户也是可以通话的。

直接打开本地 html 文件好像不行,可以本地用 node.js 或 python 起一个静态文件服务。

python -m SimpleHTTPServer

webrtc 网页默认只支持 HTTPS,参考这个 https://www.cnblogs.com/zqblog1314/p/13233160.html chrome 里面添加 URL 到信任列表就行了。

实现联通很简单,还是前面那个流程图,一定要理解清楚。

signal server: https://github.com/lesliebeijing/WebrtcSignalingDemo
源码: https://github.com/lesliebeijing/WebRtcDemo 参考里面的 WebRtc.html

相关文章

网友评论

      本文标题:webrtc android端和网页端 P2P 通信

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