From f13c99f6d68c4faf083ca269e9925f331c9bfdde Mon Sep 17 00:00:00 2001 From: WXL (wul) <wl_5969728@163.com> Date: 星期二, 19 八月 2025 13:53:00 +0800 Subject: [PATCH] 统计页面数据接入 --- src/utils/sipService.js | 255 +++++++++++++++++++++++++++++++++++--------------- 1 files changed, 177 insertions(+), 78 deletions(-) diff --git a/src/utils/sipService.js b/src/utils/sipService.js index 9c095dd..baa65a9 100644 --- a/src/utils/sipService.js +++ b/src/utils/sipService.js @@ -1,117 +1,216 @@ -import JsSIP from 'jssip' +import JsSIP from "jssip"; class SipService { constructor() { - this.ua = null - this.currentSession = null - this.onStatusChange = null // 鐘舵�佸彉鍖栧洖璋� + this.ua = null; + this.currentSession = null; + this.onStatusChange = null; + this.onCallStatusChange = null; + this.onIncomingCall = null; } - // 鍒濆鍖朣IP瀹㈡埛绔� init(config) { try { - this.updateStatus('connecting', '杩炴帴涓�...') + this.updateStatus("connecting", "杩炴帴涓�;..."); this.ua = new JsSIP.UA({ sockets: [new JsSIP.WebSocketInterface(config.wsUrl)], uri: config.sipUri, password: config.password, display_name: config.displayName, - realm: config.realm, + iceServers: [], register: true, - register_expires: 300, // 娉ㄥ唽鏈夋晥鏈�(绉�) - connection_recovery_min_interval: 2, // 鏈�灏忛噸杩為棿闅� - connection_recovery_max_interval: 30 // 鏈�澶ч噸杩為棿闅� - }) + sessionExpires: 1800, + minSessionExpires: 90, + register_expires: 300, + }); - this.ua.start() + this.ua.start(); - // 娉ㄥ唽浜嬩欢鐩戝惉 - this.ua.on('registered', () => { - this.updateStatus('registered', '宸叉敞鍐�') - }) - - this.ua.on('registrationFailed', (e) => { - this.updateStatus('failed', `娉ㄥ唽澶辫触: ${e.cause}`) - }) - - this.ua.on('disconnected', () => { - this.updateStatus('disconnected', '杩炴帴鏂紑') - }) - - this.ua.on('connected', () => { - this.updateStatus('connecting', '閲嶆柊杩炴帴涓�...') - }) - - // 鐩戝惉鏉ョ數 - this.ua.on('newRTCSession', (data) => { + // 浜嬩欢鐩戝惉 + this.ua.on("registered", () => + this.updateStatus("registered", "宸叉敞鍐�56") + ); + this.ua.on("registrationFailed", (e) => + this.updateStatus("failed", `娉ㄥ唽澶辫触11: ${e.cause}`) + ); + this.ua.on("disconnected", () => + this.updateStatus("disconnected", "杩炴帴鏂紑") + ); + this.ua.on("connected", () => + this.updateStatus("connecting", "閲嶆柊杩炴帴涓�...") + ); + this.ua.on("newRTCSession", (data) => this.handleIncomingCall(data.session) - }) - + ); } catch (error) { - this.updateStatus('failed', `鍒濆鍖栧け璐�: ${error.message}`) - console.error('SIP鍒濆鍖栧け璐�:', error) + this.updateStatus("failed", `鍒濆鍖栧け璐�: ${error.message}`); + console.error("SIP鍒濆鍖栧け璐�:", error); + throw error; } } - // 鏇存柊鐘舵�佸苟閫氱煡UI - updateStatus(type, text) { - console.log(`SIP鐘舵�佹洿鏂�: ${type} - ${text}`) - if (this.onStatusChange) { - this.onStatusChange({ type, text }) - } - } - - // 涓�閿嫧鍙� - 澧炲姞娉ㄥ唽鐘舵�佹鏌� makeCall(targetNumber) { - if (!this.ua) { - throw new Error('SIP瀹㈡埛绔湭鍒濆鍖�') - } + return new Promise((resolve, reject) => { + try { + if (!this.ua) { + throw new Error("SIP瀹㈡埛绔湭鍒濆鍖�"); + } - if (!this.ua.isRegistered()) { - throw new Error('SIP鏈敞鍐岋紝鏃犳硶鍛煎彨') - } + if (!this.ua.isRegistered()) { + throw new Error("SIP鏈敞鍐岋紝鏃犳硶鍛煎彨"); + } - const options = { - eventHandlers: { - progress: (e) => console.log('鍛煎彨涓�...'), - failed: (e) => console.error('鍛煎彨澶辫触:', e), - ended: (e) => console.log('閫氳瘽缁撴潫'), - confirmed: (e) => console.log('閫氳瘽宸叉帴閫�') - }, - mediaConstraints: { audio: true, video: false }, - rtcOfferConstraints: { offerToReceiveAudio: 1 } - } + const options = { + sessionTimers: true, // 鍚敤浼氳瘽璁℃椂鍣� + sessionTimersExpires: 150, + extraHeaders: ["Accept: application/sdp"], + mediaConstraints: { audio: true, video: false }, + rtcOfferConstraints: { + offerToReceiveAudio: true, + offerToReceiveVideo: false, + }, + eventHandlers: { + progress: () => this.updateCallStatus("calling", "鍛煎彨涓�..."), + failed: (e) => { + this.handleCallFailure(e, reject); + }, + ended: () => this.updateCallStatus("ended", "閫氳瘽缁撴潫"), + confirmed: () => { + this.updateCallStatus("connected", "閫氳瘽宸叉帴閫�"); + resolve(); + }, + }, + }; - this.currentSession = this.ua.call(`sip:${targetNumber}`, options) - this.setupAudio(this.currentSession) + this.currentSession = this.ua.call( + `sip:${targetNumber}@192.168.10.124`, + options + ); + + this.setupPeerConnection(this.currentSession); + this.setupAudio(this.currentSession); + } catch (error) { + this.updateCallStatus("failed", `鍛煎彨澶辫触22: ${error.message}`); + reject(error); + } + }); } - // 鎸傛柇褰撳墠閫氳瘽 + setupPeerConnection(session) { + session.on("peerconnection", (pc) => { + const originalCreateOffer = pc.createOffer.bind(pc); + + pc.createOffer = async (offerOptions) => { + try { + const offer = await originalCreateOffer(offerOptions); + return this.normalizeSDP(offer); + } catch (error) { + console.error("鍒涘缓Offer澶辫触:", error); + throw error; + } + }; + }); + } + + normalizeSDP(offer) { + let sdp = offer.sdp; + + // 鏍囧噯鍖朣DP + sdp = sdp.replace(/c=IN IP4.*\r\n/, "c=IN IP4 0.0.0.0\r\n"); + sdp = sdp.replace( + /m=audio \d+.*\r\n/, + "m=audio 9 UDP/TLS/RTP/SAVPF 0 8\r\n" + ); + + // 纭繚鍖呭惈鍩烘湰缂栬В鐮佸櫒 + if (!sdp.includes("PCMU/8000")) sdp += "a=rtpmap:0 PCMU/8000\r\n"; + if (!sdp.includes("PCMA/8000")) sdp += "a=rtpmap:8 PCMA/8000\r\n"; + + // 娣诲姞蹇呰灞炴�� + sdp += "a=rtcp-mux\r\n"; + sdp += "a=sendrecv\r\n"; + + console.log("鏍囧噯鍖栧悗鐨凷DP:", sdp); + return new RTCSessionDescription({ + type: offer.type, + sdp: sdp, + }); + } + + handleCallFailure(e, reject) { + if (e.response?.status_code === 422) { + const serverMinSE = e.response.headers["Min-SE"]?.[0]?.raw || "鏈煡"; + console.error(`鏈嶅姟鍣ㄨ姹� Min-SE 鈮� ${serverMinSE}锛屽綋鍓嶈缃�: 120`); + } + console.error("鍛煎彨澶辫触璇︽儏:", { + cause: e.cause, + message: e.message, + response: e.response && { + status: e.response.status_code, + reason: e.response.reason_phrase, + }, + }); + + let errorMessage = "鍛煎彨澶辫触"; + switch (e.cause) { + case "Incompatible SDP": + errorMessage = "濯掍綋鍗忓晢澶辫触锛岃妫�鏌ョ紪瑙g爜鍣ㄩ厤缃�"; + break; + case "488": + case "606": + errorMessage = "瀵规柟璁惧涓嶆敮鎸佸綋鍓嶅獟浣撻厤缃�"; + break; + case "422": + errorMessage = "浼氳瘽鍙傛暟涓嶆弧瓒虫湇鍔″櫒瑕佹眰"; + break; + default: + errorMessage = `鍛煎彨澶辫触: ${e.cause || e.message}`; + } + + this.updateCallStatus("failed55", errorMessage); + reject(new Error(errorMessage)); + } + + setupAudio(session) { + session.connection.addEventListener("addstream", (e) => { + const audioElement = document.getElementById("remoteAudio"); + if (audioElement) { + audioElement.srcObject = e.stream; + } + }); + } + endCall() { if (this.currentSession) { - this.currentSession.terminate() - this.currentSession = null + this.currentSession.terminate(); + this.updateCallStatus("ended", "閫氳瘽宸茬粨鏉�"); + this.currentSession = null; } } - // 澶勭悊闊抽娴� - setupAudio(session) { - session.connection.addEventListener('addstream', (e) => { - const audioElement = document.getElementById('remoteAudio') - if (audioElement) { - audioElement.srcObject = e.stream - } - }) + updateStatus(type, text) { + console.log(`SIP鐘舵�佹洿鏂�: ${type} - ${text}`); + if (this.onStatusChange) { + this.onStatusChange({ type, text }); + } } - // 澶勭悊鏉ョ數 + updateCallStatus(type, text) { + console.log(`閫氳瘽鐘舵�佹洿鏂�: ${type} - ${text}`); + if (this.onCallStatusChange) { + this.onCallStatusChange({ type, text }); + } + } + handleIncomingCall(session) { - if (session.direction === 'incoming') { - console.log('鏉ョ數:', session.remote_identity.uri.toString()) - // 杩欓噷鍙互瑙﹀彂UI閫氱煡 + if (session.direction === "incoming") { + console.log("鏉ョ數:", session.remote_identity.uri.toString()); + if (this.onIncomingCall) { + this.onIncomingCall(session); + } } } } -export default new SipService() +export default new SipService(); -- Gitblit v1.9.3