簡體   English   中英

無法與 Node JS 服務器作為對等方建立 WebRTC 連接

[英]Unable to establish WebRTC connection with Node JS server as a peer

我正在嘗試使用 WebRTC 數據通道將從 canvas 捕獲的圖像發送到我的 NodeJS 后端服務器。 那就是我試圖讓我的服務器成為對等點。 但由於某種原因,我無法建立連接。

客戶端

async function initChannel()
{
    const offer = await peer.createOffer();
    await peer.setLocalDescription(offer);

    const response = await fetch("/connect", {
        headers: {
            'Content-Type': 'application/json',
        },
        method: 'post',
        body: JSON.stringify({ sdp: offer, id: Math.random() })
    }).then((res) => res.json());

    peer.setRemoteDescription(response.sdp);

    const imageChannel = peer.createDataChannel("imageChannel", { ordered: false, maxPacketLifeTime: 100 });

    peer.addEventListener("icecandidate", console.log);
    peer.addEventListener("icegatheringstatechange",console.log);

     // drawCanvas function draws images got from the server.
    imageChannel.addEventListener("message", message => drawCanvas(remoteCanvasCtx, message.data, imageChannel));
                                   
     // captureImage function captures and sends image to server using imageChannel.send()
    imageChannel.addEventListener("open", () => captureImage(recordCanvasCtx, recordCanvas, imageChannel));
}

const peer = new RTCPeerConnection({ iceServers: [{ urls: "stun:stun.stunprotocol.org:3478" }] });
initChannel();

這里captureImagedrawCanvas都沒有被調用。

服務器端

import webrtc from "wrtc"; // The wrtc module ( npm i wrtc )

function handleChannel(channel)
{
    console.log(channel.label); // This function is not being called. 
}

app.use(express.static(resolve(__dirname, "public")))
    .use(bodyParser.json())
    .use(bodyParser.urlencoded({ extended: true }));

app.post("/connect", async ({ body }, res) =>
{
    console.log("Connecting to client...");

    let answer, id = body.id;

    const peer = new webrtc.RTCPeerConnection({ iceServers: [{ urls: "stun:stun.stunprotocol.org:3478" }] });
    await peer.setRemoteDescription(new webrtc.RTCSessionDescription(body.sdp));
    await peer.setLocalDescription(answer = await peer.createAnswer());

    peer.addEventListener("datachannel",handleChannel)

    return res.json({ sdp: answer });
});

app.listen(process.env.PORT || 2000);

這里 post 請求處理得很好,但從不調用handleChannel


當我運行它時,我沒有收到任何錯誤,但是當我檢查連接狀態時,它永遠顯示“新”。 我控制台記錄了遠程和本地描述,它們似乎都設置好了。 我在這里做錯了什么?

我對 WebRTC 很陌生,我什至不確定這是否是從服務器連續發送圖像(用戶網絡攝像頭的幀)和返回的正確方法,如果有人能告訴我更好的方法,請這樣做。

還有一件事,我如何通過數據通道以低延遲發送圖像 blob(從canvas.toBlob()獲得)。

在我朋友的幫助下,我終於想通了。 問題是我必須在調用peer.createOffer()之前創建 DataChannel 。 peer.onnegotiationneeded回調僅在創建通道后調用。 通常,當您通過將 stream 傳遞給 WebRTC 來創建媒體通道(音頻或視頻)時,通常會發生這種情況,但由於我不使用它們,所以我必須這樣做。

客戶端

const peer = new RTCPeerConnection({ iceServers: [{ urls: "stun:stun.l.google.com:19302" }] });
const imageChannel = peer.createDataChannel("imageChannel");

imageChannel.onmessage = ({ data }) => 
{
    // Do something with received data.
};

imageChannel.onopen = () => imageChannel.send(imageData);// Data channel opened, start sending data.

peer.onnegotiationneeded = initChannel

async function initChannel()
{
    const offer = await peer.createOffer();
    await peer.setLocalDescription(offer);

    // Send offer and fetch answer from the server
    const { sdp } = await fetch("/connect", { 
        headers: {
            "Content-Type": "application/json",
        },
        method: "post",
        body: JSON.stringify({ sdp: peer.localDescription }),
    })
        .then(res => res.json());

    peer.setRemoteDescription(new RTCSessionDescription(sdp));
}

服務器

接收客戶通過 post 請求發送的報價。 為它創建一個答案並作為響應發送。

app.post('/connect', async ({ body }, res) =>
{
    const peer = new webrtc.RTCPeerConnection({
        iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
    });
    console.log('Connecting to client...');
    peer.ondatachannel = handleChannel;

    await peer.setRemoteDescription(new webrtc.RTCSessionDescription(body.sdp));
    await peer.setLocalDescription(await peer.createAnswer());

    return res.json({ sdp: peer.localDescription });
});

function 處理數據通道。

/**
 * This function is called once a data channel is ready.
 *
 * @param {{ type: 'datachannel', channel: RTCDataChannel }} event
 */
function handleChannel({ channel })
{
    channel.addEventListener("message", {data} =>
    {
        // Do something with data received from client. 
    });
    
    // Can use the channel to send data to client.
    channel.send("Hi from server");
}

所以這就是發生的事情:

  1. 客戶端創建一個數據通道。
  2. 一旦創建了數據通道,就會調用onnegotiationneeded回調。
  3. 客戶端創建一個報價並將其發送到服務器(作為發布請求)。
  4. 服務器收到報價並創建答案。
  5. 服務器將答案發送回客戶端(作為發布響應)。
  6. 客戶端使用收到的答案完成初始化。
  7. 在服務器和客戶端上調用ondatachannel回調。

我在這里使用了發布請求來交換報價和答案,但是如果您喜歡的話,使用 Web 套接字應該很容易做到這一點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM