我们以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
网友回复
threejs如何引入中文字体json?
FLUX.1 Kontext如何api调用?
腾讯混元模型广场里都是混元模型的垂直小模型,如何api调用?
为啥所有的照片分辨率提升工具都会修改照片上的图案细节?
js如何在浏览器中将webm视频的声音分离为单独音频?
微信小程序如何播放第三方域名url的mp4视频?
ai多模态大模型能实时识别视频中的手语为文字吗?
如何远程调试别人的chrome浏览器获取调试信息?
为啥js打开新网页window.open设置窗口宽高无效?
浏览器中js的navigator.mediaDevices.getDisplayMedia屏幕录像无法录制SpeechSynthesisUtterance产生的说话声音?