logo

跨端语音处理全攻略:uniapp中实现H5录音和上传、实时语音识别(兼容App小程序)和波形可视化

作者:rousong2025.10.11 19:43浏览量:196

简介:本文详细解析了uniapp中如何实现H5录音、上传、实时语音识别及波形可视化功能,覆盖H5、App和小程序三端,提供完整代码示例与兼容性解决方案。

跨端语音处理全攻略:uniapp中实现H5录音和上传、实时语音识别(兼容App小程序)和波形可视化

一、跨端录音功能实现:H5、App、小程序三端兼容方案

1.1 H5端录音实现原理

H5端录音主要依赖Web Audio API和MediaRecorder API,核心步骤包括:

  • 获取用户麦克风权限:navigator.mediaDevices.getUserMedia({ audio: true })
  • 创建音频上下文:const audioContext = new (window.AudioContext || window.webkitAudioContext)()
  • 初始化MediaRecorder:const mediaRecorder = new MediaRecorder(stream)
  • 数据采集与处理:通过dataavailable事件获取Blob数据
  1. // H5录音完整示例
  2. async function startH5Recording() {
  3. try {
  4. const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
  5. const mediaRecorder = new MediaRecorder(stream);
  6. const audioChunks = [];
  7. mediaRecorder.ondataavailable = event => {
  8. audioChunks.push(event.data);
  9. };
  10. mediaRecorder.onstop = async () => {
  11. const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
  12. // 上传逻辑
  13. await uploadAudio(audioBlob);
  14. };
  15. mediaRecorder.start();
  16. return { stop: () => mediaRecorder.stop() };
  17. } catch (err) {
  18. console.error('录音失败:', err);
  19. }
  20. }

1.2 App端录音实现(Android/iOS)

App端需使用uniapp插件市场或原生插件:

  • Android:通过plus.audio.getRecorder获取录音对象
  • iOS:使用AVAudioRecorder原生模块
  • 推荐插件:luch-request网络请求)+ cordova-plugin-media(录音)
  1. // App端录音示例(需安装原生插件)
  2. function startAppRecording() {
  3. const recorder = plus.audio.getRecorder();
  4. recorder.record({
  5. filename: '_doc/audio/',
  6. format: 'wav'
  7. },
  8. success => {
  9. setTimeout(() => {
  10. recorder.stop();
  11. // 获取文件路径上传
  12. const filePath = success.filename;
  13. uploadAppAudio(filePath);
  14. }, 5000); // 录制5秒
  15. },
  16. error => console.error('录音错误:', error)
  17. );
  18. }

1.3 小程序端录音实现

小程序需使用wx.getRecorderManager API:

  • 配置权限:"requiredPrivateInfos": ["record"]
  • 关键参数:format: 'mp3', sampleRate: 16000
  1. // 小程序录音示例
  2. function startMiniProgramRecording() {
  3. const recorderManager = wx.getRecorderManager();
  4. recorderManager.onStart(() => console.log('录音开始'));
  5. recorderManager.onStop(res => {
  6. const tempFilePath = res.tempFilePath;
  7. // 上传临时文件
  8. uploadMiniProgramAudio(tempFilePath);
  9. });
  10. recorderManager.start({
  11. format: 'mp3',
  12. sampleRate: 16000,
  13. numberOfChannels: 1
  14. });
  15. }

二、音频上传与存储方案

2.1 分端上传策略

平台 上传方式 注意事项
H5 FormData + XMLHttpRequest 需处理跨域问题
App plus.io.resolveLocalFileSystemURL 需先获取文件路径
小程序 wx.uploadFile 需配置合法域名

2.2 通用上传函数实现

  1. async function uploadAudio(file, platform) {
  2. const formData = new FormData();
  3. formData.append('audio', file);
  4. try {
  5. const response = await fetch('https://your-api.com/upload', {
  6. method: 'POST',
  7. body: formData,
  8. headers: platform === 'h5' ? {} : {
  9. // App/小程序可能需要额外header
  10. 'X-Platform': platform
  11. }
  12. });
  13. return await response.json();
  14. } catch (error) {
  15. console.error('上传失败:', error);
  16. }
  17. }

三、实时语音识别技术实现

3.1 WebSocket实时传输方案

  1. // 实时录音并传输示例
  2. async function startRealTimeASR() {
  3. const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
  4. const mediaRecorder = new MediaRecorder(stream, {
  5. mimeType: 'audio/webm',
  6. audioBitsPerSecond: 16000
  7. });
  8. const socket = new WebSocket('wss://your-asr-api.com');
  9. mediaRecorder.ondataavailable = event => {
  10. if (socket.readyState === WebSocket.OPEN) {
  11. socket.send(event.data);
  12. }
  13. };
  14. mediaRecorder.start(100); // 每100ms发送一次数据
  15. socket.onmessage = event => {
  16. const result = JSON.parse(event.data);
  17. console.log('识别结果:', result.text);
  18. };
  19. }

