我们以微信小程序为例
后端采用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\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();小程序采用getRecorderManager与createInnerAudioContext实现实时录制与播放对方的声音,完整的微信小程序代码如下:wxml
<view class="container" style="padding-top: 20vh;">
<button bindtap="startCall" disabled="{{isCallStarted}}">开始通话</button>
<button bindtap="stopCall" disabled="{{!isCallStarted}}">结束通话</button>
</view>点击查看剩余代码
let socketTask;
Page({
data: {
isCallStarted: false,
recorderManager: null,
innerAudioContext: null,
isRecording: false,
audioQueue: [],
isPlaying: false,
},
startCall() {
const that = this;
this.setData({recorderManager:wx.getRecorderManager()});
this.setData({innerAudioContext:wx.createInnerAudioContext()});
this.data.recorderManager.onError((error) => {
console.error('录音错误:', error);
});
this.data.recorderManager.onStop((res) => {
console.log('录音停止:', res);
});
this.data.recorderManager.onFrameRecorded((res) => {
const { frameBuffer } = res;
console.log(frameBuffer)
if (frameBuffer) {
if (socketTask) {
socketTask.send({ data: frameBuffer});
}
}
});
socketTask = wx.connectSocket({
url: 'wss://web.debug.only.bfw.wiki:9502/',
success: (res) => console.log('创建成功', res),
fail: (res) => console.log('创建失败', res),
});
socketTask.onOpen(() => {
console.log('WebSocket 已连接');
that.startRecording();
});
socketTask.onClose(() => console.log('WebSocket 已断开'));
socketTask.onError((error) => console.error('WebSocket 发生错误:', error));
socketTask.onMessage((message) => {
console.log("getdata")
that.playAudio(message.data);
});
this.setData({ isCallStarted: true });
},
stopCall() {
if (this.data.recorderManager) this.data.recorderManager.stop();
if (socketTask) socketTask.close();
if (this.data.innerAudioContext) this.data.innerAudioContext.stop();
this.setData({ isCallStarted: false });
},
startRecording() {
this.data.recorderManager.start({
sampleRate: 44100,
numberOfChannels: 1,
encodeBitRate: 192000,
format:'mp3',
frameSize: 100
});
},
generateRandomId() {
return Date.now().toString(36) + Math.random().toString(36).substr(2, 5);
},
playAudio(arrayBuffer) {
let newq=this.data.audioQueue;
newq.push(arrayBuffer);
this.setData({audioQueue:newq})
if (!this.data.isPlaying) this.playNextInQueue();
},
playNextInQueue() {
var that=this;
if (this.data.audioQueue.length === 0) {
this.setData({isPlaying:false});
return;
}
this.setData({isPlaying:true});
const arrayBuffer = this.data.audioQueue.shift();
const filePath = `${wx.env.USER_DATA_PATH}/temp_audio${that.generateRandomId()}.pcm`;
console.log("playing")
wx.getFileSystemManager().writeFile({
filePath: filePath,
data: arrayBuffer,
encoding: 'binary',
success: () => {
console.log("播放")
that.data.innerAudioContext.src = filePath;
that.data.innerAudioContext.play();
that.data.innerAudioContext.onError((err) =>console.log(err));
that.data.innerAudioContext.onEnded(() => that.playNextInQueue());
},
fail: (error) => {
console.error('写入音频文件失败:', error);
that.playNextInQueue();
}
});
},
});
网友回复


