You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

sip_ua网络中断后通话无法重连问题及优化需求

问题:sip_ua 网络中断后重连导致对方通话终止

sip_ua 包目前无内置机制处理通话过程中的网络中断场景,无法自动检测网络断开、尝试重连并恢复通话。我尝试用 renegotiate 函数实现自定义重连逻辑,但网络恢复后调用该函数会意外终止对方通话,而非重新协商连接,这严重限制了库在网络波动场景下的实用性。

复现步骤

  • 使用 sip_ua 库发起并保持通话;
  • 通话过程中断开网络;
  • 检测到网络恢复后调用 renegotiate 函数尝试重连。

预期行为

网络恢复时应重新协商连接,恢复通话且不终止对方通话。

代码片段

@override
Future<void> callStateChanged(Call call, CallState callState) async {
  if (call.peerConnection != null) {
    monitorConnectionState(call);
  }
}

Timer? connectivityTimer;
int retryCount = 0;

void monitorConnectionState(Call call) {
  if (call.peerConnection?.connectionState == RTCPeerConnectionState.RTCPeerConnectionStateDisconnected) {
    startConnectivityCheck(call);
  }
}

void startConnectivityCheck(Call call) {
  stopConnectivityCheck();
  retryCount = 0;

  connectivityTimer = Timer.periodic(const Duration(seconds: 1), (timer) async {
    retryCount++;
    bool isInternetAvailable = await ConnectivityHelper.hasInternetConnection();

    if (isInternetAvailable) {
      stopConnectivityCheck();
      renegotiateCall(call);
    }

    if (retryCount >= 10) {
      stopConnectivityCheck();
      endCallDueToNetworkIssue();
    }
  });
}

void stopConnectivityCheck() {
  connectivityTimer?.cancel();
  connectivityTimer = null;
}

void renegotiateCall(Call call) {
  try {
    call.renegotiate(
      useUpdate: true,
      options: {'useUpdate': true},
      done: (response) {},
    );
  } catch (e) {}
}

void endCallDueToNetworkIssue() async {
  Provider.of<SipRegisterProvider>(context, listen: false).upDateSipCallSpeaker(false);
  await endAllCalls();
  if (Navigator.of(navigatorKey.currentContext!).canPop()) {
    Navigator.of(navigatorKey.currentContext!).pop();
  }
}

需求

提供网络中断恢复后优雅处理通话重连的方案。

系统信息

  • Flutter SDK 版本:3.24.4

解决方案

1. 重建 PeerConnection 替代直接调用 renegotiate

直接调用 renegotiate 易因原 PeerConnection 状态异常触发终止逻辑,需先销毁旧连接再重建协商:

Future<void> reconnectCall(Call call) async {
  // 关闭旧的 PeerConnection
  await call.peerConnection?.close();
  
  // 重新初始化 PeerConnection
  await call.initPeerConnection();
  
  // 用 INVITE 发起协商(避免 UPDATE 导致的通话终止)
  call.invite(
    call.remoteUri.toString(),
    options: {
      'sessionDescriptionHandlerOptions': {
        'constraints': {
          'audio': true,
          'video': call.hasVideo ? true : false,
        }
      }
    },
    done: (response) {
      if (response.statusCode == 200) {
        // 通话恢复成功
      }
    },
    onProgress: (session) {},
  );
}

2. 优化网络连通性检测

不要仅依赖系统网络状态,需结合 SIP 服务器可达性验证:

Future<bool> checkSipConnectivity(SipUAHelper sipUA) async {
  try {
    // 发送 OPTIONS 请求验证 SIP 服务器连通性
    var response = await sipUA.sendOptions(sipUA.configuration.uri.toString());
    return response.statusCode >= 200 && response.statusCode < 300;
  } catch (e) {
    return false;
  }
}

修改检测逻辑:

bool isInternetAvailable = await ConnectivityHelper.hasInternetConnection();
bool isSipReachable = await checkSipConnectivity(sipUA);

if (isInternetAvailable && isSipReachable) {
  stopConnectivityCheck();
  reconnectCall(call);
}

3. 提前通知对方重连状态

发送 SIP INFO 消息告知对方即将重连,避免对方因异常信令终止通话:

void sendReconnectNotification(Call call) {
  call.sendInfo(
    content: 'Reconnecting due to network recovery',
    contentType: 'text/plain',
    done: (response) {},
  );
}

在重连前调用:

sendReconnectNotification(call);
await reconnectCall(call);

4. 精准监听连接状态

直接监听 PeerConnection 的连接状态变化,替代仅依赖 callStateChanged:

void monitorConnectionState(Call call) {
  call.peerConnection?.onConnectionStateChange = (state) {
    if (state == RTCPeerConnectionState.RTCPeerConnectionStateDisconnected) {
      startConnectivityCheck(call);
    }
  };
}

内容的提问来源于stack exchange,提问作者Umar Aslam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 21:35:10