微信小程序web-view 外部引用h5页面调用摄像头录制视频 配有提示音

1、目前的需求是什么

因为项目是银行审批贷款的,所以需要一个视频面签的功能,进入页面时,用户点击开始录制,会提示有第一个问题提示音,用户回答,点击下一个问题,会有第二个,没有问题时,会有结束录制按钮,结束后可以看回放,再点击上传就可以提交到后台了。

2、都踩了那些坑

1、小程序

因为之前没有做过视频录制,对这一块不是很熟悉,先用的是微信小程序页面内直接做的,用的是小程序内置的组件,功能完成后发现最长只能录制30秒,比较鸡肋,重新找解决方案。

2、h5语音提示

后来就想着web-view 外部引用一个h5点页面吧,然后就看到了 recordrtc 这个,发现可以用,挺好,就开始用这个,然后接下来就开始用语音提示,用的是h5,因为我手机是ios 的 ,我在我手机上边测试都是没有问题的,然后就用同时手机测了一下,发现没有声音,我的手机是正常的,后来发现 好像 h5的语音合成好像不支持安卓?换掉,用的是 百度提示的。

3、语音合成声音录制不进去,ios有时候是麦克风,有时候是听筒发音!

调用百度api后,安卓这边录制都是没有问题的,ios这边有时候是听筒发音,有时候是麦克风发音,就好奇怪,好气,后来我让后台这边调用百度api语音合成,暂存服务器,我直接获取就可以了,ok解决问题。

4、语音合成声音录制不进去。

这边声音都正常后,看录制回放的时候,发现语音提示音录制不进去,被降噪了!人傻了。
后来找了好久,发现了一个设置的地方(之前没做过这块,所以不是很懂,别喷),就是录制的时候可以在audio中设置

      captureCamera(callback) {
       navigator.mediaDevices.getUserMedia({
         audio: { volume: { min: 0.0, max: 1.0 }, noiseSuppression: false, echoCancellation: false },
         video: { facingMode: "user" }
       }).then((camera) => {
         callback(camera);
       }).catch(function (error) {
         alert('Unable to capture your camera. Please check console logs.');
         console.error(error);
       });
     },

这样声音就好了

5、以为这样这样就结束了码?没有!ios结束的时候 有时候会不能点击结束

因为我这边问题又很多个,最后发现,在4个问题的时候是可以点击结束的,在4个以上的时候是不能点击结束的,它也不报错,然后debugger,下载recordrtc .js 研究源文件代码,发现是因为在事实结束后,会有个回调函数的,但是这边是没有回调的,

 mediaRecorder.ondataavailable  //这个应该是会自己回调的,但是没有

我以为要凉了,后来找大神指点
因为我这个是官网例子改写的,用的是这样录制的

