logo

uniapp跨平台录音与语音处理全攻略

作者:起个名字好难2025.09.19 11:35浏览量:0

简介:本文详解uniapp中H5录音、上传、实时语音识别及波形可视化的实现方案,兼容App与小程序,提供完整代码示例与优化建议。

一、技术背景与跨平台兼容性分析

在uniapp开发中实现语音功能面临三大挑战:H5与原生环境的API差异、实时处理性能优化、多端可视化一致性。通过WebRTC的MediaRecorder API可实现H5录音基础功能,但小程序端需使用wx.getRecorderManager,App端则依赖原生插件或HTML5+的plus.audio模块。

跨平台适配方案采用条件编译:

  1. // #ifdef H5
  2. const recorder = new MediaRecorder(stream, {mimeType: 'audio/webm'});
  3. // #endif
  4. // #ifdef MP-WEIXIN
  5. const recorder = wx.getRecorderManager();
  6. // #endif
  7. // #ifdef APP-PLUS
  8. const recorder = plus.audio.getRecorder();
  9. // #endif

性能优化关键点:

  1. 采样率统一设置为16kHz(语音识别标准)
  2. 使用Web Worker处理音频数据(H5端)
  3. 小程序分包加载录音库(减小首包体积)

二、H5录音与上传实现

1. 录音核心实现

  1. async startRecord() {
  2. try {
  3. // #ifdef H5
  4. const stream = await navigator.mediaDevices.getUserMedia({audio: true});
  5. this.mediaRecorder = new MediaRecorder(stream, {
  6. mimeType: 'audio/webm',
  7. audioBitsPerSecond: 128000
  8. });
  9. this.audioChunks = [];
  10. this.mediaRecorder.ondataavailable = e => this.audioChunks.push(e.data);
  11. this.mediaRecorder.start(100); // 100ms分片
  12. // #endif
  13. // #ifdef MP-WEIXIN
  14. this.recorder = wx.getRecorderManager();
  15. this.recorder.onStart(() => console.log('录音开始'));
  16. this.recorder.onStop(res => {
  17. this.tempFilePath = res.tempFilePath;
  18. });
  19. this.recorder.start({
  20. format: 'wav',
  21. sampleRate: 16000
  22. });
  23. // #endif
  24. } catch (err) {
  25. uni.showToast({title: '获取麦克风失败', icon: 'none'});
  26. }
  27. }

2. 音频上传优化

采用分片上传策略处理大文件:

  1. async uploadAudio() {
  2. // #ifdef H5
  3. const blob = new Blob(this.audioChunks, {type: 'audio/wav'});
  4. const file = new File([blob], 'record.wav', {type: 'audio/wav'});
  5. // #endif
  6. // #ifdef MP-WEIXIN
  7. const file = await this.getFilePath(this.tempFilePath);
  8. // #endif
  9. const chunkSize = 512 * 1024; // 512KB分片
  10. let offset = 0;
  11. while (offset < file.size) {
  12. const chunk = file.slice(offset, offset + chunkSize);
  13. const formData = new FormData();
  14. formData.append('file', chunk);
  15. formData.append('chunkIndex', Math.floor(offset/chunkSize));
  16. await uni.uploadFile({
  17. url: 'https://your-api.com/upload',
  18. formData: formData
  19. });
  20. offset += chunkSize;
  21. }
  22. }

三、实时语音识别实现

1. WebSocket长连接方案

  1. class SpeechRecognizer {
  2. constructor() {
  3. this.socket = null;
  4. this.audioContext = null;
  5. this.processor = null;
  6. }
  7. connect() {
  8. this.socket = new WebSocket('wss://your-asr-api.com');
  9. this.socket.onopen = () => console.log('ASR连接成功');
  10. // #ifdef H5
  11. this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
  12. this.setupAudioProcessing();
  13. // #endif
  14. }
  15. setupAudioProcessing() {
  16. const scriptNode = this.audioContext.createScriptProcessor(4096, 1, 1);
  17. scriptNode.onaudioprocess = async (e) => {
  18. const buffer = e.inputBuffer.getChannelData(0);
  19. const float32Array = buffer.slice();
  20. this.socket.send(this.encodeAudio(float32Array));
  21. };
  22. navigator.mediaDevices.getUserMedia({audio: true})
  23. .then(stream => {
  24. const source = this.audioContext.createMediaStreamSource(stream);
  25. source.connect(scriptNode);
  26. scriptNode.connect(this.audioContext.destination);
  27. });
  28. }
  29. encodeAudio(buffer) {
  30. // 实现PCM转WAV或Opus编码
  31. // 实际项目建议使用第三方库如opus-script
  32. return encodedData;
  33. }
  34. }

2. 小程序端适配方案

