Nodejs socket.io 传递对象

Nodejs socket.io 传递对象

这段代码能调用摄像头 显示在video1上,下面是客户端代码:

var hosline=io.connect(null);
function startVideo(){

    var video = document.getElementById("video1"),
    videoObj = {"video" : true },
   
    if (navigator.webkitGetUserMedia) { // WebKit-prefixed 
        navigator.webkitGetUserMedia(videoObj, function (stream) {
            var src = window.webkitURL.createObjectURL(stream);
            video.src = src;
            video.play();
        hosline.emit('priveateMessage', stream,toWho);//toWho 是 socket.id
     });

我想把这个 stream 对象(typeof(stream)为 MediaStream )经服务端转发给另一个客户端,下面是服务段代码:

clisocket.on('priveateMessage',function(stream,toWho){
    UserLists[towho].emit('priveateMessage',stream, clisocket.id});
 });

另一个客户端接收到这个 stream 然后应该就可以视频对话了,但是另一个客户端接收到的 stream(typeof(stream) 是 object)报错。下面是客户端的代码:

hosline.on('priveateMessage',function(stream,fromid){
    var src = window.webkitURL.createObjectURL(stream);//这行报一个 类型错误。
    var video = document.getElementById('video2');
    video.src = src;
    video.play();
}

哪位大侠能帮忙解决下呀,在这先谢谢谢谢谢了!!!


2 回复

在使用 Node.js 和 Socket.IO 传递 MediaStream 对象时,直接传递该对象可能会导致问题,因为 MediaStream 对象通常不能被序列化并通过 WebSocket 发送。相反,你可以考虑将流数据转换为另一种形式(如 Blob 或 Base64 编码的数据 URL),然后发送这个数据。

以下是一个改进的示例,展示了如何将媒体流转换为 Blob,并通过 Socket.IO 发送:

客户端代码

var hosline = io.connect(null);

function startVideo() {
    var video = document.getElementById("video1");
    var videoObj = { "video": true };

    if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
        navigator.mediaDevices.getUserMedia(videoObj).then(function (stream) {
            video.srcObject = stream;
            video.play();

            // 将流转换为 Blob 并发送
            const mediaRecorder = new MediaRecorder(stream);
            let chunks = [];

            mediaRecorder.ondataavailable = function (event) {
                chunks.push(event.data);
            };

            mediaRecorder.onstop = function () {
                const blob = new Blob(chunks, { type: 'video/webm' });
                chunks = [];
                hosline.emit('priveateMessage', blob, toWho); // toWho 是 socket.id
            };

            mediaRecorder.start(500); // 每500毫秒录制一次

            setTimeout(() => {
                mediaRecorder.stop();
            }, 5000); // 录制5秒后停止
        });
    }
}

// 接收并播放视频
hosline.on('priveateMessage', function (blob, fromid) {
    var video = document.getElementById('video2');
    var url = URL.createObjectURL(blob);
    video.src = url;
    video.play();
});

服务端代码

服务端不需要对流进行特殊处理,只需将其从一个客户端转发到另一个客户端即可:

const io = require('socket.io')(server);

io.on('connection', function (socket) {
    socket.on('priveateMessage', function (blob, toWho) {
        socket.broadcast.to(toWho).emit('priveateMessage', blob, socket.id);
    });
});

解释

  1. 客户端

    • 使用 navigator.mediaDevices.getUserMedia 获取媒体流。
    • 使用 MediaRecorder 对流进行录制,并将录制的数据转换为 Blob。
    • 通过 Socket.IO 发送 Blob 数据。
  2. 服务端

    • 收到 Blob 数据后,广播给指定的客户端。
  3. 接收端

    • 接收到 Blob 后,创建一个 URL 并将其设置为视频元素的 src 属性。

这种方法避免了直接传递复杂的 MediaStream 对象,而是通过 Blob 进行传递,从而解决了类型错误的问题。


传递 MediaStream 对象通过 Socket.IO 并不是直接可行的,因为 MediaStream 对象包含大量复杂的数据,并且它与浏览器上下文紧密相关,无法通过网络传输。通常的做法是传递媒体流的相关信息(例如媒体流的 URL 或媒体源 ID),然后在接收方重新获取或生成相应的媒体流。

示例

客户端代码

首先,你需要将媒体流的 URL 发送到服务器,而不是发送整个媒体流对象。

var hosline = io.connect();

function startVideo() {
    var video = document.getElementById("video1");
    var videoObj = {"video": true};

    if (navigator.webkitGetUserMedia) { // WebKit-prefixed 
        navigator.webkitGetUserMedia(videoObj, function (stream) {
            var src = window.URL.createObjectURL(stream);
            video.src = src;
            video.play();
            
            // 发送媒体流的 URL 到服务器
            hosline.emit('priveateMessage', { streamUrl: src, toWho: "socketIdHere" });
        }, function (err) {
            console.log("Error: ", err);
        });
    }
}

服务端代码

服务器接收到媒体流的 URL 后,可以将其转发给目标客户端。

const io = require('socket.io')(server);

io.on('connection', function(socket) {
    socket.on('priveateMessage', function(data) {
        const { streamUrl, toWho } = data;
        io.sockets.connected[toWho].emit('priveateMessage', { streamUrl: streamUrl });
    });
});

接收方客户端代码

接收方客户端接收到媒体流的 URL 后,可以创建一个新的视频元素并设置其 src 属性来播放视频。

hosline.on('priveateMessage', function(data) {
    var src = data.streamUrl;
    var video = document.createElement('video');
    video.src = src;
    document.body.appendChild(video); // 或者插入到任何其他 DOM 元素中
    video.play();
});

解释

  1. 客户端:使用 window.URL.createObjectURL 创建媒体流的 URL,并将其发送到服务器。
  2. 服务器:接收 URL 并转发给目标客户端。
  3. 接收方客户端:接收到 URL 后,使用 window.URL.createObjectURL 再次创建媒体流对象,并在新的视频元素上播放。

这种方法确保了数据的有效传输,并且避免了直接传递复杂的媒体流对象带来的问题。

回到顶部