0

我正在尝试测试 Xirsys 提供的示例,在该示例中我可以仅使用 PHP 进行信号传输。冰服务器/令牌和主机似乎工作正常,但在尝试连接时返回“未捕获:类型错误:无法读取 null 的属性 'sdp'。它似乎不为空的对象,不确定这里发生了什么。跟随我的代码:

    <html>
<head>
    <title>PHP Xirsys</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<div class="panel" id="video-wrapper">
<style>
    video {
        background: #cccccc;
        width: 200px;
    }
</style>

<div class="col">
    <div>
        your message: <input type="text" id="newMessage" disabled />
        <button id="sendButton" onclick="send()" disabled>send</button>
    </div>

    <div id="messages"></div>
</div>
<div id="videos">
    <video autoplay="true" id="localVideo"></video>
</div>

<div>
    username: <input type="text" id="username" />
    <button id="connectButton" onclick="connect()">connect</button>
</div>

<script>
    var token;
    var socket;
    var ice;
    var pcs = {};
    var localUsername;

    function displayMessage(message) {
        $('#messages')[0].innerHTML += message + "<br>";
    }

    window.onload = () => {
        $.post("getice.php", null, r => onIce(r));
    }

    function onIce(r) {
        ice = JSON.parse(r).v;
        navigator.mediaDevices.getUserMedia({audio: true, video: true}).then(stream => onGetMedia(stream));
    }

    function connect() {
        localUsername = $('#username')[0].value;
        $.post("gettoken.php", {username: localUsername}, r => getHost(r));
    }

    function getHost(r) {
        token = JSON.parse(r).v;
        $.post("gethost.php", {username: localUsername}, r => openSocket(r));
    }

    function openSocket(r) {
        var host = JSON.parse(r).v;
        socket = new WebSocket(host + "/v2/" + token);
        socket.addEventListener("message", onSocketMessage);
    }

    function onSocketMessage(evt) {
        var data = JSON.parse(evt.data);
        var option;
        var pc;
        switch (data.m.o) {
            case "peers":
                var users = data.p.users;
                for(i = 0; i < users.length; i++) {
                    displayMessage("user in chat:" + users[i]);
                }
                break;
            case "peer_connected":
                var f = data.m.f.split("/");
                var joining = f[f.length-1];
                displayMessage("new user joined: " + joining)
                callPeer(joining);
                break;
            case "message":
                switch(data.p.msg.type) {
                    case "offer":
                        var desc = new RTCSessionDescription(data.p.msg);
                        var f = data.m.f.split("/");
                        var sender = f[f.length-1];
                        pc = createNewPeerConnection(sender);
                        pc.setRemoteDescription(desc);
                        pc.createAnswer().then(d => onCreateAnswer(d,sender));
                        break;
                    case "answer":
                        var desc = new RTCSessionDescription(data.p.msg);
                        var f = data.m.f.split("/");
                        var sender = f[f.length-1];
                        pcs[sender].pc.setRemoteDescription(desc);
                        break;
                    case "candidate":
                        var f = data.m.f.split("/");
                        var sender = f[f.length-1];
                        var candidate = new RTCIceCandidate(data.p.msg);
                        pcs[sender].pc.addIceCandidate(candidate);
                        break;
                }
        }
    }

    function callPeer(peer) {
        var pc = createNewPeerConnection(peer);
        var dataChannel = pc.createDataChannel("data");
        pcs[peer].dc = dataChannel;
        setDataChannelHandlers(dataChannel);
        pc.createOffer().then(d => onCreateOffer(d, peer));
    }

    function onCreateOffer(d, peer) {
        pcs[peer].pc.setLocalDescription(d);
        var pkt = {t: "u", m: {f: "appchannel/" + localUsername, o: "message", t: peer}, p: {msg:d}};
        socket.send(JSON.stringify(pkt));
    }

    function onCreateAnswer(d, peer) {
        pcs[peer].pc.setLocalDescription(d);
        var pkt = {t: "u", m: {f: "appchannel/" + localUsername, o: "message", t: peer}, p: {msg:d}};
        socket.send(JSON.stringify(pkt));
    }

    function onIceCandidate(evt) {
        var remoteUsername = getUsernameByRemoteDescription(evt.target.remoteDescription.sdp);
        var candidate = evt.candidate;
        if (candidate != null && remoteUsername != null) {
            var cPkt = {type: "candidate",
                candidate: candidate.candidate,
                sdpMid: candidate.sdpMid,
                sdpMLineIndex: candidate.sdpMLineIndex
            };
            var pkt = {
                t: "u",
                m: {
                    f: "appchannel/" + localUsername,
                    o: "message",
                    t: remoteUsername
                },
                p: {msg:cPkt}
            }
            socket.send(JSON.stringify(pkt));
        }
    }

    function setDataChannelHandlers(dc) {
        dc.onmessage = evt => onDataMessage(evt);
        dc.onopen = evt => onDataChannelOpen(evt);
    }

    function onDataChannelOpen(evt) {
        $("#newMessage")[0].disabled = false;
        $("#sendButton")[0].disabled = false;
    }

    function onDataChannel(evt) {
        var dataChannel = evt.channel;
        var keys = Object.keys(pcs);
        var comp;
        var localDescription;
        var remoteDescription;
        for(var i = 0; i < keys.length; i++) {
            comp = pcs[keys[i]];
            if(evt.currentTarget.localDescription.sdp == comp.pc.localDescription.sdp) {
                comp.dc = dataChannel;
            }
        }
        setDataChannelHandlers(dataChannel);
    }

    function send() {
        var messageElement = $('#newMessage')[0];
        displayMessage("you said: " + messageElement.value);
        var message = {f: localUsername, msg: messageElement.value};
        messageElement.value = "";
        var dataChannel;
        var keys = Object.keys(pcs);
        var comp;
        for(var i = 0; i < keys.length; i++) {
            comp = pcs[keys[i]];
            dataChannel = comp.dc;
            dataChannel.send(JSON.stringify(message));
        }
    }

    function onDataMessage(evt) {
        var messageObj = JSON.parse(evt.data);
        displayMessage(messageObj.f + " said: " + messageObj.msg);
    }

    function createNewPeerConnection(username){
        var pc = new RTCPeerConnection(ice);
        pc.addStream(localStream);
        pc.onaddstream = evt => onAddStream(evt);
        pc.ondatachannel = evt => onDataChannel(evt);
        pc.onicecandidate = candidate => onIceCandidate(candidate);
        pcs[username] = {pc: pc, dc: null, s: null, v: null};
        return pc;
    }

    function getUsernameByRemoteDescription(sdp) {
        var keys = Object.keys(pcs);
        var pc;
        for(var i = 0; i < keys.length; i++) {
            pc = pcs[keys[i]].pc;
            if(pc.remoteDescription.sdp == sdp) {
                return keys[i];
            }
        }
        return null;
    }

    function onGetMedia(stream) {
        var vid = $("#localVideo")[0];
        vid.srcObject = stream;
        localStream = stream;
    }

    function onAddStream(evt) {
        var pc = evt.target;
        var stream = evt.stream;
        var peer = getUsernameByRemoteDescription(pc.remoteDescription.sdp);
        pcs[peer].s = stream;
        var v = addNewVideo(stream);
        pcs[peer].v = v;
    }

    function addNewVideo(stream) {
        var vid = document.createElement("video");
        $("#videos")[0].appendChild(vid);
        vid.srcObject = stream;
        return vid;
    }