3.2 分端兼容处理

  • H5:直接使用WebSocket
  • App:通过plus.socket.WebSocket实现
  • 小程序:使用wx.connectSocket
  1. // 小程序WebSocket示例
  2. function startMiniProgramASR() {
  3. const socketTask = wx.connectSocket({
  4. url: 'wss://your-asr-api.com',
  5. protocols: ['audio']
  6. });
  7. socketTask.onOpen(() => {
  8. const recorder = wx.getRecorderManager();
  9. recorder.onFrameRecorded(res => {
  10. socketTask.send({
  11. data: res.frameBuffer,
  12. success: () => console.log('发送成功')
  13. });
  14. });
  15. recorder.start({ format: 'pcm' });
  16. });
  17. }

四、波形可视化实现方案

4.1 Web Audio API波形绘制

  1. function drawWaveform(audioContext, stream) {
  2. const source = audioContext.createMediaStreamSource(stream);
  3. const analyser = audioContext.createAnalyser();
  4. analyser.fftSize = 2048;
  5. source.connect(analyser);
  6. const canvas = document.getElementById('waveform');
  7. const ctx = canvas.getContext('2d');
  8. const bufferLength = analyser.frequencyBinCount;
  9. const dataArray = new Uint8Array(bufferLength);
  10. function draw() {
  11. analyser.getByteFrequencyData(dataArray);
  12. ctx.fillStyle = 'rgb(200, 200, 200)';
  13. ctx.fillRect(0, 0, canvas.width, canvas.height);
  14. const barWidth = (canvas.width / bufferLength) * 2.5;
  15. let x = 0;
  16. for (let i = 0; i < bufferLength; i++) {
  17. const barHeight = dataArray[i] / 2;
  18. ctx.fillStyle = `rgb(${barHeight + 100}, 50, 50)`;
  19. ctx.fillRect(x, canvas.height - barHeight, barWidth, barHeight);
  20. x += barWidth + 1;
  21. }
  22. requestAnimationFrame(draw);
  23. }
  24. draw();
  25. }

4.2 小程序波形实现方案

小程序需使用canvas组件配合RecorderManageronFrameRecorded回调:

  1. // 小程序波形绘制
  2. Page({
  3. onReady() {
  4. this.ctx = wx.createCanvasContext('waveformCanvas');
  5. this.dataPoints = [];
  6. },
  7. onFrameRecorded(res) {
  8. const buffer = new Uint8Array(res.frameBuffer);
  9. const avg = buffer.reduce((a, b) => a + b) / buffer.length;
  10. this.dataPoints.push(avg);
  11. if (this.dataPoints.length > 100) {
  12. this.dataPoints.shift();
  13. }
  14. this.drawWaveform();
  15. },
  16. drawWaveform() {
  17. const ctx = this.ctx;
  18. ctx.clearRect(0, 0, 300, 100);
  19. this.dataPoints.forEach((val, i) => {
  20. const x = i * 3;
  21. const y = 50 - val / 2;
  22. ctx.beginPath();
  23. ctx.arc(x, y, 1, 0, 2 * Math.PI);
  24. ctx.fill();
  25. });
  26. ctx.draw();
  27. }
  28. });

五、完整项目集成建议

  1. 条件编译处理
    ```javascript
    // 使用uniapp条件编译
    //#ifdef H5
    import { startH5Recording } from ‘./h5-recorder’;
    //#endif

//#ifdef APP-PLUS
import { startAppRecording } from ‘./app-recorder’;
//#endif

//#ifdef MP-WEIXIN
import { startMiniProgramRecording } from ‘./mini-recorder’;
//#endif

  1. 2. **性能优化策略**:
  2. - 录音采样率统一为16kHzASR标准)
  3. - 波形绘制使用离屏CanvasH5
  4. - 小程序使用Worker处理音频数据
  5. 3. **错误处理机制**:
  6. ```javascript
  7. function safeRecord(platform) {
  8. try {
  9. switch(platform) {
  10. case 'h5': return startH5Recording();
  11. case 'app': return startAppRecording();
  12. case 'mini': return startMiniProgramRecording();
  13. default: throw new Error('不支持的平台');
  14. }
  15. } catch (error) {
  16. uni.showToast({
  17. title: `录音失败: ${error.message}`,
  18. icon: 'none'
  19. });
  20. // 降级处理逻辑
  21. }
  22. }

六、常见问题解决方案

  1. H5端麦克风权限问题

    • 确保HTTPS环境
    • 动态请求权限:await navigator.permissions.query({ name: 'microphone' })
  2. 小程序录音时长限制

    • 分段录制(每段<60秒)
    • 使用wx.startBackgroundAudio后台录音
  3. App端音频格式兼容

    • Android推荐:.wav.amr
    • iOS推荐:.m4a.caf
  4. 实时识别延迟优化

    • 调整发送频率(200-500ms)
    • 使用音频压缩(如Opus编码)

本文提供的方案已在多个uniapp项目中验证,开发者可根据实际需求调整参数。建议先实现H5基础功能,再通过条件编译逐步扩展App和小程序支持。对于生产环境,建议搭配专业的ASR服务(如阿里云、腾讯云)以获得更稳定的识别效果。

相关文章推荐

发表评论

活动