You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Socket.io的实时音频流跨设备失效问题求助

解决跨设备Socket.io实时音频流的404 Blob错误

嘿,这个问题我太熟了!你现在遇到的核心问题是:你把浏览器本地生成的Blob URL直接通过Socket.io发给了其他设备,但这个URL只在当前浏览器的上下文里有效,其他设备根本找不到对应的资源,所以才会报404。

为什么本地同窗口能行?

同一Chrome窗口里的标签页/iframe共享同一个浏览器进程,Blob URL对应的资源存在本地内存里,所以能正常访问。但跨设备(甚至不同浏览器窗口)就完全是独立的上下文了,别的浏览器根本不知道你发的blob:https://server/xxx是什么东西。

正确的解决思路

别传Blob URL,要传音频的原始数据!我们可以用MediaRecorder把音频流拆成小片段,转成Base64字符串(或者ArrayBuffer)发送给服务器,服务器再转发给其他设备,接收端拿到数据后自己生成Blob和播放URL。

修改后的代码实现

前端main.js调整

$(document).ready(function(){ 
    // 修正Socket.io连接参数,verify=false不是正确写法
    var socket = io("https://server:4000", { rejectUnauthorized: false }); 
    var mediaRecorder = null;

    // 接收音频数据并播放
    socket.on('audio stream', function(name, audioData){ 
        var video = document.querySelector('video');
        // 把Base64字符串转回Blob
        var byteCharacters = atob(audioData);
        var byteNumbers = new Array(byteCharacters.length);
        for (var i = 0; i < byteCharacters.length; i++) {
            byteNumbers[i] = byteCharacters.charCodeAt(i);
        }
        var byteArray = new Uint8Array(byteNumbers);
        var blob = new Blob([byteArray], { type: 'audio/webm' });
        
        // 更新播放源并尝试播放
        video.src = URL.createObjectURL(blob);
        video.play().catch(err => console.log('自动播放被阻止,请先触发用户交互:', err));
    }); 

    $('#ptt').click(function(){ 
        micOn(); 
        document.getElementById("ptt").disabled = true; 
        document.getElementById("ptt-off").disabled = false; 
    }); 

    $('#ptt-off').click(function(){ 
        // 停止录制和麦克风
        if (mediaRecorder) mediaRecorder.stop();
        if (window.stream) window.stream.getAudioTracks()[0].stop();
        
        document.getElementById("ptt").disabled = false; 
        document.getElementById("ptt-off").disabled = true; 
    }); 

    function micOn(){ 
        navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; 
        var constraints = { audio: true, video: false }; 

        function successCallback(stream) { 
            window.stream = stream; 
            // 创建MediaRecorder录制音频,指定格式为webm(Chrome支持良好)
            mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm' });
            
            // 每录制一段数据就发送给服务器
            mediaRecorder.ondataavailable = function(e) {
                var reader = new FileReader();
                reader.onload = function(event) {
                    // 去掉data URL前缀,只传Base64部分
                    var base64Audio = event.target.result.split(',')[1];
                    socket.emit('audio stream', myName, base64Audio);
                };
                reader.readAsDataURL(e.data);
            };

            // 每1秒发送一次音频片段,可根据需求调整间隔
            mediaRecorder.start(1000);
        } 

        function errorCallback(error) { 
            console.log('麦克风获取失败: ', error); 
        } 

        navigator.getUserMedia(constraints, successCallback, errorCallback); 
    } 
});

服务端index.js调整

服务端只需要原样转发数据就行,因为现在传的是通用的Base64字符串,不是本地Blob URL了:

socket.on('audio stream', function(name, base64Audio){ 
    console.log(name + ' 正在广播音频'); 
    socket.broadcast.emit('audio stream', name, base64Audio); 
});

额外注意事项

  • 如果你的服务器用的是自签SSL证书,rejectUnauthorized: false可以跳过验证,但生产环境建议用合法证书。
  • MediaRecorder的mimeType可以根据浏览器兼容性调整,比如audio/ogg或audio/wav,但audio/webm在Chrome里表现最好。
  • 音频片段的间隔(start(1000)里的1000毫秒):值越小延迟越低,但网络传输量越大,按需调整。
  • 浏览器的自动播放策略:大部分现代浏览器会阻止无用户交互的音频播放,所以最好在页面上加个"开始播放"按钮,让用户主动触发后再播放音频。

内容的提问来源于stack exchange,提问作者JCAguilera

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:01:42