+
95
-

回答

我们以php的swoole搭建一个websocket服务器

<?php

$server = new Swoole\WebSocket\Server("0.0.0.0", 9502, SWOOLE_PROCESS, SWOOLE_SOCK_TCP | SWOOLE_SSL);
$server->set([
    'daemonize' => false,
    'ssl_cert_file' => "/data/cert/6284283_web.debug.only.bfw.wiki.pem",
    'ssl_key_file'  => "/data/cert/6284283_web.debug.only.bfw.wiki.key",
]);
$server->on('open', function($server, $req) {
    echo "connection open: {$req->fd}\n";
});

$server->on('message', function($server, $frame) {
    //echo "received message: {$frame->data}\n";
    // 确保我们处理的是二进制数据
    //if ($frame->opcode == WEBSOCKET_OPCODE_BINARY) {
        // 广播音频数据到所有其他连接的客户端
      //  foreach($server->connections as $fd) {
          //  if($fd != $frame->fd) {
             //   $server->push($fd, $frame->data, WEBSOCKET_OPCODE_BINARY);
           // }
       // }
   // }
    $server->push($frame->fd, $frame->data,WEBSOCKET_OPCODE_BINARY);
});

$server->on('close', function($server, $fd) {
    echo "connection close: {$fd}\n";
});

$server->start();

html代码如下:

<!DOCTYPE html>
<html>
<head>
        <meta charset="UTF-8">
    <title>实时语音通话</title>
</head>
<body>
    <button id="startBtn">开始通话</button>
    <button id="stopBtn">结束通话</button>

    <script>
    
    let ws;
let mediaStream;
let audioContext;
let mediaStreamSource;
let processor;
  document.getElementById('startBtn').onclick = startCall;
        document.getElementById('stopBtn').onclick = stopCall;
function startCall() {
     ws = new WebSocket('wss://web.debug.only.bfw.wiki:9502');
    
    ws.binaryType = 'arraybuffer';  // 设置WebSocket以接收二进制数据
    
    ws.onmessage = function(event) {
        // 处理接收到的音频数据
        playAudio(event.data);
    };

    navigator.mediaDevices.getUserMedia({ audio: true })
        .then(stream => {
            mediaStream = stream;
            audioContext = new AudioContext();
            mediaStreamSource = audioContext.createMediaStreamSource(stream);
            processor = audioContext.createScriptProcessor(1024, 1, 1);

            mediaStreamSource.connect(processor);
            processor.connect(audioContext.destination);

            processor.onaudioprocess = function(e) {
                // 发送音频数据到服务器
                if (ws.readyState === WebSocket.OPEN) {
                    // 将音频数据转换为二进制格式
                    const audioData = e.inputBuffer.getChannelData(0);
                    const buffer = new Float32Array(audioData);
                    ws.send(buffer);
                }
            };
        })
        .catch(err => console.error('Error accessing microphone:', err));
}

        function stopCall() {
            if (ws) ws.close();
            if (mediaStream) mediaStream.getTracks().forEach(track => track.stop());
            if (processor) processor.disconnect();
            if (mediaStreamSource) mediaStreamSource.disconnect();
            if (audioContext) audioContext.close();
        }
        
            let audioQueue = [];
        let isPlaying = false;

        function playAudio(Audio) {
           
            audioQueue.push(Audio);
            if (!isPlaying) {
                playNextInQueue();
            }
        }

         function playNextInQueue() {
             console.log(audioQueue.length)
            if (audioQueue.length === 0) {
                isPlaying = false;
                return;
            }

           
            const audioData = audioQueue.shift();

            try {
                    // 实现音频播放逻辑
    // 这里需要将接收到的音频数据(ArrayBuffer)解码并播放
    const audioBuffer = audioContext.createBuffer(1, audioData.byteLength / 4, audioContext.sampleRate);
    audioBuffer.getChannelData(0).set(new Float32Array(audioData));
    
    const source = audioContext.createBufferSource();
    source.buffer = audioBuffer;
    source.connect(audioContext.destination);
    source.start();
               
            } catch (error) {
                console.error('播放音频时发生错误:', error);
                playNextInQueue(); // 如果当前音频播放失败,继续播放队列中的下一个
            }
        }

       
    </script>
</body>
</html>

如果出现声音卡顿,可降低声音采样率为单声道24k

网友回复

我知道答案,我要回答