当前位置: 首页 > news >正文

Uniapp 小程序:语音播放与暂停功能的实现及优化方案

界面部分

//开启语音 
<button class="open" v-if="showPlay==false" @click="playText">这是开启播放的图片</button >

//关闭语音 
<button class="close" v-if="showPlay==true" @click="stopText">这是关闭播放的图片</button >

播放语音方法 playText

该方法用于处理语音播放的逻辑,包括内容截断、分割、重试机制等。

playText: function() {
    // 检查是否正在等待响应,如果是则提示用户等待
    // 切换显示为正在播放状态
    this.showPlay = true; 
    // 初始化重试次数
    let retryCount = 0; 
    // 设置最大重试次数
    const maxRetryTimes = 3; 
    // 重试间隔时间(单位:毫秒)
    const retryInterval = 2000; 
    // 假设最大允许的内容长度,可根据实际调整
    const maxContentLength = 100; 

    // 截断内容的函数,如果内容长度超过最大允许长度,则截取前 maxContentLength 个字符
    const truncateContent = (content) => {
        if (content.length > maxContentLength) {
            return content.slice(0, maxContentLength);
        }
        return content;
    };

    // 分割内容的函数,将长内容按合适的分割符号(。!,?)分割成多个部分
    const splitContent = (content) => {
        const parts = [];
        let start = 0;
        while (start < content.length) {
            let end = start + maxContentLength;
            if (end >= content.length) {
                parts.push(content.slice(start));
                break;
            }
            // 从后往前查找合适的分割符号(。!,?)
            let symbolIndices = [content.lastIndexOf('。', end), content.lastIndexOf('!', end), content
               .lastIndexOf('?', end), content.lastIndexOf(',', end)
            ];
            symbolIndices = symbolIndices.filter(index => index > start);
            if (symbolIndices.length > 0) {
                end = Math.max(...symbolIndices);
            }
            parts.push(content.slice(start, end));
            start = end + 1;
        }
        return parts;
    };

    // 播放分割后的内容部分的函数
    const playParts = (parts) => {
        let index = 0;
        const playNextPart = () => {
            if (index < parts.length) {
                const part = parts[index];
                const plugin = requirePlugin('WechatSI');
                // 调用文字转语音插件
                plugin.textToSpeech({
                    lang: 'zh_CN',
                    tts: true,
                    content: part,
                    success: (res) => {
                        // 创建内部音频上下文并播放音频
                        this.innerAudioContext = uni.createInnerAudioContext();
                        this.innerAudioContext.src = res.filename;
                        this.innerAudioContext.play();
                        // 监听音频播放结束事件,播放下一部分
                        this.innerAudioContext.onEnded(() => {
                            index++;
                            playNextPart();
                        });
                    },
                    fail: (res) => {
                        console.log('文字转语音失败', res);
                        if (retryCount < maxRetryTimes) {
                            retryCount++;
                            console.log(`正在进行第${retryCount}次重试...`);
                            // 重试播放
                            setTimeout(() => playNextPart(), retryInterval);
                        } else {
                            console.log('已达到最大重试次数,文字转语音仍失败');
                        }
                    }
                });
            } else {
                // 所有部分播放完毕,切换显示为可播放状态
                this.showPlay = false; 
            }
        };
        playNextPart();
    };

    // 截断内容
    const truncatedContent = truncateContent(this.readContent);
    // 分割内容
    const splitContents = splitContent(this.readContent);
    if (splitContents.length > 1) {
        // 如果分割后的内容部分大于 1,则按部分播放
        playParts(splitContents);
    } else {
        // 内容较短,直接播放
        const retryFn = () => {
            if (retryCount < maxRetryTimes) {
                retryCount++;
                console.log(`正在进行第${retryCount}次重试...`);
                const plugin = requirePlugin('WechatSI');
                // 调用文字转语音插件
                plugin.textToSpeech({
                    lang: 'zh_CN',
                    tts: true,
                    content: truncatedContent,
                    success: (res) => {
                        // 创建内部音频上下文并播放音频
                        this.innerAudioContext = uni.createInnerAudioContext();
                        this.innerAudioContext.src = res.filename;
                        this.innerAudioContext.play();
                    },
                    fail: (res) => {
                        console.log('文字转语音失败', res);
                        // 重试播放
                        setTimeout(retryFn, retryInterval);
                    }
                });
            } else {
                console.log('已达到最大重试次数,文字转语音仍失败');
            }
        };
        const plugin = requirePlugin('WechatSI');
        // 调用文字转语音插件
        plugin.textToSpeech({
            lang: 'zh_CN',
            tts: true,
            content: truncatedContent,
            success: (res) => {
                // 创建内部音频上下文并播放音频
                this.innerAudioContext = uni.createInnerAudioContext();
                this.innerAudioContext.src = res.filename;
                this.innerAudioContext.play();
            },
            fail: (res) => {
                console.log('文字转语音失败', res);
                // 重试播放
                setTimeout(retryFn, retryInterval);
            }
        });
    }
}

