吉安感知网项目-前端
罗广辉
2026-08-13 1d552a3bad95caae4af15322df28e6240b797693
applications/drone-command/src/views/audioCall.vue
@@ -36,10 +36,11 @@
import { ref, computed, onBeforeUnmount } from 'vue'
/** ✅ 你的 WS 地址前缀(后面拼 userId) */
const WS_BASE = 'wss://域名/ws/chat?userId='
// const WS_BASE = 'ws://218.202.104.82:38201/ws/chat'
const WS_BASE = 'ws://220.177.172.27:8100/webrtc/ws/chat'
const uid = ref('2')
const peerUid = ref('3')
const uid = ref('2021474568497131521')
const peerUid = ref('2021474815063486465')
const connected = ref(false)
const state = ref('idle') // idle | calling | ringing | in-call
@@ -117,7 +118,14 @@
function createPC() {
   pc = new RTCPeerConnection({
      iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
      iceServers: [{ urls: 'stun:stun.l.google.com:19302' },
         { urls: 'stun:stun.l.google.com:19302' },
         { urls: 'stun:stun1.l.google.com:19302' },
         { urls: 'stun:stun.stunprotocol.org:3478' },
         // 添加多个公共TURN服务器以提高跨网络连接成功率
         { urls: ['turn:freeturn.net:80', 'turn:freeturn.net:443'], username: 'free', credential: 'free' },
         // 备用TURN服务器
         { urls: 'turn:turn.cloudlifter.io:443', username: 'webrtc', credential: 'webrtc' }],
   })
   pc.onicecandidate = (e) => {
@@ -126,6 +134,7 @@
      }
   }
   // 步骤7 接收音频流并且播放
   pc.ontrack = (e) => {
      log('✅ 收到远端音频流')
      const stream = e.streams[0]
@@ -167,6 +176,7 @@
      pc.getSenders().map(s => (s.track ? s.track.id : null)).filter(Boolean)
   )
   // 步骤6 发送音频流
   stream.getTracks().forEach(track => {
      if (!existingTrackIds.has(track.id)) {
         pc.addTrack(track, stream)
@@ -179,6 +189,7 @@
   return stream
}
// 步骤5
async function flushCandidates() {
   if (!pc || !pc.remoteDescription) return
   while (pendingCandidates.length) {
@@ -235,6 +246,7 @@
      return
   }
   // 步骤2
   if (t === 'offer') {
      // 被叫收到 offer:只有点击接听后才真正应答(你要求“先点接听”)
      offeredByPeer = true
@@ -254,10 +266,12 @@
      return
   }
   // 步骤3
   if (t === 'answer') {
      log('✅ 收到 answer,通话建立')
      if (!pc) createPC()
      await pc.setRemoteDescription(new RTCSessionDescription(msg.payload?.sdp))
      // 步骤4
      await flushCandidates()
      state.value = 'in-call'
@@ -297,7 +311,7 @@
function connectWS() {
   if (ws) ws.close()
   ws = new WebSocket(WS_BASE + encodeURIComponent(uid.value))
   ws = new WebSocket(WS_BASE, "eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyX2lkIjoyMDIxNDc0NTY4NDk3MTMxNTIxLCJ1c2VyX2tleSI6Ijc5MDE3ZGEwLTZlZjItNGU0MS05MzdiLWFiZjM4NzRkNTYwMSIsInVzZXJuYW1lIjoieW9uZ2h1MSJ9.hEoBlIejSOyn44aA1FZrtlVHsrbmA84KX_5Qq2Mz7slO4jNlbJkFvzuomT7EqI9QigucNzULDjfiA9IHPfww8Q")
   ws.onopen = () => {
      connected.value = true
@@ -368,6 +382,7 @@
   // ✅ 不会重复 addTrack
   await ensureLocalTracksAdded()
   // 步骤1
   const offer = await pc.createOffer()
   await pc.setLocalDescription(offer)
@@ -375,6 +390,7 @@
   log('➡️ 已发送 offer 给', peerUid.value)
}
// 步骤2
async function answerOffer(offerSdp, from) {
   if (!offerSdp) {
      log('❌ offer sdp 为空,无法接听')
@@ -436,4 +452,3 @@
   if (ws) ws.close()
})
</script>