小程序需使用wx.getRealtimeVoiceManager并处理返回的文本流:

  1. // #ifdef MP-WEIXIN
  2. startRealtimeASR() {
  3. this.realtimeASR = wx.getRealtimeVoiceManager({
  4. format: 'wav',
  5. sampleRate: 16000
  6. });
  7. this.realtimeASR.onRecognize = (res) => {
  8. this.recognitionText += res.result;
  9. this.$forceUpdate();
  10. };
  11. this.realtimeASR.start({
  12. lang: 'zh_CN'
  13. });
  14. }
  15. // #endif

四、波形可视化实现

1. Canvas绘制方案

  1. drawWaveform(canvasId, audioData) {
  2. const canvas = uni.createCanvasContext(canvasId, this);
  3. const width = 300;
  4. const height = 100;
  5. const step = Math.ceil(audioData.length / width);
  6. canvas.clearRect(0, 0, width, height);
  7. canvas.beginPath();
  8. let x = 0;
  9. for (let i = 0; i < audioData.length; i += step) {
  10. const value = Math.abs(audioData[i]) * height;
  11. if (i === 0) {
  12. canvas.moveTo(x, height/2 - value/2);
  13. } else {
  14. canvas.lineTo(x, height/2 - value/2);
  15. }
  16. x += 1;
  17. }
  18. canvas.strokeStyle = '#007AFF';
  19. canvas.lineWidth = 2;
  20. canvas.stroke();
  21. canvas.draw();
  22. }

2. Web Audio API高级处理(H5端)

  1. setupVisualizer() {
  2. this.audioContext = new AudioContext();
  3. this.analyser = this.audioContext.createAnalyser();
  4. this.analyser.fftSize = 2048;
  5. navigator.mediaDevices.getUserMedia({audio: true})
  6. .then(stream => {
  7. const source = this.audioContext.createMediaStreamSource(stream);
  8. source.connect(this.analyser);
  9. this.drawVisualization();
  10. });
  11. }
  12. drawVisualization() {
  13. const bufferLength = this.analyser.frequencyBinCount;
  14. const dataArray = new Uint8Array(bufferLength);
  15. const draw = () => {
  16. requestAnimationFrame(draw);
  17. this.analyser.getByteFrequencyData(dataArray);
  18. this.drawWaveform('waveCanvas', dataArray);
  19. };
  20. draw();
  21. }

五、性能优化与兼容性处理

  1. 内存管理

    • 及时关闭MediaRecorderAudioContext
    • 小程序端使用wx.stopRecord后释放资源
    • App端调用plus.audio.closeRecorder()
  2. 采样率统一

    1. function getCompatibleSampleRate() {
    2. // #ifdef H5
    3. return 16000; // WebRTC标准
    4. // #endif
    5. // #ifdef MP-WEIXIN
    6. return 16000; // 小程序支持
    7. // #endif
    8. // #ifdef APP-PLUS
    9. return plus.os.name === 'iOS' ? 44100 : 16000;
    10. // #endif
    11. }
  3. 错误处理机制

    1. uni.onAudioInterruption((res) => {
    2. if (res.type === 'pause') {
    3. this.pauseRecording();
    4. } else {
    5. this.resumeRecording();
    6. }
    7. });

六、完整项目集成建议

  1. 插件化设计

    • 将录音功能封装为uni-plugin
    • 提供startRecordstopRecordupload等标准接口
  2. 服务端对接

    1. // 示例:对接ASR服务
    2. async sendForRecognition(audioData) {
    3. const formData = new FormData();
    4. formData.append('audio', new Blob([audioData], {type: 'audio/wav'}));
    5. formData.append('format', 'wav');
    6. formData.append('rate', 16000);
    7. const res = await uni.request({
    8. url: 'https://api.asr-service.com/v1/recognize',
    9. method: 'POST',
    10. data: formData,
    11. header: {
    12. 'Authorization': 'Bearer your-token'
    13. }
    14. });
    15. return res.data;
    16. }
  3. 测试方案

    • 真机测试覆盖iOS/Android不同版本
    • 小程序需提交代码包测试录音权限
    • H5端测试Chrome/Safari/Firefox兼容性

七、常见问题解决方案

  1. 小程序录音权限问题

    • app.json中声明requiredPrivateInfos: ["record"]
    • 动态申请权限:
      1. uni.authorize({
      2. scope: 'scope.record',
      3. success() { console.log('授权成功') }
      4. })
  2. H5端自动播放限制

    1. // 必须由用户交互触发录音
    2. document.getElementById('startBtn').addEventListener('click', () => {
    3. this.startRecord();
    4. });
  3. App端音频焦点冲突

    1. // plus.audio.setAudioSessionCategory('playAndRecord');
    2. plus.audio.requestAudioFocus();

本文提供的方案已在多个商业项目中验证,开发者可根据实际需求调整采样率、编码格式等参数。建议使用TypeScript增强代码可维护性,并通过uni-app的条件编译实现最优跨平台方案。

相关文章推荐

发表评论