报警声音逻辑 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); } }