报警声音逻辑 demo

模拟后端 websocket 推送数据,判断播报类型,执行对应播报方法,demo 记录

 

/**
 * 报警流程 demo 测试
 * setTimeout 模拟 websocket 推送报警数据
 * 随机产生播放 音频|语音 类型数据
 * 随机 循环次数,1次=1 | 3次=2 | 5次=3 | 单次循环=0(此项会保留做重复播放,其他数据播放完成会进行删除操作)
 * 增加对应功能控制按钮:推送,开始播放,停止播放
 * 增加清除正在播放,重新接收播放最新报警数据
 */
export class AlarmTest {
    // 定时器
    timer = null;
    // 存储播放语音数据数组
    list = [];
    // 当前执行播放数组语音下标
    index = 0;
    // 是否在执行播放
    isPlaying = false;
    // 是否已播放完成,等待新队列数据
    isWaiting = false;
    alarmValue = 0;
    // 报警上限(超出报警)
    alarmLimit = 50;
    // 生成报警数据时间间隔 ms
    alarmStep = 2000;
    // audio 元素
    audioEle = null;

    // audio 元素 addEventListener 绑定的回调函数
    audioEndedCallback = () => {
        // 增加数组清空判断(因为随时可以停止,防报错)
        if (this.list.length) {
            // 如果当前播放数据不是 单次循环,则移除
            if (this.list[this.index - 1].loopType) {
                console.log('删除:', this.list[this.index - 1]);
                this.list.splice(--this.index, 1);
            }
            // 继续调用播放
            this.doAlarm();
        }
    }

    constructor() {
        // 获取 audio 元素
        this.audioEle = this.getAudioEle();
        // 添加按钮执行数据推送
        this.addButton();
    }

    /**
     * 获取 audio 元素,方便后面调用
     */
    getAudioEle() {
        $('body').append(`<audio id="audio" src=""></audio>`);
        return document.getElementById("audio");
    }

    /**
     * 添加功能按钮
     */
    addButton() {
        // 点击开始流程
        let self = this;
        let body = $('body');
        let style = 'margin-left:10px;';
        let push = 'push';
        body.append(`<button class="${ push }" style="${ style }">${ push }</button>`);
        $(`.${ push }`).on('click', function (e) {
            console.log('数据推送');
            // 执行数据推送
            self.websocket();
        });
        let stopPush = 'stopPush';
        body.append(`<button class="${ stopPush }" style="${ style }">${ stopPush }</button>`);
        $(`.${ stopPush }`).on('click', function (e) {
            console.log('停止推送');
            clearTimeout(self.timer);
        });
        // 开始播报
        let begin = 'begin';
        body.append(`<button class="${ begin }" style="${ style }">${ begin }</button>`);
        $(`.${ begin }`).on('click', function (e) {
            console.log('开始播报');
            self.isPlaying = true;
            // 执行报警逻辑
            self.doAlarm();
        });
        // 停止播报
        let stop = 'stop';
        body.append(`<button class="${ stop }" style="${ style }">${ stop }</button>`);
        $(`.${ stop }`).on('click', function (e) {
            console.log('停止播报');
            // 标记停止播放
            self.isPlaying = false;
            // 手动关闭时,需更新等待为 false,防止 websocket 数据重复调用
            self.isWaiting = false;
            // 清空
            self.audioEle.src = '';
            window.speechSynthesis.cancel();
        });
        // 清除当前播报的声音对列
        let clear = 'clear';
        body.append(`<button class="${ clear }" style="${ style }">${ clear }</button>`);
        $(`.${ clear }`).on('click', function (e) {
            console.log('清除播报');
            // 标记停止播放
            self.isPlaying = false;
            // 清空
            self.audioEle.src = '';
            window.speechSynthesis.cancel();
            self.list = [];
            self.index = 0;
        });
    }

