美文网首页
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