</script>
</div>
</body>
</html>

getice.php

<?php
$curl = curl_init();
curl_setopt_array( $curl, array (
 CURLOPT_URL =>
"https://global.xirsys.net/_turn/appchannel/",
 CURLOPT_USERPWD => "account:key",
 CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
 CURLOPT_CUSTOMREQUEST => "PUT",
 CURLOPT_RETURNTRANSFER => 1
));
$resp = curl_exec($curl);
print $resp;
curl_close($curl);
?>

获取令牌.php

$data = array( 'k' => $_POST["username"], 'expire' => 45, 'depth' => 10 );
$qs = http_build_query($data);

$curl = curl_init();
curl_setopt_array($curl, array(
     CURLOPT_RETURNTRANSFER => 1,
     CURLOPT_URL => 'https://global.xirsys.net/_token/appchannel?'.$qs,
     CURLOPT_USERPWD => "account:key",
     CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
     CURLOPT_CUSTOMREQUEST => 'PUT'
));
$resp = curl_exec($curl);
curl_close($curl);
echo($resp);

获取主机.php

$data = array( 'k' => $_POST["username"], 'type' => 'signal' );
$qs = http_build_query($data);

$curl = curl_init();
curl_setopt_array($curl, array(
     CURLOPT_RETURNTRANSFER => 1,
     CURLOPT_URL => 'https://global.xirsys.net/_host?'.$qs,
     CURLOPT_USERPWD => "account:key",
     CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
     CURLOPT_CUSTOMREQUEST => 'GET'
));
$resp = curl_exec($curl);
curl_close($curl);
echo($resp);

编辑:错误 -> 在 Chrome / Firefox 上 在 Chrome 上 在火狐上

4

0 回答 0