logo

跨端语音交互全攻略:uniapp实现H5录音、ASR与波形可视化方案

作者:热心市民鹿先生2025.09.19 11:35浏览量:14

简介:本文详细解析uniapp中H5录音、音频上传、实时语音识别及波形可视化的完整实现方案,提供跨平台兼容代码示例与性能优化策略。

一、H5录音功能实现与跨平台兼容

1.1 录音权限处理机制

在uniapp中实现录音功能,首先需要处理不同平台的权限申请。H5环境需通过navigator.mediaDevices.getUserMedia申请麦克风权限,而App和小程序端需调用原生API。推荐使用条件编译实现跨平台适配:

  1. // 录音权限申请(跨平台)
  2. async function requestAudioPermission() {
  3. // #ifdef H5
  4. try {
  5. const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
  6. stream.getTracks().forEach(track => track.stop());
  7. return true;
  8. } catch (err) {
  9. uni.showToast({ title: '请允许麦克风权限', icon: 'none' });
  10. return false;
  11. }
  12. // #endif
  13. // #ifdef APP-PLUS
  14. const res = await plus.android.invoke(
  15. plus.android.importClass('android.Manifest'),
  16. 'checkSelfPermission',
  17. 'android.permission.RECORD_AUDIO'
  18. );
  19. if (res !== 0) {
  20. plus.android.requestPermissions(['android.permission.RECORD_AUDIO']);
  21. }
  22. return true;
  23. // #endif
  24. // #ifdef MP-WEIXIN
  25. return new Promise(resolve => {
  26. uni.authorize({
  27. scope: 'scope.record',
  28. success: resolve(true),
  29. fail: () => {
  30. uni.showModal({
  31. content: '需要录音权限',
  32. success: res => res.confirm && uni.openSetting()
  33. });
  34. resolve(false);
  35. }
  36. });
  37. });
  38. // #endif
  39. }

1.2 录音核心实现方案

采用Web Audio API实现H5端高精度录音,配合Worker线程处理音频数据:

  1. // 创建音频上下文
  2. const audioContext = new (window.AudioContext || window.webkitAudioContext)();
  3. let mediaRecorder;
  4. let audioChunks = [];
  5. async function startRecording() {
  6. const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
  7. const source = audioContext.createMediaStreamSource(stream);
  8. const processor = audioContext.createScriptProcessor(4096, 1, 1);
  9. processor.onaudioprocess = e => {
  10. const buffer = e.inputBuffer.getChannelData(0);
  11. // 实时波形数据获取
  12. visualizeWaveform(buffer);
  13. };
  14. source.connect(processor);
  15. processor.connect(audioContext.destination);
  16. // #ifdef APP-PLUS || MP-WEIXIN
  17. // 使用原生录音API
  18. // #endif
  19. }

二、音频上传与云端处理

2.1 分片上传优化策略

对于大音频文件,推荐采用分片上传机制:

  1. async function uploadAudio(file, chunkSize = 1024 * 1024) {
  2. const totalChunks = Math.ceil(file.size / chunkSize);
  3. let uploaded = 0;
  4. for (let i = 0; i < totalChunks; i++) {
  5. const start = i * chunkSize;
  6. const end = Math.min(start + chunkSize, file.size);
  7. const chunk = file.slice(start, end);
  8. const formData = new FormData();
  9. formData.append('file', chunk);
  10. formData.append('index', i);
  11. formData.append('total', totalChunks);
  12. await uni.uploadFile({
  13. url: 'https://your-api.com/upload',
  14. formData,
  15. success: () => {
  16. uploaded++;
  17. const progress = Math.round((uploaded / totalChunks) * 100);
  18. uni.showLoading({ title: `上传中: ${progress}%` });
  19. }
  20. });
  21. }
  22. }

2.2 云端语音识别集成

推荐采用WebSocket实现实时语音识别,以下为伪代码示例:

  1. async function startSpeechRecognition() {
  2. const socket = new WebSocket('wss://asr-api.com/stream');
  3. const mediaRecorder = new MediaRecorder(stream, {
  4. mimeType: 'audio/webm',
  5. audioBitsPerSecond: 16000
  6. });
  7. mediaRecorder.ondataavailable = e => {
  8. if (e.data.size > 0) {
  9. socket.send(e.data);
  10. }
  11. };
  12. socket.onmessage = e => {
  13. const result = JSON.parse(e.data);
  14. if (result.isFinal) {
  15. this.transcript += result.text;
  16. this.$forceUpdate();
  17. }
  18. };
  19. mediaRecorder.start(300); // 300ms分片
  20. }

三、实时波形可视化实现

3.1 Canvas波形渲染方案