暂停语音方法 stopText

该方法用于停止语音播放并释放资源。

stopText() {
    // 切换显示为可播放状态
    this.showPlay = false;
    if (this.innerAudioContext) {
        // 停止播放
        this.innerAudioContext.stop(); 
        // 释放资源
        this.innerAudioContext = null; 
    }
}

页面隐藏和卸载时的处理

在页面隐藏和卸载时,调用 stopText 方法停止语音播放。

onHide() {
    this.stopText()
},
onUnload() {
    this.stopText()
}

总结
这段代码实现了语音播放和暂停的功能,通过界面上的按钮触发相应的操作。在播放语音时,会对内容进行截断和分割处理,以适应文字转语音插件的要求。同时,为了提高稳定性,添加了重试机制。在页面隐藏和卸载时,会自动停止语音播放并释放资源。

相关文章:

  • 相同的树-
  • 15.5 基于 RetrievalQA 的销售话术增强系统实战:构建智能销售大脑
  • RAG项目实战:金融问答系统
  • 数据存储:使用Python存储数据到redis详解
  • js 获取节点相对于屏幕的坐标位置,获取节点的宽高,获取鼠标事件回调的鼠标位置,计算鼠标相对于某个节点下的坐标
  • 【量化科普】Leverage,杠杆
  • Java中的锁机制:synchronized vs ReentrantLock,如何选择?
  • Python 函数式编程-装饰器
  • css中overflow-x:auto无效
  • 一周学会Flask3 Python Web开发-Jinja2模版中加载静态文件
  • 快速理解Raft分布式共识算法
  • CAS (Compare and swap “比较和交换“) [ Java EE 初阶 ]
  • 【借助深度学习剖析股票数据,实现优质股涨幅预测及推送通知】
  • 用PySpark和PyTorch实现跨境支付Hive数据仓库的反洗钱数据分析
  • python基础学习day01
  • JavaScript基础(BOM对象、DOM节点、表单)
  • javascript-es6 (五)
  • redission的原理
  • JS UI库DHTMLX Suite 发布v9.1:具有行扩展器、多重排序、多用户后端等功能的网格
  • 《算法笔记》9.6小节 数据结构专题(2)并查集 问题 A: 通信系统
  • 中国结算澄清“严查场外配资”传闻:账户核查为多年惯例,无特殊安排
  • 中国科学院院士、我国航天液体火箭技术专家朱森元逝世
  • 前四个月社会融资规模增量累计为16.34万亿元,比上年同期多3.61万亿元
  • 女外交官郑璇已任中国驻莫桑比克大使
  • 极限拉扯上任巴西,安切洛蒂开启夏窗主帅大挪移?
  • 云南大理铁路枢纽工程建设取得两大进展,预计明年建成