记录---uniapp 安卓端实现录音功能,保存为amr/mp3文件

🧑‍💻 写在开头

点赞 + 收藏 === 学会🤣🤣🤣

功能实现需要用到MediaRecorder、navigator.mediaDevices.getUserMedia、Blob等API,uniapp App端不支持,需要借助renderjs来实现

实现逻辑

  1. 通过navigator.mediaDevices.getUserMedia调用设备麦克风,获取音频流
  2. 使用MediaRecorder录制音频数据
  3. Blob、FileReader将音频数据转为转为base64格式
  4. 调用fs.root.getFile创建空白amr/mp3文件
  5. 通过h5plus调用安卓APIjava.io.FileOutputStream将数据保存进文件中

代码实现

获取音频流

申请媒体权限

首先需要提前申请下权限。App 端调用navigator.mediaDevices.getUserMedia时不像浏览器上会弹框申请权限,插件市场有官方提供的免费插件:App权限判断和提示 - DCloud 插件市场


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
async onLoad() {
    // 申请麦克风权限
    let isRecord = await permision.requestAndroidPermission('android.permission.RECORD_AUDIO')
     
    if (isRecord == -1) {
        uni.showModal({
            title: '提示',
            content: '未获取到麦克风权限,可能导致应用运行出现问题',
            confirmText: '去开启',
            cancelText: "暂不开启",
            success: res => {
                if (res.confirm) {
                    // 跳转权限页面
                    permision.gotoAppPermissionSetting()
                }
            }
        })
    }
}

获取音频流代码

mediaRecorder.start(60 * 1000); 表示60秒执行一次ondataavailable,可用来实现分段录制。不传参数则只在stop时执行一次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<script lang="renderjs">
export default {
    async startRecord() {
        try {
            let localStream = await navigator.mediaDevices.getUserMedia({
                video: false
                audio: true,
            });
            let mediaRecorder = new MediaRecorder(localStream);
  
            mediaRecorder.ondataavailable = event => {
                const blob = new Blob([event.data]);
                 
                var reader = new FileReader();
                reader.readAsDataURL(blob);
                reader.onload = (e) => {
                    let base64str = e.target.result
                    // 调用外层script中的base64ToFile方法,将base64传入。
                    this.$ownerInstance.callMethod('base64ToFile', base64str)
                }
            }
            // 录制停止
            mediaRecorder.onstop = (e) => { }
 
            mediaRecorder.start(60 * 1000); // 60秒执行一次ondataavailable,可实现分段录制,不传参数只在stop时执行一次
        } catch (e) {
            console.log('麦克风权限获取失败')
        }
    }
}
</script>

保存amr/mp3文件

  • 文件保存在uniapp_save文件夹下可以通过uni.getSavedFileList方法获取到。
  • plus.io.PRIVATE_DOC 位置参考:内部存储>Android>data>io.dcloud.HBuilder>apps>HBuilder>doc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<script>
    export default {
        base64ToFile(base64Str, fileName = `uniapp_save/${new Date().valueOf()}.amr`) {
            // 去除base64前缀 
            var index = base64Str.indexOf(',')
            var base64Str = base64Str.slice(index + 1, base64Str.length)
 
            plus.io.requestFileSystem(plus.io.PRIVATE_DOC, function(fs) {
                fs.root.getFile(fileName, {
                    create: true
                }, function(entry) {
                    // 获得本地路径URL,file:///xxx/doc/1663062980631.amr 
                    var fullPath = entry.fullPath;
                    var FileOutputStream = plus.android.importClass("java.io.FileOutputStream");
                    try {
                        function base64ToByteArray(base64Str) {
                            const binaryString = atob(base64Str);
                            const uint8Array = new Uint8Array(binaryString.length);
 
                            for (let i = 0; i < binaryString.length; i++) {
                                uint8Array[i] = binaryString.charCodeAt(i);
                            }
                            let arr = []
                            Array.from(uint8Array).map(num => {
                                arr.push(num >= 128 ? (num - 256) : num)
                            })
                            return arr;
                        }
                        var out = new FileOutputStream(fullPath);
                        let bytes = base64ToByteArray(base64Str);
                        if (bytes == null || bytes.length == 0) {
                            out.close();
                            uni.hideLoading();
                            uni.showModal({
                                title: "生成失败",
                                content: "nativeJS限制参数长度无法获取文件!",
                                showCancel: false
                            })
                            return
                        } else {
                            out.write(bytes);
                            out.close();
                             
                            console.log(`保存成功,文件地址为:_doc/${fileName}`)
                        }
                    } catch (e) {
                        console.log(e.message);
                    }
                })
            })
        }
    }
</script>

参考资料

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 

posted @   林恒  阅读(417)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· 【全网最全教程】使用最强DeepSeekR1+联网的火山引擎,没有生成长度限制,DeepSeek本体
历史上的今天:
2023-12-23 记录--前端验证码破解
2020-12-23 uni-app开发经验分享十六:发布android版App的详细过程
欢迎阅读『记录---uniapp 安卓端实现录音功能,保存为amr/mp3文件』
点击右上角即可分享
微信分享提示