that.recorder = RecordRTC(camera, {
            //   type: 'video'
            // })

大神将这串代码改成了

           var config = {
              mimeType: 'video/webm', // vp8, vp9, h264, mkv, opus/vorbis
              audioBitsPerSecond : 256 * 8 * 1024,
              videoBitsPerSecond : 256 * 8 * 1024,
              bitsPerSecond: 256 * 8 * 1024,  // if this is provided, skip above two
              checkForInactiveTracks: true,
              timeSlice: 1000, // concatenate intervals based blobs
              ondataavailable: function() {} // get intervals based blobs
            }
            that.recorder = new MediaStreamRecorder(camera, config);

功能就可以使用了!

因为最近都是在用vue 开发,原生的都不是很熟练,所以虽然是一个单页面应用,我用的还是vue axios…别喷
上全套代码

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.bootcdn.net/ajax/libs/RecordRTC/5.6.2/RecordRTC.js"></script>
<script crossorigin="anonymous"
 integrity="sha512-qRXBGtdrMm3Vdv+YXYud0bixlSfZuGz+FmD+vfXuezWYfw4m5Ov0O4liA6UAlKw2rh9MOYULxbhSFrQCsF1hgg=="
 src="https://lib.baomitu.com/vue/2.6.14/vue.common.dev.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js"></script>
<style type="text/css">
   .demo {
   width: 80%;
   height: 20px;
   position: absolute;
   top: 480px;
   left: 6%;
   border: 2px solid #BBDEFB;
   border-radius: 8px;
 }

 .shixin {
   width: 0;
   height: 0;
   border: 8px solid transparent;
   border-bottom-color: #BBDEFB;
   position: relative;
   top: -39px;
   left: 9%;
 }

 .kongxin {
   width: 0;
   height: 0;
   border: 8px solid transparent;
   border-bottom-color: #fff;
   position: relative;
   top: -52px;
   left: 9%;
 }
 .center {
   display: flex;
   justify-content: center;
 }

 audio {
   display: none;
 }

 button {
   width: 70%;
   padding: 3px;
   background-color: #428bca;
   border-color: #357ebd;
   color: #fff;
   -moz-border-radius: 10px;
   -webkit-border-radius: 10px;
   border-radius: 15px;
   /* future proofing */
   -khtml-border-radius: 10px;
   /* for old Konqueror browsers */
   text-align: center;
   vertical-align: middle;
   border: 1px solid transparent;
   font-weight: 900;
   font-size: 125%
 }
</style>
<title></title>
</head>

<body>
<div id="app">
 <h4 class="center">视频认证</h4>
 <hr>
 <video controls autoplay playsinline ref="video" width="100%" height="400px"></video>
 <div  v-if="showIos" class="demo" style="text-align: center;">
   <span > 请点击开始按钮</span>
   <div class="shixin"></div>
   <div class="kongxin"></div>
 </div>
 <span class="center"  style="margin-top: 30px;" v-show="nextQuestion">{{value}}</span>
 <div class="center" style="margin-top: 30px;">
   <button @click="StartRecording" v-if="startRecording" size="small">开始视频认证</button>
   <button @click="StopRecording" v-else-if="stopRecording" size="small" id="btn-stop-recording">结束视频认证
   </button>
   <button @click="question(problem)" v-else-if="nextQuestion">{{nameButton}}</button>
   <button v-else>上传视频</button>
   </button>
 </div>
</div>
<script>
 new Vue({
   el: '#app',
   //model
   data: {
     nameButton: "开始提问",
     startRecording: true,
     stopRecording: false,
     nextQuestion: false,
     index: 0,
     video: null,
     value: "",
     equipmentType:"",
     videoStart: false,
     recorder: null,
     blob: "",
     showIos:false,
     problem: [
       "请问您是李先生或女士吗?您的身份证号码是11111111122吗?",
       "您此次购买的车型是奔驰E300吗?",
       "您的家人是否知晓并同意您办理的此笔个人汽车金融贷款业务?",
       "您对此笔个人汽车金融贷款业务是否仍存有异议?",
       "如您未按时足额偿还每期月供,将会产生逾期,影响您的央行征信,是否已知晓?",
       "办理此笔汽车金额贷款是您本人的真实意识表达,承诺提供资料均真实有效,若存在欺诈行为,xxxx有权以合同诈骗提报公安机关立案侦查并追究相应的法律责任,您是否已知晓?",
     ]
   },
   //函数
   mounted() {
     this.video = document.querySelector('video');
     this. detect()
   },
   methods: {
     detect() {
       var agent = navigator.userAgent.toLowerCase();
       var android = agent.indexOf("android");
       var iphone = agent.indexOf("iphone");
       var ipad = agent.indexOf("ipad");
       if (android != -1) {
         this.equipmentType = "android";
       }
       if (iphone != -1 || ipad != -1) {
         this.equipmentType = "ios";
       }
       return this.equipmentType;
     },
     question(problem) {
       this.nameButton = "下一个问题"
       this.value = problem[this.index]

       this.baiduToken(this.value)
       if (this.index < (problem.length - 1)) {
         this.index = this.index + 1
       } else {
         this.nextQuestion = false
         this.stopRecording = true
       }
     },
     baiduToken(value) {
       axios.get(`xxxxx?text=${value}`   //向后台调用获取音频路径 ,如果是测试的可以先写一个固定的本地因为路径
       ).then(response => {
         if (response.status === 200) {
           // this.src = response.data.msg
           this.Audio(response.data.msg)
         } else {
           alert(response)
         }
       })

     },
 
     Audio(src) {
       console.log("111", src)
       var audio = document.createElement('audio');
       audio.autoplay = true;
       audio.preload = true;
       audio.controls = true;
       audio.src = src;
       // this.src =
       audio.addEventListener('ended', function () {
         // 设置则播放完后移除audio的dom对象
         document.body.removeChild(audio);
       }, false);
       audio.addEventListener('error', function () {
         document.body.removeChild(audio);
         console.log('合成出错url:' + this.src + '\nAudio错误码:' + audio.error.code);
       }, false);
       audio.loop = false;
       audio.volume = 1;
       // 在body元素下apppend音频控件
       document.body.append(audio);
     },
     stopRecordingCallback() {

       this.video.src = this.video.srcObject = null;
       this.video.muted = false;
       this.video.volume = 1;
       // let Blob = this.recorder.getBlob()
       console.log("let ", this.blob)
       this.video.src = URL.createObjectURL(this.blob);
       this.recorder.camera.stop();
       this.recorder.destroy();
       this.recorder = null;
       this.stopRecording = false
       // alert("点击了3")
     },
     StartRecording() {
       if(this.equipmentType ==="ios" ){
         this.showIos = true
       }
       let that = this
       this.startRecording = false
       this.nextQuestion = true
       this.captureCamera((camera) => {
         that.video.muted = true;
         that.video.volume = 0;
         that.video.srcObject = camera;
         var config = {
           mimeType: 'video/webm', // vp8, vp9, h264, mkv, opus/vorbis
           audioBitsPerSecond : 256 * 8 * 1024,
           videoBitsPerSecond : 256 * 8 * 1024,
           bitsPerSecond: 256 * 8 * 1024,  // if this is provided, skip above two
           checkForInactiveTracks: true,
           timeSlice: 1000, // concatenate intervals based blobs
           ondataavailable: function() {} // get intervals based blobs
         }
         that.recorder = new MediaStreamRecorder(camera, config);

         that.recorder.record();
         // release camera on stopRecording
         that.recorder.camera = camera;
       });
     },
     StopRecording() {
       let that = this
       // console.log("this", this.blob)
       // console.log("1111".this.recorder.stopRecording())
       this.recorder.stop(
         function (blob) {
           // alert("222")
           console.log("this", this)
           that.blob = blob;
           // that.stopRecordingCallback()
           that.video.src = that.video.srcObject = null;
           console.log("this.video.srcObject", that.video.srcObject)
           that.video.muted = false;
           that.video.volume = 1;
           // let Blob = this.recorder.getBlob()
           console.log("let ", that.blob)
           that.video.src = URL.createObjectURL(that.blob);
           that.recorder.camera.stop();
           //that.recorder.destroy();
           that.recorder = null;
           that.stopRecording = false
         }
       )
     },

     captureCamera(callback) {
       navigator.mediaDevices.getUserMedia({
         audio: { volume: { min: 0.0, max: 1.0 }, noiseSuppression: false, echoCancellation: false },
         video: { facingMode: "user" }
       }).then((camera) => {
         callback(camera);
       }).catch(function (error) {
         alert('Unable to capture your camera. Please check console logs.');
         console.error(error);
       });
     },

   }
 })
</script>
</body>

</html>

对了,有个小bug,最后一个问题是没有显示的,有语音播报,v-if判断有点问题,你们修改吧~我懒,哈哈哈哈,

如若又描述不清楚、代码不规范之处 ,请指出,

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,针对你的问题,我可以给你一些思路和实现方式。 在微信小程序中,我们可以使用自定义组件来封装一些常用的UI组件或者业务逻辑组件,具体可以参考微信小程序官方文档中的自定义组件部分。而在H5页面中,我们可以使用微信小程序web-view组件嵌入小程序页面,从而实现小程序组件在H5页面中的调用。 接下来,我们需要在小程序中定义一个自定义组件,并将其封装为一个可以在web-view调用的方法。具体实现步骤如下: 1. 在小程序中定义自定义组件,并实现相应的业务逻辑。 2. 在自定义组件中添加一个事件监听器,用来接收来自web-view的消息。 3. 在web-view中使用postMessage()方法发送消息给小程序,消息内容为需要调用的方法名及相应的参数。 4. 在自定义组件中根据接收到的消息内容,调用相应的方法并返回结果给web-view。 下面是一个简单的示例代码: 小程序端代码: ```javascript // 定义自定义组件 Component({ methods: { // 自定义方法 add: function(a, b) { return a + b; }, // 监听web-view发送的消息 onMessage: function(e) { // 解析消息内容 var data = JSON.parse(e.detail.data); // 调用相应的方法并返回结果 if (data.method == 'add') { var result = this.add(data.a, data.b); wx.webViewPostMessage({ data: JSON.stringify({ method: 'add', result: result }) }); } } } }) ``` H5页面端代码: ```javascript // 获取web-view组件 var webview = document.getElementById('webview'); // 发送消息给小程序 webview.contentWindow.postMessage(JSON.stringify({ method: 'add', a: 1, b: 2 }), '*'); // 监听小程序返回的消息 window.addEventListener('message', function(e) { // 解析消息内容 var data = JSON.parse(e.data); // 处理返回结果 if (data.method == 'add') { console.log('1 + 2 = ' + data.result); } }); ``` 通过以上代码实现,我们就可以在H5页面调用小程序中封装的方法了。需要注意的是,为了保证安全性,我们在发送消息时需要指定目标源,所以在postMessage()方法中需要指定'*'或者目标web-view的src属性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值