@ezuikit/control-broadcast 0.0.1 → 0.1.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 +6 -0
- package/dist/index.mjs +6 -0
- package/dist/index.umd.js +3 -3
- package/dist/types/index.d.ts +5 -0
- package/package.json +42 -33
- package/dist/index.js +0 -6
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @ezuikit/control-broadcast v0.1.0-beta.1
|
|
3
|
+
* Copyright (c) 2026-05-04 Ezviz-OpenBiz
|
|
4
|
+
* Released under the MIT License.
|
|
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.1",Broadcast.EVENTS=EVENTS,module.exports=Broadcast;
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @ezuikit/control-broadcast v0.1.0-beta.1
|
|
3
|
+
* Copyright (c) 2026-05-04 Ezviz-OpenBiz
|
|
4
|
+
* Released under the MIT License.
|
|
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.1",Broadcast.EVENTS=EVENTS;export{Broadcast as default};
|
package/dist/index.umd.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* @ezuikit/control-broadcast v0.0.1
|
|
3
|
-
* Copyright (c) 2026-04
|
|
2
|
+
* @ezuikit/control-broadcast v0.1.0-beta.1
|
|
3
|
+
* Copyright (c) 2026-05-04 Ezviz-OpenBiz
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
6
|
-
!function(global,factory){"object"==typeof exports&&"undefined"!=typeof module?module.exports=factory():"function"==typeof define&&define.amd?define(factory):(global="undefined"!=typeof globalThis?globalThis:global||self).Broadcast=factory()}(this,function(){"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}();return Broadcast.VERSION="0.0.1",Broadcast.EVENTS=EVENTS,Broadcast});
|
|
6
|
+
!function(global,factory){"object"==typeof exports&&"undefined"!=typeof module?module.exports=factory():"function"==typeof define&&define.amd?define(factory):(global="undefined"!=typeof globalThis?globalThis:global||self).Broadcast=factory()}(this,function(){"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}();return Broadcast.VERSION="0.1.0-beta.1",Broadcast.EVENTS=EVENTS,Broadcast});
|
package/dist/types/index.d.ts
CHANGED
|
@@ -190,6 +190,11 @@ declare class BroadcastUI {
|
|
|
190
190
|
private lastTouchTime;
|
|
191
191
|
private pendingStop;
|
|
192
192
|
private orientationChangeHandler;
|
|
193
|
+
/**
|
|
194
|
+
*
|
|
195
|
+
* @param container
|
|
196
|
+
* @param options
|
|
197
|
+
*/
|
|
193
198
|
constructor(container: HTMLElement | string, options: BroadcastUIOptions);
|
|
194
199
|
/**
|
|
195
200
|
* 设置屏幕方向变化监听器(移动端)
|
package/package.json
CHANGED
|
@@ -1,33 +1,42 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@ezuikit/control-broadcast",
|
|
3
|
-
"version": "0.0.1",
|
|
4
|
-
"description": "broadcast voice control",
|
|
5
|
-
"title": "broadcast",
|
|
6
|
-
"main": "dist/index.
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@ezuikit/control-broadcast",
|
|
3
|
+
"version": "0.1.0-beta.1",
|
|
4
|
+
"description": "broadcast voice control",
|
|
5
|
+
"title": "broadcast",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.mjs",
|
|
8
|
+
"types": "dist/types/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/types/index.d.ts",
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"require": "./dist/index.cjs",
|
|
14
|
+
"default": "./dist/index.cjs"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"ezuikit",
|
|
19
|
+
"broadcast",
|
|
20
|
+
"voice"
|
|
21
|
+
],
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"author": "Ezviz-OpenBiz",
|
|
26
|
+
"license": "",
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@ezuikit/utils-i18n": "^2.0.0"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"registry": "https://registry.npmjs.org/",
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/Ezviz-OpenBiz/EZUIKit-player-controls.git"
|
|
37
|
+
},
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/Ezviz-OpenBiz/EZUIKit-player-controls/issues"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/Ezviz-OpenBiz/EZUIKit-player-controls#readme"
|
|
42
|
+
}
|
package/dist/index.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @ezuikit/control-broadcast v0.0.1
|
|
3
|
-
* Copyright (c) 2026-04-09 Ezviz-OpenBiz
|
|
4
|
-
* Released under the MIT License.
|
|
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.0.1",Broadcast.EVENTS=EVENTS,module.exports=Broadcast;
|