使用Canvas API实现高性能波形绘制:

  1. class WaveformVisualizer {
  2. constructor(canvas) {
  3. this.canvas = canvas;
  4. this.ctx = canvas.getContext('2d');
  5. this.width = canvas.width;
  6. this.height = canvas.height;
  7. this.data = new Uint8Array(1024);
  8. }
  9. update(audioData) {
  10. // 简化处理:实际需计算RMS值
  11. const values = new Array(1024).fill(0);
  12. for (let i = 0; i < audioData.length; i++) {
  13. values[Math.floor(i / audioData.length * 1024)] +=
  14. Math.abs(audioData[i]) * 100;
  15. }
  16. this.ctx.clearRect(0, 0, this.width, this.height);
  17. this.ctx.fillStyle = '#00ff00';
  18. const step = this.width / values.length;
  19. values.forEach((val, i) => {
  20. const h = val / 255 * this.height;
  21. this.ctx.fillRect(i * step, this.height - h, step, h);
  22. });
  23. }
  24. }

3.2 Web Worker音频处理

创建Worker线程处理音频数据,避免主线程阻塞:

  1. // waveform.worker.js
  2. self.onmessage = function(e) {
  3. const { audioData, width, height } = e.data;
  4. const values = new Array(width).fill(0);
  5. // 计算波形数据
  6. for (let i = 0; i < audioData.length; i++) {
  7. const pos = Math.floor(i / audioData.length * width);
  8. values[pos] = Math.max(values[pos], Math.abs(audioData[i]) * height);
  9. }
  10. postMessage({ values });
  11. };
  12. // 主线程调用
  13. const worker = new Worker('./waveform.worker.js');
  14. worker.postMessage({
  15. audioData: buffer,
  16. width: canvas.width,
  17. height: canvas.height
  18. });
  19. worker.onmessage = e => {
  20. // 更新波形
  21. };

四、跨平台兼容性优化

4.1 平台差异处理策略

功能 H5实现 App实现 小程序实现
录音权限 MediaDevices API plus.android.requestPermissions wx.authorize
音频处理 Web Audio API AudioRecorder wx.getRecorderManager
实时传输 WebSocket SocketTask wx.connectSocket

4.2 性能优化建议

  1. 音频采样率统一:建议统一使用16kHz采样率,平衡音质与传输效率
  2. 内存管理:及时释放不再使用的AudioBuffer和MediaStream
  3. 降级方案:H5端检测不支持Web Audio时,使用MediaRecorder作为备选
  4. 网络优化:实现断点续传和自动重连机制

五、完整实现示例

  1. // 主组件实现
  2. export default {
  3. data() {
  4. return {
  5. isRecording: false,
  6. transcript: '',
  7. waveformData: new Uint8Array(1024)
  8. };
  9. },
  10. methods: {
  11. async startCapture() {
  12. if (!await this.checkPermissions()) return;
  13. this.isRecording = true;
  14. // #ifdef H5
  15. this.startH5Recording();
  16. // #endif
  17. // #ifdef APP-PLUS
  18. this.startAppRecording();
  19. // #endif
  20. // #ifdef MP-WEIXIN
  21. this.startMpRecording();
  22. // #endif
  23. },
  24. startH5Recording() {
  25. const audioContext = new AudioContext();
  26. const worker = new Worker('./waveform.worker.js');
  27. navigator.mediaDevices.getUserMedia({ audio: true })
  28. .then(stream => {
  29. const source = audioContext.createMediaStreamSource(stream);
  30. const scriptNode = audioContext.createScriptProcessor(4096, 1, 1);
  31. scriptNode.onaudioprocess = e => {
  32. const buffer = e.inputBuffer.getChannelData(0);
  33. worker.postMessage({
  34. audioData: buffer,
  35. width: 512,
  36. height: 128
  37. });
  38. // 实时ASR处理...
  39. };
  40. source.connect(scriptNode);
  41. scriptNode.connect(audioContext.destination);
  42. });
  43. },
  44. stopRecording() {
  45. this.isRecording = false;
  46. // 停止各平台录音实例...
  47. }
  48. }
  49. };

六、常见问题解决方案

  1. H5录音空白问题:检查是否在HTTPS环境或localhost开发
  2. 小程序录音延迟:调整bufferSize为合适值(建议1024-4096)
  3. App端权限失败:确保在manifest.json中配置了必要权限
  4. 波形卡顿:降低绘制频率或使用requestAnimationFrame优化

本方案通过条件编译和平台特性检测,实现了跨H5、App和小程序的统一语音处理能力。实际开发中建议将各平台实现封装为独立模块,通过接口统一调用,提升代码可维护性。对于高并发场景,可考虑使用WebAssembly优化音频处理性能。

相关文章推荐

发表评论

活动