求方案:COCOS3.7如何获取声音输入/录音
您好 有方案?
小游戏,发布到微信和抖音呢?使用平台自己提供的API吗?
这种cocos平台应该没有集成吧,这不属于引擎适配的范畴,但微信和抖音是有支持,和登录授权那些差不多,可以自己适配一下:
媒体 / 录音 / wx.getRecorderManager (qq.com)
tt.getRecorderManager_小游戏_抖音开放平台 (open-douyin.com)
感谢大佬
,我研究一下
提供个微信录音
// 开始录音
startRecord() {
// 先拉取设置, 看下有没有权限
wx.getSetting({
success: (res) => {
// 录音配置
const options = {
duration: 20 * 1000, // 最高20秒
sampleRate: 8000,
numberOfChannels: 1,
encodeBitRate: 24000,
format: 'mp3',
}
const record = res.authSetting["scope.record"];
if (record === false) {
// 已经拒绝了权限
// app.popup.showToast("无法录音, 请通过设置界面开启录音权限");
} else if (record === true) {
// 可以录音
this.rm.start(options);
} else {
// 找不到设置权限的痕迹, 进行获取权限开启录音
wx.authorize({
scope: "scope.record",
success: () => {
this.rm.start(options);
},
fail: () => {
console.warn("没给予授权!");
// app.popup.showToast("无法录音, 请通过设置界面开启录音权限");
}
});
}
},
fail: () => {
console.error("获取微信设置失败!")
}
});
}
// 主动停止录音
stopRecord() {
// 如果录音超过最大时长, 会主动停止, 调用该函数将不会有任何处理
console.warn("主动结束录音");
this.rm.stop();
}
// 开始录音了
setOnStartCallBack() {
this.rm.onStart(() => {
console.warn("监听到录音开始");
});
}
如果是多玩家, 需要通过服务器做中介来发送录音文件, 或者直接读取微信录音文件来发送. 这里采用的是读取录音文件来发送
const OffsetIndex = 1;
const MaxChunkSize = 40 * 1024; // 40KB
/**
* tempFilePath string 录音文件的临时路径 (本地路径)
* duration number 录音总时长,单位:ms
* fileSize number 录音文件大小,单位:Byte
*/
setOnStopCallBack() {
this.rm.onStop((res: {
tempFilePath: string, // 录音文件的临时路径 (本地路径)
duration: number, // 录音总时长,单位:ms
fileSize: number, // 录音文件大小,单位:Byte
}) => {
console.warn("监听到录音结束:", res);
if (res.duration < 1 * 1000) {
// showToast("发送语音时间太短");
return;
}
const time = new Date().getTime();
// 读取二进制, 上报服务端, 通过返回结果, 进行包数监听, 监听完毕则放入队列
wx.getFileSystemManager().readFile({
filePath: res.tempFilePath,
success: (readResult) => {
const buffer: ArrayBuffer = readResult.data as ArrayBuffer;
const sliceCount = Math.ceil((buffer.byteLength) / MaxChunkSize) + 1; // 循环分包次数+余数1
// 切割
let arr: ArrayBuffer[] = [];
for (let i = 0; i < sliceCount; i++) {
const start = i * MaxChunkSize;
const end = Math.min(start + MaxChunkSize, buffer.byteLength);
const slice = buffer.slice(start, end);
if (slice.byteLength == 0) { continue; }
arr.push(slice);
}
// 发送切割的数据
arr.forEach(async (v, i) => {
await sleep(50); // 预防粘包 , 采用的是 await Promise+setTimeout
const voiceData = new Uint8Array(v.byteLength);
voiceData.set(new Uint8Array(v), 0);
// TODO发送数据给服务端
let obj = {
uniqueId: time,
totalPackageNum: arr.length,
curPackageIndex: i + OffsetIndex, // 索引从1开始
voiceData
}
});
},
fail: (errMsg) => {
console.error("读取失败");
}
});
});
}
private writeMp3(data: { uniqueId, curPackageIndex, totalPackageNum }) {
if (!data) { console.error("数据异常"); return; }
const id = data.uniqueId;
if (!this.receiveData[id]) { this.receiveData[id] = []; }
this.receiveData[id][data.curPackageIndex] = data; // 为了确保id顺序一次, 采用index存储
// 检验是否收到了所有数据(减1是因为index从1开始)
if (this.receiveData[id].length - OffsetIndex != data.totalPackageNum) { return; }
/**
*~ 有个问题, 发送数据是通过 Uint8Array 包含 ArrayBuffer, 收到时却变成了另一个数据 (ArrayBuffer? 看着也不像)
*~ 不影响使用, 就不改了
*~ 还有个无敌坑的问题: 微信开发工具发送的录音数据, 在真机无法播放! 测试时务必使用两台真机
*/
// 合并接收到的切片数据
const arr: ArrayBuffer[] = [];
for (const chunk of this.receiveData[id]) {
if (chunk?.uniqueId == null) { continue; }
arr.push(chunk.voiceData); //~ 收到的协议没有 chunk.voiceData.buffer
}
const mergedData = new Uint8Array(arr.reduce((acc: number, chunk: ArrayBuffer) => {
return acc + chunk.length; //~ 收到的协议没有 chunk.byteLength
}, 0));
let offset = 0;
for (const chunk of arr) {
mergedData.set(new Uint8Array(chunk), offset);
offset += chunk.length; //~ 收到的协议没有 chunk.byteLength
}
// 将合并后的数据保存为完整的 MP3 文件
const path = wx.env.USER_DATA_PATH + `/recorder_${data.uniqueId}.mp3`;
wx.getFileSystemManager().writeFile({
filePath: path,
data: mergedData.buffer,
encoding: "binary",
success: (res) => {
// 确定写入成功, 加入播放队列
console.warn("写入录音 binary", path, res);
this.playRecord(path); // 这里方便理解, 直接播放, 队列播放请自行实现
},
fail(error) {
console.error("写入失败", error);
}
});
}
// 播放录音
playRecord(path: string) {
const ac = wx.createInnerAudioContext();
this.curAudioContext = ac;
ac.src = path;
// 监听播放完成
ac.onEnded(() => {
console.log("录音播放结束");
ac.destroy(); // 完成后记得销毁, 否则会一直持有存在内存中!
});
ac.onError((res) => {
console.error("播放报错", res);
});
ac.onPlay(() => {
console.log("开始播放");
});
ac.autoplay = true;
ac.play();
return ac;
}
2赞
厉害厉害 

感谢大佬,膜拜