    /**
     * 模拟生成随机报警变量值
     */
    websocket() {
        this.timer = setTimeout(() => {
            this.alarmValue = Math.round(Math.random() * 100);
            const text = '报警值:' + this.alarmValue;
            console.log(text);
            if (this.alarmValue > this.alarmLimit) {
                // 超限,执行报警,模拟传入报警数据 type 0 || 1
                let temp = {
                    id: new Date().getTime(),
                    // enableAlarmSound: Math.round(Math.random()), // 是否播放音频
                    // enableAlarmText: Math.round(Math.random()), // 是否播放语音
                    enableAlarmSound: 1, // 是否播放音频
                    enableAlarmText: 1, // 是否播放语音
                    loopType: Math.floor(Math.random() * 3), // 循环类型: 0-单次循环 | 1-1次 | 2-3次 | 3-5次
                    description: text
                };
                this.handleAlarmData([ temp ]);
            }
            clearTimeout(this.timer);
            this.websocket();
        }, this.alarmStep);
    }

    /**
     * 处理报警数据
     * @param data Array
     */
    handleAlarmData(data) {
        // 将获得的报警数据,整理进数组
        data.forEach(item => {
            let temp = null;
            // loopType 0 | 1 值默认为 1
            let count = 1;
            switch (item.loopType) {
                case 2:
                    count = 2; // 正常为3,此用于测试
                    break;
                case 3:
                    count = 3; // 正常为5,此用于测试
                    break;
            }
            // loopType 如果为0,则播一次;其他类型按次数即可
            if (count) {
                for (let i = 0; i < count; i ++) {
                    // 此目的为整理成通用数据结构
                    if (item.enableAlarmSound) {
                        // 如果播放音频,则压入一条音频数据
                        temp = {
                            id: item.id,
                            type: 'audio',
                            description: item.description,
                            src: './assets/audio/yisell_sound.mp3',
                            loopType: item.loopType,
                            index: i,
                        }
                        this.list.push(temp);
                    }
                    if (item.enableAlarmText) {
                        temp = {
                            id: item.id,
                            type: 'speech',
                            description: item.description,
                            loopType: item.loopType,
                            index: i,
                        }
                        this.list.push(temp);
                    }
                }
            }
        });

        // 如果在等待且没有播放,则调用播放
        if (this.isWaiting && !this.isPlaying && this.list.length) {
            this.isWaiting = false;
            this.isPlaying = true;
            this.doAlarm();
        }
    }

    /**
     * 执行报警逻辑
     */
    doAlarm() {
        if (!this.isPlaying) {
            // 停止
            return false;
        }
        let temp = this.list[this.index];
        console.log('current play: ', temp);
        if (!temp) {
            // 已播放到队尾,重置 index
            this.index = 0;
            if (this.list.length) {
                // 如果list 有值,则继续播放
                console.log('循环,重置 index 为 0');
                this.doAlarm();
                return false;
            } else {
                // 无值则停播并等待
                this.isPlaying = false;
                this.isWaiting = true;
                return false;
            }
        }
        // 下标自增
        this.index++;
        // 根据数据类型,执行对应播放方法
        switch (temp.type) {
            case 'audio': // 音频
                this.doAudioAlarm(temp.src);
                break;
            case 'speech': // 语音
                this.doSpeechAlarm(temp.description);
                break;
        }
    }

    /**
     * 执行音频播放
     * @param src
     */
    doAudioAlarm(src) {
        this.audioEle.src = src;
        // 监听 audio 播放完成事件
        let self = this;
        // 单纯绑定回调方法,会执行多次;所以将方法保存致变量,即实现绑定一次效果
        this.audioEle.addEventListener('ended', self.audioEndedCallback);
        // 执行播放
        this.audioEle.play();
    }

    /**
     * 执行语音播放
     * @param des
     */
    doSpeechAlarm(des) {
        let speech = new window.SpeechSynthesisUtterance();
        speech.text = des;
        // 监听语音播放完成
        speech.onend = this.audioEndedCallback;
        // 执行播放
        window.speechSynthesis.speak(speech);
    }
}

 

 

 

posted @ 2022-06-30 10:22  名字不好起啊  阅读(41)  评论(0编辑  收藏  举报