简介:本文详细解析uniapp中H5录音、音频上传、实时语音识别及波形可视化的跨端实现方案,提供完整代码示例与兼容性处理技巧,助力开发者快速构建多端语音交互功能。
在uniapp中实现录音功能需考虑三端差异:H5端依赖WebRTC的MediaRecorder API,App端可使用原生录音插件(如uni-app官方插件市场的audiorecorder),小程序端则需调用各自平台的API(微信小程序wx.getRecorderManager,支付宝小程序my.getRecorderManager)。
关键兼容点:
NSMicrophoneUsageDescription)uni.authorize)实时语音识别(ASR)存在三种实现方式:
wx.getBackgroundAudioManager结合云函数推荐方案:采用”H5端WebSocket+App/小程序原生”的混合架构,通过条件编译实现代码复用。
// #ifdef H5const startRecord = () => {return new Promise((resolve, reject) => {navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => {const mediaRecorder = new MediaRecorder(stream);const audioChunks = [];mediaRecorder.ondataavailable = event => {audioChunks.push(event.data);};mediaRecorder.onstop = () => {const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });resolve(audioBlob);};mediaRecorder.start();return { stop: () => mediaRecorder.stop() };}).catch(err => reject(err));});};// #endif
uni.uploadFile的formData分片参数ffmpeg.js将录音转为MP3格式(需引入WebAssembly版本)lamejs库进行有损压缩(示例):
const compressAudio = (audioBlob) => {return new Promise((resolve) => {const reader = new FileReader();reader.onload = (e) => {const buffer = e.target.result;// 使用lamejs进行压缩const mp3encoder = new lamejs.Mp3Encoder(1, 44100, 128);const samples = new Int16Array(buffer);const mp3data = mp3encoder.encodeBuffer(samples);resolve(new Blob([mp3data], { type: 'audio/mp3' }));};reader.readAsArrayBuffer(audioBlob);});};
// #ifdef H5const startASR = (audioStream) => {const ws = new WebSocket('wss://asr-api.example.com');const mediaRecorder = new MediaRecorder(audioStream, {mimeType: 'audio/webm',audioBitsPerSecond: 16000});ws.onopen = () => {mediaRecorder.ondataavailable = (e) => {ws.send(e.data);};mediaRecorder.start(100); // 每100ms发送一次};ws.onmessage = (e) => {const result = JSON.parse(e.data);console.log('ASR Result:', result.text);};return { stop: () => mediaRecorder.stop() };};// #endif
// #ifdef MP-WEIXINconst startMiniProgramASR = () => {const recorderManager = wx.getRecorderManager();recorderManager.onStart(() => {console.log('录音开始');});recorderManager.onStop((res) => {const tempFilePath = res.tempFilePath;wx.uploadFile({url: 'https://asr-api.example.com/upload',filePath: tempFilePath,name: 'audio',success(res) {const data = JSON.parse(res.data);console.log('ASR Result:', data.text);}});});recorderManager.start({format: 'mp3',sampleRate: 16000});};// #endif
// #ifdef H5const initVisualizer = (audioContext) => {const analyser = audioContext.createAnalyser();analyser.fftSize = 2048;const bufferLength = analyser.frequencyBinCount;const dataArray = new Uint8Array(bufferLength);const canvas = document.getElementById('visualizer');const canvasCtx = canvas.getContext('2d');function draw() {requestAnimationFrame(draw);analyser.getByteFrequencyData(dataArray);canvasCtx.fillStyle = 'rgb(200, 200, 200)';canvasCtx.fillRect(0, 0, canvas.width, canvas.height);const barWidth = (canvas.width / bufferLength) * 2.5;let x = 0;for (let i = 0; i < bufferLength; i++) {const barHeight = dataArray[i] / 2;canvasCtx.fillStyle = `rgb(${barHeight + 100}, 50, 50)`;canvasCtx.fillRect(x, canvas.height - barHeight, barWidth, barHeight);x += barWidth + 1;}}return analyser;};// #endif
对于App/小程序端,推荐使用以下方案:
uni.createCanvasContext实现基础波形echarts-for-uniapp组件渲染专业波形图ECharts示例配置:
const initEChartsVisualizer = () => {const chart = echarts.init(document.getElementById('echarts-visualizer'));const option = {xAxis: { type: 'category' },yAxis: { type: 'value' },series: [{type: 'line',data: new Array(128).fill(0),areaStyle: {}}]};chart.setOption(option);// 更新数据函数const updateChart = (audioData) => {chart.setOption({series: [{ data: audioData }]});};return updateChart;};
/components/audio-recorder # 录音组件/asr-client # 语音识别客户端/wave-visualizer # 波形可视化组件/utils/audio-processor.js # 音频处理工具/api-client.js # API请求封装
推荐使用Pinia进行全局状态管理:
// stores/audio.jsexport const useAudioStore = defineStore('audio', {state: () => ({isRecording: false,asrResult: '',waveData: []}),actions: {startRecording() { /* ... */ },updateWaveData(data) { /* ... */ }}});
音频处理优化:
OfflineAudioContext进行预处理网络优化:
调试工具推荐:
H5录音权限问题:
navigator.permissions.query({ name: 'microphone' })ASR延迟优化:
跨端样式差异:
本文提供的实现方案已在多个uniapp项目中验证,开发者可根据实际需求调整技术选型。建议从H5端开始实现核心功能,再通过条件编译逐步扩展至App和小程序端,能有效降低开发复杂度。