ysyt-agent-sdk 1.0.16 → 1.0.17
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.
|
@@ -110,7 +110,7 @@ const Zs=e=>(t,s)=>{void 0!==s?s.addInitializer(()=>{customElements.define(e,t)}
|
|
|
110
110
|
:host([type='loading']) {
|
|
111
111
|
background: #595959;
|
|
112
112
|
}
|
|
113
|
-
`}connectedCallback(){super.connectedCallback(),setTimeout(()=>{this.remove()},this.duration+300)}render(){return Ds`<div>${this.content}</div>`}};jt([ei({type:String})],ii.prototype,"type",void 0),jt([ei({type:String})],ii.prototype,"content",void 0),jt([ei({type:Number})],ii.prototype,"duration",void 0),ii=jt([Zs("my-message")],ii);const ri=(e,t,s=3e3)=>{let i=document.querySelector("#message-container");i||(i=document.createElement("div"),i.id="message-container",Object.assign(i.style,{position:"fixed",top:"14px",left:"50%",transform:"translateX(-50%)",zIndex:"9999"}),document.body.appendChild(i));const r=document.createElement("my-message");r.setAttribute("type",e),r.setAttribute("content",t),r.setAttribute("duration",String(s)),r.style.setProperty("--fade-delay",s/1e3+"s"),i.appendChild(r)},ni=(e,t=3e3)=>ri("success",e,t),oi=(e,t=3e3)=>ri("error",e,t),ai=(e,t=3e3)=>ri("warning",e,t),ci="/v1/aicc/bmserver",hi="/v1/aicc/ccs";let di="",li="",gi="";async function ui(e,t){const s=function(){const e=Ft(li,gi);return qt.create({prefixUrl:`${di}/api`,timeout:!1,headers:{Authorization:e},hooks:{afterResponse:[async(e,t,s)=>{const i=await s.clone().json();if(0!==i.code)throw oi(i.msg),new Error(JSON.stringify(i)||"请求失败");return s.json=async()=>i,s}]}})}(),i=e.replace(/^\/+/,"");return s.post(i,{json:t}).json()}const pi={agentInfo:{},isRtcReconnecting:!1,sessionId:"",enableBrowserAlert:!1,autoStateTimer:null};const fi=new class extends Qe{updateRttObject(e){this.setState({rttObject:e})}}({rttObject:{rtt:null,jitter:null,packetsLost:null,packetsReceived:null,packetsSent:null,sendBitrate:null,recvBitrate:null,codec:null}});class mi{constructor(e,t){this.config=e,this.eventCallback=t,this.userAgent=null,this.registerer=null,this.activeSession=null,this.callTimeoutTimer=null,this.incomingInvitation=null,this.reconnectAttempts=0,this.maxReconnectAttempts=5,this.reconnectTimer=null,this.isOffline=!1,this.autoAnswerTimer=null,this.handleMessage=e=>{},this.handleNetworkInfoChange=e=>{
|
|
113
|
+
`}connectedCallback(){super.connectedCallback(),setTimeout(()=>{this.remove()},this.duration+300)}render(){return Ds`<div>${this.content}</div>`}};jt([ei({type:String})],ii.prototype,"type",void 0),jt([ei({type:String})],ii.prototype,"content",void 0),jt([ei({type:Number})],ii.prototype,"duration",void 0),ii=jt([Zs("my-message")],ii);const ri=(e,t,s=3e3)=>{let i=document.querySelector("#message-container");i||(i=document.createElement("div"),i.id="message-container",Object.assign(i.style,{position:"fixed",top:"14px",left:"50%",transform:"translateX(-50%)",zIndex:"9999"}),document.body.appendChild(i));const r=document.createElement("my-message");r.setAttribute("type",e),r.setAttribute("content",t),r.setAttribute("duration",String(s)),r.style.setProperty("--fade-delay",s/1e3+"s"),i.appendChild(r)},ni=(e,t=3e3)=>ri("success",e,t),oi=(e,t=3e3)=>ri("error",e,t),ai=(e,t=3e3)=>ri("warning",e,t),ci="/v1/aicc/bmserver",hi="/v1/aicc/ccs";let di="",li="",gi="";async function ui(e,t){const s=function(){const e=Ft(li,gi);return qt.create({prefixUrl:`${di}/api`,timeout:!1,headers:{Authorization:e},hooks:{afterResponse:[async(e,t,s)=>{const i=await s.clone().json();if(0!==i.code)throw oi(i.msg),new Error(JSON.stringify(i)||"请求失败");return s.json=async()=>i,s}]}})}(),i=e.replace(/^\/+/,"");return s.post(i,{json:t}).json()}const pi={agentInfo:{},isRtcReconnecting:!1,sessionId:"",enableBrowserAlert:!1,autoStateTimer:null};const fi=new class extends Qe{updateRttObject(e){this.setState({rttObject:e})}}({rttObject:{rtt:null,jitter:null,packetsLost:null,packetsReceived:null,packetsSent:null,sendBitrate:null,recvBitrate:null,codec:null}});class mi{constructor(e,t){this.config=e,this.eventCallback=t,this.userAgent=null,this.registerer=null,this.activeSession=null,this.callTimeoutTimer=null,this.incomingInvitation=null,this.reconnectAttempts=0,this.maxReconnectAttempts=5,this.reconnectTimer=null,this.isOffline=!1,this.autoAnswerTimer=null,this.handleMessage=e=>{},this.handleNetworkInfoChange=e=>{const t=e.rttObject?.rtt||0;console.log(t),0===t?this.isOffline||(this.isOffline=!0,this.handleOffline()):this.isOffline&&(this.isOffline=!1,this.handleOnline())},this.handleOffline=()=>{console.warn("[SIPClient] 网络断开,准备销毁 SIP 客户端",(new Date).toLocaleString())},this.handleOnline=()=>{console.warn("[SIPClient] 网络恢复,准备重新启动 SIP 客户端",(new Date).toLocaleString())},fi.subscribe(this.handleNetworkInfoChange)}async start(){const e=Xe.makeURI(`sip:${this.config.user}@${this.config.server}`);if(!e)throw new Error("无效的SIP配置");const t={uri:e,authorizationUsername:this.config.user,authorizationPassword:this.config.password,transportOptions:{server:this.config.webSocket,connectionTimeout:30,keepAliveInterval:0},sessionDescriptionHandlerFactoryOptions:{alwaysAcquireMediaFirst:!0,peerConnectionConfiguration:{iceServers:[]},iceGatheringTimeout:400},logBuiltinEnabled:!1};this.userAgent=new Xe(t),this.setupEventListeners(),await this.userAgent.start(),await this.register()}setupEventListeners(){this.userAgent&&(this.userAgent.transport.stateChange.addListener(e=>{let t;switch(e){case ee.Connecting:t=st.WEB_RTC_CONNECTING;break;case ee.Connected:t=st.WEB_RTC_CONNECTED,this.reconnectAttempts=0,pi.isRtcReconnecting=!1,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null);break;case ee.Disconnecting:t=st.WEB_RTC_DISCONNECTING;break;case ee.Disconnected:{t=st.WEB_RTC_DISCONNECTED;const e=dt.get("answerDevice");if(!pi.isRtcReconnecting&&this.reconnectAttempts<this.maxReconnectAttempts&&1===e){this.reconnectAttempts++;const e=1e3*this.reconnectAttempts;console.warn(`SIP WebSocket 断开,第 ${this.reconnectAttempts} 次尝试重连,${e}ms 后重试...`),this.reconnectTimer=setTimeout(()=>{this.reconnect()},e)}else this.reconnectAttempts>=this.maxReconnectAttempts&&console.error("SIP 重连失败:已达到最大重试次数");break}default:t="unknown"}this.eventCallback?.({type:t})}),this.userAgent.transport.stateChange.addListener(e=>{}),this.userAgent.delegate={onInvite:e=>{this.handleIncomingCall(e)}})}async register(){if(this.userAgent){this.registerer=new ne(this.userAgent),this.registerer?.stateChange.addListener(e=>{let t;switch(e){case X.Initial:t="initial";break;case X.Registered:t=st.WEB_RTC_REGISTERED;break;case X.Unregistered:t=st.WEB_RTC_UNREGISTERED;break;case X.Terminated:t=st.WEB_RTC_TERMINATED;break;default:t="unknown"}this.eventCallback?.({type:t})});try{await this.registerer.register()}catch(e){this.eventCallback?.({type:st.WEB_RTC_REGISTER_FAILED,data:e})}}}attachRemoteAudio(e){const t=e.sessionDescriptionHandler;if(t){const e=t.peerConnection;if(!e)return;const s=new MediaStream;e.getReceivers().forEach(e=>{e.track&&"audio"===e.track.kind&&s.addTrack(e.track)});let i=document.getElementById("sip-remote-audio");i||(i=document.createElement("audio"),i.id="sip-remote-audio",i.autoplay=!0,i.style.display="none",document.body.appendChild(i)),i.srcObject=s,i.play().catch(e=>{console.error("音频播放失败,需要用户交互触发",e)})}}handleSessionState(e,t,s){e.stateChange.addListener(t=>{switch(t){case K.Established:clearTimeout(this.callTimeoutTimer),this.activeSession=e,this.attachRemoteAudio(e);break;case K.Terminating:break;case K.Terminated:this.activeSession=null,clearTimeout(this.callTimeoutTimer);case K.Establishing:}})}handleIncomingCall(e){this.incomingInvitation=e,this.handleSessionState(e,!1);const{soft_device_auto_answer:t,auto_answer_time:s}=pi.agentInfo,i=dt.get("direction"),r=1===t;if(i===tt.OUTGOING)this.answerCall();else if(r&&i===tt.INCOMING){const e=Number(s)||0;e>0?this.autoAnswerTimer=setTimeout(()=>{this.answerCall(),this.autoAnswerTimer=null},e):this.answerCall()}}async makeCall(e){if(dt.getState().isCalling)throw new Error("正在呼叫中,请勿重复点击");if(!this.userAgent)throw dt.updateIsCalling(!1),dt.updateDirection(null),new Error("SIP客户端未初始化");dt.updateIsCalling(!0),dt.updateDirection(tt.OUTGOING);const t=Xe.makeURI(`sip:${e}@${this.config.server}`);if(!t)throw new Error("无效的被叫号码");const s=new Z(this.userAgent,t);this.handleSessionState(s,!0,e);try{this.activeSession=s,await s.invite(),this.config.callTimeout&&(this.callTimeoutTimer=setTimeout(()=>{s.state!==K.Established&&(this.hangup(),this.eventCallback?.({type:"error",data:{message:"呼叫超时未接通"}}))},this.config.callTimeout))}catch(e){this.eventCallback?.({type:"error",data:{message:"呼叫失败",detail:e}}),dt.updateIsCalling(!1),dt.updateDirection(null)}}async answerCall(){if(!this.incomingInvitation)throw new Error("无来电可接听");this.autoAnswerTimer&&(clearTimeout(this.autoAnswerTimer),this.autoAnswerTimer=null);try{console.log((new Date).toLocaleString()),await this.incomingInvitation.accept(),console.log((new Date).toLocaleString()),this.activeSession=this.incomingInvitation,this.incomingInvitation=null}catch(e){this.eventCallback?.({type:st.WEB_RTC_ANSWER_FAILED,data:{detail:e}})}}async rejectInCall(){if(this.incomingInvitation)try{await this.incomingInvitation.reject(),this.incomingInvitation=null,dt.updateDirection(null),dt.updateIsCalling(!1),clearTimeout(this.callTimeoutTimer)}catch(e){this.eventCallback?.({type:"error",data:{message:"拒接失败",detail:e}})}}sendDTMF(e){if(!this.activeSession)throw new Error("当前没有活跃的通话");const t=this.activeSession.sessionDescriptionHandler;t&&"function"==typeof t.sendDtmf?(t.sendDtmf(e),this.eventCallback?.({type:st.WEB_RTC_SEND_DTMF,data:{tone:e}})):console.warn("DTMF发送不支持或未初始化")}async hangup(){if(this.activeSession){clearTimeout(this.callTimeoutTimer);const e=this.activeSession;if(!e)return;const t=e.state;try{t===K.Established?await e.bye():t===K.Establishing&&(e instanceof Z?await e.cancel():e instanceof J&&await e.reject()),clearTimeout(this.callTimeoutTimer)}catch(e){console.error("挂断失败",e)}finally{this.activeSession=null}}}async rejectOutCall(){this.activeSession instanceof J&&(await this.activeSession.reject(),this.activeSession=null)}async destroy(){if(clearTimeout(this.callTimeoutTimer),this.activeSession&&await this.hangup(),this.registerer){try{await this.registerer.unregister()}catch(e){console.warn("注销失败",e)}this.registerer=null}this.userAgent&&(await this.userAgent.stop(),this.userAgent=null)}async reconnect(){if(!pi.isRtcReconnecting){pi.isRtcReconnecting=!0;try{await this.destroy(),await this.start(),console.log("重连成功"),this.isOffline=!1}catch(e){console.error("重连失败",e)}finally{pi.isRtcReconnecting=!1}}}async getNetworkStats(){if(this.activeSession){const e=this.activeSession.sessionDescriptionHandler?.peerConnection;if(!e)return null;const t=await e.getStats(),s={};return t.forEach(e=>{"candidate-pair"===e.type&&"succeeded"===e.state&&null!=e.currentRoundTripTime&&(s.rtt=+(1e3*e.currentRoundTripTime).toFixed(2)),"inbound-rtp"===e.type&&"audio"===e.kind&&(s.jitter=+(1e3*e.jitter).toFixed(2),s.packetsLost=e.packetsLost,s.packetsReceived=e.packetsReceived,e.bytesReceived&&e.timestamp&&(s.recvBitrate=+(e.bytesReceived/1024).toFixed(2))),"outbound-rtp"===e.type&&"audio"===e.kind&&(s.packetsSent=e.packetsSent,e.bytesSent&&e.timestamp&&(s.sendBitrate=+(e.bytesSent/1024).toFixed(2))),"codec"===e.type&&e.mimeType&&(s.codec=e.mimeType)}),{...s,rtt:s?.rtt||40}}try{const e=Date.now();await ui(`${ci}/config/ping`,{});const t=Date.now();return{rtt:t-e||1}}catch(e){console.log(e)}}}const vi={statusColor:{[et.IDLE]:"#1D92E9",[et.BUSY]:"#F5212D",[et.OFFLINE]:"#8c8c8c",[et.RINGING]:"#e9b91d"}},wi=["call_number"],yi=[],bi=["hangup"],Ti=["hold","hangup","unhold","mute","unmute","transfer","consult","satisfaction","dtmf"],Si=["consult_transfer"],Ci=["hangup"],Ei=["answer","reject"],Ai=["hangup","consult","transfer","hold","unhold","mute","unmute","satisfaction","dtmf"];let _i=class extends zs{static{this.styles=Yt`
|
|
114
114
|
.timer-text {
|
|
115
115
|
width: 70px;
|
|
116
116
|
font-size: 14px;
|
|
@@ -110,7 +110,7 @@ const Xs=e=>(t,s)=>{void 0!==s?s.addInitializer(()=>{customElements.define(e,t)}
|
|
|
110
110
|
:host([type='loading']) {
|
|
111
111
|
background: #595959;
|
|
112
112
|
}
|
|
113
|
-
`}connectedCallback(){super.connectedCallback(),setTimeout(()=>{this.remove()},this.duration+300)}render(){return xs`<div>${this.content}</div>`}};Bt([ti({type:String})],ri.prototype,"type",void 0),Bt([ti({type:String})],ri.prototype,"content",void 0),Bt([ti({type:Number})],ri.prototype,"duration",void 0),ri=Bt([Xs("my-message")],ri);const ni=(e,t,s=3e3)=>{let i=document.querySelector("#message-container");i||(i=document.createElement("div"),i.id="message-container",Object.assign(i.style,{position:"fixed",top:"14px",left:"50%",transform:"translateX(-50%)",zIndex:"9999"}),document.body.appendChild(i));const r=document.createElement("my-message");r.setAttribute("type",e),r.setAttribute("content",t),r.setAttribute("duration",String(s)),r.style.setProperty("--fade-delay",s/1e3+"s"),i.appendChild(r)},oi=(e,t=3e3)=>ni("success",e,t),ai=(e,t=3e3)=>ni("error",e,t),ci=(e,t=3e3)=>ni("warning",e,t),hi="/v1/aicc/bmserver",di="/v1/aicc/ccs";let li="",gi="",ui="";async function pi(e,t){const s=function(){const e=jt(gi,ui);return Lt.create({prefixUrl:`${li}/api`,timeout:!1,headers:{Authorization:e},hooks:{afterResponse:[async(e,t,s)=>{const i=await s.clone().json();if(0!==i.code)throw ai(i.msg),new Error(JSON.stringify(i)||"请求失败");return s.json=async()=>i,s}]}})}(),i=e.replace(/^\/+/,"");return s.post(i,{json:t}).json()}const fi={agentInfo:{},isRtcReconnecting:!1,sessionId:"",enableBrowserAlert:!1,autoStateTimer:null};const mi=new class extends Qe{updateRttObject(e){this.setState({rttObject:e})}}({rttObject:{rtt:null,jitter:null,packetsLost:null,packetsReceived:null,packetsSent:null,sendBitrate:null,recvBitrate:null,codec:null}});class vi{constructor(e,t){this.config=e,this.eventCallback=t,this.userAgent=null,this.registerer=null,this.activeSession=null,this.callTimeoutTimer=null,this.incomingInvitation=null,this.reconnectAttempts=0,this.maxReconnectAttempts=5,this.reconnectTimer=null,this.isOffline=!1,this.autoAnswerTimer=null,this.handleMessage=e=>{},this.handleNetworkInfoChange=e=>{
|
|
113
|
+
`}connectedCallback(){super.connectedCallback(),setTimeout(()=>{this.remove()},this.duration+300)}render(){return xs`<div>${this.content}</div>`}};Bt([ti({type:String})],ri.prototype,"type",void 0),Bt([ti({type:String})],ri.prototype,"content",void 0),Bt([ti({type:Number})],ri.prototype,"duration",void 0),ri=Bt([Xs("my-message")],ri);const ni=(e,t,s=3e3)=>{let i=document.querySelector("#message-container");i||(i=document.createElement("div"),i.id="message-container",Object.assign(i.style,{position:"fixed",top:"14px",left:"50%",transform:"translateX(-50%)",zIndex:"9999"}),document.body.appendChild(i));const r=document.createElement("my-message");r.setAttribute("type",e),r.setAttribute("content",t),r.setAttribute("duration",String(s)),r.style.setProperty("--fade-delay",s/1e3+"s"),i.appendChild(r)},oi=(e,t=3e3)=>ni("success",e,t),ai=(e,t=3e3)=>ni("error",e,t),ci=(e,t=3e3)=>ni("warning",e,t),hi="/v1/aicc/bmserver",di="/v1/aicc/ccs";let li="",gi="",ui="";async function pi(e,t){const s=function(){const e=jt(gi,ui);return Lt.create({prefixUrl:`${li}/api`,timeout:!1,headers:{Authorization:e},hooks:{afterResponse:[async(e,t,s)=>{const i=await s.clone().json();if(0!==i.code)throw ai(i.msg),new Error(JSON.stringify(i)||"请求失败");return s.json=async()=>i,s}]}})}(),i=e.replace(/^\/+/,"");return s.post(i,{json:t}).json()}const fi={agentInfo:{},isRtcReconnecting:!1,sessionId:"",enableBrowserAlert:!1,autoStateTimer:null};const mi=new class extends Qe{updateRttObject(e){this.setState({rttObject:e})}}({rttObject:{rtt:null,jitter:null,packetsLost:null,packetsReceived:null,packetsSent:null,sendBitrate:null,recvBitrate:null,codec:null}});class vi{constructor(e,t){this.config=e,this.eventCallback=t,this.userAgent=null,this.registerer=null,this.activeSession=null,this.callTimeoutTimer=null,this.incomingInvitation=null,this.reconnectAttempts=0,this.maxReconnectAttempts=5,this.reconnectTimer=null,this.isOffline=!1,this.autoAnswerTimer=null,this.handleMessage=e=>{},this.handleNetworkInfoChange=e=>{const t=e.rttObject?.rtt||0;console.log(t),0===t?this.isOffline||(this.isOffline=!0,this.handleOffline()):this.isOffline&&(this.isOffline=!1,this.handleOnline())},this.handleOffline=()=>{console.warn("[SIPClient] 网络断开,准备销毁 SIP 客户端",(new Date).toLocaleString())},this.handleOnline=()=>{console.warn("[SIPClient] 网络恢复,准备重新启动 SIP 客户端",(new Date).toLocaleString())},mi.subscribe(this.handleNetworkInfoChange)}async start(){const e=Xe.makeURI(`sip:${this.config.user}@${this.config.server}`);if(!e)throw new Error("无效的SIP配置");const t={uri:e,authorizationUsername:this.config.user,authorizationPassword:this.config.password,transportOptions:{server:this.config.webSocket,connectionTimeout:30,keepAliveInterval:0},sessionDescriptionHandlerFactoryOptions:{alwaysAcquireMediaFirst:!0,peerConnectionConfiguration:{iceServers:[]},iceGatheringTimeout:400},logBuiltinEnabled:!1};this.userAgent=new Xe(t),this.setupEventListeners(),await this.userAgent.start(),await this.register()}setupEventListeners(){this.userAgent&&(this.userAgent.transport.stateChange.addListener(e=>{let t;switch(e){case ee.Connecting:t=st.WEB_RTC_CONNECTING;break;case ee.Connected:t=st.WEB_RTC_CONNECTED,this.reconnectAttempts=0,fi.isRtcReconnecting=!1,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null);break;case ee.Disconnecting:t=st.WEB_RTC_DISCONNECTING;break;case ee.Disconnected:{t=st.WEB_RTC_DISCONNECTED;const e=dt.get("answerDevice");if(!fi.isRtcReconnecting&&this.reconnectAttempts<this.maxReconnectAttempts&&1===e){this.reconnectAttempts++;const e=1e3*this.reconnectAttempts;console.warn(`SIP WebSocket 断开,第 ${this.reconnectAttempts} 次尝试重连,${e}ms 后重试...`),this.reconnectTimer=setTimeout(()=>{this.reconnect()},e)}else this.reconnectAttempts>=this.maxReconnectAttempts&&console.error("SIP 重连失败:已达到最大重试次数");break}default:t="unknown"}this.eventCallback?.({type:t})}),this.userAgent.transport.stateChange.addListener(e=>{}),this.userAgent.delegate={onInvite:e=>{this.handleIncomingCall(e)}})}async register(){if(this.userAgent){this.registerer=new ne(this.userAgent),this.registerer?.stateChange.addListener(e=>{let t;switch(e){case X.Initial:t="initial";break;case X.Registered:t=st.WEB_RTC_REGISTERED;break;case X.Unregistered:t=st.WEB_RTC_UNREGISTERED;break;case X.Terminated:t=st.WEB_RTC_TERMINATED;break;default:t="unknown"}this.eventCallback?.({type:t})});try{await this.registerer.register()}catch(e){this.eventCallback?.({type:st.WEB_RTC_REGISTER_FAILED,data:e})}}}attachRemoteAudio(e){const t=e.sessionDescriptionHandler;if(t){const e=t.peerConnection;if(!e)return;const s=new MediaStream;e.getReceivers().forEach(e=>{e.track&&"audio"===e.track.kind&&s.addTrack(e.track)});let i=document.getElementById("sip-remote-audio");i||(i=document.createElement("audio"),i.id="sip-remote-audio",i.autoplay=!0,i.style.display="none",document.body.appendChild(i)),i.srcObject=s,i.play().catch(e=>{console.error("音频播放失败,需要用户交互触发",e)})}}handleSessionState(e,t,s){e.stateChange.addListener(t=>{switch(t){case K.Established:clearTimeout(this.callTimeoutTimer),this.activeSession=e,this.attachRemoteAudio(e);break;case K.Terminating:break;case K.Terminated:this.activeSession=null,clearTimeout(this.callTimeoutTimer);case K.Establishing:}})}handleIncomingCall(e){this.incomingInvitation=e,this.handleSessionState(e,!1);const{soft_device_auto_answer:t,auto_answer_time:s}=fi.agentInfo,i=dt.get("direction"),r=1===t;if(i===tt.OUTGOING)this.answerCall();else if(r&&i===tt.INCOMING){const e=Number(s)||0;e>0?this.autoAnswerTimer=setTimeout(()=>{this.answerCall(),this.autoAnswerTimer=null},e):this.answerCall()}}async makeCall(e){if(dt.getState().isCalling)throw new Error("正在呼叫中,请勿重复点击");if(!this.userAgent)throw dt.updateIsCalling(!1),dt.updateDirection(null),new Error("SIP客户端未初始化");dt.updateIsCalling(!0),dt.updateDirection(tt.OUTGOING);const t=Xe.makeURI(`sip:${e}@${this.config.server}`);if(!t)throw new Error("无效的被叫号码");const s=new Z(this.userAgent,t);this.handleSessionState(s,!0,e);try{this.activeSession=s,await s.invite(),this.config.callTimeout&&(this.callTimeoutTimer=setTimeout(()=>{s.state!==K.Established&&(this.hangup(),this.eventCallback?.({type:"error",data:{message:"呼叫超时未接通"}}))},this.config.callTimeout))}catch(e){this.eventCallback?.({type:"error",data:{message:"呼叫失败",detail:e}}),dt.updateIsCalling(!1),dt.updateDirection(null)}}async answerCall(){if(!this.incomingInvitation)throw new Error("无来电可接听");this.autoAnswerTimer&&(clearTimeout(this.autoAnswerTimer),this.autoAnswerTimer=null);try{console.log((new Date).toLocaleString()),await this.incomingInvitation.accept(),console.log((new Date).toLocaleString()),this.activeSession=this.incomingInvitation,this.incomingInvitation=null}catch(e){this.eventCallback?.({type:st.WEB_RTC_ANSWER_FAILED,data:{detail:e}})}}async rejectInCall(){if(this.incomingInvitation)try{await this.incomingInvitation.reject(),this.incomingInvitation=null,dt.updateDirection(null),dt.updateIsCalling(!1),clearTimeout(this.callTimeoutTimer)}catch(e){this.eventCallback?.({type:"error",data:{message:"拒接失败",detail:e}})}}sendDTMF(e){if(!this.activeSession)throw new Error("当前没有活跃的通话");const t=this.activeSession.sessionDescriptionHandler;t&&"function"==typeof t.sendDtmf?(t.sendDtmf(e),this.eventCallback?.({type:st.WEB_RTC_SEND_DTMF,data:{tone:e}})):console.warn("DTMF发送不支持或未初始化")}async hangup(){if(this.activeSession){clearTimeout(this.callTimeoutTimer);const e=this.activeSession;if(!e)return;const t=e.state;try{t===K.Established?await e.bye():t===K.Establishing&&(e instanceof Z?await e.cancel():e instanceof J&&await e.reject()),clearTimeout(this.callTimeoutTimer)}catch(e){console.error("挂断失败",e)}finally{this.activeSession=null}}}async rejectOutCall(){this.activeSession instanceof J&&(await this.activeSession.reject(),this.activeSession=null)}async destroy(){if(clearTimeout(this.callTimeoutTimer),this.activeSession&&await this.hangup(),this.registerer){try{await this.registerer.unregister()}catch(e){console.warn("注销失败",e)}this.registerer=null}this.userAgent&&(await this.userAgent.stop(),this.userAgent=null)}async reconnect(){if(!fi.isRtcReconnecting){fi.isRtcReconnecting=!0;try{await this.destroy(),await this.start(),console.log("重连成功"),this.isOffline=!1}catch(e){console.error("重连失败",e)}finally{fi.isRtcReconnecting=!1}}}async getNetworkStats(){if(this.activeSession){const e=this.activeSession.sessionDescriptionHandler?.peerConnection;if(!e)return null;const t=await e.getStats(),s={};return t.forEach(e=>{"candidate-pair"===e.type&&"succeeded"===e.state&&null!=e.currentRoundTripTime&&(s.rtt=+(1e3*e.currentRoundTripTime).toFixed(2)),"inbound-rtp"===e.type&&"audio"===e.kind&&(s.jitter=+(1e3*e.jitter).toFixed(2),s.packetsLost=e.packetsLost,s.packetsReceived=e.packetsReceived,e.bytesReceived&&e.timestamp&&(s.recvBitrate=+(e.bytesReceived/1024).toFixed(2))),"outbound-rtp"===e.type&&"audio"===e.kind&&(s.packetsSent=e.packetsSent,e.bytesSent&&e.timestamp&&(s.sendBitrate=+(e.bytesSent/1024).toFixed(2))),"codec"===e.type&&e.mimeType&&(s.codec=e.mimeType)}),{...s,rtt:s?.rtt||40}}try{const e=Date.now();await pi(`${hi}/config/ping`,{});const t=Date.now();return{rtt:t-e||1}}catch(e){console.log(e)}}}const wi={statusColor:{[et.IDLE]:"#1D92E9",[et.BUSY]:"#F5212D",[et.OFFLINE]:"#8c8c8c",[et.RINGING]:"#e9b91d"}},yi=["call_number"],bi=[],Ti=["hangup"],Si=["hold","hangup","unhold","mute","unmute","transfer","consult","satisfaction","dtmf"],Ci=["consult_transfer"],Ei=["hangup"],Ai=["answer","reject"],_i=["hangup","consult","transfer","hold","unhold","mute","unmute","satisfaction","dtmf"];let Ii=class extends Js{static{this.styles=zt`
|
|
114
114
|
.timer-text {
|
|
115
115
|
width: 70px;
|
|
116
116
|
font-size: 14px;
|
|
@@ -110,7 +110,7 @@ const Zs=e=>(t,s)=>{void 0!==s?s.addInitializer(()=>{customElements.define(e,t)}
|
|
|
110
110
|
:host([type='loading']) {
|
|
111
111
|
background: #595959;
|
|
112
112
|
}
|
|
113
|
-
`}connectedCallback(){super.connectedCallback(),setTimeout(()=>{this.remove()},this.duration+300)}render(){return Ds`<div>${this.content}</div>`}};jt([ei({type:String})],ii.prototype,"type",void 0),jt([ei({type:String})],ii.prototype,"content",void 0),jt([ei({type:Number})],ii.prototype,"duration",void 0),ii=jt([Zs("my-message")],ii);const ri=(e,t,s=3e3)=>{let i=document.querySelector("#message-container");i||(i=document.createElement("div"),i.id="message-container",Object.assign(i.style,{position:"fixed",top:"14px",left:"50%",transform:"translateX(-50%)",zIndex:"9999"}),document.body.appendChild(i));const r=document.createElement("my-message");r.setAttribute("type",e),r.setAttribute("content",t),r.setAttribute("duration",String(s)),r.style.setProperty("--fade-delay",s/1e3+"s"),i.appendChild(r)},ni=(e,t=3e3)=>ri("success",e,t),oi=(e,t=3e3)=>ri("error",e,t),ai=(e,t=3e3)=>ri("warning",e,t),ci="/v1/aicc/bmserver",hi="/v1/aicc/ccs";let di="",li="",gi="";async function ui(e,t){const s=function(){const e=Ft(li,gi);return qt.create({prefixUrl:`${di}/api`,timeout:!1,headers:{Authorization:e},hooks:{afterResponse:[async(e,t,s)=>{const i=await s.clone().json();if(0!==i.code)throw oi(i.msg),new Error(JSON.stringify(i)||"请求失败");return s.json=async()=>i,s}]}})}(),i=e.replace(/^\/+/,"");return s.post(i,{json:t}).json()}const pi={agentInfo:{},isRtcReconnecting:!1,sessionId:"",enableBrowserAlert:!1,autoStateTimer:null};const fi=new class extends Qe{updateRttObject(e){this.setState({rttObject:e})}}({rttObject:{rtt:null,jitter:null,packetsLost:null,packetsReceived:null,packetsSent:null,sendBitrate:null,recvBitrate:null,codec:null}});class mi{constructor(e,t){this.config=e,this.eventCallback=t,this.userAgent=null,this.registerer=null,this.activeSession=null,this.callTimeoutTimer=null,this.incomingInvitation=null,this.reconnectAttempts=0,this.maxReconnectAttempts=5,this.reconnectTimer=null,this.isOffline=!1,this.autoAnswerTimer=null,this.handleMessage=e=>{},this.handleNetworkInfoChange=e=>{
|
|
113
|
+
`}connectedCallback(){super.connectedCallback(),setTimeout(()=>{this.remove()},this.duration+300)}render(){return Ds`<div>${this.content}</div>`}};jt([ei({type:String})],ii.prototype,"type",void 0),jt([ei({type:String})],ii.prototype,"content",void 0),jt([ei({type:Number})],ii.prototype,"duration",void 0),ii=jt([Zs("my-message")],ii);const ri=(e,t,s=3e3)=>{let i=document.querySelector("#message-container");i||(i=document.createElement("div"),i.id="message-container",Object.assign(i.style,{position:"fixed",top:"14px",left:"50%",transform:"translateX(-50%)",zIndex:"9999"}),document.body.appendChild(i));const r=document.createElement("my-message");r.setAttribute("type",e),r.setAttribute("content",t),r.setAttribute("duration",String(s)),r.style.setProperty("--fade-delay",s/1e3+"s"),i.appendChild(r)},ni=(e,t=3e3)=>ri("success",e,t),oi=(e,t=3e3)=>ri("error",e,t),ai=(e,t=3e3)=>ri("warning",e,t),ci="/v1/aicc/bmserver",hi="/v1/aicc/ccs";let di="",li="",gi="";async function ui(e,t){const s=function(){const e=Ft(li,gi);return qt.create({prefixUrl:`${di}/api`,timeout:!1,headers:{Authorization:e},hooks:{afterResponse:[async(e,t,s)=>{const i=await s.clone().json();if(0!==i.code)throw oi(i.msg),new Error(JSON.stringify(i)||"请求失败");return s.json=async()=>i,s}]}})}(),i=e.replace(/^\/+/,"");return s.post(i,{json:t}).json()}const pi={agentInfo:{},isRtcReconnecting:!1,sessionId:"",enableBrowserAlert:!1,autoStateTimer:null};const fi=new class extends Qe{updateRttObject(e){this.setState({rttObject:e})}}({rttObject:{rtt:null,jitter:null,packetsLost:null,packetsReceived:null,packetsSent:null,sendBitrate:null,recvBitrate:null,codec:null}});class mi{constructor(e,t){this.config=e,this.eventCallback=t,this.userAgent=null,this.registerer=null,this.activeSession=null,this.callTimeoutTimer=null,this.incomingInvitation=null,this.reconnectAttempts=0,this.maxReconnectAttempts=5,this.reconnectTimer=null,this.isOffline=!1,this.autoAnswerTimer=null,this.handleMessage=e=>{},this.handleNetworkInfoChange=e=>{const t=e.rttObject?.rtt||0;console.log(t),0===t?this.isOffline||(this.isOffline=!0,this.handleOffline()):this.isOffline&&(this.isOffline=!1,this.handleOnline())},this.handleOffline=()=>{console.warn("[SIPClient] 网络断开,准备销毁 SIP 客户端",(new Date).toLocaleString())},this.handleOnline=()=>{console.warn("[SIPClient] 网络恢复,准备重新启动 SIP 客户端",(new Date).toLocaleString())},fi.subscribe(this.handleNetworkInfoChange)}async start(){const e=Xe.makeURI(`sip:${this.config.user}@${this.config.server}`);if(!e)throw new Error("无效的SIP配置");const t={uri:e,authorizationUsername:this.config.user,authorizationPassword:this.config.password,transportOptions:{server:this.config.webSocket,connectionTimeout:30,keepAliveInterval:0},sessionDescriptionHandlerFactoryOptions:{alwaysAcquireMediaFirst:!0,peerConnectionConfiguration:{iceServers:[]},iceGatheringTimeout:400},logBuiltinEnabled:!1};this.userAgent=new Xe(t),this.setupEventListeners(),await this.userAgent.start(),await this.register()}setupEventListeners(){this.userAgent&&(this.userAgent.transport.stateChange.addListener(e=>{let t;switch(e){case ee.Connecting:t=st.WEB_RTC_CONNECTING;break;case ee.Connected:t=st.WEB_RTC_CONNECTED,this.reconnectAttempts=0,pi.isRtcReconnecting=!1,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null);break;case ee.Disconnecting:t=st.WEB_RTC_DISCONNECTING;break;case ee.Disconnected:{t=st.WEB_RTC_DISCONNECTED;const e=dt.get("answerDevice");if(!pi.isRtcReconnecting&&this.reconnectAttempts<this.maxReconnectAttempts&&1===e){this.reconnectAttempts++;const e=1e3*this.reconnectAttempts;console.warn(`SIP WebSocket 断开,第 ${this.reconnectAttempts} 次尝试重连,${e}ms 后重试...`),this.reconnectTimer=setTimeout(()=>{this.reconnect()},e)}else this.reconnectAttempts>=this.maxReconnectAttempts&&console.error("SIP 重连失败:已达到最大重试次数");break}default:t="unknown"}this.eventCallback?.({type:t})}),this.userAgent.transport.stateChange.addListener(e=>{}),this.userAgent.delegate={onInvite:e=>{this.handleIncomingCall(e)}})}async register(){if(this.userAgent){this.registerer=new ne(this.userAgent),this.registerer?.stateChange.addListener(e=>{let t;switch(e){case X.Initial:t="initial";break;case X.Registered:t=st.WEB_RTC_REGISTERED;break;case X.Unregistered:t=st.WEB_RTC_UNREGISTERED;break;case X.Terminated:t=st.WEB_RTC_TERMINATED;break;default:t="unknown"}this.eventCallback?.({type:t})});try{await this.registerer.register()}catch(e){this.eventCallback?.({type:st.WEB_RTC_REGISTER_FAILED,data:e})}}}attachRemoteAudio(e){const t=e.sessionDescriptionHandler;if(t){const e=t.peerConnection;if(!e)return;const s=new MediaStream;e.getReceivers().forEach(e=>{e.track&&"audio"===e.track.kind&&s.addTrack(e.track)});let i=document.getElementById("sip-remote-audio");i||(i=document.createElement("audio"),i.id="sip-remote-audio",i.autoplay=!0,i.style.display="none",document.body.appendChild(i)),i.srcObject=s,i.play().catch(e=>{console.error("音频播放失败,需要用户交互触发",e)})}}handleSessionState(e,t,s){e.stateChange.addListener(t=>{switch(t){case K.Established:clearTimeout(this.callTimeoutTimer),this.activeSession=e,this.attachRemoteAudio(e);break;case K.Terminating:break;case K.Terminated:this.activeSession=null,clearTimeout(this.callTimeoutTimer);case K.Establishing:}})}handleIncomingCall(e){this.incomingInvitation=e,this.handleSessionState(e,!1);const{soft_device_auto_answer:t,auto_answer_time:s}=pi.agentInfo,i=dt.get("direction"),r=1===t;if(i===tt.OUTGOING)this.answerCall();else if(r&&i===tt.INCOMING){const e=Number(s)||0;e>0?this.autoAnswerTimer=setTimeout(()=>{this.answerCall(),this.autoAnswerTimer=null},e):this.answerCall()}}async makeCall(e){if(dt.getState().isCalling)throw new Error("正在呼叫中,请勿重复点击");if(!this.userAgent)throw dt.updateIsCalling(!1),dt.updateDirection(null),new Error("SIP客户端未初始化");dt.updateIsCalling(!0),dt.updateDirection(tt.OUTGOING);const t=Xe.makeURI(`sip:${e}@${this.config.server}`);if(!t)throw new Error("无效的被叫号码");const s=new Z(this.userAgent,t);this.handleSessionState(s,!0,e);try{this.activeSession=s,await s.invite(),this.config.callTimeout&&(this.callTimeoutTimer=setTimeout(()=>{s.state!==K.Established&&(this.hangup(),this.eventCallback?.({type:"error",data:{message:"呼叫超时未接通"}}))},this.config.callTimeout))}catch(e){this.eventCallback?.({type:"error",data:{message:"呼叫失败",detail:e}}),dt.updateIsCalling(!1),dt.updateDirection(null)}}async answerCall(){if(!this.incomingInvitation)throw new Error("无来电可接听");this.autoAnswerTimer&&(clearTimeout(this.autoAnswerTimer),this.autoAnswerTimer=null);try{console.log((new Date).toLocaleString()),await this.incomingInvitation.accept(),console.log((new Date).toLocaleString()),this.activeSession=this.incomingInvitation,this.incomingInvitation=null}catch(e){this.eventCallback?.({type:st.WEB_RTC_ANSWER_FAILED,data:{detail:e}})}}async rejectInCall(){if(this.incomingInvitation)try{await this.incomingInvitation.reject(),this.incomingInvitation=null,dt.updateDirection(null),dt.updateIsCalling(!1),clearTimeout(this.callTimeoutTimer)}catch(e){this.eventCallback?.({type:"error",data:{message:"拒接失败",detail:e}})}}sendDTMF(e){if(!this.activeSession)throw new Error("当前没有活跃的通话");const t=this.activeSession.sessionDescriptionHandler;t&&"function"==typeof t.sendDtmf?(t.sendDtmf(e),this.eventCallback?.({type:st.WEB_RTC_SEND_DTMF,data:{tone:e}})):console.warn("DTMF发送不支持或未初始化")}async hangup(){if(this.activeSession){clearTimeout(this.callTimeoutTimer);const e=this.activeSession;if(!e)return;const t=e.state;try{t===K.Established?await e.bye():t===K.Establishing&&(e instanceof Z?await e.cancel():e instanceof J&&await e.reject()),clearTimeout(this.callTimeoutTimer)}catch(e){console.error("挂断失败",e)}finally{this.activeSession=null}}}async rejectOutCall(){this.activeSession instanceof J&&(await this.activeSession.reject(),this.activeSession=null)}async destroy(){if(clearTimeout(this.callTimeoutTimer),this.activeSession&&await this.hangup(),this.registerer){try{await this.registerer.unregister()}catch(e){console.warn("注销失败",e)}this.registerer=null}this.userAgent&&(await this.userAgent.stop(),this.userAgent=null)}async reconnect(){if(!pi.isRtcReconnecting){pi.isRtcReconnecting=!0;try{await this.destroy(),await this.start(),console.log("重连成功"),this.isOffline=!1}catch(e){console.error("重连失败",e)}finally{pi.isRtcReconnecting=!1}}}async getNetworkStats(){if(this.activeSession){const e=this.activeSession.sessionDescriptionHandler?.peerConnection;if(!e)return null;const t=await e.getStats(),s={};return t.forEach(e=>{"candidate-pair"===e.type&&"succeeded"===e.state&&null!=e.currentRoundTripTime&&(s.rtt=+(1e3*e.currentRoundTripTime).toFixed(2)),"inbound-rtp"===e.type&&"audio"===e.kind&&(s.jitter=+(1e3*e.jitter).toFixed(2),s.packetsLost=e.packetsLost,s.packetsReceived=e.packetsReceived,e.bytesReceived&&e.timestamp&&(s.recvBitrate=+(e.bytesReceived/1024).toFixed(2))),"outbound-rtp"===e.type&&"audio"===e.kind&&(s.packetsSent=e.packetsSent,e.bytesSent&&e.timestamp&&(s.sendBitrate=+(e.bytesSent/1024).toFixed(2))),"codec"===e.type&&e.mimeType&&(s.codec=e.mimeType)}),{...s,rtt:s?.rtt||40}}try{const e=Date.now();await ui(`${ci}/config/ping`,{});const t=Date.now();return{rtt:t-e||1}}catch(e){console.log(e)}}}const vi={statusColor:{[et.IDLE]:"#1D92E9",[et.BUSY]:"#F5212D",[et.OFFLINE]:"#8c8c8c",[et.RINGING]:"#e9b91d"}},wi=["call_number"],yi=[],bi=["hangup"],Ti=["hold","hangup","unhold","mute","unmute","transfer","consult","satisfaction","dtmf"],Si=["consult_transfer"],Ci=["hangup"],Ei=["answer","reject"],Ai=["hangup","consult","transfer","hold","unhold","mute","unmute","satisfaction","dtmf"];let _i=class extends zs{static{this.styles=Yt`
|
|
114
114
|
.timer-text {
|
|
115
115
|
width: 70px;
|
|
116
116
|
font-size: 14px;
|