@ezuikit/control-broadcast 0.1.0-beta.3 → 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +3 -3
- package/dist/index.esm.js +3 -3
- package/dist/index.umd.js +15 -3
- package/dist/style/index.js +3 -0
- package/dist/style/style/broadcast.scss +323 -0
- package/dist/style/style.css +1 -0
- package/dist/style/style.js +6 -0
- package/dist/types/index.d.ts +277 -220
- package/package.json +12 -6
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* @ezuikit/control-broadcast
|
|
3
|
-
* Copyright (c) 2026-
|
|
2
|
+
* @ezuikit/control-broadcast v1.0.0-beta.1
|
|
3
|
+
* Copyright (c) 2026-11-14 15:37:02 Ezviz-OpenBiz
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
6
|
-
"use strict";var EventEmitter=function(){function EventEmitter(){this.events=new Map}var _proto=EventEmitter.prototype;return _proto.on=function(event,callback){this.events.has(event)||this.events.set(event,[]),this.events.get(event).push(callback)},_proto.off=function(event,callback){if(this.events.has(event)){var callbacks=this.events.get(event),index=callbacks.indexOf(callback);index>-1&&callbacks.splice(index,1),0===callbacks.length&&this.events.delete(event)}},_proto.emit=function(event){for(var _len=arguments.length,args=new Array(_len>1?_len-1:0),_key=1;_key<_len;_key++)args[_key-1]=arguments[_key];this.events.has(event)&&this.events.get(event).forEach(function(callback){try{callback.apply(void 0,[].concat(args))}catch(error){}})},_proto.once=function(event,callback){var _this=this,onceCallback=function(){for(var _len=arguments.length,args=new Array(_len),_key=0;_key<_len;_key++)args[_key]=arguments[_key];callback.apply(void 0,[].concat(args)),_this.off(event,onceCallback)};this.on(event,onceCallback)},_proto.removeAllListeners=function(){this.events.clear()},_proto.listenerCount=function(event){var _this_events_get;return(null==(_this_events_get=this.events.get(event))?void 0:_this_events_get.length)||0},EventEmitter}();function _array_like_to_array(arr,len){(null==len||len>arr.length)&&(len=arr.length);for(var i=0,arr2=new Array(len);i<len;i++)arr2[i]=arr[i];return arr2}function asyncGeneratorStep$2(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg),value=info.value}catch(error){return void reject(error)}info.done?resolve(value):Promise.resolve(value).then(_next,_throw)}function _async_to_generator$2(fn){return function(){var self=this,args=arguments;return new Promise(function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep$2(gen,resolve,reject,_next,_throw,"next",value)}function _throw(err){asyncGeneratorStep$2(gen,resolve,reject,_next,_throw,"throw",err)}_next(void 0)})}}function _create_for_of_iterator_helper_loose(o,allowArrayLike){var it="undefined"!=typeof Symbol&&o[Symbol.iterator]||o["@@iterator"];if(it)return(it=it.call(o)).next.bind(it);if(Array.isArray(o)||(it=function(o,minLen){if(o){if("string"==typeof o)return _array_like_to_array(o,minLen);var n=Object.prototype.toString.call(o).slice(8,-1);return"Object"===n&&o.constructor&&(n=o.constructor.name),"Map"===n||"Set"===n?Array.from(n):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?_array_like_to_array(o,minLen):void 0}}(o))||allowArrayLike){it&&(o=it);var i=0;return function(){return i>=o.length?{done:!0}:{done:!1,value:o[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _ts_generator$2(thisArg,body){var f,y,t,_={label:0,sent:function(){if(1&t[0])throw t[1];return t[1]},trys:[],ops:[]},g=Object.create(("function"==typeof Iterator?Iterator:Object).prototype);return g.next=verb(0),g.throw=verb(1),g.return=verb(2),"function"==typeof Symbol&&(g[Symbol.iterator]=function(){return this}),g;function verb(n){return function(v){return function(op){if(f)throw new TypeError("Generator is already executing.");for(;g&&(g=0,op[0]&&(_=0)),_;)try{if(f=1,y&&(t=2&op[0]?y.return:op[0]?y.throw||((t=y.return)&&t.call(y),0):y.next)&&!(t=t.call(y,op[1])).done)return t;switch(y=0,t&&(op=[2&op[0],t.value]),op[0]){case 0:case 1:t=op;break;case 4:return _.label++,{value:op[1],done:!1};case 5:_.label++,y=op[1],op=[0];continue;case 7:op=_.ops.pop(),_.trys.pop();continue;default:if(!(t=_.trys,(t=t.length>0&&t[t.length-1])||6!==op[0]&&2!==op[0])){_=0;continue}if(3===op[0]&&(!t||op[1]>t[0]&&op[1]<t[3])){_.label=op[1];break}if(6===op[0]&&_.label<t[1]){_.label=t[1],t=op;break}if(t&&_.label<t[2]){_.label=t[2],_.ops.push(op);break}t[2]&&_.ops.pop(),_.trys.pop();continue}op=body.call(thisArg,_)}catch(e){op=[6,e],y=0}finally{f=t=0}if(5&op[0])throw op[1];return{value:op[0]?op[1]:void 0,done:!0}}([n,v])}}}var VoiceRecorder=function(){function VoiceRecorder(options){void 0===options&&(options={}),this.options={minDuration:options.minDuration||3,maxDuration:options.maxDuration||59,sampleRate:options.sampleRate||16e3,channelCount:options.channelCount||1},this.audioContext=null,this.mediaStreamSource=null,this.scriptProcessor=null,this.stream=null,this.startTime=0,this.maxTimer=null,this.audioBuffers=[],this.isRecordingFlag=!1,this.isIOSDevice=/iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream,this.mediaRecorder=null,this.recordedChunks=[]}var _proto=VoiceRecorder.prototype;return _proto.start=function(){return _async_to_generator$2(function(){var error;return _ts_generator$2(this,function(_state){switch(_state.label){case 0:if(this.isRecordingFlag)return[2];_state.label=1;case 1:return _state.trys.push([1,3,,4]),[4,this.startWithScriptProcessor()];case 2:return _state.sent(),this.startTime=Date.now(),this.isRecordingFlag=!0,[3,4];case 3:throw error=_state.sent(),this.isRecordingFlag=!1,error;case 4:return[2]}})}).call(this)},_proto.startWithMediaRecorder=function(){return _async_to_generator$2(function(){var _this,_,mimeType;return _ts_generator$2(this,function(_state){switch(_state.label){case 0:return _this=this,_=this,[4,navigator.mediaDevices.getUserMedia({audio:!0})];case 1:return _.stream=_state.sent(),this.recordedChunks=[],mimeType="",MediaRecorder.isTypeSupported("audio/mp4")?mimeType="audio/mp4":MediaRecorder.isTypeSupported("audio/webm")?mimeType="audio/webm":MediaRecorder.isTypeSupported("audio/wav")&&(mimeType="audio/wav"),this.mediaRecorder=new MediaRecorder(this.stream,{mimeType:mimeType||void 0}),this.mediaRecorder.ondataavailable=function(event){event.data.size>0&&_this.recordedChunks.push(event.data)},this.mediaRecorder.start(),[2]}})}).call(this)},_proto.startWithScriptProcessor=function(){return _async_to_generator$2(function(){var _this,audioConstraints,_;return _ts_generator$2(this,function(_state){switch(_state.label){case 0:return _this=this,audioConstraints=this.isIOSDevice?{audio:!0}:{audio:{sampleRate:this.options.sampleRate,channelCount:this.options.channelCount,echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0}},_=this,[4,navigator.mediaDevices.getUserMedia(audioConstraints)];case 1:return _.stream=_state.sent(),this.audioContext=new(window.AudioContext||window.webkitAudioContext)({sampleRate:this.options.sampleRate}),this.mediaStreamSource=this.audioContext.createMediaStreamSource(this.stream),this.scriptProcessor=this.audioContext.createScriptProcessor(4096,1,1),this.audioBuffers=[],this.scriptProcessor.onaudioprocess=function(event){if(_this.isRecordingFlag){var inputData=event.inputBuffer.getChannelData(0);_this.audioBuffers.push(new Float32Array(inputData))}},this.mediaStreamSource.connect(this.scriptProcessor),this.scriptProcessor.connect(this.audioContext.destination),[2]}})}).call(this)},_proto.stop=function(){return _async_to_generator$2(function(){var _this;return _ts_generator$2(this,function(_state){switch(_state.label){case 0:return _this=this,[4,new Promise(function(resolve,reject){if(_this.isRecordingFlag){var duration=(Date.now()-_this.startTime)/1e3;if(duration<_this.options.minDuration)return reject(new Error("录音时长不足"+_this.options.minDuration+"秒")),void _this.cleanup();try{_this.isRecordingFlag=!1,_this.stopWithScriptProcessor(duration,resolve,reject)}catch(error){_this.cleanup(),reject(error)}}else resolve(new Blob([],{type:"audio/wav"}))})];case 1:return[2,_state.sent()]}})}).call(this)},_proto.stopWithMediaRecorder=function(duration,resolve,reject){var _this=this;if(!this.mediaRecorder)return reject(new Error("MediaRecorder 未初始化")),void this.cleanup();this.mediaRecorder.onstop=function(){try{var _this_recordedChunks_,mimeType=(null==(_this_recordedChunks_=_this.recordedChunks[0])?void 0:_this_recordedChunks_.type)||"audio/wav",audioBlob=new Blob(_this.recordedChunks,{type:mimeType});_this.cleanup(),resolve(audioBlob)}catch(error){_this.cleanup(),reject(error)}},this.mediaRecorder.stop()},_proto.stopWithScriptProcessor=function(duration,resolve,reject){try{for(var _step,totalLength=this.audioBuffers.reduce(function(acc,buffer){return acc+buffer.length},0),mergedBuffer=new Float32Array(totalLength),offset=0,_iterator=_create_for_of_iterator_helper_loose(this.audioBuffers);!(_step=_iterator()).done;){var buffer=_step.value;mergedBuffer.set(buffer,offset),offset+=buffer.length}var wavBlob=this.encodeWAV(mergedBuffer,this.options.sampleRate);this.cleanup(),resolve(wavBlob)}catch(error){this.cleanup(),reject(error)}},_proto.encodeWAV=function(samples,sampleRate){var buffer=new ArrayBuffer(44+2*samples.length),view=new DataView(buffer),writeString=function(offset,string){for(var i=0;i<string.length;i++)view.setUint8(offset+i,string.charCodeAt(i))};return writeString(0,"RIFF"),view.setUint32(4,36+2*samples.length,!0),writeString(8,"WAVE"),writeString(12,"fmt "),view.setUint32(16,16,!0),view.setUint16(20,1,!0),view.setUint16(22,1,!0),view.setUint32(24,sampleRate,!0),view.setUint32(28,2*sampleRate,!0),view.setUint16(32,2,!0),view.setUint16(34,16,!0),writeString(36,"data"),view.setUint32(40,2*samples.length,!0),function(output,offset,input){for(var i=0;i<input.length;i++,offset+=2){var s=Math.max(-1,Math.min(1,input[i]));output.setInt16(offset,s<0?32768*s:32767*s,!0)}}(view,44,samples),new Blob([buffer],{type:"audio/wav"})},_proto.cleanup=function(){this.isRecordingFlag=!1,this.mediaRecorder&&("inactive"!==this.mediaRecorder.state&&this.mediaRecorder.stop(),this.mediaRecorder=null),this.recordedChunks=[],this.scriptProcessor&&(this.scriptProcessor.disconnect(),this.scriptProcessor=null),this.mediaStreamSource&&(this.mediaStreamSource.disconnect(),this.mediaStreamSource=null),this.audioContext&&(this.audioContext.close(),this.audioContext=null),this.stream&&(this.stream.getTracks().forEach(function(track){return track.stop()}),this.stream=null),this.audioBuffers=[]},_proto.destroy=function(){this.cleanup(),this.maxTimer&&(clearTimeout(this.maxTimer),this.maxTimer=null)},_proto.getDuration=function(){return 0===this.startTime?0:(Date.now()-this.startTime)/1e3},_proto.isRecording=function(){return this.isRecordingFlag},VoiceRecorder}(),zh_CN={title:"广播喊话",defaultVoice:"默认语音",pressToTalk:"按住说话",clickToTalk:"点击录音",sendVoice:"下发语音",recording:"录音中",stopRecording:"停止录音",loading:"加载中...",noVoice:"暂无语音数据",recordingRemaining:"还可录制 {time} 秒",releaseToStop:"松开结束录制",clickToStop:"再次点击按钮结束录制",voiceSentSuccess:"语音下发成功",recordComplete:"录音完成",voiceSendFailed:"语音下发失败",recordFailed:"录音失败",recordTooShort:"录音时长不足3秒",micPermissionDenied:"请允许麦克风权限"},en_US={title:"Voice Broadcast",defaultVoice:"Default Voice",pressToTalk:"Press to Talk",clickToTalk:"Click to Record",sendVoice:"Send Voice",recording:"Recording",stopRecording:"Stop Recording",loading:"Loading...",noVoice:"No voice data",recordingRemaining:"{time}s remaining",releaseToStop:"Release to stop",clickToStop:"Click again to stop",voiceSentSuccess:"Voice sent successfully",recordComplete:"Recording completed",voiceSendFailed:"Failed to send voice",recordFailed:"Recording failed",recordTooShort:"Recording is too short (min 3s)",micPermissionDenied:"Please allow microphone permission"},i18n=new(function(){function I18n(){this.currentLanguage="zh",this.translations={zh:zh_CN,en:en_US}}var _proto=I18n.prototype;return _proto.setLanguage=function(language){this.currentLanguage=language},_proto.t=function(key){return this.translations[this.currentLanguage][key]||key},_proto.getLanguage=function(){return this.currentLanguage},I18n}()),RecordingToast=function(){function RecordingToast(options){void 0===options&&(options={}),this.options={maxDuration:options.maxDuration||59,minDuration:options.minDuration||3,container:options.container||document.body,isMobile:options.isMobile||!1,language:options.language||"zh"},this.container=this.options.container,this.toastElement=null,this.waveformElement=null,this.timer=null,this.currentTime=this.options.maxDuration,this.waveAnimationFrame=null,i18n.setLanguage(this.options.language),this.injectStyles()}var _proto=RecordingToast.prototype;return _proto.injectStyles=function(){var styleId="ezuikit-recording-toast-styles";if(!document.getElementById(styleId)){var style=document.createElement("style");style.id=styleId,style.textContent="\n .ezuikit-recording-toast {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%) translateY(-80px);\n z-index: 9999;\n background: rgba(44, 44, 44, 0.95);\n border-radius: 16px;\n width: 120px;\n height: 120px;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 16px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);\n animation: ezuikit-toast-fade-in 0.2s ease;\n }\n\n /* 当 RecordingToast 在特定容器内时,使用绝对定位并居中 */\n .ezuikit-broadcast-panel .ezuikit-recording-toast {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n z-index: 1;\n }\n\n @keyframes ezuikit-toast-fade-in {\n from {\n opacity: 0;\n transform: translate(-50%, -50%) translateY(-80px) scale(0.9);\n }\n to {\n opacity: 1;\n transform: translate(-50%, -50%) translateY(-80px) scale(1);\n }\n }\n\n /* 面板内的 toast 淡入动画 */\n .ezuikit-broadcast-panel .ezuikit-recording-toast {\n animation: ezuikit-toast-fade-in-panel 0.2s ease;\n }\n\n @keyframes ezuikit-toast-fade-in-panel {\n from {\n opacity: 0;\n transform: translate(-50%, -50%) scale(0.9);\n }\n to {\n opacity: 1;\n transform: translate(-50%, -50%) scale(1);\n }\n }\n\n .ezuikit-recording-waveform {\n width: 80px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .ezuikit-recording-svg {\n width: 100%;\n height: 100%;\n object-fit: contain;\n }\n\n #ezuikit-recording-hint {\n font-size: 12px;\n color: rgba(255, 255, 255, 0.9);\n text-align: center;\n line-height: 20px;\n padding: 0 12px;\n }\n ",document.head.appendChild(style)}},_proto.getWaveformDefs=function(){return'\n \x3c!-- 柱子0: 最左,最暗 #CCCCCC --\x3e\n <linearGradient id="waveGradient0" x1="0%" y1="0%" x2="0%" y2="100%">\n <stop offset="0%" stop-color="#CCCCCC" stop-opacity="1" />\n <stop offset="100%" stop-color="#CCCCCC" stop-opacity="1" />\n </linearGradient>\n\n \x3c!-- 柱子1: #D6D6D6 --\x3e\n <linearGradient id="waveGradient1" x1="0%" y1="0%" x2="0%" y2="100%">\n <stop offset="0%" stop-color="#D6D6D6" stop-opacity="1" />\n <stop offset="100%" stop-color="#D6D6D6" stop-opacity="1" />\n </linearGradient>\n\n \x3c!-- 柱子2: #E0E0E0 --\x3e\n <linearGradient id="waveGradient2" x1="0%" y1="0%" x2="0%" y2="100%">\n <stop offset="0%" stop-color="#E0E0E0" stop-opacity="1" />\n <stop offset="100%" stop-color="#E0E0E0" stop-opacity="1" />\n </linearGradient>\n\n \x3c!-- 柱子3: #EBEBEB --\x3e\n <linearGradient id="waveGradient3" x1="0%" y1="0%" x2="0%" y2="100%">\n <stop offset="0%" stop-color="#EBEBEB" stop-opacity="1" />\n <stop offset="100%" stop-color="#EBEBEB" stop-opacity="1" />\n </linearGradient>\n\n \x3c!-- 柱子4: 中间,最亮 #FFFFFF --\x3e\n <linearGradient id="waveGradient4" x1="0%" y1="0%" x2="0%" y2="100%">\n <stop offset="0%" stop-color="#FFFFFF" stop-opacity="1" />\n <stop offset="100%" stop-color="#FFFFFF" stop-opacity="1" />\n </linearGradient>\n\n \x3c!-- 柱子5: #EBEBEB --\x3e\n <linearGradient id="waveGradient5" x1="0%" y1="0%" x2="0%" y2="100%">\n <stop offset="0%" stop-color="#EBEBEB" stop-opacity="1" />\n <stop offset="100%" stop-color="#EBEBEB" stop-opacity="1" />\n </linearGradient>\n\n \x3c!-- 柱子6: #E0E0E0 --\x3e\n <linearGradient id="waveGradient6" x1="0%" y1="0%" x2="0%" y2="100%">\n <stop offset="0%" stop-color="#E0E0E0" stop-opacity="1" />\n <stop offset="100%" stop-color="#E0E0E0" stop-opacity="1" />\n </linearGradient>\n\n \x3c!-- 柱子7: #D6D6D6 --\x3e\n <linearGradient id="waveGradient7" x1="0%" y1="0%" x2="0%" y2="100%">\n <stop offset="0%" stop-color="#D6D6D6" stop-opacity="1" />\n <stop offset="100%" stop-color="#D6D6D6" stop-opacity="1" />\n </linearGradient>\n\n \x3c!-- 柱子8: 最右,最暗 #CCCCCC --\x3e\n <linearGradient id="waveGradient8" x1="0%" y1="0%" x2="0%" y2="100%">\n <stop offset="0%" stop-color="#CCCCCC" stop-opacity="1" />\n <stop offset="100%" stop-color="#CCCCCC" stop-opacity="1" />\n </linearGradient>\n '},_proto.createToastHTML=function(){var getBarX=function(index){return 5+16*index},remainingText=i18n.t("recordingRemaining").replace("{time}",String(this.options.maxDuration));return'\n <div class="ezuikit-recording-waveform">\n <svg id="ezuikit-waveform-svg" viewBox="0 0 150 100" xmlns="http://www.w3.org/2000/svg" width="80" height="40">\n <defs>\n '+this.getWaveformDefs()+'\n </defs>\n \x3c!-- 9个柱子,宽度12px,间距4px,所有柱子高度变化范围都是30~80px,形成波浪效果,颜色从中间向两边渐变 --\x3e\n <rect id="wave-bar-0" x="'+getBarX(0)+'" y="42.5" width="12" height="15" fill="url(#waveGradient0)" rx="6" />\n <rect id="wave-bar-1" x="'+getBarX(1)+'" y="35" width="12" height="30" fill="url(#waveGradient1)" rx="6" />\n <rect id="wave-bar-2" x="'+getBarX(2)+'" y="27.5" width="12" height="45" fill="url(#waveGradient2)" rx="6" />\n <rect id="wave-bar-3" x="'+getBarX(3)+'" y="20" width="12" height="60" fill="url(#waveGradient3)" rx="6" />\n <rect id="wave-bar-4" x="'+getBarX(4)+'" y="7.5" width="12" height="85" fill="url(#waveGradient4)" rx="6" />\n <rect id="wave-bar-5" x="'+getBarX(5)+'" y="20" width="12" height="60" fill="url(#waveGradient5)" rx="6" />\n <rect id="wave-bar-6" x="'+getBarX(6)+'" y="27.5" width="12" height="45" fill="url(#waveGradient6)" rx="6" />\n <rect id="wave-bar-7" x="'+getBarX(7)+'" y="35" width="12" height="30" fill="url(#waveGradient7)" rx="6" />\n <rect id="wave-bar-8" x="'+getBarX(8)+'" y="42.5" width="12" height="15" fill="url(#waveGradient8)" rx="6" />\n </svg>\n </div>\n <div id="ezuikit-recording-hint">'+remainingText+"</div>\n "},_proto.startWaveformAnimation=function(){var frameIndex=0;this.waveAnimationFrame=window.setInterval(function(){for(var i=0;i<9;i++){var rect=document.getElementById("wave-bar-"+i);if(rect){var phase=(.3*frameIndex+.8*i)%(2*Math.PI),height=30+50*((Math.sin(phase)+1)/2),y=50-height/2;rect.setAttribute("height",height.toFixed(2)),rect.setAttribute("y",y.toFixed(2))}}frameIndex++},100)},_proto.stopWaveformAnimation=function(){this.waveAnimationFrame&&(clearInterval(this.waveAnimationFrame),this.waveAnimationFrame=null)},_proto.show=function(){this.toastElement||(this.toastElement=document.createElement("div"),this.toastElement.className="ezuikit-recording-toast",this.toastElement.innerHTML=this.createToastHTML(),this.container.appendChild(this.toastElement),this.waveformElement=this.toastElement.querySelector(".ezuikit-recording-waveform"),this.currentTime=this.options.maxDuration,this.startCountdown(),this.startWaveformAnimation())},_proto.hide=function(){var _this_toastElement;this.stopCountdown(),this.stopWaveformAnimation(),(null==(_this_toastElement=this.toastElement)?void 0:_this_toastElement.parentNode)&&this.toastElement.parentNode.removeChild(this.toastElement),this.toastElement=null,this.waveformElement=null},_proto.startCountdown=function(){var _this=this;this.timer=window.setInterval(function(){_this.currentTime--;var hintElement=document.getElementById("ezuikit-recording-hint");if(hintElement){var remainingMin=Math.max(0,_this.currentTime);hintElement.innerHTML=remainingMin>0?i18n.t("recordingRemaining").replace("{time}",String(remainingMin)):_this.options.isMobile?i18n.t("releaseToStop"):i18n.t("clickToStop")}_this.currentTime<=0&&_this.stopCountdown()},1e3)},_proto.stopCountdown=function(){this.timer&&(clearInterval(this.timer),this.timer=null)},_proto.getCurrentTime=function(){return this.currentTime},_proto.destroy=function(){this.hide()},RecordingToast}();function asyncGeneratorStep$1(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg),value=info.value}catch(error){return void reject(error)}info.done?resolve(value):Promise.resolve(value).then(_next,_throw)}function _async_to_generator$1(fn){return function(){var self=this,args=arguments;return new Promise(function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep$1(gen,resolve,reject,_next,_throw,"next",value)}function _throw(err){asyncGeneratorStep$1(gen,resolve,reject,_next,_throw,"throw",err)}_next(void 0)})}}function _instanceof(left,right){return null!=right&&"undefined"!=typeof Symbol&&right[Symbol.hasInstance]?!!right[Symbol.hasInstance](left):left instanceof right}function _ts_generator$1(thisArg,body){var f,y,t,_={label:0,sent:function(){if(1&t[0])throw t[1];return t[1]},trys:[],ops:[]},g=Object.create(("function"==typeof Iterator?Iterator:Object).prototype);return g.next=verb(0),g.throw=verb(1),g.return=verb(2),"function"==typeof Symbol&&(g[Symbol.iterator]=function(){return this}),g;function verb(n){return function(v){return function(op){if(f)throw new TypeError("Generator is already executing.");for(;g&&(g=0,op[0]&&(_=0)),_;)try{if(f=1,y&&(t=2&op[0]?y.return:op[0]?y.throw||((t=y.return)&&t.call(y),0):y.next)&&!(t=t.call(y,op[1])).done)return t;switch(y=0,t&&(op=[2&op[0],t.value]),op[0]){case 0:case 1:t=op;break;case 4:return _.label++,{value:op[1],done:!1};case 5:_.label++,y=op[1],op=[0];continue;case 7:op=_.ops.pop(),_.trys.pop();continue;default:if(!(t=_.trys,(t=t.length>0&&t[t.length-1])||6!==op[0]&&2!==op[0])){_=0;continue}if(3===op[0]&&(!t||op[1]>t[0]&&op[1]<t[3])){_.label=op[1];break}if(6===op[0]&&_.label<t[1]){_.label=t[1],t=op;break}if(t&&_.label<t[2]){_.label=t[2],_.ops.push(op);break}t[2]&&_.ops.pop(),_.trys.pop();continue}op=body.call(thisArg,_)}catch(e){op=[6,e],y=0}finally{f=t=0}if(5&op[0])throw op[1];return{value:op[0]?op[1]:void 0,done:!0}}([n,v])}}}var BroadcastUI=function(){function BroadcastUI(container,options){if("string"==typeof container){var element=document.getElementById(container);this.container=element||document.body}else _instanceof(container,HTMLElement)?this.container=container:this.container=document.body;this.options=options,this.modalElement=null,this.voiceListElement=null,this.talkButton=null,this.isRecording=!1,this.isStarting=!1,this.lastTouchTime=0,this.pendingStop=!1,this.voiceList=options.voiceList||[],this.orientationChangeHandler=null,this.createUI();var panel=this.modalElement.querySelector(".ezuikit-broadcast-panel"),toastContainer=_instanceof(panel,HTMLElement)?panel:this.container;this.recordingToast=new RecordingToast({maxDuration:59,minDuration:3,container:toastContainer,isMobile:options.isMobile,language:options.language}),i18n.setLanguage(options.language),this.options.isMobile&&this.setupOrientationListener()}var _proto=BroadcastUI.prototype;return _proto.setupOrientationListener=function(){var _window_screen,_this=this;this.orientationChangeHandler=function(){_this.modalElement&&"none"!==_this.modalElement.style.display&&_this.positionModalBelowContainer()},window.addEventListener("resize",this.orientationChangeHandler),(null==(_window_screen=window.screen)?void 0:_window_screen.orientation)&&window.screen.orientation.addEventListener("change",this.orientationChangeHandler)},_proto.removeOrientationListener=function(){var _window_screen;this.orientationChangeHandler&&(window.removeEventListener("resize",this.orientationChangeHandler),(null==(_window_screen=window.screen)?void 0:_window_screen.orientation)&&window.screen.orientation.removeEventListener("change",this.orientationChangeHandler),this.orientationChangeHandler=null)},_proto.createUI=function(){this.modalElement=document.createElement("div"),this.modalElement.className="ezuikit-broadcast-modal",this.options.isMobile&&this.modalElement.classList.add("ezuikit-broadcast-modal-mobile"),this.modalElement.innerHTML=this.getModalHTML(),this.injectStyles(),this.options.isMobile?(document.body.appendChild(this.modalElement),this.positionModalBelowContainer()):this.container.appendChild(this.modalElement),this.voiceListElement=this.modalElement.querySelector(".ezuikit-broadcast-voice-list"),this.bindEvents(),this.modalElement.style.display="none",this.voiceList.length>0&&this.renderVoiceList()},_proto.positionModalBelowContainer=function(){var _this_options_player;if(this.options.isMobile&&this.modalElement){var isFullscreen=(null==(_this_options_player=this.options.player)?void 0:_this_options_player.isCurrentFullscreen)||!1;if(this.modalElement.classList.remove("normal-mode","fullscreen-landscape-mode"),isFullscreen)this.modalElement.classList.add("fullscreen-landscape-mode"),this.modalElement.style.position="fixed",this.modalElement.style.left="0",this.modalElement.style.right="0",this.modalElement.style.bottom="0",this.modalElement.style.top="auto";else{this.modalElement.classList.add("normal-mode");var containerRect=this.container.getBoundingClientRect();this.modalElement.style.position="fixed",this.modalElement.style.left="0",this.modalElement.style.right="0",this.modalElement.style.top=containerRect.bottom+"px",this.modalElement.style.bottom="0"}}},_proto.getModalHTML=function(){var t=i18n.t.bind(i18n);return'\n <div class="ezuikit-broadcast-overlay"></div>\n <div class="ezuikit-broadcast-panel" data-direction="'+(this.options.direction||"bottom")+'">\n \x3c!-- 标题栏 --\x3e\n <div class="ezuikit-broadcast-header">\n <button class="ezuikit-broadcast-close" type="button">\n <svg width="24" height="24" viewBox="0 0 24 24" fill="none">\n <path d="M18 6L6 18M6 6L18 18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>\n </svg>\n </button>\n <h2 class="ezuikit-broadcast-title">'+t("title")+'</h2>\n </div>\n\n \x3c!-- Tab区域 --\x3e\n <div class="ezuikit-broadcast-tabs">\n <div class="ezuikit-broadcast-tab active">\n '+t("defaultVoice")+'\n </div>\n </div>\n\n \x3c!-- 内容区域 --\x3e\n <div class="ezuikit-broadcast-content">\n \x3c!-- 语音列表 --\x3e\n <div class="ezuikit-broadcast-voice-list">\n \x3c!-- 语音项将通过 updateVoiceList 动态添加 --\x3e\n <div class="ezuikit-broadcast-voice-empty">\n '+t("loading")+'\n </div>\n </div>\n </div>\n\n \x3c!-- 底部按钮 --\x3e\n <div class="ezuikit-broadcast-footer">\n <button class="ezuikit-broadcast-talk-btn" type="button">\n <span class="ezuikit-broadcast-talk-text">'+(this.options.isMobile?t("pressToTalk"):t("clickToTalk"))+"</span>\n </button>\n </div>\n </div>\n "},_proto.injectStyles=function(){var styleId="ezuikit-broadcast-styles";if(!document.getElementById(styleId)){var style=document.createElement("style");style.id=styleId,style.textContent='\n /* 模态框 */\n .ezuikit-broadcast-modal {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 30;\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;\n pointer-events: none;\n }\n\n /* 移动端模态框:固定定位,覆盖整个视口 */\n .ezuikit-broadcast-modal-mobile {\n position: fixed;\n top: auto;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 9999;\n }\n\n .ezuikit-broadcast-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n animation: ezuikit-broadcast-fade-in 0.3s ease;\n pointer-events: auto;\n }\n\n /* 移动端遮罩层:覆盖整个视口 */\n .ezuikit-broadcast-modal-mobile .ezuikit-broadcast-overlay {\n position: fixed;\n }\n\n /* 移动端遮罩层:全屏模式(应用与播放器相同的伪全屏变换) */\n .ezuikit-broadcast-modal-mobile.fullscreen-landscape-mode .ezuikit-broadcast-overlay {\n position: fixed !important;\n left: 0 !important;\n right: 0 !important;\n bottom: 0 !important;\n top: 0 !important;\n width: 100vh !important;\n width: var(--ezplayer-mobile-inner-height, 100vh) !important;\n height: 100vw !important;\n height: var(--ezplayer-mobile-inner-width, 100vw) !important;\n transform: rotate(90.001deg) translateY(-100%) !important;\n -webkit-transform: rotate(90.001deg) translateY(-100%) !important;\n transform-origin: 0 0 !important;\n -webkit-transform-origin: 0 0 !important;\n }\n\n /* 主面板 */\n .ezuikit-broadcast-panel {\n position: absolute;\n background: #F5F5F5;\n display: flex;\n flex-direction: column;\n box-shadow: 0 -2px 20px rgba(0, 0, 0, 0.1);\n pointer-events: auto;\n overflow: hidden;\n }\n\n /* 移动端面板:固定定位,基础样式 */\n .ezuikit-broadcast-modal-mobile .ezuikit-broadcast-panel {\n position: fixed !important;\n }\n\n /* 移动端面板:普通模式(定位在 container 下方,从下往上展开) */\n .ezuikit-broadcast-modal-mobile.normal-mode .ezuikit-broadcast-panel {\n bottom: 0 !important;\n top: auto !important;\n left: 0 !important;\n right: 0 !important;\n height: 0;\n animation: ezuikit-broadcast-expand-height-mobile 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards !important;\n }\n\n /* 移动端面板:全屏模式(应用与播放器相同的伪全屏变换,从横屏后的下方往上展开) */\n .ezuikit-broadcast-modal-mobile.fullscreen-landscape-mode .ezuikit-broadcast-panel {\n position: fixed !important;\n left: 0 !important;\n right: auto !important;\n bottom: 0 !important;\n top: 0 !important;\n height: 100vw !important;\n height: var(--ezplayer-mobile-inner-width, 100vw) !important;\n transform: rotate(90.001deg) translateY(-100%) !important;\n -webkit-transform: rotate(90.001deg) translateY(-100%) !important;\n transform-origin: 0 0 !important;\n -webkit-transform-origin: 0 0 !important;\n animation: ezuikit-broadcast-expand-width-mobile-fullscreen 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards !important;\n }\n\n /* 不同方向的展开动画 - 从容器边缘展开 */\n .ezuikit-broadcast-panel[data-direction="bottom"] {\n left: 0;\n right: 0;\n bottom: 0;\n width: 100%;\n height: 0;\n animation: ezuikit-broadcast-expand-height 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;\n }\n\n .ezuikit-broadcast-panel[data-direction="top"] {\n left: 0;\n right: 0;\n top: 0;\n width: 100%;\n height: 0;\n animation: ezuikit-broadcast-expand-height 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;\n }\n\n .ezuikit-broadcast-panel[data-direction="left"] {\n left: 0;\n top: 0;\n bottom: 0;\n width: 100%;\n animation: ezuikit-broadcast-expand-width 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;\n }\n\n .ezuikit-broadcast-panel[data-direction="right"] {\n right: 0;\n top: 0;\n bottom: 0;\n width: 100%;\n animation: ezuikit-broadcast-expand-width 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;\n }\n\n /* 标题栏 */\n .ezuikit-broadcast-header {\n position: relative;\n padding: 16px 20px;\n text-align: center;\n background: rgba(245, 247, 250, 1);\n }\n\n .ezuikit-broadcast-title {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: #333333;\n }\n\n .ezuikit-broadcast-close {\n position: absolute;\n left: 16px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: #666666;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: color 0.2s;\n }\n\n .ezuikit-broadcast-close:hover {\n color: #333333;\n }\n\n /* Tab区域 */\n .ezuikit-broadcast-tabs {\n display: flex;\n padding: 0 20px;\n background: rgba(245, 247, 250, 1);\n }\n\n .ezuikit-broadcast-tab {\n position: relative;\n padding: 12px 16px 4px;\n font-size: 20px;\n color: #999999;\n cursor: pointer;\n transition: color 0.2s;\n font-weight: 700;\n }\n\n .ezuikit-broadcast-tab.active {\n color: rgba(100, 143, 252, 1);\n font-weight: 700;\n }\n\n .ezuikit-broadcast-tab.active::after {\n content: \'\';\n position: absolute;\n bottom: 0;\n left: 50%;\n transform: translateX(-50%);\n width: 10px;\n height: 2px;\n background: #6B9EFF;\n }\n\n /* 内容区域 */\n .ezuikit-broadcast-content {\n flex: 1;\n overflow-y: auto;\n padding: 16px 20px;\n background: rgba(245, 247, 250, 1);\n }\n\n /* 语音列表 */\n .ezuikit-broadcast-voice-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .ezuikit-broadcast-voice-empty {\n text-align: center;\n padding: 40px 20px;\n color: #999999;\n font-size: 14px;\n }\n\n .ezuikit-broadcast-voice-item {\n display: flex;\n align-items: center;\n padding: 11px 16px;\n background: rgba(237, 237, 237, 1);\n border-radius: 16px;\n height: 42px;\n box-sizing: border-box;\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .ezuikit-broadcast-voice-item:hover {\n background: rgba(237, 237, 237, 1);\n }\n\n .ezuikit-broadcast-voice-item.selected {\n background: rgba(237, 237, 237, 1);\n }\n\n .ezuikit-broadcast-voice-icon {\n width: 24px;\n height: 24px;\n margin-right: 12px;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #FFFFFF;\n background: #2C2C2C;\n border-radius: 50%;\n padding: 3px;\n box-sizing: border-box;\n transition: background 0.2s;\n }\n\n .ezuikit-broadcast-voice-item.selected .ezuikit-broadcast-voice-icon {\n background: rgba(100, 143, 252, 1);\n color: #FFFFFF;\n }\n\n .ezuikit-broadcast-voice-text {\n flex: 1;\n font-size: 14px;\n color: rgba(102, 102, 102, 1);\n line-height: 20px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n /* 底部按钮 */\n .ezuikit-broadcast-footer {\n padding: 16px 20px 20px;\n background: #F5F5F5;\n }\n\n .ezuikit-broadcast-talk-btn {\n width: 100%;\n padding: 16px;\n background: #6B9EFF;\n color: #FFFFFF;\n border: none;\n font-size: 16px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n user-select: none;\n border-radius: 8px;\n }\n\n .ezuikit-broadcast-talk-btn:hover {\n background: #5A8EEE;\n }\n\n .ezuikit-broadcast-talk-btn:active {\n transform: scale(0.98);\n }\n\n .ezuikit-broadcast-talk-btn.recording {\n background: #FF5252;\n }\n\n .ezuikit-broadcast-talk-btn.disabled {\n background: #CCCCCC;\n cursor: not-allowed;\n }\n\n /* 动画 */\n @keyframes ezuikit-broadcast-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n\n @keyframes ezuikit-broadcast-expand-height {\n from { height: 0; }\n to { height: 80%; }\n }\n\n @keyframes ezuikit-broadcast-expand-height-mobile {\n from { height: 0; }\n to { height: 70vh; }\n }\n\n /* 全屏时从右侧展开的动画(宽度展开) */\n @keyframes ezuikit-broadcast-expand-width-mobile-fullscreen {\n from { width: 0; }\n to { width: 70vh; }\n }\n\n /* 全屏时从底部展开的动画 */\n @keyframes ezuikit-broadcast-expand-height-mobile-fullscreen {\n from { height: 0; }\n to { height: 85vh; }\n }\n\n @keyframes ezuikit-broadcast-expand-width {\n from { width: 0; }\n to {\n width: 80%;\n max-width: 400px;\n }\n }\n ',document.head.appendChild(style)}},_proto.bindEvents=function(){var _this=this;if(this.modalElement){var closeBtn=this.modalElement.querySelector(".ezuikit-broadcast-close");closeBtn&&closeBtn.addEventListener("click",function(){_this.close()});var overlay=this.modalElement.querySelector(".ezuikit-broadcast-overlay");overlay&&overlay.addEventListener("click",function(){_this.close()}),this.talkButton=this.modalElement.querySelector(".ezuikit-broadcast-talk-btn"),this.talkButton&&(this.options.isMobile?(this.talkButton.addEventListener("touchstart",function(e){e.preventDefault(),e.stopPropagation();var now=Date.now();now-_this.lastTouchTime<300||(_this.lastTouchTime=now,_this.handleRecordStart())},{passive:!1}),this.talkButton.addEventListener("touchend",function(e){e.preventDefault(),e.stopPropagation(),_this.handleRecordStop()},{passive:!1}),this.talkButton.addEventListener("touchcancel",function(){_this.isRecording&&_this.handleRecordStop()})):this.talkButton.addEventListener("click",function(e){e.preventDefault(),_this.handleRecordToggle()}))}},_proto.handleRecordToggle=function(){this.isRecording?this.handleRecordStop():this.handleRecordStart()},_proto.handleRecordStart=function(){return _async_to_generator$1(function(){var textElement,error,textElement1;return _ts_generator$1(this,function(_state){switch(_state.label){case 0:if(this.isRecording||this.isStarting)return[2];_state.label=1;case 1:return _state.trys.push([1,5,,6]),this.pendingStop=!1,this.isStarting=!0,this.recordingToast.show(),this.talkButton&&(this.talkButton.classList.add("recording"),(textElement=this.talkButton.querySelector(".ezuikit-broadcast-talk-text"))&&(textElement.textContent=this.options.isMobile?i18n.t("recording"):i18n.t("stopRecording"))),[4,this.options.onRecordStart()];case 2:return _state.sent(),this.isRecording=!0,this.isStarting=!1,this.pendingStop?(this.pendingStop=!1,[4,this.handleRecordStop()]):[3,4];case 3:_state.sent(),_state.label=4;case 4:return[3,6];case 5:return error=_state.sent(),this.isStarting=!1,this.isRecording=!1,this.pendingStop=!1,this.recordingToast.hide(),this.talkButton&&(this.talkButton.classList.remove("recording"),(textElement1=this.talkButton.querySelector(".ezuikit-broadcast-talk-text"))&&(textElement1.textContent=this.options.isMobile?i18n.t("pressToTalk"):i18n.t("clickToTalk"))),this.showError(_instanceof(error,Error)?error.message:"开始录音失败"),[3,6];case 6:return[2]}})}).call(this)},_proto.handleRecordStop=function(){return _async_to_generator$1(function(){var textElement,error,textElement1;return _ts_generator$1(this,function(_state){switch(_state.label){case 0:if(this.isStarting)return this.pendingStop=!0,[2];if(!this.isRecording)return[2];_state.label=1;case 1:return _state.trys.push([1,3,,4]),this.recordingToast.hide(),this.talkButton&&(this.talkButton.classList.remove("recording"),(textElement=this.talkButton.querySelector(".ezuikit-broadcast-talk-text"))&&(textElement.textContent=this.options.isMobile?i18n.t("pressToTalk"):i18n.t("clickToTalk"))),[4,this.options.onRecordStop()];case 2:return _state.sent(),this.isRecording=!1,[3,4];case 3:return error=_state.sent(),this.isRecording=!1,this.recordingToast.hide(),this.talkButton&&(this.talkButton.classList.remove("recording"),(textElement1=this.talkButton.querySelector(".ezuikit-broadcast-talk-text"))&&(textElement1.textContent=this.options.isMobile?i18n.t("pressToTalk"):i18n.t("clickToTalk"))),this.showError(_instanceof(error,Error)?error.message:"停止录音失败"),[3,4];case 4:return[2]}})}).call(this)},_proto.show=function(){this.modalElement&&(this.modalElement.style.display="block",this.options.isMobile&&this.positionModalBelowContainer())},_proto.hide=function(){if(this.isRecording)try{this.handleRecordStop()}catch(error){this.isRecording=!1,this.recordingToast.hide()}this.modalElement&&(this.modalElement.style.display="none")},_proto.close=function(){this.hide(),this.options.onClose()},_proto.updateVoiceList=function(voiceList){this.voiceList=voiceList,this.renderVoiceList()},_proto.renderVoiceList=function(){var _this=this;this.voiceListElement&&(0!==this.voiceList.length?(this.voiceListElement.innerHTML=this.voiceList.map(function(voice,index){return'\n <div class="ezuikit-broadcast-voice-item" data-index="'+index+'">\n <div class="ezuikit-broadcast-voice-icon">\n <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">\n <path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/>\n </svg>\n </div>\n <div class="ezuikit-broadcast-voice-text" title="'+voice.voiceName+'">'+voice.voiceName+"</div>\n </div>\n "}).join(""),this.voiceListElement.querySelectorAll(".ezuikit-broadcast-voice-item").forEach(function(item){item.addEventListener("click",function(){var index=parseInt(item.getAttribute("data-index")||"-1");_this.selectVoice(index)})})):this.voiceListElement.innerHTML='\n <div class="ezuikit-broadcast-voice-empty">\n '+i18n.t("noVoice")+"\n </div>\n ")},_proto.selectVoice=function(index){if(this.voiceListElement&&(this.voiceListElement.querySelectorAll(".ezuikit-broadcast-voice-item").forEach(function(item){item.classList.remove("selected")}),index>=0&&index<this.voiceList.length)){var selectedItem=this.voiceListElement.querySelector('[data-index="'+index+'"]');selectedItem&&selectedItem.classList.add("selected");var selectedVoice=this.voiceList[index];this.options.onVoiceSend(selectedVoice.fileUrl)}},_proto.setRecordingState=function(isRecording){this.isRecording=isRecording},_proto.showSuccess=function(message){},_proto.showError=function(message){},_proto.destroy=function(){var _this_modalElement;this.removeOrientationListener(),this.recordingToast.destroy(),(null==(_this_modalElement=this.modalElement)?void 0:_this_modalElement.parentNode)&&this.modalElement.parentNode.removeChild(this.modalElement),this.modalElement=null,this.voiceListElement=null,this.talkButton=null},BroadcastUI}();function asyncGeneratorStep(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg),value=info.value}catch(error){return void reject(error)}info.done?resolve(value):Promise.resolve(value).then(_next,_throw)}function _async_to_generator(fn){return function(){var self=this,args=arguments;return new Promise(function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"next",value)}function _throw(err){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"throw",err)}_next(void 0)})}}function _ts_generator(thisArg,body){var f,y,t,_={label:0,sent:function(){if(1&t[0])throw t[1];return t[1]},trys:[],ops:[]},g=Object.create(("function"==typeof Iterator?Iterator:Object).prototype);return g.next=verb(0),g.throw=verb(1),g.return=verb(2),"function"==typeof Symbol&&(g[Symbol.iterator]=function(){return this}),g;function verb(n){return function(v){return function(op){if(f)throw new TypeError("Generator is already executing.");for(;g&&(g=0,op[0]&&(_=0)),_;)try{if(f=1,y&&(t=2&op[0]?y.return:op[0]?y.throw||((t=y.return)&&t.call(y),0):y.next)&&!(t=t.call(y,op[1])).done)return t;switch(y=0,t&&(op=[2&op[0],t.value]),op[0]){case 0:case 1:t=op;break;case 4:return _.label++,{value:op[1],done:!1};case 5:_.label++,y=op[1],op=[0];continue;case 7:op=_.ops.pop(),_.trys.pop();continue;default:if(!(t=_.trys,(t=t.length>0&&t[t.length-1])||6!==op[0]&&2!==op[0])){_=0;continue}if(3===op[0]&&(!t||op[1]>t[0]&&op[1]<t[3])){_.label=op[1];break}if(6===op[0]&&_.label<t[1]){_.label=t[1],t=op;break}if(t&&_.label<t[2]){_.label=t[2],_.ops.push(op);break}t[2]&&_.ops.pop(),_.trys.pop();continue}op=body.call(thisArg,_)}catch(e){op=[6,e],y=0}finally{f=t=0}if(5&op[0])throw op[1];return{value:op[0]?op[1]:void 0,done:!0}}([n,v])}}}var EVENTS={open:"open",close:"close",requestQueryVoiceList:"requestQueryVoiceList",voiceListLoaded:"voiceListLoaded",voiceListError:"voiceListError",requestSendVoiceOnce:"requestSendVoiceOnce",requestSendVoice:"requestSendVoice",voiceSelected:"voiceSelected",voiceRecorded:"voiceRecorded",recordStart:"recordStart",recordStop:"recordStop",recordComplete:"recordComplete",recordError:"recordError",voiceSent:"voiceSent",voiceSendError:"voiceSendError",error:"error"},DefaultOptions={channelNo:"1",env:{domain:"https://open.ys7.com"},language:"zh"},Broadcast=function(){function Broadcast(options){var _this=this;this.options=Object.assign({},DefaultOptions,options),this.eventEmitter=new EventEmitter,this.voiceRecorder=null,this.isOpen=!1,this.voiceList=options.voiceList||[],this.maxDurationTimer=null,this.pendingAudioBlob=null;var container=this.options.container||document.body;this.broadcastUI=new BroadcastUI(container,{language:this.options.language||"zh",direction:this.options.direction||"right",voiceList:this.voiceList,isMobile:this.options.isMobile||!1,player:this.options.player,onClose:function(){return _this.close()},onRecordStart:function(){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,this.startRecord()];case 1:return[2,_state.sent()]}})}).call(_this)},onRecordStop:function(){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,this.stopRecord()];case 1:return[2,_state.sent()]}})}).call(_this)},onVoiceSend:function(fileUrl){return _this.sendVoice(fileUrl)},onVoiceSendOnce:function(){}}),this.setupEventListeners()}var _proto=Broadcast.prototype;return _proto.initMicrophonePermission=function(){return _async_to_generator(function(){var error;return _ts_generator(this,function(_state){switch(_state.label){case 0:return _state.trys.push([0,2,,3]),[4,navigator.mediaDevices.getUserMedia({audio:{sampleRate:16e3,channelCount:1,echoCancellation:!0,noiseSuppression:!0}})];case 1:return _state.sent().getTracks().forEach(function(track){return track.stop()}),[3,3];case 2:return error=_state.sent(),this.eventEmitter.emit(EVENTS.error,{eventType:EVENTS.error,code:-1,msg:"麦克风权限获取失败",error:error}),[3,3];case 3:return[2]}})}).call(this)},_proto.requestMicrophonePermission=function(){return _async_to_generator(function(){var error;return _ts_generator(this,function(_state){switch(_state.label){case 0:return _state.trys.push([0,2,,3]),[4,navigator.mediaDevices.getUserMedia({audio:{sampleRate:16e3,channelCount:1,echoCancellation:!0,noiseSuppression:!0}})];case 1:return _state.sent().getTracks().forEach(function(track){return track.stop()}),[2,!0];case 2:return error=_state.sent(),this.eventEmitter.emit(EVENTS.error,{eventType:EVENTS.error,code:-1,msg:"麦克风权限获取失败",error:error}),[2,!1];case 3:return[2]}})}).call(this)},_proto.setupEventListeners=function(){var _this=this;this.eventEmitter.on(EVENTS.voiceListLoaded,function(data){_this.voiceList=data.data||[],_this.broadcastUI&&_this.broadcastUI.updateVoiceList(_this.voiceList)}),this.eventEmitter.on(EVENTS.voiceListError,function(data){_this.broadcastUI&&_this.broadcastUI.showError(data.msg||"语音列表加载失败")}),this.eventEmitter.on(EVENTS.voiceSent,function(data){_this.broadcastUI&&_this.broadcastUI.showSuccess(data.msg||"语音下发成功")}),this.eventEmitter.on(EVENTS.voiceSendError,function(data){_this.broadcastUI&&_this.broadcastUI.showError(data.msg||"语音下发失败")})},_proto.open=function(){if(!this.isOpen)try{this.broadcastUI.show(),this.isOpen=!0,0===this.voiceList.length&&this.loadVoiceList(),this.eventEmitter.emit(EVENTS.open,{eventType:EVENTS.open,code:0,msg:"云广播界面已打开"})}catch(error){this.eventEmitter.emit(EVENTS.error,{eventType:EVENTS.error,code:-1,msg:"打开云广播界面失败",error:error})}},_proto.close=function(){if(this.isOpen)try{if(this.voiceRecorder)try{this.voiceRecorder.stop()}catch(error){}this.broadcastUI&&this.broadcastUI.hide(),this.isOpen=!1,this.eventEmitter.emit(EVENTS.close,{eventType:EVENTS.close,code:0,msg:"云广播界面已关闭"})}catch(error){}},_proto.loadVoiceList=function(){this.eventEmitter.emit(EVENTS.requestQueryVoiceList,{eventType:EVENTS.requestQueryVoiceList,params:{deviceSerial:this.options.deviceSerial,channelNo:this.options.channelNo,pageSize:50}})},_proto.startRecord=function(){return _async_to_generator(function(){var _this,error;return _ts_generator(this,function(_state){switch(_state.label){case 0:_this=this,_state.label=1;case 1:return _state.trys.push([1,3,,4]),this.pendingAudioBlob=null,this.voiceRecorder||(this.voiceRecorder=new VoiceRecorder({minDuration:3,maxDuration:59,sampleRate:16e3})),[4,this.voiceRecorder.start()];case 2:return _state.sent(),this.maxDurationTimer=window.setTimeout(function(){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,this.stopRecordAndCache()];case 1:return _state.sent(),[2]}})}).call(_this)},59e3),this.eventEmitter.emit(EVENTS.recordStart,{eventType:EVENTS.recordStart,code:0,msg:"开始录音"}),this.broadcastUI&&this.broadcastUI.setRecordingState(!0),[3,4];case 3:return error=_state.sent(),this.eventEmitter.emit(EVENTS.recordError,{eventType:EVENTS.recordError,code:-1,msg:"开始录音失败",error:error}),[3,4];case 4:return[2]}})}).call(this)},_proto.stopRecordAndCache=function(){return _async_to_generator(function(){var audioBlob;return _ts_generator(this,function(_state){switch(_state.label){case 0:return _state.trys.push([0,2,,3]),this.voiceRecorder&&this.voiceRecorder.isRecording()?[4,this.voiceRecorder.stop()]:[2];case 1:return 0===(audioBlob=_state.sent()).size?[2]:(this.pendingAudioBlob=audioBlob,this.eventEmitter.emit(EVENTS.recordComplete,{eventType:EVENTS.recordComplete,code:0,data:audioBlob,msg:"录音完成,等待下发"}),[3,3]);case 2:return _state.sent(),this.broadcastUI&&this.broadcastUI.setRecordingState(!1),[3,3];case 3:return[2]}})}).call(this)},_proto.stopRecord=function(){return _async_to_generator(function(){var audioBlob,audioBlob1,error;return _ts_generator(this,function(_state){switch(_state.label){case 0:if(_state.trys.push([0,2,,3]),this.maxDurationTimer&&(clearTimeout(this.maxDurationTimer),this.maxDurationTimer=null),this.pendingAudioBlob)return audioBlob=this.pendingAudioBlob,this.pendingAudioBlob=null,this.eventEmitter.emit(EVENTS.recordStop,{eventType:EVENTS.recordStop,code:0,msg:"停止录音"}),this.broadcastUI&&this.broadcastUI.setRecordingState(!1),this.sendVoiceOnce(audioBlob),[2];if(!this.voiceRecorder)throw new Error("录音器未初始化");return this.voiceRecorder.isRecording()?[4,this.voiceRecorder.stop()]:(this.broadcastUI&&this.broadcastUI.setRecordingState(!1),[2]);case 1:return 0===(audioBlob1=_state.sent()).size?(this.broadcastUI&&this.broadcastUI.setRecordingState(!1),[2]):(this.eventEmitter.emit(EVENTS.recordStop,{eventType:EVENTS.recordStop,code:0,msg:"停止录音"}),this.eventEmitter.emit(EVENTS.recordComplete,{eventType:EVENTS.recordComplete,code:0,data:audioBlob1,msg:"录音完成"}),this.broadcastUI&&this.broadcastUI.setRecordingState(!1),this.sendVoiceOnce(audioBlob1),[3,3]);case 2:return error=_state.sent(),this.eventEmitter.emit(EVENTS.recordError,{eventType:EVENTS.recordError,code:-1,msg:"停止录音失败",error:error}),this.broadcastUI&&this.broadcastUI.setRecordingState(!1),[3,3];case 3:return[2]}})}).call(this)},_proto.sendVoiceOnce=function(voiceFile){this.eventEmitter.emit(EVENTS.voiceRecorded,{eventType:EVENTS.voiceRecorded,voiceFile:voiceFile,deviceSerial:this.options.deviceSerial,channelNo:this.options.channelNo}),this.eventEmitter.emit(EVENTS.requestSendVoiceOnce,{eventType:EVENTS.requestSendVoiceOnce,voiceFile:voiceFile,deviceSerial:this.options.deviceSerial,channelNo:this.options.channelNo})},_proto.sendVoice=function(fileUrl){this.eventEmitter.emit(EVENTS.requestSendVoice,{eventType:EVENTS.requestSendVoice,fileUrl:fileUrl,deviceSerial:this.options.deviceSerial,channelNo:this.options.channelNo})},_proto.updateOptions=function(options){this.options=Object.assign(this.options,options)},_proto.on=function(event,callback){this.eventEmitter.on(event,callback)},_proto.off=function(event,callback){this.eventEmitter.off(event,callback)},_proto.destroy=function(){this.close(),this.voiceRecorder&&(this.voiceRecorder.destroy(),this.voiceRecorder=null),this.broadcastUI&&this.broadcastUI.destroy(),this.voiceList=[],this.eventEmitter.removeAllListeners()},Broadcast}();Broadcast.VERSION="0.1.0-beta.2",Broadcast.EVENTS=EVENTS,module.exports=Broadcast;
|
|
6
|
+
"use strict";var Logger=require("@ezuikit/utils-logger"),Drawer=require("@ezuikit/control-drawer"),Message=require("@ezuikit/control-message");function createLogger(logger){var root=null!=logger?logger:Logger();return"function"==typeof root.context?root.context("Broadcast"):root}function _array_like_to_array(arr,len){(null==len||len>arr.length)&&(len=arr.length);for(var i=0,arr2=new Array(len);i<len;i++)arr2[i]=arr[i];return arr2}function asyncGeneratorStep$2(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg),value=info.value}catch(error){return void reject(error)}info.done?resolve(value):Promise.resolve(value).then(_next,_throw)}function _async_to_generator$2(fn){return function(){var self=this,args=arguments;return new Promise(function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep$2(gen,resolve,reject,_next,_throw,"next",value)}function _throw(err){asyncGeneratorStep$2(gen,resolve,reject,_next,_throw,"throw",err)}_next(void 0)})}}function _create_for_of_iterator_helper_loose(o,allowArrayLike){var it="undefined"!=typeof Symbol&&o[Symbol.iterator]||o["@@iterator"];if(it)return(it=it.call(o)).next.bind(it);if(Array.isArray(o)||(it=function(o,minLen){if(!o)return;if("string"==typeof o)return _array_like_to_array(o,minLen);var n=Object.prototype.toString.call(o).slice(8,-1);"Object"===n&&o.constructor&&(n=o.constructor.name);if("Map"===n||"Set"===n)return Array.from(n);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return _array_like_to_array(o,minLen)}(o))||allowArrayLike){it&&(o=it);var i=0;return function(){return i>=o.length?{done:!0}:{done:!1,value:o[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _ts_generator$2(thisArg,body){var f,y,t,_={label:0,sent:function(){if(1&t[0])throw t[1];return t[1]},trys:[],ops:[]},g=Object.create(("function"==typeof Iterator?Iterator:Object).prototype),d=Object.defineProperty;return d(g,"next",{value:verb(0)}),d(g,"throw",{value:verb(1)}),d(g,"return",{value:verb(2)}),"function"==typeof Symbol&&d(g,Symbol.iterator,{value:function(){return this}}),g;function verb(n){return function(v){return function(op){if(f)throw new TypeError("Generator is already executing.");for(;g&&(g=0,op[0]&&(_=0)),_;)try{if(f=1,y&&(t=2&op[0]?y.return:op[0]?y.throw||((t=y.return)&&t.call(y),0):y.next)&&!(t=t.call(y,op[1])).done)return t;switch(y=0,t&&(op=[2&op[0],t.value]),op[0]){case 0:case 1:t=op;break;case 4:return _.label++,{value:op[1],done:!1};case 5:_.label++,y=op[1],op=[0];continue;case 7:op=_.ops.pop(),_.trys.pop();continue;default:if(!(t=_.trys,(t=t.length>0&&t[t.length-1])||6!==op[0]&&2!==op[0])){_=0;continue}if(3===op[0]&&(!t||op[1]>t[0]&&op[1]<t[3])){_.label=op[1];break}if(6===op[0]&&_.label<t[1]){_.label=t[1],t=op;break}if(t&&_.label<t[2]){_.label=t[2],_.ops.push(op);break}t[2]&&_.ops.pop(),_.trys.pop();continue}op=body.call(thisArg,_)}catch(e){op=[6,e],y=0}finally{f=t=0}if(5&op[0])throw op[1];return{value:op[0]?op[1]:void 0,done:!0}}([n,v])}}}var VoiceRecorder=function(){function VoiceRecorder(options){var _options_logger;void 0===options&&(options={}),this.options={minDuration:options.minDuration||3,maxDuration:options.maxDuration||59,sampleRate:options.sampleRate||16e3,channelCount:options.channelCount||1},this.logger=null!=(_options_logger=options.logger)?_options_logger:createLogger(),this.audioContext=null,this.mediaStreamSource=null,this.scriptProcessor=null,this.stream=null,this.startTime=0,this.maxTimer=null,this.audioBuffers=[],this.isRecordingFlag=!1,this.isIOSDevice=/iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream,this.mediaRecorder=null,this.recordedChunks=[]}var _proto=VoiceRecorder.prototype;return _proto.start=function(){return _async_to_generator$2(function(){var error;return _ts_generator$2(this,function(_state){switch(_state.label){case 0:if(this.isRecordingFlag)return this.logger.warn("[VoiceRecorder] 录音已在进行中,忽略重复启动"),[2];_state.label=1;case 1:return _state.trys.push([1,3,,4]),[4,this.startWithScriptProcessor()];case 2:return _state.sent(),this.startTime=Date.now(),this.isRecordingFlag=!0,this.logger.log("[VoiceRecorder] 录音已开始"),[3,4];case 3:throw error=_state.sent(),this.logger.error("[VoiceRecorder] 开始录音失败",error),this.isRecordingFlag=!1,error;case 4:return[2]}})}).call(this)},_proto.startWithMediaRecorder=function(){return _async_to_generator$2(function(){var _this,_,mimeType;return _ts_generator$2(this,function(_state){switch(_state.label){case 0:return _this=this,_=this,[4,navigator.mediaDevices.getUserMedia({audio:!0})];case 1:return _.stream=_state.sent(),this.recordedChunks=[],mimeType="",MediaRecorder.isTypeSupported("audio/mp4")?mimeType="audio/mp4":MediaRecorder.isTypeSupported("audio/webm")?mimeType="audio/webm":MediaRecorder.isTypeSupported("audio/wav")&&(mimeType="audio/wav"),this.mediaRecorder=new MediaRecorder(this.stream,{mimeType:mimeType||void 0}),this.mediaRecorder.ondataavailable=function(event){event.data.size>0&&_this.recordedChunks.push(event.data)},this.mediaRecorder.start(),[2]}})}).call(this)},_proto.startWithScriptProcessor=function(){return _async_to_generator$2(function(){var _this,audioConstraints,_;return _ts_generator$2(this,function(_state){switch(_state.label){case 0:return _this=this,audioConstraints=this.isIOSDevice?{audio:!0}:{audio:{sampleRate:this.options.sampleRate,channelCount:this.options.channelCount,echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0}},_=this,[4,navigator.mediaDevices.getUserMedia(audioConstraints)];case 1:return _.stream=_state.sent(),this.audioContext=new(window.AudioContext||window.webkitAudioContext)({sampleRate:this.options.sampleRate}),this.mediaStreamSource=this.audioContext.createMediaStreamSource(this.stream),this.scriptProcessor=this.audioContext.createScriptProcessor(4096,1,1),this.audioBuffers=[],this.scriptProcessor.onaudioprocess=function(event){if(_this.isRecordingFlag){var inputData=event.inputBuffer.getChannelData(0);_this.audioBuffers.push(new Float32Array(inputData))}},this.mediaStreamSource.connect(this.scriptProcessor),this.scriptProcessor.connect(this.audioContext.destination),[2]}})}).call(this)},_proto.stop=function(){return _async_to_generator$2(function(){var _this;return _ts_generator$2(this,function(_state){switch(_state.label){case 0:return _this=this,[4,new Promise(function(resolve,reject){if(!_this.isRecordingFlag)return _this.logger.warn("[VoiceRecorder] 录音器未在录音状态"),void resolve(new Blob([],{type:"audio/wav"}));var duration=(Date.now()-_this.startTime)/1e3;if(duration<_this.options.minDuration)return _this.logger.error("[VoiceRecorder] 录音时长不足",{duration:duration.toFixed(2),required:_this.options.minDuration}),reject(new Error("录音时长不足"+_this.options.minDuration+"秒")),void _this.cleanup();try{_this.isRecordingFlag=!1,_this.stopWithScriptProcessor(duration,resolve,reject)}catch(error){_this.logger.error("[VoiceRecorder] 停止录音失败",error),_this.cleanup(),reject(error)}})];case 1:return[2,_state.sent()]}})}).call(this)},_proto.stopWithMediaRecorder=function(duration,resolve,reject){var _this=this;if(!this.mediaRecorder)return this.logger.error("[VoiceRecorder] MediaRecorder 未初始化"),reject(new Error("MediaRecorder 未初始化")),void this.cleanup();this.mediaRecorder.onstop=function(){try{var _this_recordedChunks_,mimeType=(null==(_this_recordedChunks_=_this.recordedChunks[0])?void 0:_this_recordedChunks_.type)||"audio/wav",audioBlob=new Blob(_this.recordedChunks,{type:mimeType});_this.logger.log("[VoiceRecorder] 录音已停止",{duration:duration.toFixed(2)+"s",size:(audioBlob.size/1024).toFixed(2)+"KB"}),_this.cleanup(),resolve(audioBlob)}catch(error){_this.logger.error("[VoiceRecorder] 处理录音数据失败",error),_this.cleanup(),reject(error)}},this.mediaRecorder.stop()},_proto.stopWithScriptProcessor=function(duration,resolve,reject){try{for(var _step,totalLength=this.audioBuffers.reduce(function(acc,buffer){return acc+buffer.length},0),mergedBuffer=new Float32Array(totalLength),offset=0,_iterator=_create_for_of_iterator_helper_loose(this.audioBuffers);!(_step=_iterator()).done;){var buffer=_step.value;mergedBuffer.set(buffer,offset),offset+=buffer.length}var wavBlob=this.encodeWAV(mergedBuffer,this.options.sampleRate);this.logger.log("[VoiceRecorder] 录音已停止",{duration:duration.toFixed(2)+"s",size:(wavBlob.size/1024).toFixed(2)+"KB"}),this.cleanup(),resolve(wavBlob)}catch(error){this.logger.error("[VoiceRecorder] 处理录音数据失败",error),this.cleanup(),reject(error)}},_proto.encodeWAV=function(samples,sampleRate){var buffer=new ArrayBuffer(44+2*samples.length),view=new DataView(buffer),writeString=function(offset,string){for(var i=0;i<string.length;i++)view.setUint8(offset+i,string.charCodeAt(i))};return writeString(0,"RIFF"),view.setUint32(4,36+2*samples.length,!0),writeString(8,"WAVE"),writeString(12,"fmt "),view.setUint32(16,16,!0),view.setUint16(20,1,!0),view.setUint16(22,1,!0),view.setUint32(24,sampleRate,!0),view.setUint32(28,2*sampleRate,!0),view.setUint16(32,2,!0),view.setUint16(34,16,!0),writeString(36,"data"),view.setUint32(40,2*samples.length,!0),function(output,offset,input){for(var i=0;i<input.length;i++,offset+=2){var s=Math.max(-1,Math.min(1,input[i]));output.setInt16(offset,s<0?32768*s:32767*s,!0)}}(view,44,samples),new Blob([buffer],{type:"audio/wav"})},_proto.cleanup=function(){this.isRecordingFlag=!1,this.mediaRecorder&&("inactive"!==this.mediaRecorder.state&&this.mediaRecorder.stop(),this.mediaRecorder=null),this.recordedChunks=[],this.scriptProcessor&&(this.scriptProcessor.disconnect(),this.scriptProcessor=null),this.mediaStreamSource&&(this.mediaStreamSource.disconnect(),this.mediaStreamSource=null),this.audioContext&&(this.audioContext.close(),this.audioContext=null),this.stream&&(this.stream.getTracks().forEach(function(track){return track.stop()}),this.stream=null),this.audioBuffers=[]},_proto.destroy=function(){this.cleanup(),this.maxTimer&&(clearTimeout(this.maxTimer),this.maxTimer=null)},_proto.getDuration=function(){return 0===this.startTime?0:(Date.now()-this.startTime)/1e3},_proto.isRecording=function(){return this.isRecordingFlag},VoiceRecorder}(),zh_CN={title:"广播喊话",defaultVoice:"默认语音",pressToTalk:"按住说话",clickToTalk:"点击录音",sendVoice:"下发语音",recording:"录音中",stopRecording:"停止录音",loading:"加载中...",noVoice:"暂无语音数据",recordingRemaining:"还可录制 {time} 秒",releaseToStop:"松开结束录制",clickToStop:"再次点击按钮结束录制",voiceSentSuccess:"语音下发成功",recordComplete:"录音完成",voiceSendFailed:"语音下发失败",recordFailed:"录音失败",recordTooShort:"录音时长不足3秒",micPermissionDenied:"请允许麦克风权限"},en_US={title:"Voice Broadcast",defaultVoice:"Default Voice",pressToTalk:"Press to Talk",clickToTalk:"Click to Record",sendVoice:"Send Voice",recording:"Recording",stopRecording:"Stop Recording",loading:"Loading...",noVoice:"No voice data",recordingRemaining:"{time}s remaining",releaseToStop:"Release to stop",clickToStop:"Click again to stop",voiceSentSuccess:"Voice sent successfully",recordComplete:"Recording completed",voiceSendFailed:"Failed to send voice",recordFailed:"Recording failed",recordTooShort:"Recording is too short (min 3s)",micPermissionDenied:"Please allow microphone permission"},i18n=new(function(){function I18n(){this.currentLanguage="zh",this.translations={zh:zh_CN,en:en_US}}var _proto=I18n.prototype;return _proto.setLanguage=function(language){this.currentLanguage=language},_proto.t=function(key){return this.translations[this.currentLanguage][key]||key},_proto.getLanguage=function(){return this.currentLanguage},I18n}());function asyncGeneratorStep$1(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg),value=info.value}catch(error){return void reject(error)}info.done?resolve(value):Promise.resolve(value).then(_next,_throw)}function _async_to_generator$1(fn){return function(){var self=this,args=arguments;return new Promise(function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep$1(gen,resolve,reject,_next,_throw,"next",value)}function _throw(err){asyncGeneratorStep$1(gen,resolve,reject,_next,_throw,"throw",err)}_next(void 0)})}}function _instanceof(left,right){return null!=right&&"undefined"!=typeof Symbol&&right[Symbol.hasInstance]?!!right[Symbol.hasInstance](left):left instanceof right}function _set_prototype_of$1(o,p){return _set_prototype_of$1=Object.setPrototypeOf||function(o,p){return o.__proto__=p,o},_set_prototype_of$1(o,p)}function _ts_generator$1(thisArg,body){var f,y,t,_={label:0,sent:function(){if(1&t[0])throw t[1];return t[1]},trys:[],ops:[]},g=Object.create(("function"==typeof Iterator?Iterator:Object).prototype),d=Object.defineProperty;return d(g,"next",{value:verb(0)}),d(g,"throw",{value:verb(1)}),d(g,"return",{value:verb(2)}),"function"==typeof Symbol&&d(g,Symbol.iterator,{value:function(){return this}}),g;function verb(n){return function(v){return function(op){if(f)throw new TypeError("Generator is already executing.");for(;g&&(g=0,op[0]&&(_=0)),_;)try{if(f=1,y&&(t=2&op[0]?y.return:op[0]?y.throw||((t=y.return)&&t.call(y),0):y.next)&&!(t=t.call(y,op[1])).done)return t;switch(y=0,t&&(op=[2&op[0],t.value]),op[0]){case 0:case 1:t=op;break;case 4:return _.label++,{value:op[1],done:!1};case 5:_.label++,y=op[1],op=[0];continue;case 7:op=_.ops.pop(),_.trys.pop();continue;default:if(!(t=_.trys,(t=t.length>0&&t[t.length-1])||6!==op[0]&&2!==op[0])){_=0;continue}if(3===op[0]&&(!t||op[1]>t[0]&&op[1]<t[3])){_.label=op[1];break}if(6===op[0]&&_.label<t[1]){_.label=t[1],t=op;break}if(t&&_.label<t[2]){_.label=t[2],_.ops.push(op);break}t[2]&&_.ops.pop(),_.trys.pop();continue}op=body.call(thisArg,_)}catch(e){op=[6,e],y=0}finally{f=t=0}if(5&op[0])throw op[1];return{value:op[0]?op[1]:void 0,done:!0}}([n,v])}}}var PREFIX="ebroadcast",WAVE_BARS=[{height:15,color:"#CCCCCC"},{height:30,color:"#D6D6D6"},{height:45,color:"#E0E0E0"},{height:60,color:"#EBEBEB"},{height:85,color:"#FFFFFF"},{height:60,color:"#EBEBEB"},{height:45,color:"#E0E0E0"},{height:30,color:"#D6D6D6"},{height:15,color:"#CCCCCC"}],BroadcastUI=function(Drawer){function BroadcastUI(container,options){var _this;i18n.setLanguage(options.language||"zh");var isMobile=!!options.isMobile,placement=BroadcastUI.resolvePlacement(options.direction),contentRoot=BroadcastUI.buildContent(isMobile),drawerOptions={title:i18n.t("title"),content:contentRoot,placement:placement,showHeader:!0,showClose:!0,maskClosable:!0,closeOnEscape:!0,className:PREFIX+"-drawer"};return"left"===placement||"right"===placement?drawerOptions.width="80%":drawerOptions.height="80%",(_this=Drawer.call(this,container,drawerOptions)||this).broadcastOptions=options,_this.logger=createLogger(options.logger),_this.isMobile=isMobile,_this.voiceList=options.voiceList||[],_this.isRecording=!1,_this.isStarting=!1,_this.lastTouchTime=0,_this.pendingStop=!1,_this.pendingCancel=!1,_this.tipTimer=null,_this.recordingMessageId=null,_this.waveBars=[],_this.recordingHint=null,_this.waveTimer=null,_this.countdownTimer=null,_this.remainingTime=59,_this.options.onOpenChange=function(open){return _this.handleOpenChange(open)},_this.voiceListElement=contentRoot.querySelector(".ebroadcast-voice-list"),_this.loadingElement=contentRoot.querySelector(".ebroadcast-loading"),_this.emptyElement=contentRoot.querySelector(".ebroadcast-empty"),_this.errorElement=contentRoot.querySelector(".ebroadcast-error"),_this.tipElement=contentRoot.querySelector(".ebroadcast-tip"),_this.talkButton=contentRoot.querySelector(".ebroadcast-talk-btn"),_this.recordingMessage=new Message(contentRoot,{className:PREFIX+"-recording",duration:0,maxCount:1,zIndex:1}),_this.bindEvents(),_this.voiceList.length>0?_this.renderVoiceList():_this.setLoading(!0),_this.logger.log("[BroadcastUI] UI创建完成,isMobile:",isMobile),_this}!function(subClass,superClass){if("function"!=typeof superClass&&null!==superClass)throw new TypeError("Super expression must either be null or a function");subClass.prototype=Object.create(superClass&&superClass.prototype,{constructor:{value:subClass,writable:!0,configurable:!0}}),superClass&&_set_prototype_of$1(subClass,superClass)}(BroadcastUI,Drawer);var _proto=BroadcastUI.prototype;return _proto.handleOpenChange=function(open){open||this.cancelRecording()},_proto.cancelRecording=function(){this.isStarting&&(this.pendingCancel=!0),this.isRecording=!1,this.pendingStop=!1,this.hideRecordingMessage(),this.setTalkButtonRecording(!1),this.cancelRecord()},_proto.bindEvents=function(){var _this_voiceListElement,_this=this;null==(_this_voiceListElement=this.voiceListElement)||_this_voiceListElement.addEventListener("click",function(e){var item=e.target.closest(".ebroadcast-voice-item");if(item){var index=parseInt(item.getAttribute("data-index")||"-1",10);_this.selectVoice(index)}}),this.talkButton&&(this.logger.log("[BroadcastUI] 绑定按钮事件,isMobile:",this.isMobile),this.isMobile?(this.logger.log("[BroadcastUI] 使用移动端交互:按住说话"),this.talkButton.addEventListener("touchstart",function(e){e.preventDefault(),e.stopPropagation();var now=Date.now();now-_this.lastTouchTime<300?_this.logger.log("[BroadcastUI] 触摸事件防抖,忽略快速点击"):(_this.lastTouchTime=now,_this.handleRecordStart())},{passive:!1}),this.talkButton.addEventListener("touchend",function(e){e.preventDefault(),e.stopPropagation(),_this.handleRecordStop()},{passive:!1}),this.talkButton.addEventListener("touchcancel",function(){_this.isRecording&&_this.handleRecordStop()})):(this.logger.log("[BroadcastUI] 使用PC端交互:点击切换"),this.talkButton.addEventListener("click",function(e){e.preventDefault(),_this.logger.log("[BroadcastUI] PC端按钮点击事件触发"),_this.handleRecordToggle()})))},_proto.handleRecordToggle=function(){this.isRecording?this.handleRecordStop():this.handleRecordStart()},_proto.handleRecordStart=function(){return _async_to_generator$1(function(){var error;return _ts_generator$1(this,function(_state){switch(_state.label){case 0:if(this.isRecording||this.isStarting)return this.logger.log("[BroadcastUI] 录音已在进行中,忽略重复启动"),[2];_state.label=1;case 1:return _state.trys.push([1,5,,6]),this.logger.log("[BroadcastUI] 开始录音..."),this.pendingStop=!1,this.pendingCancel=!1,this.isStarting=!0,this.showRecordingMessage(),this.setTalkButtonRecording(!0),[4,this.startRecord()];case 2:return _state.sent(),this.isStarting=!1,this.pendingCancel?(this.logger.log("[BroadcastUI] 启动期间面板已关闭,取消录音"),this.pendingCancel=!1,this.isRecording=!1,this.cancelRecord(),[2]):(this.isRecording=!0,this.pendingStop?(this.logger.log("[BroadcastUI] 检测到待处理的停止请求,立即停止录音"),this.pendingStop=!1,[4,this.handleRecordStop()]):[3,4]);case 3:_state.sent(),_state.label=4;case 4:return[3,6];case 5:return error=_state.sent(),this.logger.error("[BroadcastUI] 开始录音失败",error),this.isStarting=!1,this.isRecording=!1,this.pendingStop=!1,this.pendingCancel=!1,this.hideRecordingMessage(),this.setTalkButtonRecording(!1),this.showError(_instanceof(error,Error)?error.message:"开始录音失败"),[3,6];case 6:return[2]}})}).call(this)},_proto.handleRecordStop=function(){return _async_to_generator$1(function(){var error;return _ts_generator$1(this,function(_state){switch(_state.label){case 0:if(this.isStarting)return this.logger.log("[BroadcastUI] 录音正在启动中,标记为待停止"),this.pendingStop=!0,[2];if(!this.isRecording)return this.logger.log("[BroadcastUI] 未在录音状态,忽略停止请求"),[2];_state.label=1;case 1:return _state.trys.push([1,3,,4]),this.logger.log("[BroadcastUI] 停止录音..."),this.hideRecordingMessage(),this.setTalkButtonRecording(!1),[4,this.stopRecord()];case 2:return _state.sent(),this.isRecording=!1,[3,4];case 3:return error=_state.sent(),this.logger.error("[BroadcastUI] 停止录音失败",error),this.isRecording=!1,this.hideRecordingMessage(),this.setTalkButtonRecording(!1),this.showError(_instanceof(error,Error)?error.message:"停止录音失败"),[3,4];case 4:return[2]}})}).call(this)},_proto.setTalkButtonRecording=function(recording){if(this.talkButton){this.talkButton.classList.toggle(PREFIX+"-talk-btn-recording",recording);var textElement=this.talkButton.querySelector(".ebroadcast-talk-text");textElement&&(textElement.textContent=recording?this.isMobile?i18n.t("recording"):i18n.t("stopRecording"):this.isMobile?i18n.t("pressToTalk"):i18n.t("clickToTalk"))}},_proto.showRecordingMessage=function(){if(!this.recordingMessageId){var content=BroadcastUI.buildRecordingContent();this.waveBars=Array.from(content.querySelectorAll("rect")),this.recordingHint=content.querySelector(".ebroadcast-recording-hint"),this.remainingTime=59,this.updateRecordingHint(),this.recordingMessageId=this.recordingMessage.info(content,{duration:0}),this.startWaveAnimation(),this.startCountdown(),this.logger.log("[BroadcastUI] 录音提示已显示")}},_proto.hideRecordingMessage=function(){this.stopWaveAnimation(),this.stopCountdown(),this.recordingMessageId&&(this.recordingMessage.close(this.recordingMessageId),this.recordingMessageId=null,this.logger.log("[BroadcastUI] 录音提示已隐藏")),this.waveBars=[],this.recordingHint=null},_proto.startWaveAnimation=function(){var _this=this;this.stopWaveAnimation();var frame=0;this.waveTimer=window.setInterval(function(){_this.waveBars.forEach(function(bar,index){var phase=(.3*frame+.8*index)%(2*Math.PI),height=30+(Math.sin(phase)+1)/2*50;bar.setAttribute("height",height.toFixed(2)),bar.setAttribute("y",(50-height/2).toFixed(2))}),frame++},100)},_proto.stopWaveAnimation=function(){null!==this.waveTimer&&(clearInterval(this.waveTimer),this.waveTimer=null)},_proto.startCountdown=function(){var _this=this;this.stopCountdown(),this.countdownTimer=window.setInterval(function(){_this.remainingTime--,_this.updateRecordingHint(),_this.remainingTime<=0&&_this.stopCountdown()},1e3)},_proto.stopCountdown=function(){null!==this.countdownTimer&&(clearInterval(this.countdownTimer),this.countdownTimer=null)},_proto.updateRecordingHint=function(){if(this.recordingHint){var remaining=Math.max(0,this.remainingTime);this.recordingHint.textContent=remaining>0?i18n.t("recordingRemaining").replace("{time}",String(remaining)):this.isMobile?i18n.t("releaseToStop"):i18n.t("clickToStop")}},_proto.close=function(){this.open=!1},_proto.updateVoiceList=function(voiceList){this.voiceList=Array.isArray(voiceList)?voiceList:[],this.renderVoiceList()},_proto.renderVoiceList=function(){if(this.voiceListElement){if(this.setLoading(!1),this.setError(""),0===this.voiceList.length)return this.voiceListElement.innerHTML="",this.voiceListElement.parentElement&&(this.voiceListElement.parentElement.style.display="none"),void(this.emptyElement&&(this.emptyElement.style.display="flex"));this.voiceListElement.parentElement&&(this.voiceListElement.parentElement.style.display=""),this.emptyElement&&(this.emptyElement.style.display="none"),this.voiceListElement.innerHTML=this.voiceList.map(function(voice,index){var name=BroadcastUI.escape(voice.voiceName);return'\n <div class="ebroadcast-voice-item" data-index="'+index+'">\n <div class="'+PREFIX+'-voice-icon">\n <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">\n <path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/>\n </svg>\n </div>\n <div class="'+PREFIX+'-voice-text" title="'+name+'">'+name+"</div>\n </div>\n "}).join(""),this.logger.log("[BroadcastUI] 语音列表已渲染",this.voiceList.length)}},_proto.selectVoice=function(index){if(this.voiceListElement&&(this.voiceListElement.querySelectorAll(".ebroadcast-voice-item").forEach(function(item){item.classList.remove(PREFIX+"-voice-item-selected")}),index>=0&&index<this.voiceList.length)){var selectedItem=this.voiceListElement.querySelector('[data-index="'+index+'"]');selectedItem&&selectedItem.classList.add(PREFIX+"-voice-item-selected");var selectedVoice=this.voiceList[index];this.logger.log("[BroadcastUI] 已选中语音:",selectedVoice.voiceName),this.sendVoice(selectedVoice.fileUrl)}},_proto.setRecordingState=function(isRecording){this.isRecording=isRecording,this.logger.log("[BroadcastUI] 录音状态:",isRecording)},_proto.setLoading=function(loading){var _this_voiceListElement;this.loadingElement&&(this.loadingElement.style.display=loading?"flex":"none");var content=null==(_this_voiceListElement=this.voiceListElement)?void 0:_this_voiceListElement.parentElement;loading?(this.emptyElement&&(this.emptyElement.style.display="none"),this.errorElement&&(this.errorElement.style.display="none"),content&&(content.style.display="none")):content&&this.voiceList.length>0&&(content.style.display="")},_proto.setError=function(message){var _this_voiceListElement;if(this.errorElement){this.errorElement.textContent=message,this.errorElement.style.display=message?"flex":"none";var content=null==(_this_voiceListElement=this.voiceListElement)?void 0:_this_voiceListElement.parentElement;message?(this.loadingElement&&(this.loadingElement.style.display="none"),this.emptyElement&&(this.emptyElement.style.display="none"),content&&(content.style.display="none")):content&&this.voiceList.length>0&&(content.style.display="")}},_proto.showSuccess=function(message){this.logger.log("[BroadcastUI] 成功:",message),this.showTip(message,!1)},_proto.showError=function(message){this.logger.error("[BroadcastUI] 错误:",message),this.showTip(message,!0)},_proto.showTip=function(message,isError){var _this=this;this.tipElement&&message&&(this.tipElement.textContent=message,this.tipElement.classList.toggle(PREFIX+"-tip-error",isError),this.tipElement.style.display="block",this.tipElement.offsetWidth,this.tipElement.classList.add(PREFIX+"-tip-visible"),this.tipTimer&&clearTimeout(this.tipTimer),this.tipTimer=window.setTimeout(function(){var _this_tipElement;_this.tipTimer=null,null==(_this_tipElement=_this.tipElement)||_this_tipElement.classList.remove(PREFIX+"-tip-visible"),_this.tipTimer=window.setTimeout(function(){_this.tipTimer=null,_this.tipElement&&(_this.tipElement.style.display="none")},200)},2e3))},_proto.destroy=function(){this.tipTimer&&(clearTimeout(this.tipTimer),this.tipTimer=null),this.stopWaveAnimation(),this.stopCountdown(),this.recordingMessageId=null,this.waveBars=[],this.recordingHint=null,this.recordingMessage.destroy(),Drawer.prototype.destroy.call(this),this.voiceListElement=null,this.loadingElement=null,this.emptyElement=null,this.errorElement=null,this.tipElement=null,this.talkButton=null,this.logger.log("[BroadcastUI] UI已销毁")},BroadcastUI.resolvePlacement=function(direction){return"top"===direction||"bottom"===direction||"left"===direction||"right"===direction?direction:"right"},BroadcastUI.buildContent=function(isMobile){var t=i18n.t.bind(i18n),root=document.createElement("div");return root.className=PREFIX+"-content-root",root.innerHTML='\n \x3c!-- Tab区域 --\x3e\n <div class="ebroadcast-tabs">\n <div class="ebroadcast-tab ebroadcast-tab-active">'+t("defaultVoice")+'</div>\n </div>\n\n \x3c!-- 内容区域 --\x3e\n <div class="'+PREFIX+'-content">\n <div class="'+PREFIX+'-voice-list"></div>\n </div>\n\n \x3c!-- 状态区:加载 / 空 / 错误,互斥展示 --\x3e\n <div class="'+PREFIX+'-loading" style="display:none;">'+t("loading")+'</div>\n <div class="'+PREFIX+'-empty" style="display:none;">'+t("noVoice")+'</div>\n <div class="'+PREFIX+'-error" style="display:none;"></div>\n\n \x3c!-- 底部按钮 --\x3e\n <div class="'+PREFIX+'-footer">\n <button class="'+PREFIX+'-talk-btn" type="button">\n <span class="'+PREFIX+'-talk-text">'+t(isMobile?"pressToTalk":"clickToTalk")+'</span>\n </button>\n </div>\n\n \x3c!-- 轻提示:showSuccess / showError 复用 --\x3e\n <div class="'+PREFIX+'-tip" style="display:none;"></div>\n ',root},BroadcastUI.buildRecordingContent=function(){var bars=WAVE_BARS.map(function(bar,index){return'<rect x="'+(5+16*index)+'" y="'+(50-bar.height/2)+'" width="12" height="'+bar.height+'" rx="6" fill="'+bar.color+'" />'}).join(""),root=document.createElement("span");return root.className=PREFIX+"-recording-content",root.innerHTML='<svg class="ebroadcast-recording-wave" viewBox="0 0 150 100" width="80" height="40" aria-hidden="true" focusable="false">'+bars+'</svg><span class="'+PREFIX+'-recording-hint" aria-live="off"></span>',root},BroadcastUI.escape=function(value){return String(null!=value?value:"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")},BroadcastUI}(Drawer);function asyncGeneratorStep(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg),value=info.value}catch(error){return void reject(error)}info.done?resolve(value):Promise.resolve(value).then(_next,_throw)}function _async_to_generator(fn){return function(){var self=this,args=arguments;return new Promise(function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"next",value)}function _throw(err){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"throw",err)}_next(void 0)})}}function _set_prototype_of(o,p){return _set_prototype_of=Object.setPrototypeOf||function(o,p){return o.__proto__=p,o},_set_prototype_of(o,p)}function _ts_generator(thisArg,body){var f,y,t,_={label:0,sent:function(){if(1&t[0])throw t[1];return t[1]},trys:[],ops:[]},g=Object.create(("function"==typeof Iterator?Iterator:Object).prototype),d=Object.defineProperty;return d(g,"next",{value:verb(0)}),d(g,"throw",{value:verb(1)}),d(g,"return",{value:verb(2)}),"function"==typeof Symbol&&d(g,Symbol.iterator,{value:function(){return this}}),g;function verb(n){return function(v){return function(op){if(f)throw new TypeError("Generator is already executing.");for(;g&&(g=0,op[0]&&(_=0)),_;)try{if(f=1,y&&(t=2&op[0]?y.return:op[0]?y.throw||((t=y.return)&&t.call(y),0):y.next)&&!(t=t.call(y,op[1])).done)return t;switch(y=0,t&&(op=[2&op[0],t.value]),op[0]){case 0:case 1:t=op;break;case 4:return _.label++,{value:op[1],done:!1};case 5:_.label++,y=op[1],op=[0];continue;case 7:op=_.ops.pop(),_.trys.pop();continue;default:if(!(t=_.trys,(t=t.length>0&&t[t.length-1])||6!==op[0]&&2!==op[0])){_=0;continue}if(3===op[0]&&(!t||op[1]>t[0]&&op[1]<t[3])){_.label=op[1];break}if(6===op[0]&&_.label<t[1]){_.label=t[1],t=op;break}if(t&&_.label<t[2]){_.label=t[2],_.ops.push(op);break}t[2]&&_.ops.pop(),_.trys.pop();continue}op=body.call(thisArg,_)}catch(e){op=[6,e],y=0}finally{f=t=0}if(5&op[0])throw op[1];return{value:op[0]?op[1]:void 0,done:!0}}([n,v])}}}var _BROADCAST_DefaultOptions_={channelNo:"1",env:{domain:"https://open.ys7.com"},language:"zh"},Broadcast=function(BroadcastUI){function Broadcast(options){var _this,broadcastOptions=Object.assign({},_BROADCAST_DefaultOptions_,options);return(_this=BroadcastUI.call(this,broadcastOptions.container||document.body,broadcastOptions)||this).voiceRecorder=null,_this.maxDurationTimer=null,_this.pendingAudioBlob=null,_this.logger.log("1.0.0-beta.1 init"),_this}!function(subClass,superClass){if("function"!=typeof superClass&&null!==superClass)throw new TypeError("Super expression must either be null or a function");subClass.prototype=Object.create(superClass&&superClass.prototype,{constructor:{value:subClass,writable:!0,configurable:!0}}),superClass&&_set_prototype_of(subClass,superClass)}(Broadcast,BroadcastUI);var _proto=Broadcast.prototype;return _proto.invoke=function(name){for(var _len=arguments.length,args=new Array(_len>1?_len-1:0),_key=1;_key<_len;_key++)args[_key-1]=arguments[_key];var callback=this.broadcastOptions[name];if("function"==typeof callback)try{callback.apply(void 0,[].concat(args))}catch(error){this.logger.error('回调 "'+name+'" 执行出错:',error)}},_proto.initMicrophonePermission=function(){return _async_to_generator(function(){var error;return _ts_generator(this,function(_state){switch(_state.label){case 0:return _state.trys.push([0,2,,3]),this.logger.log("开始请求麦克风权限..."),[4,navigator.mediaDevices.getUserMedia({audio:{sampleRate:16e3,channelCount:1,echoCancellation:!0,noiseSuppression:!0}})];case 1:return _state.sent().getTracks().forEach(function(track){return track.stop()}),this.logger.log("麦克风权限已获取"),[3,3];case 2:return error=_state.sent(),this.logger.warn("麦克风权限获取失败,将在首次录音时再次请求",error),this.invoke("onError",{msg:"麦克风权限获取失败",error:error}),[3,3];case 3:return[2]}})}).call(this)},_proto.requestMicrophonePermission=function(){return _async_to_generator(function(){var error;return _ts_generator(this,function(_state){switch(_state.label){case 0:return _state.trys.push([0,2,,3]),this.logger.log("手动请求麦克风权限..."),[4,navigator.mediaDevices.getUserMedia({audio:{sampleRate:16e3,channelCount:1,echoCancellation:!0,noiseSuppression:!0}})];case 1:return _state.sent().getTracks().forEach(function(track){return track.stop()}),this.logger.log("麦克风权限已获取"),[2,!0];case 2:return error=_state.sent(),this.logger.error("麦克风权限获取失败",error),this.invoke("onError",{msg:"麦克风权限获取失败",error:error}),[2,!1];case 3:return[2]}})}).call(this)},_proto.handleOpenChange=function(open){BroadcastUI.prototype.handleOpenChange.call(this,open),open?(0===this.voiceList.length&&this.loadVoiceList(),this.invoke("onOpen"),this.logger.log("云广播界面已打开")):(this.invoke("onClose"),this.logger.log("云广播界面已关闭"))},_proto.loadVoiceList=function(){this.logger.log("请求加载语音列表"),this.invoke("onRequestQueryVoiceList",{deviceSerial:this.broadcastOptions.deviceSerial,channelNo:this.broadcastOptions.channelNo,pageSize:50})},_proto.startRecord=function(){return _async_to_generator(function(){var _this,error;return _ts_generator(this,function(_state){switch(_state.label){case 0:_this=this,_state.label=1;case 1:return _state.trys.push([1,3,,4]),this.logger.log("开始录音"),this.pendingAudioBlob=null,this.voiceRecorder||(this.voiceRecorder=new VoiceRecorder({minDuration:3,maxDuration:59,sampleRate:16e3,logger:this.logger})),[4,this.voiceRecorder.start()];case 2:return _state.sent(),this.maxDurationTimer=window.setTimeout(function(){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:return this.logger.log("达到最大录音时长,停止录音并暂存"),[4,this.stopRecordAndCache()];case 1:return _state.sent(),[2]}})}).call(_this)},59e3),this.invoke("onRecordStart"),this.setRecordingState(!0),[3,4];case 3:return error=_state.sent(),this.logger.error("开始录音失败",error),this.invoke("onRecordError",{msg:"开始录音失败",error:error}),[3,4];case 4:return[2]}})}).call(this)},_proto.stopRecordAndCache=function(){return _async_to_generator(function(){var audioBlob,error;return _ts_generator(this,function(_state){switch(_state.label){case 0:return _state.trys.push([0,2,,3]),this.voiceRecorder?this.voiceRecorder.isRecording()?[4,this.voiceRecorder.stop()]:(this.logger.warn("录音器已停止"),[2]):[2];case 1:return 0===(audioBlob=_state.sent()).size?(this.logger.warn("录音数据为空"),[2]):(this.pendingAudioBlob=audioBlob,this.invoke("onRecordComplete",audioBlob),[3,3]);case 2:return error=_state.sent(),this.logger.error("停止录音失败",error),this.setRecordingState(!1),[3,3];case 3:return[2]}})}).call(this)},_proto.stopRecord=function(){return _async_to_generator(function(){var audioBlob,audioBlob1,error;return _ts_generator(this,function(_state){switch(_state.label){case 0:if(_state.trys.push([0,2,,3]),this.clearMaxDurationTimer(),this.pendingAudioBlob)return audioBlob=this.pendingAudioBlob,this.pendingAudioBlob=null,this.invoke("onRecordStop"),this.setRecordingState(!1),this.sendVoiceOnce(audioBlob),[2];if(!this.voiceRecorder)throw new Error("录音器未初始化");return this.voiceRecorder.isRecording()?[4,this.voiceRecorder.stop()]:(this.logger.warn("录音器已停止"),this.setRecordingState(!1),[2]);case 1:return 0===(audioBlob1=_state.sent()).size?(this.logger.error("录音数据为空,不进行下发"),this.setRecordingState(!1),[2]):(this.invoke("onRecordStop"),this.invoke("onRecordComplete",audioBlob1),this.setRecordingState(!1),this.sendVoiceOnce(audioBlob1),[3,3]);case 2:return error=_state.sent(),this.logger.error("停止录音失败",error),this.invoke("onRecordError",{msg:"停止录音失败",error:error}),this.setRecordingState(!1),[3,3];case 3:return[2]}})}).call(this)},_proto.cancelRecord=function(){var _this_voiceRecorder,_this=this;this.clearMaxDurationTimer(),this.pendingAudioBlob=null,(null==(_this_voiceRecorder=this.voiceRecorder)?void 0:_this_voiceRecorder.isRecording())&&this.voiceRecorder.stop().then(function(){return _this.logger.log("已取消录音,录音已丢弃")},function(){return _this.logger.log("已取消录音(录音时长不足)")})},_proto.clearMaxDurationTimer=function(){this.maxDurationTimer&&(clearTimeout(this.maxDurationTimer),this.maxDurationTimer=null)},_proto.sendVoiceOnce=function(voiceFile){var _this_broadcastOptions=this.broadcastOptions,deviceSerial=_this_broadcastOptions.deviceSerial,channelNo=_this_broadcastOptions.channelNo;this.invoke("onVoiceRecorded",{voiceFile:voiceFile,deviceSerial:deviceSerial,channelNo:channelNo}),this.invoke("onRequestSendVoiceOnce",{voiceFile:voiceFile,deviceSerial:deviceSerial,channelNo:channelNo})},_proto.sendVoice=function(fileUrl){this.logger.log("请求下发默认语音",fileUrl),this.invoke("onRequestSendVoice",{fileUrl:fileUrl,deviceSerial:this.broadcastOptions.deviceSerial,channelNo:this.broadcastOptions.channelNo})},_proto.updateOptions=function(options){this.broadcastOptions=Object.assign(this.broadcastOptions,options),this.logger.log("配置已更新",Object.keys(options))},_proto.destroy=function(){this.logger.log("开始销毁"),this.close(),this.clearMaxDurationTimer(),this.pendingAudioBlob=null,this.voiceRecorder&&(this.voiceRecorder.destroy(),this.voiceRecorder=null),BroadcastUI.prototype.destroy.call(this),this.voiceList=[],this.logger.log("销毁完成")},Broadcast}(BroadcastUI);Broadcast.VERSION="1.0.0-beta.1",module.exports=Broadcast;
|
package/dist/index.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* @ezuikit/control-broadcast
|
|
3
|
-
* Copyright (c) 2026-
|
|
2
|
+
* @ezuikit/control-broadcast v1.0.0-beta.1
|
|
3
|
+
* Copyright (c) 2026-11-14 15:37:02 Ezviz-OpenBiz
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
6
|
-
var EventEmitter=function(){function EventEmitter(){this.events=new Map}var _proto=EventEmitter.prototype;return _proto.on=function(event,callback){this.events.has(event)||this.events.set(event,[]),this.events.get(event).push(callback)},_proto.off=function(event,callback){if(this.events.has(event)){var callbacks=this.events.get(event),index=callbacks.indexOf(callback);index>-1&&callbacks.splice(index,1),0===callbacks.length&&this.events.delete(event)}},_proto.emit=function(event){for(var _len=arguments.length,args=new Array(_len>1?_len-1:0),_key=1;_key<_len;_key++)args[_key-1]=arguments[_key];this.events.has(event)&&this.events.get(event).forEach(function(callback){try{callback.apply(void 0,[].concat(args))}catch(error){}})},_proto.once=function(event,callback){var _this=this,onceCallback=function(){for(var _len=arguments.length,args=new Array(_len),_key=0;_key<_len;_key++)args[_key]=arguments[_key];callback.apply(void 0,[].concat(args)),_this.off(event,onceCallback)};this.on(event,onceCallback)},_proto.removeAllListeners=function(){this.events.clear()},_proto.listenerCount=function(event){var _this_events_get;return(null==(_this_events_get=this.events.get(event))?void 0:_this_events_get.length)||0},EventEmitter}();function _array_like_to_array(arr,len){(null==len||len>arr.length)&&(len=arr.length);for(var i=0,arr2=new Array(len);i<len;i++)arr2[i]=arr[i];return arr2}function asyncGeneratorStep$2(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg),value=info.value}catch(error){return void reject(error)}info.done?resolve(value):Promise.resolve(value).then(_next,_throw)}function _async_to_generator$2(fn){return function(){var self=this,args=arguments;return new Promise(function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep$2(gen,resolve,reject,_next,_throw,"next",value)}function _throw(err){asyncGeneratorStep$2(gen,resolve,reject,_next,_throw,"throw",err)}_next(void 0)})}}function _create_for_of_iterator_helper_loose(o,allowArrayLike){var it="undefined"!=typeof Symbol&&o[Symbol.iterator]||o["@@iterator"];if(it)return(it=it.call(o)).next.bind(it);if(Array.isArray(o)||(it=function(o,minLen){if(o){if("string"==typeof o)return _array_like_to_array(o,minLen);var n=Object.prototype.toString.call(o).slice(8,-1);return"Object"===n&&o.constructor&&(n=o.constructor.name),"Map"===n||"Set"===n?Array.from(n):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?_array_like_to_array(o,minLen):void 0}}(o))||allowArrayLike){it&&(o=it);var i=0;return function(){return i>=o.length?{done:!0}:{done:!1,value:o[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _ts_generator$2(thisArg,body){var f,y,t,_={label:0,sent:function(){if(1&t[0])throw t[1];return t[1]},trys:[],ops:[]},g=Object.create(("function"==typeof Iterator?Iterator:Object).prototype);return g.next=verb(0),g.throw=verb(1),g.return=verb(2),"function"==typeof Symbol&&(g[Symbol.iterator]=function(){return this}),g;function verb(n){return function(v){return function(op){if(f)throw new TypeError("Generator is already executing.");for(;g&&(g=0,op[0]&&(_=0)),_;)try{if(f=1,y&&(t=2&op[0]?y.return:op[0]?y.throw||((t=y.return)&&t.call(y),0):y.next)&&!(t=t.call(y,op[1])).done)return t;switch(y=0,t&&(op=[2&op[0],t.value]),op[0]){case 0:case 1:t=op;break;case 4:return _.label++,{value:op[1],done:!1};case 5:_.label++,y=op[1],op=[0];continue;case 7:op=_.ops.pop(),_.trys.pop();continue;default:if(!(t=_.trys,(t=t.length>0&&t[t.length-1])||6!==op[0]&&2!==op[0])){_=0;continue}if(3===op[0]&&(!t||op[1]>t[0]&&op[1]<t[3])){_.label=op[1];break}if(6===op[0]&&_.label<t[1]){_.label=t[1],t=op;break}if(t&&_.label<t[2]){_.label=t[2],_.ops.push(op);break}t[2]&&_.ops.pop(),_.trys.pop();continue}op=body.call(thisArg,_)}catch(e){op=[6,e],y=0}finally{f=t=0}if(5&op[0])throw op[1];return{value:op[0]?op[1]:void 0,done:!0}}([n,v])}}}var VoiceRecorder=function(){function VoiceRecorder(options){void 0===options&&(options={}),this.options={minDuration:options.minDuration||3,maxDuration:options.maxDuration||59,sampleRate:options.sampleRate||16e3,channelCount:options.channelCount||1},this.audioContext=null,this.mediaStreamSource=null,this.scriptProcessor=null,this.stream=null,this.startTime=0,this.maxTimer=null,this.audioBuffers=[],this.isRecordingFlag=!1,this.isIOSDevice=/iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream,this.mediaRecorder=null,this.recordedChunks=[]}var _proto=VoiceRecorder.prototype;return _proto.start=function(){return _async_to_generator$2(function(){var error;return _ts_generator$2(this,function(_state){switch(_state.label){case 0:if(this.isRecordingFlag)return[2];_state.label=1;case 1:return _state.trys.push([1,3,,4]),[4,this.startWithScriptProcessor()];case 2:return _state.sent(),this.startTime=Date.now(),this.isRecordingFlag=!0,[3,4];case 3:throw error=_state.sent(),this.isRecordingFlag=!1,error;case 4:return[2]}})}).call(this)},_proto.startWithMediaRecorder=function(){return _async_to_generator$2(function(){var _this,_,mimeType;return _ts_generator$2(this,function(_state){switch(_state.label){case 0:return _this=this,_=this,[4,navigator.mediaDevices.getUserMedia({audio:!0})];case 1:return _.stream=_state.sent(),this.recordedChunks=[],mimeType="",MediaRecorder.isTypeSupported("audio/mp4")?mimeType="audio/mp4":MediaRecorder.isTypeSupported("audio/webm")?mimeType="audio/webm":MediaRecorder.isTypeSupported("audio/wav")&&(mimeType="audio/wav"),this.mediaRecorder=new MediaRecorder(this.stream,{mimeType:mimeType||void 0}),this.mediaRecorder.ondataavailable=function(event){event.data.size>0&&_this.recordedChunks.push(event.data)},this.mediaRecorder.start(),[2]}})}).call(this)},_proto.startWithScriptProcessor=function(){return _async_to_generator$2(function(){var _this,audioConstraints,_;return _ts_generator$2(this,function(_state){switch(_state.label){case 0:return _this=this,audioConstraints=this.isIOSDevice?{audio:!0}:{audio:{sampleRate:this.options.sampleRate,channelCount:this.options.channelCount,echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0}},_=this,[4,navigator.mediaDevices.getUserMedia(audioConstraints)];case 1:return _.stream=_state.sent(),this.audioContext=new(window.AudioContext||window.webkitAudioContext)({sampleRate:this.options.sampleRate}),this.mediaStreamSource=this.audioContext.createMediaStreamSource(this.stream),this.scriptProcessor=this.audioContext.createScriptProcessor(4096,1,1),this.audioBuffers=[],this.scriptProcessor.onaudioprocess=function(event){if(_this.isRecordingFlag){var inputData=event.inputBuffer.getChannelData(0);_this.audioBuffers.push(new Float32Array(inputData))}},this.mediaStreamSource.connect(this.scriptProcessor),this.scriptProcessor.connect(this.audioContext.destination),[2]}})}).call(this)},_proto.stop=function(){return _async_to_generator$2(function(){var _this;return _ts_generator$2(this,function(_state){switch(_state.label){case 0:return _this=this,[4,new Promise(function(resolve,reject){if(_this.isRecordingFlag){var duration=(Date.now()-_this.startTime)/1e3;if(duration<_this.options.minDuration)return reject(new Error("录音时长不足"+_this.options.minDuration+"秒")),void _this.cleanup();try{_this.isRecordingFlag=!1,_this.stopWithScriptProcessor(duration,resolve,reject)}catch(error){_this.cleanup(),reject(error)}}else resolve(new Blob([],{type:"audio/wav"}))})];case 1:return[2,_state.sent()]}})}).call(this)},_proto.stopWithMediaRecorder=function(duration,resolve,reject){var _this=this;if(!this.mediaRecorder)return reject(new Error("MediaRecorder 未初始化")),void this.cleanup();this.mediaRecorder.onstop=function(){try{var _this_recordedChunks_,mimeType=(null==(_this_recordedChunks_=_this.recordedChunks[0])?void 0:_this_recordedChunks_.type)||"audio/wav",audioBlob=new Blob(_this.recordedChunks,{type:mimeType});_this.cleanup(),resolve(audioBlob)}catch(error){_this.cleanup(),reject(error)}},this.mediaRecorder.stop()},_proto.stopWithScriptProcessor=function(duration,resolve,reject){try{for(var _step,totalLength=this.audioBuffers.reduce(function(acc,buffer){return acc+buffer.length},0),mergedBuffer=new Float32Array(totalLength),offset=0,_iterator=_create_for_of_iterator_helper_loose(this.audioBuffers);!(_step=_iterator()).done;){var buffer=_step.value;mergedBuffer.set(buffer,offset),offset+=buffer.length}var wavBlob=this.encodeWAV(mergedBuffer,this.options.sampleRate);this.cleanup(),resolve(wavBlob)}catch(error){this.cleanup(),reject(error)}},_proto.encodeWAV=function(samples,sampleRate){var buffer=new ArrayBuffer(44+2*samples.length),view=new DataView(buffer),writeString=function(offset,string){for(var i=0;i<string.length;i++)view.setUint8(offset+i,string.charCodeAt(i))};return writeString(0,"RIFF"),view.setUint32(4,36+2*samples.length,!0),writeString(8,"WAVE"),writeString(12,"fmt "),view.setUint32(16,16,!0),view.setUint16(20,1,!0),view.setUint16(22,1,!0),view.setUint32(24,sampleRate,!0),view.setUint32(28,2*sampleRate,!0),view.setUint16(32,2,!0),view.setUint16(34,16,!0),writeString(36,"data"),view.setUint32(40,2*samples.length,!0),function(output,offset,input){for(var i=0;i<input.length;i++,offset+=2){var s=Math.max(-1,Math.min(1,input[i]));output.setInt16(offset,s<0?32768*s:32767*s,!0)}}(view,44,samples),new Blob([buffer],{type:"audio/wav"})},_proto.cleanup=function(){this.isRecordingFlag=!1,this.mediaRecorder&&("inactive"!==this.mediaRecorder.state&&this.mediaRecorder.stop(),this.mediaRecorder=null),this.recordedChunks=[],this.scriptProcessor&&(this.scriptProcessor.disconnect(),this.scriptProcessor=null),this.mediaStreamSource&&(this.mediaStreamSource.disconnect(),this.mediaStreamSource=null),this.audioContext&&(this.audioContext.close(),this.audioContext=null),this.stream&&(this.stream.getTracks().forEach(function(track){return track.stop()}),this.stream=null),this.audioBuffers=[]},_proto.destroy=function(){this.cleanup(),this.maxTimer&&(clearTimeout(this.maxTimer),this.maxTimer=null)},_proto.getDuration=function(){return 0===this.startTime?0:(Date.now()-this.startTime)/1e3},_proto.isRecording=function(){return this.isRecordingFlag},VoiceRecorder}(),zh_CN={title:"广播喊话",defaultVoice:"默认语音",pressToTalk:"按住说话",clickToTalk:"点击录音",sendVoice:"下发语音",recording:"录音中",stopRecording:"停止录音",loading:"加载中...",noVoice:"暂无语音数据",recordingRemaining:"还可录制 {time} 秒",releaseToStop:"松开结束录制",clickToStop:"再次点击按钮结束录制",voiceSentSuccess:"语音下发成功",recordComplete:"录音完成",voiceSendFailed:"语音下发失败",recordFailed:"录音失败",recordTooShort:"录音时长不足3秒",micPermissionDenied:"请允许麦克风权限"},en_US={title:"Voice Broadcast",defaultVoice:"Default Voice",pressToTalk:"Press to Talk",clickToTalk:"Click to Record",sendVoice:"Send Voice",recording:"Recording",stopRecording:"Stop Recording",loading:"Loading...",noVoice:"No voice data",recordingRemaining:"{time}s remaining",releaseToStop:"Release to stop",clickToStop:"Click again to stop",voiceSentSuccess:"Voice sent successfully",recordComplete:"Recording completed",voiceSendFailed:"Failed to send voice",recordFailed:"Recording failed",recordTooShort:"Recording is too short (min 3s)",micPermissionDenied:"Please allow microphone permission"},i18n=new(function(){function I18n(){this.currentLanguage="zh",this.translations={zh:zh_CN,en:en_US}}var _proto=I18n.prototype;return _proto.setLanguage=function(language){this.currentLanguage=language},_proto.t=function(key){return this.translations[this.currentLanguage][key]||key},_proto.getLanguage=function(){return this.currentLanguage},I18n}()),RecordingToast=function(){function RecordingToast(options){void 0===options&&(options={}),this.options={maxDuration:options.maxDuration||59,minDuration:options.minDuration||3,container:options.container||document.body,isMobile:options.isMobile||!1,language:options.language||"zh"},this.container=this.options.container,this.toastElement=null,this.waveformElement=null,this.timer=null,this.currentTime=this.options.maxDuration,this.waveAnimationFrame=null,i18n.setLanguage(this.options.language),this.injectStyles()}var _proto=RecordingToast.prototype;return _proto.injectStyles=function(){var styleId="ezuikit-recording-toast-styles";if(!document.getElementById(styleId)){var style=document.createElement("style");style.id=styleId,style.textContent="\n .ezuikit-recording-toast {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%) translateY(-80px);\n z-index: 9999;\n background: rgba(44, 44, 44, 0.95);\n border-radius: 16px;\n width: 120px;\n height: 120px;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 16px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);\n animation: ezuikit-toast-fade-in 0.2s ease;\n }\n\n /* 当 RecordingToast 在特定容器内时,使用绝对定位并居中 */\n .ezuikit-broadcast-panel .ezuikit-recording-toast {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n z-index: 1;\n }\n\n @keyframes ezuikit-toast-fade-in {\n from {\n opacity: 0;\n transform: translate(-50%, -50%) translateY(-80px) scale(0.9);\n }\n to {\n opacity: 1;\n transform: translate(-50%, -50%) translateY(-80px) scale(1);\n }\n }\n\n /* 面板内的 toast 淡入动画 */\n .ezuikit-broadcast-panel .ezuikit-recording-toast {\n animation: ezuikit-toast-fade-in-panel 0.2s ease;\n }\n\n @keyframes ezuikit-toast-fade-in-panel {\n from {\n opacity: 0;\n transform: translate(-50%, -50%) scale(0.9);\n }\n to {\n opacity: 1;\n transform: translate(-50%, -50%) scale(1);\n }\n }\n\n .ezuikit-recording-waveform {\n width: 80px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .ezuikit-recording-svg {\n width: 100%;\n height: 100%;\n object-fit: contain;\n }\n\n #ezuikit-recording-hint {\n font-size: 12px;\n color: rgba(255, 255, 255, 0.9);\n text-align: center;\n line-height: 20px;\n padding: 0 12px;\n }\n ",document.head.appendChild(style)}},_proto.getWaveformDefs=function(){return'\n \x3c!-- 柱子0: 最左,最暗 #CCCCCC --\x3e\n <linearGradient id="waveGradient0" x1="0%" y1="0%" x2="0%" y2="100%">\n <stop offset="0%" stop-color="#CCCCCC" stop-opacity="1" />\n <stop offset="100%" stop-color="#CCCCCC" stop-opacity="1" />\n </linearGradient>\n\n \x3c!-- 柱子1: #D6D6D6 --\x3e\n <linearGradient id="waveGradient1" x1="0%" y1="0%" x2="0%" y2="100%">\n <stop offset="0%" stop-color="#D6D6D6" stop-opacity="1" />\n <stop offset="100%" stop-color="#D6D6D6" stop-opacity="1" />\n </linearGradient>\n\n \x3c!-- 柱子2: #E0E0E0 --\x3e\n <linearGradient id="waveGradient2" x1="0%" y1="0%" x2="0%" y2="100%">\n <stop offset="0%" stop-color="#E0E0E0" stop-opacity="1" />\n <stop offset="100%" stop-color="#E0E0E0" stop-opacity="1" />\n </linearGradient>\n\n \x3c!-- 柱子3: #EBEBEB --\x3e\n <linearGradient id="waveGradient3" x1="0%" y1="0%" x2="0%" y2="100%">\n <stop offset="0%" stop-color="#EBEBEB" stop-opacity="1" />\n <stop offset="100%" stop-color="#EBEBEB" stop-opacity="1" />\n </linearGradient>\n\n \x3c!-- 柱子4: 中间,最亮 #FFFFFF --\x3e\n <linearGradient id="waveGradient4" x1="0%" y1="0%" x2="0%" y2="100%">\n <stop offset="0%" stop-color="#FFFFFF" stop-opacity="1" />\n <stop offset="100%" stop-color="#FFFFFF" stop-opacity="1" />\n </linearGradient>\n\n \x3c!-- 柱子5: #EBEBEB --\x3e\n <linearGradient id="waveGradient5" x1="0%" y1="0%" x2="0%" y2="100%">\n <stop offset="0%" stop-color="#EBEBEB" stop-opacity="1" />\n <stop offset="100%" stop-color="#EBEBEB" stop-opacity="1" />\n </linearGradient>\n\n \x3c!-- 柱子6: #E0E0E0 --\x3e\n <linearGradient id="waveGradient6" x1="0%" y1="0%" x2="0%" y2="100%">\n <stop offset="0%" stop-color="#E0E0E0" stop-opacity="1" />\n <stop offset="100%" stop-color="#E0E0E0" stop-opacity="1" />\n </linearGradient>\n\n \x3c!-- 柱子7: #D6D6D6 --\x3e\n <linearGradient id="waveGradient7" x1="0%" y1="0%" x2="0%" y2="100%">\n <stop offset="0%" stop-color="#D6D6D6" stop-opacity="1" />\n <stop offset="100%" stop-color="#D6D6D6" stop-opacity="1" />\n </linearGradient>\n\n \x3c!-- 柱子8: 最右,最暗 #CCCCCC --\x3e\n <linearGradient id="waveGradient8" x1="0%" y1="0%" x2="0%" y2="100%">\n <stop offset="0%" stop-color="#CCCCCC" stop-opacity="1" />\n <stop offset="100%" stop-color="#CCCCCC" stop-opacity="1" />\n </linearGradient>\n '},_proto.createToastHTML=function(){var getBarX=function(index){return 5+16*index},remainingText=i18n.t("recordingRemaining").replace("{time}",String(this.options.maxDuration));return'\n <div class="ezuikit-recording-waveform">\n <svg id="ezuikit-waveform-svg" viewBox="0 0 150 100" xmlns="http://www.w3.org/2000/svg" width="80" height="40">\n <defs>\n '+this.getWaveformDefs()+'\n </defs>\n \x3c!-- 9个柱子,宽度12px,间距4px,所有柱子高度变化范围都是30~80px,形成波浪效果,颜色从中间向两边渐变 --\x3e\n <rect id="wave-bar-0" x="'+getBarX(0)+'" y="42.5" width="12" height="15" fill="url(#waveGradient0)" rx="6" />\n <rect id="wave-bar-1" x="'+getBarX(1)+'" y="35" width="12" height="30" fill="url(#waveGradient1)" rx="6" />\n <rect id="wave-bar-2" x="'+getBarX(2)+'" y="27.5" width="12" height="45" fill="url(#waveGradient2)" rx="6" />\n <rect id="wave-bar-3" x="'+getBarX(3)+'" y="20" width="12" height="60" fill="url(#waveGradient3)" rx="6" />\n <rect id="wave-bar-4" x="'+getBarX(4)+'" y="7.5" width="12" height="85" fill="url(#waveGradient4)" rx="6" />\n <rect id="wave-bar-5" x="'+getBarX(5)+'" y="20" width="12" height="60" fill="url(#waveGradient5)" rx="6" />\n <rect id="wave-bar-6" x="'+getBarX(6)+'" y="27.5" width="12" height="45" fill="url(#waveGradient6)" rx="6" />\n <rect id="wave-bar-7" x="'+getBarX(7)+'" y="35" width="12" height="30" fill="url(#waveGradient7)" rx="6" />\n <rect id="wave-bar-8" x="'+getBarX(8)+'" y="42.5" width="12" height="15" fill="url(#waveGradient8)" rx="6" />\n </svg>\n </div>\n <div id="ezuikit-recording-hint">'+remainingText+"</div>\n "},_proto.startWaveformAnimation=function(){var frameIndex=0;this.waveAnimationFrame=window.setInterval(function(){for(var i=0;i<9;i++){var rect=document.getElementById("wave-bar-"+i);if(rect){var phase=(.3*frameIndex+.8*i)%(2*Math.PI),height=30+50*((Math.sin(phase)+1)/2),y=50-height/2;rect.setAttribute("height",height.toFixed(2)),rect.setAttribute("y",y.toFixed(2))}}frameIndex++},100)},_proto.stopWaveformAnimation=function(){this.waveAnimationFrame&&(clearInterval(this.waveAnimationFrame),this.waveAnimationFrame=null)},_proto.show=function(){this.toastElement||(this.toastElement=document.createElement("div"),this.toastElement.className="ezuikit-recording-toast",this.toastElement.innerHTML=this.createToastHTML(),this.container.appendChild(this.toastElement),this.waveformElement=this.toastElement.querySelector(".ezuikit-recording-waveform"),this.currentTime=this.options.maxDuration,this.startCountdown(),this.startWaveformAnimation())},_proto.hide=function(){var _this_toastElement;this.stopCountdown(),this.stopWaveformAnimation(),(null==(_this_toastElement=this.toastElement)?void 0:_this_toastElement.parentNode)&&this.toastElement.parentNode.removeChild(this.toastElement),this.toastElement=null,this.waveformElement=null},_proto.startCountdown=function(){var _this=this;this.timer=window.setInterval(function(){_this.currentTime--;var hintElement=document.getElementById("ezuikit-recording-hint");if(hintElement){var remainingMin=Math.max(0,_this.currentTime);hintElement.innerHTML=remainingMin>0?i18n.t("recordingRemaining").replace("{time}",String(remainingMin)):_this.options.isMobile?i18n.t("releaseToStop"):i18n.t("clickToStop")}_this.currentTime<=0&&_this.stopCountdown()},1e3)},_proto.stopCountdown=function(){this.timer&&(clearInterval(this.timer),this.timer=null)},_proto.getCurrentTime=function(){return this.currentTime},_proto.destroy=function(){this.hide()},RecordingToast}();function asyncGeneratorStep$1(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg),value=info.value}catch(error){return void reject(error)}info.done?resolve(value):Promise.resolve(value).then(_next,_throw)}function _async_to_generator$1(fn){return function(){var self=this,args=arguments;return new Promise(function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep$1(gen,resolve,reject,_next,_throw,"next",value)}function _throw(err){asyncGeneratorStep$1(gen,resolve,reject,_next,_throw,"throw",err)}_next(void 0)})}}function _instanceof(left,right){return null!=right&&"undefined"!=typeof Symbol&&right[Symbol.hasInstance]?!!right[Symbol.hasInstance](left):left instanceof right}function _ts_generator$1(thisArg,body){var f,y,t,_={label:0,sent:function(){if(1&t[0])throw t[1];return t[1]},trys:[],ops:[]},g=Object.create(("function"==typeof Iterator?Iterator:Object).prototype);return g.next=verb(0),g.throw=verb(1),g.return=verb(2),"function"==typeof Symbol&&(g[Symbol.iterator]=function(){return this}),g;function verb(n){return function(v){return function(op){if(f)throw new TypeError("Generator is already executing.");for(;g&&(g=0,op[0]&&(_=0)),_;)try{if(f=1,y&&(t=2&op[0]?y.return:op[0]?y.throw||((t=y.return)&&t.call(y),0):y.next)&&!(t=t.call(y,op[1])).done)return t;switch(y=0,t&&(op=[2&op[0],t.value]),op[0]){case 0:case 1:t=op;break;case 4:return _.label++,{value:op[1],done:!1};case 5:_.label++,y=op[1],op=[0];continue;case 7:op=_.ops.pop(),_.trys.pop();continue;default:if(!(t=_.trys,(t=t.length>0&&t[t.length-1])||6!==op[0]&&2!==op[0])){_=0;continue}if(3===op[0]&&(!t||op[1]>t[0]&&op[1]<t[3])){_.label=op[1];break}if(6===op[0]&&_.label<t[1]){_.label=t[1],t=op;break}if(t&&_.label<t[2]){_.label=t[2],_.ops.push(op);break}t[2]&&_.ops.pop(),_.trys.pop();continue}op=body.call(thisArg,_)}catch(e){op=[6,e],y=0}finally{f=t=0}if(5&op[0])throw op[1];return{value:op[0]?op[1]:void 0,done:!0}}([n,v])}}}var BroadcastUI=function(){function BroadcastUI(container,options){if("string"==typeof container){var element=document.getElementById(container);this.container=element||document.body}else _instanceof(container,HTMLElement)?this.container=container:this.container=document.body;this.options=options,this.modalElement=null,this.voiceListElement=null,this.talkButton=null,this.isRecording=!1,this.isStarting=!1,this.lastTouchTime=0,this.pendingStop=!1,this.voiceList=options.voiceList||[],this.orientationChangeHandler=null,this.createUI();var panel=this.modalElement.querySelector(".ezuikit-broadcast-panel"),toastContainer=_instanceof(panel,HTMLElement)?panel:this.container;this.recordingToast=new RecordingToast({maxDuration:59,minDuration:3,container:toastContainer,isMobile:options.isMobile,language:options.language}),i18n.setLanguage(options.language),this.options.isMobile&&this.setupOrientationListener()}var _proto=BroadcastUI.prototype;return _proto.setupOrientationListener=function(){var _window_screen,_this=this;this.orientationChangeHandler=function(){_this.modalElement&&"none"!==_this.modalElement.style.display&&_this.positionModalBelowContainer()},window.addEventListener("resize",this.orientationChangeHandler),(null==(_window_screen=window.screen)?void 0:_window_screen.orientation)&&window.screen.orientation.addEventListener("change",this.orientationChangeHandler)},_proto.removeOrientationListener=function(){var _window_screen;this.orientationChangeHandler&&(window.removeEventListener("resize",this.orientationChangeHandler),(null==(_window_screen=window.screen)?void 0:_window_screen.orientation)&&window.screen.orientation.removeEventListener("change",this.orientationChangeHandler),this.orientationChangeHandler=null)},_proto.createUI=function(){this.modalElement=document.createElement("div"),this.modalElement.className="ezuikit-broadcast-modal",this.options.isMobile&&this.modalElement.classList.add("ezuikit-broadcast-modal-mobile"),this.modalElement.innerHTML=this.getModalHTML(),this.injectStyles(),this.options.isMobile?(document.body.appendChild(this.modalElement),this.positionModalBelowContainer()):this.container.appendChild(this.modalElement),this.voiceListElement=this.modalElement.querySelector(".ezuikit-broadcast-voice-list"),this.bindEvents(),this.modalElement.style.display="none",this.voiceList.length>0&&this.renderVoiceList()},_proto.positionModalBelowContainer=function(){var _this_options_player;if(this.options.isMobile&&this.modalElement){var isFullscreen=(null==(_this_options_player=this.options.player)?void 0:_this_options_player.isCurrentFullscreen)||!1;if(this.modalElement.classList.remove("normal-mode","fullscreen-landscape-mode"),isFullscreen)this.modalElement.classList.add("fullscreen-landscape-mode"),this.modalElement.style.position="fixed",this.modalElement.style.left="0",this.modalElement.style.right="0",this.modalElement.style.bottom="0",this.modalElement.style.top="auto";else{this.modalElement.classList.add("normal-mode");var containerRect=this.container.getBoundingClientRect();this.modalElement.style.position="fixed",this.modalElement.style.left="0",this.modalElement.style.right="0",this.modalElement.style.top=containerRect.bottom+"px",this.modalElement.style.bottom="0"}}},_proto.getModalHTML=function(){var t=i18n.t.bind(i18n);return'\n <div class="ezuikit-broadcast-overlay"></div>\n <div class="ezuikit-broadcast-panel" data-direction="'+(this.options.direction||"bottom")+'">\n \x3c!-- 标题栏 --\x3e\n <div class="ezuikit-broadcast-header">\n <button class="ezuikit-broadcast-close" type="button">\n <svg width="24" height="24" viewBox="0 0 24 24" fill="none">\n <path d="M18 6L6 18M6 6L18 18" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>\n </svg>\n </button>\n <h2 class="ezuikit-broadcast-title">'+t("title")+'</h2>\n </div>\n\n \x3c!-- Tab区域 --\x3e\n <div class="ezuikit-broadcast-tabs">\n <div class="ezuikit-broadcast-tab active">\n '+t("defaultVoice")+'\n </div>\n </div>\n\n \x3c!-- 内容区域 --\x3e\n <div class="ezuikit-broadcast-content">\n \x3c!-- 语音列表 --\x3e\n <div class="ezuikit-broadcast-voice-list">\n \x3c!-- 语音项将通过 updateVoiceList 动态添加 --\x3e\n <div class="ezuikit-broadcast-voice-empty">\n '+t("loading")+'\n </div>\n </div>\n </div>\n\n \x3c!-- 底部按钮 --\x3e\n <div class="ezuikit-broadcast-footer">\n <button class="ezuikit-broadcast-talk-btn" type="button">\n <span class="ezuikit-broadcast-talk-text">'+(this.options.isMobile?t("pressToTalk"):t("clickToTalk"))+"</span>\n </button>\n </div>\n </div>\n "},_proto.injectStyles=function(){var styleId="ezuikit-broadcast-styles";if(!document.getElementById(styleId)){var style=document.createElement("style");style.id=styleId,style.textContent='\n /* 模态框 */\n .ezuikit-broadcast-modal {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 30;\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;\n pointer-events: none;\n }\n\n /* 移动端模态框:固定定位,覆盖整个视口 */\n .ezuikit-broadcast-modal-mobile {\n position: fixed;\n top: auto;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 9999;\n }\n\n .ezuikit-broadcast-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n animation: ezuikit-broadcast-fade-in 0.3s ease;\n pointer-events: auto;\n }\n\n /* 移动端遮罩层:覆盖整个视口 */\n .ezuikit-broadcast-modal-mobile .ezuikit-broadcast-overlay {\n position: fixed;\n }\n\n /* 移动端遮罩层:全屏模式(应用与播放器相同的伪全屏变换) */\n .ezuikit-broadcast-modal-mobile.fullscreen-landscape-mode .ezuikit-broadcast-overlay {\n position: fixed !important;\n left: 0 !important;\n right: 0 !important;\n bottom: 0 !important;\n top: 0 !important;\n width: 100vh !important;\n width: var(--ezplayer-mobile-inner-height, 100vh) !important;\n height: 100vw !important;\n height: var(--ezplayer-mobile-inner-width, 100vw) !important;\n transform: rotate(90.001deg) translateY(-100%) !important;\n -webkit-transform: rotate(90.001deg) translateY(-100%) !important;\n transform-origin: 0 0 !important;\n -webkit-transform-origin: 0 0 !important;\n }\n\n /* 主面板 */\n .ezuikit-broadcast-panel {\n position: absolute;\n background: #F5F5F5;\n display: flex;\n flex-direction: column;\n box-shadow: 0 -2px 20px rgba(0, 0, 0, 0.1);\n pointer-events: auto;\n overflow: hidden;\n }\n\n /* 移动端面板:固定定位,基础样式 */\n .ezuikit-broadcast-modal-mobile .ezuikit-broadcast-panel {\n position: fixed !important;\n }\n\n /* 移动端面板:普通模式(定位在 container 下方,从下往上展开) */\n .ezuikit-broadcast-modal-mobile.normal-mode .ezuikit-broadcast-panel {\n bottom: 0 !important;\n top: auto !important;\n left: 0 !important;\n right: 0 !important;\n height: 0;\n animation: ezuikit-broadcast-expand-height-mobile 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards !important;\n }\n\n /* 移动端面板:全屏模式(应用与播放器相同的伪全屏变换,从横屏后的下方往上展开) */\n .ezuikit-broadcast-modal-mobile.fullscreen-landscape-mode .ezuikit-broadcast-panel {\n position: fixed !important;\n left: 0 !important;\n right: auto !important;\n bottom: 0 !important;\n top: 0 !important;\n height: 100vw !important;\n height: var(--ezplayer-mobile-inner-width, 100vw) !important;\n transform: rotate(90.001deg) translateY(-100%) !important;\n -webkit-transform: rotate(90.001deg) translateY(-100%) !important;\n transform-origin: 0 0 !important;\n -webkit-transform-origin: 0 0 !important;\n animation: ezuikit-broadcast-expand-width-mobile-fullscreen 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards !important;\n }\n\n /* 不同方向的展开动画 - 从容器边缘展开 */\n .ezuikit-broadcast-panel[data-direction="bottom"] {\n left: 0;\n right: 0;\n bottom: 0;\n width: 100%;\n height: 0;\n animation: ezuikit-broadcast-expand-height 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;\n }\n\n .ezuikit-broadcast-panel[data-direction="top"] {\n left: 0;\n right: 0;\n top: 0;\n width: 100%;\n height: 0;\n animation: ezuikit-broadcast-expand-height 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;\n }\n\n .ezuikit-broadcast-panel[data-direction="left"] {\n left: 0;\n top: 0;\n bottom: 0;\n width: 100%;\n animation: ezuikit-broadcast-expand-width 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;\n }\n\n .ezuikit-broadcast-panel[data-direction="right"] {\n right: 0;\n top: 0;\n bottom: 0;\n width: 100%;\n animation: ezuikit-broadcast-expand-width 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;\n }\n\n /* 标题栏 */\n .ezuikit-broadcast-header {\n position: relative;\n padding: 16px 20px;\n text-align: center;\n background: rgba(245, 247, 250, 1);\n }\n\n .ezuikit-broadcast-title {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n color: #333333;\n }\n\n .ezuikit-broadcast-close {\n position: absolute;\n left: 16px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: #666666;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: color 0.2s;\n }\n\n .ezuikit-broadcast-close:hover {\n color: #333333;\n }\n\n /* Tab区域 */\n .ezuikit-broadcast-tabs {\n display: flex;\n padding: 0 20px;\n background: rgba(245, 247, 250, 1);\n }\n\n .ezuikit-broadcast-tab {\n position: relative;\n padding: 12px 16px 4px;\n font-size: 20px;\n color: #999999;\n cursor: pointer;\n transition: color 0.2s;\n font-weight: 700;\n }\n\n .ezuikit-broadcast-tab.active {\n color: rgba(100, 143, 252, 1);\n font-weight: 700;\n }\n\n .ezuikit-broadcast-tab.active::after {\n content: \'\';\n position: absolute;\n bottom: 0;\n left: 50%;\n transform: translateX(-50%);\n width: 10px;\n height: 2px;\n background: #6B9EFF;\n }\n\n /* 内容区域 */\n .ezuikit-broadcast-content {\n flex: 1;\n overflow-y: auto;\n padding: 16px 20px;\n background: rgba(245, 247, 250, 1);\n }\n\n /* 语音列表 */\n .ezuikit-broadcast-voice-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .ezuikit-broadcast-voice-empty {\n text-align: center;\n padding: 40px 20px;\n color: #999999;\n font-size: 14px;\n }\n\n .ezuikit-broadcast-voice-item {\n display: flex;\n align-items: center;\n padding: 11px 16px;\n background: rgba(237, 237, 237, 1);\n border-radius: 16px;\n height: 42px;\n box-sizing: border-box;\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .ezuikit-broadcast-voice-item:hover {\n background: rgba(237, 237, 237, 1);\n }\n\n .ezuikit-broadcast-voice-item.selected {\n background: rgba(237, 237, 237, 1);\n }\n\n .ezuikit-broadcast-voice-icon {\n width: 24px;\n height: 24px;\n margin-right: 12px;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #FFFFFF;\n background: #2C2C2C;\n border-radius: 50%;\n padding: 3px;\n box-sizing: border-box;\n transition: background 0.2s;\n }\n\n .ezuikit-broadcast-voice-item.selected .ezuikit-broadcast-voice-icon {\n background: rgba(100, 143, 252, 1);\n color: #FFFFFF;\n }\n\n .ezuikit-broadcast-voice-text {\n flex: 1;\n font-size: 14px;\n color: rgba(102, 102, 102, 1);\n line-height: 20px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n /* 底部按钮 */\n .ezuikit-broadcast-footer {\n padding: 16px 20px 20px;\n background: #F5F5F5;\n }\n\n .ezuikit-broadcast-talk-btn {\n width: 100%;\n padding: 16px;\n background: #6B9EFF;\n color: #FFFFFF;\n border: none;\n font-size: 16px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n user-select: none;\n border-radius: 8px;\n }\n\n .ezuikit-broadcast-talk-btn:hover {\n background: #5A8EEE;\n }\n\n .ezuikit-broadcast-talk-btn:active {\n transform: scale(0.98);\n }\n\n .ezuikit-broadcast-talk-btn.recording {\n background: #FF5252;\n }\n\n .ezuikit-broadcast-talk-btn.disabled {\n background: #CCCCCC;\n cursor: not-allowed;\n }\n\n /* 动画 */\n @keyframes ezuikit-broadcast-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n\n @keyframes ezuikit-broadcast-expand-height {\n from { height: 0; }\n to { height: 80%; }\n }\n\n @keyframes ezuikit-broadcast-expand-height-mobile {\n from { height: 0; }\n to { height: 70vh; }\n }\n\n /* 全屏时从右侧展开的动画(宽度展开) */\n @keyframes ezuikit-broadcast-expand-width-mobile-fullscreen {\n from { width: 0; }\n to { width: 70vh; }\n }\n\n /* 全屏时从底部展开的动画 */\n @keyframes ezuikit-broadcast-expand-height-mobile-fullscreen {\n from { height: 0; }\n to { height: 85vh; }\n }\n\n @keyframes ezuikit-broadcast-expand-width {\n from { width: 0; }\n to {\n width: 80%;\n max-width: 400px;\n }\n }\n ',document.head.appendChild(style)}},_proto.bindEvents=function(){var _this=this;if(this.modalElement){var closeBtn=this.modalElement.querySelector(".ezuikit-broadcast-close");closeBtn&&closeBtn.addEventListener("click",function(){_this.close()});var overlay=this.modalElement.querySelector(".ezuikit-broadcast-overlay");overlay&&overlay.addEventListener("click",function(){_this.close()}),this.talkButton=this.modalElement.querySelector(".ezuikit-broadcast-talk-btn"),this.talkButton&&(this.options.isMobile?(this.talkButton.addEventListener("touchstart",function(e){e.preventDefault(),e.stopPropagation();var now=Date.now();now-_this.lastTouchTime<300||(_this.lastTouchTime=now,_this.handleRecordStart())},{passive:!1}),this.talkButton.addEventListener("touchend",function(e){e.preventDefault(),e.stopPropagation(),_this.handleRecordStop()},{passive:!1}),this.talkButton.addEventListener("touchcancel",function(){_this.isRecording&&_this.handleRecordStop()})):this.talkButton.addEventListener("click",function(e){e.preventDefault(),_this.handleRecordToggle()}))}},_proto.handleRecordToggle=function(){this.isRecording?this.handleRecordStop():this.handleRecordStart()},_proto.handleRecordStart=function(){return _async_to_generator$1(function(){var textElement,error,textElement1;return _ts_generator$1(this,function(_state){switch(_state.label){case 0:if(this.isRecording||this.isStarting)return[2];_state.label=1;case 1:return _state.trys.push([1,5,,6]),this.pendingStop=!1,this.isStarting=!0,this.recordingToast.show(),this.talkButton&&(this.talkButton.classList.add("recording"),(textElement=this.talkButton.querySelector(".ezuikit-broadcast-talk-text"))&&(textElement.textContent=this.options.isMobile?i18n.t("recording"):i18n.t("stopRecording"))),[4,this.options.onRecordStart()];case 2:return _state.sent(),this.isRecording=!0,this.isStarting=!1,this.pendingStop?(this.pendingStop=!1,[4,this.handleRecordStop()]):[3,4];case 3:_state.sent(),_state.label=4;case 4:return[3,6];case 5:return error=_state.sent(),this.isStarting=!1,this.isRecording=!1,this.pendingStop=!1,this.recordingToast.hide(),this.talkButton&&(this.talkButton.classList.remove("recording"),(textElement1=this.talkButton.querySelector(".ezuikit-broadcast-talk-text"))&&(textElement1.textContent=this.options.isMobile?i18n.t("pressToTalk"):i18n.t("clickToTalk"))),this.showError(_instanceof(error,Error)?error.message:"开始录音失败"),[3,6];case 6:return[2]}})}).call(this)},_proto.handleRecordStop=function(){return _async_to_generator$1(function(){var textElement,error,textElement1;return _ts_generator$1(this,function(_state){switch(_state.label){case 0:if(this.isStarting)return this.pendingStop=!0,[2];if(!this.isRecording)return[2];_state.label=1;case 1:return _state.trys.push([1,3,,4]),this.recordingToast.hide(),this.talkButton&&(this.talkButton.classList.remove("recording"),(textElement=this.talkButton.querySelector(".ezuikit-broadcast-talk-text"))&&(textElement.textContent=this.options.isMobile?i18n.t("pressToTalk"):i18n.t("clickToTalk"))),[4,this.options.onRecordStop()];case 2:return _state.sent(),this.isRecording=!1,[3,4];case 3:return error=_state.sent(),this.isRecording=!1,this.recordingToast.hide(),this.talkButton&&(this.talkButton.classList.remove("recording"),(textElement1=this.talkButton.querySelector(".ezuikit-broadcast-talk-text"))&&(textElement1.textContent=this.options.isMobile?i18n.t("pressToTalk"):i18n.t("clickToTalk"))),this.showError(_instanceof(error,Error)?error.message:"停止录音失败"),[3,4];case 4:return[2]}})}).call(this)},_proto.show=function(){this.modalElement&&(this.modalElement.style.display="block",this.options.isMobile&&this.positionModalBelowContainer())},_proto.hide=function(){if(this.isRecording)try{this.handleRecordStop()}catch(error){this.isRecording=!1,this.recordingToast.hide()}this.modalElement&&(this.modalElement.style.display="none")},_proto.close=function(){this.hide(),this.options.onClose()},_proto.updateVoiceList=function(voiceList){this.voiceList=voiceList,this.renderVoiceList()},_proto.renderVoiceList=function(){var _this=this;this.voiceListElement&&(0!==this.voiceList.length?(this.voiceListElement.innerHTML=this.voiceList.map(function(voice,index){return'\n <div class="ezuikit-broadcast-voice-item" data-index="'+index+'">\n <div class="ezuikit-broadcast-voice-icon">\n <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">\n <path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/>\n </svg>\n </div>\n <div class="ezuikit-broadcast-voice-text" title="'+voice.voiceName+'">'+voice.voiceName+"</div>\n </div>\n "}).join(""),this.voiceListElement.querySelectorAll(".ezuikit-broadcast-voice-item").forEach(function(item){item.addEventListener("click",function(){var index=parseInt(item.getAttribute("data-index")||"-1");_this.selectVoice(index)})})):this.voiceListElement.innerHTML='\n <div class="ezuikit-broadcast-voice-empty">\n '+i18n.t("noVoice")+"\n </div>\n ")},_proto.selectVoice=function(index){if(this.voiceListElement&&(this.voiceListElement.querySelectorAll(".ezuikit-broadcast-voice-item").forEach(function(item){item.classList.remove("selected")}),index>=0&&index<this.voiceList.length)){var selectedItem=this.voiceListElement.querySelector('[data-index="'+index+'"]');selectedItem&&selectedItem.classList.add("selected");var selectedVoice=this.voiceList[index];this.options.onVoiceSend(selectedVoice.fileUrl)}},_proto.setRecordingState=function(isRecording){this.isRecording=isRecording},_proto.showSuccess=function(message){},_proto.showError=function(message){},_proto.destroy=function(){var _this_modalElement;this.removeOrientationListener(),this.recordingToast.destroy(),(null==(_this_modalElement=this.modalElement)?void 0:_this_modalElement.parentNode)&&this.modalElement.parentNode.removeChild(this.modalElement),this.modalElement=null,this.voiceListElement=null,this.talkButton=null},BroadcastUI}();function asyncGeneratorStep(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg),value=info.value}catch(error){return void reject(error)}info.done?resolve(value):Promise.resolve(value).then(_next,_throw)}function _async_to_generator(fn){return function(){var self=this,args=arguments;return new Promise(function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"next",value)}function _throw(err){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"throw",err)}_next(void 0)})}}function _ts_generator(thisArg,body){var f,y,t,_={label:0,sent:function(){if(1&t[0])throw t[1];return t[1]},trys:[],ops:[]},g=Object.create(("function"==typeof Iterator?Iterator:Object).prototype);return g.next=verb(0),g.throw=verb(1),g.return=verb(2),"function"==typeof Symbol&&(g[Symbol.iterator]=function(){return this}),g;function verb(n){return function(v){return function(op){if(f)throw new TypeError("Generator is already executing.");for(;g&&(g=0,op[0]&&(_=0)),_;)try{if(f=1,y&&(t=2&op[0]?y.return:op[0]?y.throw||((t=y.return)&&t.call(y),0):y.next)&&!(t=t.call(y,op[1])).done)return t;switch(y=0,t&&(op=[2&op[0],t.value]),op[0]){case 0:case 1:t=op;break;case 4:return _.label++,{value:op[1],done:!1};case 5:_.label++,y=op[1],op=[0];continue;case 7:op=_.ops.pop(),_.trys.pop();continue;default:if(!(t=_.trys,(t=t.length>0&&t[t.length-1])||6!==op[0]&&2!==op[0])){_=0;continue}if(3===op[0]&&(!t||op[1]>t[0]&&op[1]<t[3])){_.label=op[1];break}if(6===op[0]&&_.label<t[1]){_.label=t[1],t=op;break}if(t&&_.label<t[2]){_.label=t[2],_.ops.push(op);break}t[2]&&_.ops.pop(),_.trys.pop();continue}op=body.call(thisArg,_)}catch(e){op=[6,e],y=0}finally{f=t=0}if(5&op[0])throw op[1];return{value:op[0]?op[1]:void 0,done:!0}}([n,v])}}}var EVENTS={open:"open",close:"close",requestQueryVoiceList:"requestQueryVoiceList",voiceListLoaded:"voiceListLoaded",voiceListError:"voiceListError",requestSendVoiceOnce:"requestSendVoiceOnce",requestSendVoice:"requestSendVoice",voiceSelected:"voiceSelected",voiceRecorded:"voiceRecorded",recordStart:"recordStart",recordStop:"recordStop",recordComplete:"recordComplete",recordError:"recordError",voiceSent:"voiceSent",voiceSendError:"voiceSendError",error:"error"},DefaultOptions={channelNo:"1",env:{domain:"https://open.ys7.com"},language:"zh"},Broadcast=function(){function Broadcast(options){var _this=this;this.options=Object.assign({},DefaultOptions,options),this.eventEmitter=new EventEmitter,this.voiceRecorder=null,this.isOpen=!1,this.voiceList=options.voiceList||[],this.maxDurationTimer=null,this.pendingAudioBlob=null;var container=this.options.container||document.body;this.broadcastUI=new BroadcastUI(container,{language:this.options.language||"zh",direction:this.options.direction||"right",voiceList:this.voiceList,isMobile:this.options.isMobile||!1,player:this.options.player,onClose:function(){return _this.close()},onRecordStart:function(){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,this.startRecord()];case 1:return[2,_state.sent()]}})}).call(_this)},onRecordStop:function(){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,this.stopRecord()];case 1:return[2,_state.sent()]}})}).call(_this)},onVoiceSend:function(fileUrl){return _this.sendVoice(fileUrl)},onVoiceSendOnce:function(){}}),this.setupEventListeners()}var _proto=Broadcast.prototype;return _proto.initMicrophonePermission=function(){return _async_to_generator(function(){var error;return _ts_generator(this,function(_state){switch(_state.label){case 0:return _state.trys.push([0,2,,3]),[4,navigator.mediaDevices.getUserMedia({audio:{sampleRate:16e3,channelCount:1,echoCancellation:!0,noiseSuppression:!0}})];case 1:return _state.sent().getTracks().forEach(function(track){return track.stop()}),[3,3];case 2:return error=_state.sent(),this.eventEmitter.emit(EVENTS.error,{eventType:EVENTS.error,code:-1,msg:"麦克风权限获取失败",error:error}),[3,3];case 3:return[2]}})}).call(this)},_proto.requestMicrophonePermission=function(){return _async_to_generator(function(){var error;return _ts_generator(this,function(_state){switch(_state.label){case 0:return _state.trys.push([0,2,,3]),[4,navigator.mediaDevices.getUserMedia({audio:{sampleRate:16e3,channelCount:1,echoCancellation:!0,noiseSuppression:!0}})];case 1:return _state.sent().getTracks().forEach(function(track){return track.stop()}),[2,!0];case 2:return error=_state.sent(),this.eventEmitter.emit(EVENTS.error,{eventType:EVENTS.error,code:-1,msg:"麦克风权限获取失败",error:error}),[2,!1];case 3:return[2]}})}).call(this)},_proto.setupEventListeners=function(){var _this=this;this.eventEmitter.on(EVENTS.voiceListLoaded,function(data){_this.voiceList=data.data||[],_this.broadcastUI&&_this.broadcastUI.updateVoiceList(_this.voiceList)}),this.eventEmitter.on(EVENTS.voiceListError,function(data){_this.broadcastUI&&_this.broadcastUI.showError(data.msg||"语音列表加载失败")}),this.eventEmitter.on(EVENTS.voiceSent,function(data){_this.broadcastUI&&_this.broadcastUI.showSuccess(data.msg||"语音下发成功")}),this.eventEmitter.on(EVENTS.voiceSendError,function(data){_this.broadcastUI&&_this.broadcastUI.showError(data.msg||"语音下发失败")})},_proto.open=function(){if(!this.isOpen)try{this.broadcastUI.show(),this.isOpen=!0,0===this.voiceList.length&&this.loadVoiceList(),this.eventEmitter.emit(EVENTS.open,{eventType:EVENTS.open,code:0,msg:"云广播界面已打开"})}catch(error){this.eventEmitter.emit(EVENTS.error,{eventType:EVENTS.error,code:-1,msg:"打开云广播界面失败",error:error})}},_proto.close=function(){if(this.isOpen)try{if(this.voiceRecorder)try{this.voiceRecorder.stop()}catch(error){}this.broadcastUI&&this.broadcastUI.hide(),this.isOpen=!1,this.eventEmitter.emit(EVENTS.close,{eventType:EVENTS.close,code:0,msg:"云广播界面已关闭"})}catch(error){}},_proto.loadVoiceList=function(){this.eventEmitter.emit(EVENTS.requestQueryVoiceList,{eventType:EVENTS.requestQueryVoiceList,params:{deviceSerial:this.options.deviceSerial,channelNo:this.options.channelNo,pageSize:50}})},_proto.startRecord=function(){return _async_to_generator(function(){var _this,error;return _ts_generator(this,function(_state){switch(_state.label){case 0:_this=this,_state.label=1;case 1:return _state.trys.push([1,3,,4]),this.pendingAudioBlob=null,this.voiceRecorder||(this.voiceRecorder=new VoiceRecorder({minDuration:3,maxDuration:59,sampleRate:16e3})),[4,this.voiceRecorder.start()];case 2:return _state.sent(),this.maxDurationTimer=window.setTimeout(function(){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:return[4,this.stopRecordAndCache()];case 1:return _state.sent(),[2]}})}).call(_this)},59e3),this.eventEmitter.emit(EVENTS.recordStart,{eventType:EVENTS.recordStart,code:0,msg:"开始录音"}),this.broadcastUI&&this.broadcastUI.setRecordingState(!0),[3,4];case 3:return error=_state.sent(),this.eventEmitter.emit(EVENTS.recordError,{eventType:EVENTS.recordError,code:-1,msg:"开始录音失败",error:error}),[3,4];case 4:return[2]}})}).call(this)},_proto.stopRecordAndCache=function(){return _async_to_generator(function(){var audioBlob;return _ts_generator(this,function(_state){switch(_state.label){case 0:return _state.trys.push([0,2,,3]),this.voiceRecorder&&this.voiceRecorder.isRecording()?[4,this.voiceRecorder.stop()]:[2];case 1:return 0===(audioBlob=_state.sent()).size?[2]:(this.pendingAudioBlob=audioBlob,this.eventEmitter.emit(EVENTS.recordComplete,{eventType:EVENTS.recordComplete,code:0,data:audioBlob,msg:"录音完成,等待下发"}),[3,3]);case 2:return _state.sent(),this.broadcastUI&&this.broadcastUI.setRecordingState(!1),[3,3];case 3:return[2]}})}).call(this)},_proto.stopRecord=function(){return _async_to_generator(function(){var audioBlob,audioBlob1,error;return _ts_generator(this,function(_state){switch(_state.label){case 0:if(_state.trys.push([0,2,,3]),this.maxDurationTimer&&(clearTimeout(this.maxDurationTimer),this.maxDurationTimer=null),this.pendingAudioBlob)return audioBlob=this.pendingAudioBlob,this.pendingAudioBlob=null,this.eventEmitter.emit(EVENTS.recordStop,{eventType:EVENTS.recordStop,code:0,msg:"停止录音"}),this.broadcastUI&&this.broadcastUI.setRecordingState(!1),this.sendVoiceOnce(audioBlob),[2];if(!this.voiceRecorder)throw new Error("录音器未初始化");return this.voiceRecorder.isRecording()?[4,this.voiceRecorder.stop()]:(this.broadcastUI&&this.broadcastUI.setRecordingState(!1),[2]);case 1:return 0===(audioBlob1=_state.sent()).size?(this.broadcastUI&&this.broadcastUI.setRecordingState(!1),[2]):(this.eventEmitter.emit(EVENTS.recordStop,{eventType:EVENTS.recordStop,code:0,msg:"停止录音"}),this.eventEmitter.emit(EVENTS.recordComplete,{eventType:EVENTS.recordComplete,code:0,data:audioBlob1,msg:"录音完成"}),this.broadcastUI&&this.broadcastUI.setRecordingState(!1),this.sendVoiceOnce(audioBlob1),[3,3]);case 2:return error=_state.sent(),this.eventEmitter.emit(EVENTS.recordError,{eventType:EVENTS.recordError,code:-1,msg:"停止录音失败",error:error}),this.broadcastUI&&this.broadcastUI.setRecordingState(!1),[3,3];case 3:return[2]}})}).call(this)},_proto.sendVoiceOnce=function(voiceFile){this.eventEmitter.emit(EVENTS.voiceRecorded,{eventType:EVENTS.voiceRecorded,voiceFile:voiceFile,deviceSerial:this.options.deviceSerial,channelNo:this.options.channelNo}),this.eventEmitter.emit(EVENTS.requestSendVoiceOnce,{eventType:EVENTS.requestSendVoiceOnce,voiceFile:voiceFile,deviceSerial:this.options.deviceSerial,channelNo:this.options.channelNo})},_proto.sendVoice=function(fileUrl){this.eventEmitter.emit(EVENTS.requestSendVoice,{eventType:EVENTS.requestSendVoice,fileUrl:fileUrl,deviceSerial:this.options.deviceSerial,channelNo:this.options.channelNo})},_proto.updateOptions=function(options){this.options=Object.assign(this.options,options)},_proto.on=function(event,callback){this.eventEmitter.on(event,callback)},_proto.off=function(event,callback){this.eventEmitter.off(event,callback)},_proto.destroy=function(){this.close(),this.voiceRecorder&&(this.voiceRecorder.destroy(),this.voiceRecorder=null),this.broadcastUI&&this.broadcastUI.destroy(),this.voiceList=[],this.eventEmitter.removeAllListeners()},Broadcast}();Broadcast.VERSION="0.1.0-beta.2",Broadcast.EVENTS=EVENTS;export{Broadcast as default};
|
|
6
|
+
import Logger from"@ezuikit/utils-logger";import Drawer from"@ezuikit/control-drawer";import Message from"@ezuikit/control-message";function createLogger(logger){var root=null!=logger?logger:Logger();return"function"==typeof root.context?root.context("Broadcast"):root}function _array_like_to_array(arr,len){(null==len||len>arr.length)&&(len=arr.length);for(var i=0,arr2=new Array(len);i<len;i++)arr2[i]=arr[i];return arr2}function asyncGeneratorStep$2(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg),value=info.value}catch(error){return void reject(error)}info.done?resolve(value):Promise.resolve(value).then(_next,_throw)}function _async_to_generator$2(fn){return function(){var self=this,args=arguments;return new Promise(function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep$2(gen,resolve,reject,_next,_throw,"next",value)}function _throw(err){asyncGeneratorStep$2(gen,resolve,reject,_next,_throw,"throw",err)}_next(void 0)})}}function _create_for_of_iterator_helper_loose(o,allowArrayLike){var it="undefined"!=typeof Symbol&&o[Symbol.iterator]||o["@@iterator"];if(it)return(it=it.call(o)).next.bind(it);if(Array.isArray(o)||(it=function(o,minLen){if(!o)return;if("string"==typeof o)return _array_like_to_array(o,minLen);var n=Object.prototype.toString.call(o).slice(8,-1);"Object"===n&&o.constructor&&(n=o.constructor.name);if("Map"===n||"Set"===n)return Array.from(n);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return _array_like_to_array(o,minLen)}(o))||allowArrayLike){it&&(o=it);var i=0;return function(){return i>=o.length?{done:!0}:{done:!1,value:o[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _ts_generator$2(thisArg,body){var f,y,t,_={label:0,sent:function(){if(1&t[0])throw t[1];return t[1]},trys:[],ops:[]},g=Object.create(("function"==typeof Iterator?Iterator:Object).prototype),d=Object.defineProperty;return d(g,"next",{value:verb(0)}),d(g,"throw",{value:verb(1)}),d(g,"return",{value:verb(2)}),"function"==typeof Symbol&&d(g,Symbol.iterator,{value:function(){return this}}),g;function verb(n){return function(v){return function(op){if(f)throw new TypeError("Generator is already executing.");for(;g&&(g=0,op[0]&&(_=0)),_;)try{if(f=1,y&&(t=2&op[0]?y.return:op[0]?y.throw||((t=y.return)&&t.call(y),0):y.next)&&!(t=t.call(y,op[1])).done)return t;switch(y=0,t&&(op=[2&op[0],t.value]),op[0]){case 0:case 1:t=op;break;case 4:return _.label++,{value:op[1],done:!1};case 5:_.label++,y=op[1],op=[0];continue;case 7:op=_.ops.pop(),_.trys.pop();continue;default:if(!(t=_.trys,(t=t.length>0&&t[t.length-1])||6!==op[0]&&2!==op[0])){_=0;continue}if(3===op[0]&&(!t||op[1]>t[0]&&op[1]<t[3])){_.label=op[1];break}if(6===op[0]&&_.label<t[1]){_.label=t[1],t=op;break}if(t&&_.label<t[2]){_.label=t[2],_.ops.push(op);break}t[2]&&_.ops.pop(),_.trys.pop();continue}op=body.call(thisArg,_)}catch(e){op=[6,e],y=0}finally{f=t=0}if(5&op[0])throw op[1];return{value:op[0]?op[1]:void 0,done:!0}}([n,v])}}}var VoiceRecorder=function(){function VoiceRecorder(options){var _options_logger;void 0===options&&(options={}),this.options={minDuration:options.minDuration||3,maxDuration:options.maxDuration||59,sampleRate:options.sampleRate||16e3,channelCount:options.channelCount||1},this.logger=null!=(_options_logger=options.logger)?_options_logger:createLogger(),this.audioContext=null,this.mediaStreamSource=null,this.scriptProcessor=null,this.stream=null,this.startTime=0,this.maxTimer=null,this.audioBuffers=[],this.isRecordingFlag=!1,this.isIOSDevice=/iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream,this.mediaRecorder=null,this.recordedChunks=[]}var _proto=VoiceRecorder.prototype;return _proto.start=function(){return _async_to_generator$2(function(){var error;return _ts_generator$2(this,function(_state){switch(_state.label){case 0:if(this.isRecordingFlag)return this.logger.warn("[VoiceRecorder] 录音已在进行中,忽略重复启动"),[2];_state.label=1;case 1:return _state.trys.push([1,3,,4]),[4,this.startWithScriptProcessor()];case 2:return _state.sent(),this.startTime=Date.now(),this.isRecordingFlag=!0,this.logger.log("[VoiceRecorder] 录音已开始"),[3,4];case 3:throw error=_state.sent(),this.logger.error("[VoiceRecorder] 开始录音失败",error),this.isRecordingFlag=!1,error;case 4:return[2]}})}).call(this)},_proto.startWithMediaRecorder=function(){return _async_to_generator$2(function(){var _this,_,mimeType;return _ts_generator$2(this,function(_state){switch(_state.label){case 0:return _this=this,_=this,[4,navigator.mediaDevices.getUserMedia({audio:!0})];case 1:return _.stream=_state.sent(),this.recordedChunks=[],mimeType="",MediaRecorder.isTypeSupported("audio/mp4")?mimeType="audio/mp4":MediaRecorder.isTypeSupported("audio/webm")?mimeType="audio/webm":MediaRecorder.isTypeSupported("audio/wav")&&(mimeType="audio/wav"),this.mediaRecorder=new MediaRecorder(this.stream,{mimeType:mimeType||void 0}),this.mediaRecorder.ondataavailable=function(event){event.data.size>0&&_this.recordedChunks.push(event.data)},this.mediaRecorder.start(),[2]}})}).call(this)},_proto.startWithScriptProcessor=function(){return _async_to_generator$2(function(){var _this,audioConstraints,_;return _ts_generator$2(this,function(_state){switch(_state.label){case 0:return _this=this,audioConstraints=this.isIOSDevice?{audio:!0}:{audio:{sampleRate:this.options.sampleRate,channelCount:this.options.channelCount,echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0}},_=this,[4,navigator.mediaDevices.getUserMedia(audioConstraints)];case 1:return _.stream=_state.sent(),this.audioContext=new(window.AudioContext||window.webkitAudioContext)({sampleRate:this.options.sampleRate}),this.mediaStreamSource=this.audioContext.createMediaStreamSource(this.stream),this.scriptProcessor=this.audioContext.createScriptProcessor(4096,1,1),this.audioBuffers=[],this.scriptProcessor.onaudioprocess=function(event){if(_this.isRecordingFlag){var inputData=event.inputBuffer.getChannelData(0);_this.audioBuffers.push(new Float32Array(inputData))}},this.mediaStreamSource.connect(this.scriptProcessor),this.scriptProcessor.connect(this.audioContext.destination),[2]}})}).call(this)},_proto.stop=function(){return _async_to_generator$2(function(){var _this;return _ts_generator$2(this,function(_state){switch(_state.label){case 0:return _this=this,[4,new Promise(function(resolve,reject){if(!_this.isRecordingFlag)return _this.logger.warn("[VoiceRecorder] 录音器未在录音状态"),void resolve(new Blob([],{type:"audio/wav"}));var duration=(Date.now()-_this.startTime)/1e3;if(duration<_this.options.minDuration)return _this.logger.error("[VoiceRecorder] 录音时长不足",{duration:duration.toFixed(2),required:_this.options.minDuration}),reject(new Error("录音时长不足"+_this.options.minDuration+"秒")),void _this.cleanup();try{_this.isRecordingFlag=!1,_this.stopWithScriptProcessor(duration,resolve,reject)}catch(error){_this.logger.error("[VoiceRecorder] 停止录音失败",error),_this.cleanup(),reject(error)}})];case 1:return[2,_state.sent()]}})}).call(this)},_proto.stopWithMediaRecorder=function(duration,resolve,reject){var _this=this;if(!this.mediaRecorder)return this.logger.error("[VoiceRecorder] MediaRecorder 未初始化"),reject(new Error("MediaRecorder 未初始化")),void this.cleanup();this.mediaRecorder.onstop=function(){try{var _this_recordedChunks_,mimeType=(null==(_this_recordedChunks_=_this.recordedChunks[0])?void 0:_this_recordedChunks_.type)||"audio/wav",audioBlob=new Blob(_this.recordedChunks,{type:mimeType});_this.logger.log("[VoiceRecorder] 录音已停止",{duration:duration.toFixed(2)+"s",size:(audioBlob.size/1024).toFixed(2)+"KB"}),_this.cleanup(),resolve(audioBlob)}catch(error){_this.logger.error("[VoiceRecorder] 处理录音数据失败",error),_this.cleanup(),reject(error)}},this.mediaRecorder.stop()},_proto.stopWithScriptProcessor=function(duration,resolve,reject){try{for(var _step,totalLength=this.audioBuffers.reduce(function(acc,buffer){return acc+buffer.length},0),mergedBuffer=new Float32Array(totalLength),offset=0,_iterator=_create_for_of_iterator_helper_loose(this.audioBuffers);!(_step=_iterator()).done;){var buffer=_step.value;mergedBuffer.set(buffer,offset),offset+=buffer.length}var wavBlob=this.encodeWAV(mergedBuffer,this.options.sampleRate);this.logger.log("[VoiceRecorder] 录音已停止",{duration:duration.toFixed(2)+"s",size:(wavBlob.size/1024).toFixed(2)+"KB"}),this.cleanup(),resolve(wavBlob)}catch(error){this.logger.error("[VoiceRecorder] 处理录音数据失败",error),this.cleanup(),reject(error)}},_proto.encodeWAV=function(samples,sampleRate){var buffer=new ArrayBuffer(44+2*samples.length),view=new DataView(buffer),writeString=function(offset,string){for(var i=0;i<string.length;i++)view.setUint8(offset+i,string.charCodeAt(i))};return writeString(0,"RIFF"),view.setUint32(4,36+2*samples.length,!0),writeString(8,"WAVE"),writeString(12,"fmt "),view.setUint32(16,16,!0),view.setUint16(20,1,!0),view.setUint16(22,1,!0),view.setUint32(24,sampleRate,!0),view.setUint32(28,2*sampleRate,!0),view.setUint16(32,2,!0),view.setUint16(34,16,!0),writeString(36,"data"),view.setUint32(40,2*samples.length,!0),function(output,offset,input){for(var i=0;i<input.length;i++,offset+=2){var s=Math.max(-1,Math.min(1,input[i]));output.setInt16(offset,s<0?32768*s:32767*s,!0)}}(view,44,samples),new Blob([buffer],{type:"audio/wav"})},_proto.cleanup=function(){this.isRecordingFlag=!1,this.mediaRecorder&&("inactive"!==this.mediaRecorder.state&&this.mediaRecorder.stop(),this.mediaRecorder=null),this.recordedChunks=[],this.scriptProcessor&&(this.scriptProcessor.disconnect(),this.scriptProcessor=null),this.mediaStreamSource&&(this.mediaStreamSource.disconnect(),this.mediaStreamSource=null),this.audioContext&&(this.audioContext.close(),this.audioContext=null),this.stream&&(this.stream.getTracks().forEach(function(track){return track.stop()}),this.stream=null),this.audioBuffers=[]},_proto.destroy=function(){this.cleanup(),this.maxTimer&&(clearTimeout(this.maxTimer),this.maxTimer=null)},_proto.getDuration=function(){return 0===this.startTime?0:(Date.now()-this.startTime)/1e3},_proto.isRecording=function(){return this.isRecordingFlag},VoiceRecorder}(),zh_CN={title:"广播喊话",defaultVoice:"默认语音",pressToTalk:"按住说话",clickToTalk:"点击录音",sendVoice:"下发语音",recording:"录音中",stopRecording:"停止录音",loading:"加载中...",noVoice:"暂无语音数据",recordingRemaining:"还可录制 {time} 秒",releaseToStop:"松开结束录制",clickToStop:"再次点击按钮结束录制",voiceSentSuccess:"语音下发成功",recordComplete:"录音完成",voiceSendFailed:"语音下发失败",recordFailed:"录音失败",recordTooShort:"录音时长不足3秒",micPermissionDenied:"请允许麦克风权限"},en_US={title:"Voice Broadcast",defaultVoice:"Default Voice",pressToTalk:"Press to Talk",clickToTalk:"Click to Record",sendVoice:"Send Voice",recording:"Recording",stopRecording:"Stop Recording",loading:"Loading...",noVoice:"No voice data",recordingRemaining:"{time}s remaining",releaseToStop:"Release to stop",clickToStop:"Click again to stop",voiceSentSuccess:"Voice sent successfully",recordComplete:"Recording completed",voiceSendFailed:"Failed to send voice",recordFailed:"Recording failed",recordTooShort:"Recording is too short (min 3s)",micPermissionDenied:"Please allow microphone permission"},i18n=new(function(){function I18n(){this.currentLanguage="zh",this.translations={zh:zh_CN,en:en_US}}var _proto=I18n.prototype;return _proto.setLanguage=function(language){this.currentLanguage=language},_proto.t=function(key){return this.translations[this.currentLanguage][key]||key},_proto.getLanguage=function(){return this.currentLanguage},I18n}());function asyncGeneratorStep$1(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg),value=info.value}catch(error){return void reject(error)}info.done?resolve(value):Promise.resolve(value).then(_next,_throw)}function _async_to_generator$1(fn){return function(){var self=this,args=arguments;return new Promise(function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep$1(gen,resolve,reject,_next,_throw,"next",value)}function _throw(err){asyncGeneratorStep$1(gen,resolve,reject,_next,_throw,"throw",err)}_next(void 0)})}}function _instanceof(left,right){return null!=right&&"undefined"!=typeof Symbol&&right[Symbol.hasInstance]?!!right[Symbol.hasInstance](left):left instanceof right}function _set_prototype_of$1(o,p){return _set_prototype_of$1=Object.setPrototypeOf||function(o,p){return o.__proto__=p,o},_set_prototype_of$1(o,p)}function _ts_generator$1(thisArg,body){var f,y,t,_={label:0,sent:function(){if(1&t[0])throw t[1];return t[1]},trys:[],ops:[]},g=Object.create(("function"==typeof Iterator?Iterator:Object).prototype),d=Object.defineProperty;return d(g,"next",{value:verb(0)}),d(g,"throw",{value:verb(1)}),d(g,"return",{value:verb(2)}),"function"==typeof Symbol&&d(g,Symbol.iterator,{value:function(){return this}}),g;function verb(n){return function(v){return function(op){if(f)throw new TypeError("Generator is already executing.");for(;g&&(g=0,op[0]&&(_=0)),_;)try{if(f=1,y&&(t=2&op[0]?y.return:op[0]?y.throw||((t=y.return)&&t.call(y),0):y.next)&&!(t=t.call(y,op[1])).done)return t;switch(y=0,t&&(op=[2&op[0],t.value]),op[0]){case 0:case 1:t=op;break;case 4:return _.label++,{value:op[1],done:!1};case 5:_.label++,y=op[1],op=[0];continue;case 7:op=_.ops.pop(),_.trys.pop();continue;default:if(!(t=_.trys,(t=t.length>0&&t[t.length-1])||6!==op[0]&&2!==op[0])){_=0;continue}if(3===op[0]&&(!t||op[1]>t[0]&&op[1]<t[3])){_.label=op[1];break}if(6===op[0]&&_.label<t[1]){_.label=t[1],t=op;break}if(t&&_.label<t[2]){_.label=t[2],_.ops.push(op);break}t[2]&&_.ops.pop(),_.trys.pop();continue}op=body.call(thisArg,_)}catch(e){op=[6,e],y=0}finally{f=t=0}if(5&op[0])throw op[1];return{value:op[0]?op[1]:void 0,done:!0}}([n,v])}}}var PREFIX="ebroadcast",WAVE_BARS=[{height:15,color:"#CCCCCC"},{height:30,color:"#D6D6D6"},{height:45,color:"#E0E0E0"},{height:60,color:"#EBEBEB"},{height:85,color:"#FFFFFF"},{height:60,color:"#EBEBEB"},{height:45,color:"#E0E0E0"},{height:30,color:"#D6D6D6"},{height:15,color:"#CCCCCC"}],BroadcastUI=function(Drawer){function BroadcastUI(container,options){var _this;i18n.setLanguage(options.language||"zh");var isMobile=!!options.isMobile,placement=BroadcastUI.resolvePlacement(options.direction),contentRoot=BroadcastUI.buildContent(isMobile),drawerOptions={title:i18n.t("title"),content:contentRoot,placement:placement,showHeader:!0,showClose:!0,maskClosable:!0,closeOnEscape:!0,className:PREFIX+"-drawer"};return"left"===placement||"right"===placement?drawerOptions.width="80%":drawerOptions.height="80%",(_this=Drawer.call(this,container,drawerOptions)||this).broadcastOptions=options,_this.logger=createLogger(options.logger),_this.isMobile=isMobile,_this.voiceList=options.voiceList||[],_this.isRecording=!1,_this.isStarting=!1,_this.lastTouchTime=0,_this.pendingStop=!1,_this.pendingCancel=!1,_this.tipTimer=null,_this.recordingMessageId=null,_this.waveBars=[],_this.recordingHint=null,_this.waveTimer=null,_this.countdownTimer=null,_this.remainingTime=59,_this.options.onOpenChange=function(open){return _this.handleOpenChange(open)},_this.voiceListElement=contentRoot.querySelector(".ebroadcast-voice-list"),_this.loadingElement=contentRoot.querySelector(".ebroadcast-loading"),_this.emptyElement=contentRoot.querySelector(".ebroadcast-empty"),_this.errorElement=contentRoot.querySelector(".ebroadcast-error"),_this.tipElement=contentRoot.querySelector(".ebroadcast-tip"),_this.talkButton=contentRoot.querySelector(".ebroadcast-talk-btn"),_this.recordingMessage=new Message(contentRoot,{className:PREFIX+"-recording",duration:0,maxCount:1,zIndex:1}),_this.bindEvents(),_this.voiceList.length>0?_this.renderVoiceList():_this.setLoading(!0),_this.logger.log("[BroadcastUI] UI创建完成,isMobile:",isMobile),_this}!function(subClass,superClass){if("function"!=typeof superClass&&null!==superClass)throw new TypeError("Super expression must either be null or a function");subClass.prototype=Object.create(superClass&&superClass.prototype,{constructor:{value:subClass,writable:!0,configurable:!0}}),superClass&&_set_prototype_of$1(subClass,superClass)}(BroadcastUI,Drawer);var _proto=BroadcastUI.prototype;return _proto.handleOpenChange=function(open){open||this.cancelRecording()},_proto.cancelRecording=function(){this.isStarting&&(this.pendingCancel=!0),this.isRecording=!1,this.pendingStop=!1,this.hideRecordingMessage(),this.setTalkButtonRecording(!1),this.cancelRecord()},_proto.bindEvents=function(){var _this_voiceListElement,_this=this;null==(_this_voiceListElement=this.voiceListElement)||_this_voiceListElement.addEventListener("click",function(e){var item=e.target.closest(".ebroadcast-voice-item");if(item){var index=parseInt(item.getAttribute("data-index")||"-1",10);_this.selectVoice(index)}}),this.talkButton&&(this.logger.log("[BroadcastUI] 绑定按钮事件,isMobile:",this.isMobile),this.isMobile?(this.logger.log("[BroadcastUI] 使用移动端交互:按住说话"),this.talkButton.addEventListener("touchstart",function(e){e.preventDefault(),e.stopPropagation();var now=Date.now();now-_this.lastTouchTime<300?_this.logger.log("[BroadcastUI] 触摸事件防抖,忽略快速点击"):(_this.lastTouchTime=now,_this.handleRecordStart())},{passive:!1}),this.talkButton.addEventListener("touchend",function(e){e.preventDefault(),e.stopPropagation(),_this.handleRecordStop()},{passive:!1}),this.talkButton.addEventListener("touchcancel",function(){_this.isRecording&&_this.handleRecordStop()})):(this.logger.log("[BroadcastUI] 使用PC端交互:点击切换"),this.talkButton.addEventListener("click",function(e){e.preventDefault(),_this.logger.log("[BroadcastUI] PC端按钮点击事件触发"),_this.handleRecordToggle()})))},_proto.handleRecordToggle=function(){this.isRecording?this.handleRecordStop():this.handleRecordStart()},_proto.handleRecordStart=function(){return _async_to_generator$1(function(){var error;return _ts_generator$1(this,function(_state){switch(_state.label){case 0:if(this.isRecording||this.isStarting)return this.logger.log("[BroadcastUI] 录音已在进行中,忽略重复启动"),[2];_state.label=1;case 1:return _state.trys.push([1,5,,6]),this.logger.log("[BroadcastUI] 开始录音..."),this.pendingStop=!1,this.pendingCancel=!1,this.isStarting=!0,this.showRecordingMessage(),this.setTalkButtonRecording(!0),[4,this.startRecord()];case 2:return _state.sent(),this.isStarting=!1,this.pendingCancel?(this.logger.log("[BroadcastUI] 启动期间面板已关闭,取消录音"),this.pendingCancel=!1,this.isRecording=!1,this.cancelRecord(),[2]):(this.isRecording=!0,this.pendingStop?(this.logger.log("[BroadcastUI] 检测到待处理的停止请求,立即停止录音"),this.pendingStop=!1,[4,this.handleRecordStop()]):[3,4]);case 3:_state.sent(),_state.label=4;case 4:return[3,6];case 5:return error=_state.sent(),this.logger.error("[BroadcastUI] 开始录音失败",error),this.isStarting=!1,this.isRecording=!1,this.pendingStop=!1,this.pendingCancel=!1,this.hideRecordingMessage(),this.setTalkButtonRecording(!1),this.showError(_instanceof(error,Error)?error.message:"开始录音失败"),[3,6];case 6:return[2]}})}).call(this)},_proto.handleRecordStop=function(){return _async_to_generator$1(function(){var error;return _ts_generator$1(this,function(_state){switch(_state.label){case 0:if(this.isStarting)return this.logger.log("[BroadcastUI] 录音正在启动中,标记为待停止"),this.pendingStop=!0,[2];if(!this.isRecording)return this.logger.log("[BroadcastUI] 未在录音状态,忽略停止请求"),[2];_state.label=1;case 1:return _state.trys.push([1,3,,4]),this.logger.log("[BroadcastUI] 停止录音..."),this.hideRecordingMessage(),this.setTalkButtonRecording(!1),[4,this.stopRecord()];case 2:return _state.sent(),this.isRecording=!1,[3,4];case 3:return error=_state.sent(),this.logger.error("[BroadcastUI] 停止录音失败",error),this.isRecording=!1,this.hideRecordingMessage(),this.setTalkButtonRecording(!1),this.showError(_instanceof(error,Error)?error.message:"停止录音失败"),[3,4];case 4:return[2]}})}).call(this)},_proto.setTalkButtonRecording=function(recording){if(this.talkButton){this.talkButton.classList.toggle(PREFIX+"-talk-btn-recording",recording);var textElement=this.talkButton.querySelector(".ebroadcast-talk-text");textElement&&(textElement.textContent=recording?this.isMobile?i18n.t("recording"):i18n.t("stopRecording"):this.isMobile?i18n.t("pressToTalk"):i18n.t("clickToTalk"))}},_proto.showRecordingMessage=function(){if(!this.recordingMessageId){var content=BroadcastUI.buildRecordingContent();this.waveBars=Array.from(content.querySelectorAll("rect")),this.recordingHint=content.querySelector(".ebroadcast-recording-hint"),this.remainingTime=59,this.updateRecordingHint(),this.recordingMessageId=this.recordingMessage.info(content,{duration:0}),this.startWaveAnimation(),this.startCountdown(),this.logger.log("[BroadcastUI] 录音提示已显示")}},_proto.hideRecordingMessage=function(){this.stopWaveAnimation(),this.stopCountdown(),this.recordingMessageId&&(this.recordingMessage.close(this.recordingMessageId),this.recordingMessageId=null,this.logger.log("[BroadcastUI] 录音提示已隐藏")),this.waveBars=[],this.recordingHint=null},_proto.startWaveAnimation=function(){var _this=this;this.stopWaveAnimation();var frame=0;this.waveTimer=window.setInterval(function(){_this.waveBars.forEach(function(bar,index){var phase=(.3*frame+.8*index)%(2*Math.PI),height=30+(Math.sin(phase)+1)/2*50;bar.setAttribute("height",height.toFixed(2)),bar.setAttribute("y",(50-height/2).toFixed(2))}),frame++},100)},_proto.stopWaveAnimation=function(){null!==this.waveTimer&&(clearInterval(this.waveTimer),this.waveTimer=null)},_proto.startCountdown=function(){var _this=this;this.stopCountdown(),this.countdownTimer=window.setInterval(function(){_this.remainingTime--,_this.updateRecordingHint(),_this.remainingTime<=0&&_this.stopCountdown()},1e3)},_proto.stopCountdown=function(){null!==this.countdownTimer&&(clearInterval(this.countdownTimer),this.countdownTimer=null)},_proto.updateRecordingHint=function(){if(this.recordingHint){var remaining=Math.max(0,this.remainingTime);this.recordingHint.textContent=remaining>0?i18n.t("recordingRemaining").replace("{time}",String(remaining)):this.isMobile?i18n.t("releaseToStop"):i18n.t("clickToStop")}},_proto.close=function(){this.open=!1},_proto.updateVoiceList=function(voiceList){this.voiceList=Array.isArray(voiceList)?voiceList:[],this.renderVoiceList()},_proto.renderVoiceList=function(){if(this.voiceListElement){if(this.setLoading(!1),this.setError(""),0===this.voiceList.length)return this.voiceListElement.innerHTML="",this.voiceListElement.parentElement&&(this.voiceListElement.parentElement.style.display="none"),void(this.emptyElement&&(this.emptyElement.style.display="flex"));this.voiceListElement.parentElement&&(this.voiceListElement.parentElement.style.display=""),this.emptyElement&&(this.emptyElement.style.display="none"),this.voiceListElement.innerHTML=this.voiceList.map(function(voice,index){var name=BroadcastUI.escape(voice.voiceName);return'\n <div class="ebroadcast-voice-item" data-index="'+index+'">\n <div class="'+PREFIX+'-voice-icon">\n <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">\n <path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/>\n </svg>\n </div>\n <div class="'+PREFIX+'-voice-text" title="'+name+'">'+name+"</div>\n </div>\n "}).join(""),this.logger.log("[BroadcastUI] 语音列表已渲染",this.voiceList.length)}},_proto.selectVoice=function(index){if(this.voiceListElement&&(this.voiceListElement.querySelectorAll(".ebroadcast-voice-item").forEach(function(item){item.classList.remove(PREFIX+"-voice-item-selected")}),index>=0&&index<this.voiceList.length)){var selectedItem=this.voiceListElement.querySelector('[data-index="'+index+'"]');selectedItem&&selectedItem.classList.add(PREFIX+"-voice-item-selected");var selectedVoice=this.voiceList[index];this.logger.log("[BroadcastUI] 已选中语音:",selectedVoice.voiceName),this.sendVoice(selectedVoice.fileUrl)}},_proto.setRecordingState=function(isRecording){this.isRecording=isRecording,this.logger.log("[BroadcastUI] 录音状态:",isRecording)},_proto.setLoading=function(loading){var _this_voiceListElement;this.loadingElement&&(this.loadingElement.style.display=loading?"flex":"none");var content=null==(_this_voiceListElement=this.voiceListElement)?void 0:_this_voiceListElement.parentElement;loading?(this.emptyElement&&(this.emptyElement.style.display="none"),this.errorElement&&(this.errorElement.style.display="none"),content&&(content.style.display="none")):content&&this.voiceList.length>0&&(content.style.display="")},_proto.setError=function(message){var _this_voiceListElement;if(this.errorElement){this.errorElement.textContent=message,this.errorElement.style.display=message?"flex":"none";var content=null==(_this_voiceListElement=this.voiceListElement)?void 0:_this_voiceListElement.parentElement;message?(this.loadingElement&&(this.loadingElement.style.display="none"),this.emptyElement&&(this.emptyElement.style.display="none"),content&&(content.style.display="none")):content&&this.voiceList.length>0&&(content.style.display="")}},_proto.showSuccess=function(message){this.logger.log("[BroadcastUI] 成功:",message),this.showTip(message,!1)},_proto.showError=function(message){this.logger.error("[BroadcastUI] 错误:",message),this.showTip(message,!0)},_proto.showTip=function(message,isError){var _this=this;this.tipElement&&message&&(this.tipElement.textContent=message,this.tipElement.classList.toggle(PREFIX+"-tip-error",isError),this.tipElement.style.display="block",this.tipElement.offsetWidth,this.tipElement.classList.add(PREFIX+"-tip-visible"),this.tipTimer&&clearTimeout(this.tipTimer),this.tipTimer=window.setTimeout(function(){var _this_tipElement;_this.tipTimer=null,null==(_this_tipElement=_this.tipElement)||_this_tipElement.classList.remove(PREFIX+"-tip-visible"),_this.tipTimer=window.setTimeout(function(){_this.tipTimer=null,_this.tipElement&&(_this.tipElement.style.display="none")},200)},2e3))},_proto.destroy=function(){this.tipTimer&&(clearTimeout(this.tipTimer),this.tipTimer=null),this.stopWaveAnimation(),this.stopCountdown(),this.recordingMessageId=null,this.waveBars=[],this.recordingHint=null,this.recordingMessage.destroy(),Drawer.prototype.destroy.call(this),this.voiceListElement=null,this.loadingElement=null,this.emptyElement=null,this.errorElement=null,this.tipElement=null,this.talkButton=null,this.logger.log("[BroadcastUI] UI已销毁")},BroadcastUI.resolvePlacement=function(direction){return"top"===direction||"bottom"===direction||"left"===direction||"right"===direction?direction:"right"},BroadcastUI.buildContent=function(isMobile){var t=i18n.t.bind(i18n),root=document.createElement("div");return root.className=PREFIX+"-content-root",root.innerHTML='\n \x3c!-- Tab区域 --\x3e\n <div class="ebroadcast-tabs">\n <div class="ebroadcast-tab ebroadcast-tab-active">'+t("defaultVoice")+'</div>\n </div>\n\n \x3c!-- 内容区域 --\x3e\n <div class="'+PREFIX+'-content">\n <div class="'+PREFIX+'-voice-list"></div>\n </div>\n\n \x3c!-- 状态区:加载 / 空 / 错误,互斥展示 --\x3e\n <div class="'+PREFIX+'-loading" style="display:none;">'+t("loading")+'</div>\n <div class="'+PREFIX+'-empty" style="display:none;">'+t("noVoice")+'</div>\n <div class="'+PREFIX+'-error" style="display:none;"></div>\n\n \x3c!-- 底部按钮 --\x3e\n <div class="'+PREFIX+'-footer">\n <button class="'+PREFIX+'-talk-btn" type="button">\n <span class="'+PREFIX+'-talk-text">'+t(isMobile?"pressToTalk":"clickToTalk")+'</span>\n </button>\n </div>\n\n \x3c!-- 轻提示:showSuccess / showError 复用 --\x3e\n <div class="'+PREFIX+'-tip" style="display:none;"></div>\n ',root},BroadcastUI.buildRecordingContent=function(){var bars=WAVE_BARS.map(function(bar,index){return'<rect x="'+(5+16*index)+'" y="'+(50-bar.height/2)+'" width="12" height="'+bar.height+'" rx="6" fill="'+bar.color+'" />'}).join(""),root=document.createElement("span");return root.className=PREFIX+"-recording-content",root.innerHTML='<svg class="ebroadcast-recording-wave" viewBox="0 0 150 100" width="80" height="40" aria-hidden="true" focusable="false">'+bars+'</svg><span class="'+PREFIX+'-recording-hint" aria-live="off"></span>',root},BroadcastUI.escape=function(value){return String(null!=value?value:"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")},BroadcastUI}(Drawer);function asyncGeneratorStep(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg),value=info.value}catch(error){return void reject(error)}info.done?resolve(value):Promise.resolve(value).then(_next,_throw)}function _async_to_generator(fn){return function(){var self=this,args=arguments;return new Promise(function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"next",value)}function _throw(err){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"throw",err)}_next(void 0)})}}function _set_prototype_of(o,p){return _set_prototype_of=Object.setPrototypeOf||function(o,p){return o.__proto__=p,o},_set_prototype_of(o,p)}function _ts_generator(thisArg,body){var f,y,t,_={label:0,sent:function(){if(1&t[0])throw t[1];return t[1]},trys:[],ops:[]},g=Object.create(("function"==typeof Iterator?Iterator:Object).prototype),d=Object.defineProperty;return d(g,"next",{value:verb(0)}),d(g,"throw",{value:verb(1)}),d(g,"return",{value:verb(2)}),"function"==typeof Symbol&&d(g,Symbol.iterator,{value:function(){return this}}),g;function verb(n){return function(v){return function(op){if(f)throw new TypeError("Generator is already executing.");for(;g&&(g=0,op[0]&&(_=0)),_;)try{if(f=1,y&&(t=2&op[0]?y.return:op[0]?y.throw||((t=y.return)&&t.call(y),0):y.next)&&!(t=t.call(y,op[1])).done)return t;switch(y=0,t&&(op=[2&op[0],t.value]),op[0]){case 0:case 1:t=op;break;case 4:return _.label++,{value:op[1],done:!1};case 5:_.label++,y=op[1],op=[0];continue;case 7:op=_.ops.pop(),_.trys.pop();continue;default:if(!(t=_.trys,(t=t.length>0&&t[t.length-1])||6!==op[0]&&2!==op[0])){_=0;continue}if(3===op[0]&&(!t||op[1]>t[0]&&op[1]<t[3])){_.label=op[1];break}if(6===op[0]&&_.label<t[1]){_.label=t[1],t=op;break}if(t&&_.label<t[2]){_.label=t[2],_.ops.push(op);break}t[2]&&_.ops.pop(),_.trys.pop();continue}op=body.call(thisArg,_)}catch(e){op=[6,e],y=0}finally{f=t=0}if(5&op[0])throw op[1];return{value:op[0]?op[1]:void 0,done:!0}}([n,v])}}}var _BROADCAST_DefaultOptions_={channelNo:"1",env:{domain:"https://open.ys7.com"},language:"zh"},Broadcast=function(BroadcastUI){function Broadcast(options){var _this,broadcastOptions=Object.assign({},_BROADCAST_DefaultOptions_,options);return(_this=BroadcastUI.call(this,broadcastOptions.container||document.body,broadcastOptions)||this).voiceRecorder=null,_this.maxDurationTimer=null,_this.pendingAudioBlob=null,_this.logger.log("1.0.0-beta.1 init"),_this}!function(subClass,superClass){if("function"!=typeof superClass&&null!==superClass)throw new TypeError("Super expression must either be null or a function");subClass.prototype=Object.create(superClass&&superClass.prototype,{constructor:{value:subClass,writable:!0,configurable:!0}}),superClass&&_set_prototype_of(subClass,superClass)}(Broadcast,BroadcastUI);var _proto=Broadcast.prototype;return _proto.invoke=function(name){for(var _len=arguments.length,args=new Array(_len>1?_len-1:0),_key=1;_key<_len;_key++)args[_key-1]=arguments[_key];var callback=this.broadcastOptions[name];if("function"==typeof callback)try{callback.apply(void 0,[].concat(args))}catch(error){this.logger.error('回调 "'+name+'" 执行出错:',error)}},_proto.initMicrophonePermission=function(){return _async_to_generator(function(){var error;return _ts_generator(this,function(_state){switch(_state.label){case 0:return _state.trys.push([0,2,,3]),this.logger.log("开始请求麦克风权限..."),[4,navigator.mediaDevices.getUserMedia({audio:{sampleRate:16e3,channelCount:1,echoCancellation:!0,noiseSuppression:!0}})];case 1:return _state.sent().getTracks().forEach(function(track){return track.stop()}),this.logger.log("麦克风权限已获取"),[3,3];case 2:return error=_state.sent(),this.logger.warn("麦克风权限获取失败,将在首次录音时再次请求",error),this.invoke("onError",{msg:"麦克风权限获取失败",error:error}),[3,3];case 3:return[2]}})}).call(this)},_proto.requestMicrophonePermission=function(){return _async_to_generator(function(){var error;return _ts_generator(this,function(_state){switch(_state.label){case 0:return _state.trys.push([0,2,,3]),this.logger.log("手动请求麦克风权限..."),[4,navigator.mediaDevices.getUserMedia({audio:{sampleRate:16e3,channelCount:1,echoCancellation:!0,noiseSuppression:!0}})];case 1:return _state.sent().getTracks().forEach(function(track){return track.stop()}),this.logger.log("麦克风权限已获取"),[2,!0];case 2:return error=_state.sent(),this.logger.error("麦克风权限获取失败",error),this.invoke("onError",{msg:"麦克风权限获取失败",error:error}),[2,!1];case 3:return[2]}})}).call(this)},_proto.handleOpenChange=function(open){BroadcastUI.prototype.handleOpenChange.call(this,open),open?(0===this.voiceList.length&&this.loadVoiceList(),this.invoke("onOpen"),this.logger.log("云广播界面已打开")):(this.invoke("onClose"),this.logger.log("云广播界面已关闭"))},_proto.loadVoiceList=function(){this.logger.log("请求加载语音列表"),this.invoke("onRequestQueryVoiceList",{deviceSerial:this.broadcastOptions.deviceSerial,channelNo:this.broadcastOptions.channelNo,pageSize:50})},_proto.startRecord=function(){return _async_to_generator(function(){var _this,error;return _ts_generator(this,function(_state){switch(_state.label){case 0:_this=this,_state.label=1;case 1:return _state.trys.push([1,3,,4]),this.logger.log("开始录音"),this.pendingAudioBlob=null,this.voiceRecorder||(this.voiceRecorder=new VoiceRecorder({minDuration:3,maxDuration:59,sampleRate:16e3,logger:this.logger})),[4,this.voiceRecorder.start()];case 2:return _state.sent(),this.maxDurationTimer=window.setTimeout(function(){return _async_to_generator(function(){return _ts_generator(this,function(_state){switch(_state.label){case 0:return this.logger.log("达到最大录音时长,停止录音并暂存"),[4,this.stopRecordAndCache()];case 1:return _state.sent(),[2]}})}).call(_this)},59e3),this.invoke("onRecordStart"),this.setRecordingState(!0),[3,4];case 3:return error=_state.sent(),this.logger.error("开始录音失败",error),this.invoke("onRecordError",{msg:"开始录音失败",error:error}),[3,4];case 4:return[2]}})}).call(this)},_proto.stopRecordAndCache=function(){return _async_to_generator(function(){var audioBlob,error;return _ts_generator(this,function(_state){switch(_state.label){case 0:return _state.trys.push([0,2,,3]),this.voiceRecorder?this.voiceRecorder.isRecording()?[4,this.voiceRecorder.stop()]:(this.logger.warn("录音器已停止"),[2]):[2];case 1:return 0===(audioBlob=_state.sent()).size?(this.logger.warn("录音数据为空"),[2]):(this.pendingAudioBlob=audioBlob,this.invoke("onRecordComplete",audioBlob),[3,3]);case 2:return error=_state.sent(),this.logger.error("停止录音失败",error),this.setRecordingState(!1),[3,3];case 3:return[2]}})}).call(this)},_proto.stopRecord=function(){return _async_to_generator(function(){var audioBlob,audioBlob1,error;return _ts_generator(this,function(_state){switch(_state.label){case 0:if(_state.trys.push([0,2,,3]),this.clearMaxDurationTimer(),this.pendingAudioBlob)return audioBlob=this.pendingAudioBlob,this.pendingAudioBlob=null,this.invoke("onRecordStop"),this.setRecordingState(!1),this.sendVoiceOnce(audioBlob),[2];if(!this.voiceRecorder)throw new Error("录音器未初始化");return this.voiceRecorder.isRecording()?[4,this.voiceRecorder.stop()]:(this.logger.warn("录音器已停止"),this.setRecordingState(!1),[2]);case 1:return 0===(audioBlob1=_state.sent()).size?(this.logger.error("录音数据为空,不进行下发"),this.setRecordingState(!1),[2]):(this.invoke("onRecordStop"),this.invoke("onRecordComplete",audioBlob1),this.setRecordingState(!1),this.sendVoiceOnce(audioBlob1),[3,3]);case 2:return error=_state.sent(),this.logger.error("停止录音失败",error),this.invoke("onRecordError",{msg:"停止录音失败",error:error}),this.setRecordingState(!1),[3,3];case 3:return[2]}})}).call(this)},_proto.cancelRecord=function(){var _this_voiceRecorder,_this=this;this.clearMaxDurationTimer(),this.pendingAudioBlob=null,(null==(_this_voiceRecorder=this.voiceRecorder)?void 0:_this_voiceRecorder.isRecording())&&this.voiceRecorder.stop().then(function(){return _this.logger.log("已取消录音,录音已丢弃")},function(){return _this.logger.log("已取消录音(录音时长不足)")})},_proto.clearMaxDurationTimer=function(){this.maxDurationTimer&&(clearTimeout(this.maxDurationTimer),this.maxDurationTimer=null)},_proto.sendVoiceOnce=function(voiceFile){var _this_broadcastOptions=this.broadcastOptions,deviceSerial=_this_broadcastOptions.deviceSerial,channelNo=_this_broadcastOptions.channelNo;this.invoke("onVoiceRecorded",{voiceFile:voiceFile,deviceSerial:deviceSerial,channelNo:channelNo}),this.invoke("onRequestSendVoiceOnce",{voiceFile:voiceFile,deviceSerial:deviceSerial,channelNo:channelNo})},_proto.sendVoice=function(fileUrl){this.logger.log("请求下发默认语音",fileUrl),this.invoke("onRequestSendVoice",{fileUrl:fileUrl,deviceSerial:this.broadcastOptions.deviceSerial,channelNo:this.broadcastOptions.channelNo})},_proto.updateOptions=function(options){this.broadcastOptions=Object.assign(this.broadcastOptions,options),this.logger.log("配置已更新",Object.keys(options))},_proto.destroy=function(){this.logger.log("开始销毁"),this.close(),this.clearMaxDurationTimer(),this.pendingAudioBlob=null,this.voiceRecorder&&(this.voiceRecorder.destroy(),this.voiceRecorder=null),BroadcastUI.prototype.destroy.call(this),this.voiceList=[],this.logger.log("销毁完成")},Broadcast}(BroadcastUI);Broadcast.VERSION="1.0.0-beta.1";export{Broadcast as default};
|