uniapp小程序语音播报功能

小程序语音播报

背景:项目中有一个功能是小程序扫码之后进行语音播报,使用uni.createInnerAudioContext方法,并不是一帆风顺的,所以记录一下。

需要注意的点

  • 全局使用一个音频实例(uni 官方建议这种方法,因为频繁切换 src,可能会出现-99 的错误)
  • 语音播放过程中,调用uni.scanCode会中断语音
  • 据测试,ios直接播放,会出现延迟播放的情况,项目里面使用uni.downloadFile将资源下载下来,再播放可以有效缓解该问题
  • ios直接进行播放,可能是由于音频资源没准备好,可能会直接进入到onError,这时根据错误码重新调用播放即可。 碰到的两种错误信息如下:
  1. {"errMsg": "operateAudio:fail jsapi has no permission, event=operateAudio, runningState=background, permissionMsg=permission got, detail=jsapi has no permission, appId=wxd161895220febc6f", "errCode": -1}

  2. {"errMsg": "operateAudio:fail audioInstance is not set", "errCode": -1}

代码示例

ts 复制代码
import { onUnload } from "@dcloudio/uni-app";
let innerAudioContext: any = null;
// 销毁音频
const destroyAudio = () => {
  if (innerAudioContext) {
    innerAudioContext.stop();
    innerAudioContext.destroy();
    innerAudioContext = null;
  }
};
// 创建音频
const createAudio = (audioSrc: string) => {
  destroyAudio(); // 每次创建将上一个实例销毁
  innerAudioContext = uni.createInnerAudioContext();
  innerAudioContext.src = audioSrc;
  // 播放事件
  innerAudioContext.onPlay(() => {
    console.log("play audio");
  });
  // 播放结束事件
  innerAudioContext.onEnded(() => {
    console.log("ended audio");
  });
  // 播放错误事件
  innerAudioContext.onError((error: any) => {
    console.log("play audio error", error);
    // 兼容ios(估计是官方bug),可能是ios资源没准备好时,播放会发生错误返回errCode为-1,这时需要重新播放,直至播放成功
    if (error.errCode === -1) {
      createAudio(audioSrc);
    } else {
      // 比如文件不存在等情况,会进入到这个提示
      uni.showToast({
        title: "播放失败:" + error.errMsg,
        icon: "none",
      });
    }
  });
  innerAudioContext.play();
};
const downloadAudio = (fileName: string) => {
  if (!fileName) {
    return;
  }
  // 扫码失败时接口返回一个音频文件名,通过文件名拼接成完整的音频地址
  const audioUrl = "https://xxx.com/static/" + fileName;
  // 先将资源下载下来,在ios下播放速度会更快(经本人测试,不下载,直接播放,ios机型会有明显的延迟播放行为)
  uni.downloadFile({
    url: audioUrl,
    success: ({ tempFilePath }) => {
      createAudio(tempFilePath);
    },
  });
};
const onScan = () => {
    uni.scanCode({
        success(res) {
            // 扫码结果
            scanCheck(res.result);
        },
    });
};
const scanCheck = (code: string) => {
  // 发送扫码请求
  scanRequest(code)
    .then(() => {
      // 扫码成功之后,每隔1s进行一次扫码
      setTimeout(() => onScan(), 1000);
      uni.showToast({
        title:"扫码成功",
        icon:'none',
        mask:true
      }
      );
    })
    .catch((res) => {
      // 扫码失败之后,利用接口返回的文件名创建语音实例,播报音频
      downloadAudio(res.fileName);
      uni.showToast({
        title:res.msg|| "扫码失败",
        icon:'none',
        mask:true,
        duration:2000
      }
    });
};
onUnload(() => {
  // 页面卸载时销毁音频
  destroyAudio();
});
相关推荐
晓夜残歌24 分钟前
安全基线-rm命令防护
运维·服务器·前端·chrome·安全·ubuntu
inxunoffice1 小时前
批量删除 PPT 空白幻灯片页面
前端·powerpoint
Setsuna_F_Seiei3 小时前
前端切图仔的一次不务正业游戏开发之旅
前端·游戏·cocos creator
laimaxgg3 小时前
Qt窗口控件之颜色对话框QColorDialog
开发语言·前端·c++·qt·命令模式·qt6.3
爱编程的鱼3 小时前
Unity—从入门到精通(第一天)
前端·unity·ue5·游戏引擎
默默无闻 静静学习3 小时前
sass介绍
前端·sass
大怪v4 小时前
前端佬们,装起来!给设计模式【祛魅】
前端·javascript·设计模式
vvilkim4 小时前
Vue.js 插槽(Slot)详解:让组件更灵活、更强大
前端·javascript·vue.js
学无止境鸭4 小时前
uniapp报错 Right-hand side of ‘instanceof‘ is not an object
前端·javascript·uni-app
豆豆(设计前端)4 小时前
一键秒连WiFi智能设备,uni-app全栈式物联开发指南。
前端