6. webRTC
阅读原文时间:2023年07月10日阅读:2

webrtc网上封装的很多,demo很多都是一个页面里实现的,今天实现了个完整的 , A 发视频给 B。

1.) A 方


<head>  
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
    <meta charset="utf-8">  
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">  
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">  
    <style>

        p { padding: 1em; }

        li {  
            border-bottom: 1px solid rgb(189, 189, 189);  
            border-left: 1px solid rgb(189, 189, 189);  
            padding: .5em;  
        }

    </style>  
</head>

<body>

        <script>  
             var mediaConstraints = {  
                optional: \[\],  
                mandatory: {  
                    OfferToReceiveAudio: false,  
                    OfferToReceiveVideo: true  
                }  
            };  
        </script>  
        <script>  
            var offerer  
                ,answererWin

            window.RTCPeerConnection = window.mozRTCPeerConnection || window.webkitRTCPeerConnection;  
            window.RTCSessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription;  
            window.RTCIceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate;

            navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia;  
            window.URL = window.webkitURL || window.URL;

            window.iceServers = {  
                iceServers: \[{  
                        url: 'stun:23.21.150.121'  
                    }  
                \]  
            };  
        </script>  
        <script>  
            /\* offerer \*/  
                function offererPeer(video\_stream) {  
                    offerer = new RTCPeerConnection(window.iceServers)  
                    offerer.addStream(video\_stream)

                    offerer.onaddstream = function (event) {  
                           // 本地显示video  
                }

                offerer.onicecandidate = function (event) {  
                    if (!event || !event.candidate) return

                    sendToP2({  
                        'action' : 'candidate',  
                        'candidate' :event.candidate  
                    })

                }

                offerer.createOffer(function (offer) {  
                    offerer.setLocalDescription(offer)  
                    sendToP2({  
                    'action' : 'create',  
                    'offer':offer  
                    })

                }, function() {}, mediaConstraints)  
            }  
        </script>  
        <script>  
            var video\_constraints = {  
                mandatory: {},  
                optional: \[\]  
            }

            function getUserMedia(callback) {  
                var n = navigator  
                n.getMedia = n.webkitGetUserMedia || n.mozGetUserMedia  
                n.getMedia({  
                    audio: false,  
                    video: video\_constraints  
                }, callback, onerror)

                function onerror(e) {  
                    alert(JSON.stringify(e, null, '\\t'))  
                }  
            }  
        </script>  
        <script>  
            function sendToP2(data){  
                answererWin.postMessage(JSON.stringify(data) ,window.location)

            }  
            function receiveMessage(data){  
                data = JSON.parse(data.data)  
                switch ( data.action) {  
                    case 'answer' :  
                        offerer.setRemoteDescription(new RTCSessionDescription(data.answer))  
                        break  
                    case "candidate":  
                        offerer.addIceCandidate(new RTCIceCandidate(data.candidate))  
                        break

                }  
                console.log('msg' ,data)  
            }

            window.addEventListener("message", receiveMessage, false)  
            answererWin = window.open('answer.html' ,'t')  
            getUserMedia(function (video\_stream) {  
                offererPeer(video\_stream)  
            });  
        </script>

</body>

2.) B







</head>

<body>  
    <article>  
            <div style="text-align:center;">  
            <div class="videos-container">  
                <video id="peer1-to-peer2" autoplay controls></video>  
                 <h2>Offerer-to-Answerer</h2>  
                 <h2>此页面刷新之后,必须重新刷新一下Offer页面</h2>  
            </div>  
        </div>  
        <script>  
             var mediaConstraints = {  
                optional: \[\],  
                mandatory: {  
                    OfferToReceiveAudio: true,  
                    OfferToReceiveVideo: true  
                }  
            };  
        </script>  
        <script>  
            var offerer, answerer;  
            var offererToAnswerer = document.getElementById('peer1-to-peer2');

            window.RTCPeerConnection = window.mozRTCPeerConnection || window.webkitRTCPeerConnection;  
            window.RTCSessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription;  
            window.RTCIceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate;

            navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia;  
            window.URL = window.webkitURL || window.URL;

            window.iceServers = {  
                iceServers: \[{  
                        url: 'stun:23.21.150.121'  
                    }  
                \]  
            };  
        </script>  
        <script>  
            /\* answerer \*/

            function answererPeer(offer, video\_stream) {  
                answerer = new RTCPeerConnection(window.iceServers);  
               // answerer.addStream(video\_stream);

                answerer.onaddstream = function (event) {  
                    offererToAnswerer.src = URL.createObjectURL(event.stream);  
                    offererToAnswerer.play();  
                };

                answerer.onicecandidate = function (event) {  
                    if (!event || !event.candidate) return;  
                    sendToP1({  
                    'action' : 'candidate',  
                    'candidate' :event.candidate  
                    })  
                    //offerer.addIceCandidate(event.candidate);  
                };

                answerer.setRemoteDescription(new RTCSessionDescription(offer));  
                answerer.createAnswer(function (answer) {  
                    answerer.setLocalDescription(answer);  
                    sendToP1({  
                        'action' : 'answer' ,  
                        'answer' : answer  
                    })  
                    //offerer.setRemoteDescription(answer);  
                }, function() {}, mediaConstraints);  
            }

            function receiveMessage(data){  
                data = JSON.parse(data.data)  
                console.log(data)  
                switch(data.action){  
                    case "create":  
                        answererPeer(data.offer , data.stream)  
                        break  
                    case "candidate":  
                        answerer.addIceCandidate(new RTCIceCandidate(data.candidate))  
                        break  
                }  
            }  
            window.addEventListener("message", receiveMessage, false)

            function sendToP1(data) {  
                opener.postMessage(JSON.stringify(data) , window.location)  
            }  
        </script>

    </article>

</body>

demo用 postMessage传递数据, 业务使用可以用websocket

A 先 createOffer ,生成的offer 供自己setLocalDescription ,并发给B

B 拿A的offer ,setRemoteDescription(offer) , 然后 createAnswer ,生成的answer 供自己setLocalDescription ,并发给A

A 拿B的answer 设置 setRemoteDescription(answer)

A onicecandidate 事件被触发 将得到的通道发给B

B addIceCandidate(new RTCIceCandidate(candidate)) 建立通道

B onicecandidate 事件被触发 将得到的通道发给A

A addIceCandidate(new RTCIceCandidate(candidate)) 建立通道

通道建立后视频就可以共享了

使用时,打开:offer.html 即可。