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

React Native集成Twilio Voice与callkeep后通话立即中断问题求助

问题:Expo React Native集成Twilio Voice与react-native-callkeep时通话被自动终止

我用Expo开发React Native应用,集成Twilio Voice SDK和react-native-callkeep处理VoIP来电,目标是有VoIP来电时通过react-native-callkeep展示iOS原生CallKit来电UI,用户接听后连接到Twilio会议通话。

当前问题:通话能短暂成功连接,但react-native-callkeep随即触发endCall事件终止通话。推测是CallKeep与Twilio Voice SDK的音频会话冲突——当Twilio SDK激活音频会话时,CallKit将其视为其他通话接管,从而结束当前管理的通话。

控制台日志事件序列:

1  LOG  DEBUG: Twilio: Call.Event.Connected event received
2  LOG  ============================================================
3  LOG  TwilioService: ✅ CALL CONNECTED
4  LOG  TwilioService: Call SID: CA3e35f733949a1b8b30ada886241de85c
5  LOG  TwilioService: Call State: connected
6  LOG  TwilioService: Is Muted: false
7  LOG  ============================================================
8  LOG  CallManager: Twilio call connected
9  LOG  CallManager: State change: CONNECTING -> CONNECTED
10  LOG  useCallManager: Call state changed: CONNECTED
11  LOG  DEBUG: CallKeep endCall event received for UUID: e31feea4-6a02-4555-8d09-c061cc17ef83
12  LOG  DEBUG: Active session matches. Current state: CONNECTED
13  LOG  DEBUG: Call is connected, calling endCall()
14  LOG  CallManager: Ending call
15  LOG  CallManager: Handling call ended

已尝试方案:

  • 延迟Twilio连接至CallKeep的didActivateAudioSession事件触发后,同步音频会话激活:
    1. 用户通过CallKit接听时触发answerCall事件,向后端请求Twilio参会信息
    2. 收到参会信息后存储至this.conferenceJoinInfo
    3. 监听CallKeep的didActivateAudioSession事件,触发后再连接Twilio
      但问题仍存在。

相关代码(call-manager.ts):

// services/call-manager.ts

// ... (imports and class definition)

private initializeCallKeep(): Promise<void> {
  // ...
  await RNCallKeep.setup({
    ios: {
      appName: 'My VoIP App',
      // ... other options
    },
    // ...
  });
  this.setupCallKeepListeners();
  // ...
}

private setupCallKeepListeners(): void {
  RNCallKeep.addEventListener('answerCall', async ({ callUUID }) => {
    if (this.activeSession && this.activeSession.callUUID === callUUID) {
      await this.handleAcceptCall();
    }
  });

  RNCallKeep.addEventListener('endCall', async ({ callUUID }) => {
    // ... (logic to end or reject the call)
  });

  RNCallKeep.addEventListener('didActivateAudioSession', () => {
    if (this.conferenceJoinInfo) {
      this.connectTwilio();
    }
  });
}

private async handleConferenceJoinInfo(message: any): Promise<void> {
  this.conferenceJoinInfo = message;
  // Now we wait for the didActivateAudioSession event
}

private async connectTwilio(): Promise<void> {
  if (!this.conferenceJoinInfo) {
    return;
  }
  // ... (logic to extract token and other info from conferenceJoinInfo)
  const call = await twilioService.connectToConference(
    twilioToken,
    conferenceId,
    backendUrl
  );
  // ...
}

解决方案:正确管理音频会话与事件序列

核心是确保Twilio Voice SDK完全复用CallKit管理的音频会话,避免独立激活音频会话触发CallKit的终止逻辑,具体步骤如下:

1. 禁用Twilio自动管理音频会话

在Twilio连接配置中,强制禁用其自动创建和管理音频会话,改用CallKeep的音频会话:

// 修改twilioService.connectToConference方法的连接逻辑
const call = await TwilioVoice.connect({
  accessToken: twilioToken,
  params: {
    'ConferenceName': conferenceId,
    'TwilioBackendUrl': backendUrl
  },
  // 关键配置:禁止Twilio自行管理音频会话
  audioSession: {
    enabled: false
  }
});

2. 手动接管音频会话的激活与停用

在CallKeep的音频会话事件中,手动控制Twilio的音频会话状态:

// 在setupCallKeepListeners中补充监听
RNCallKeep.addEventListener('didActivateAudioSession', async () => {
  if (this.conferenceJoinInfo) {
    await this.connectTwilio();
    // 连接成功后手动激活Twilio音频会话
    await TwilioVoice.audioSession.start();
  }
});

RNCallKeep.addEventListener('didDeactivateAudioSession', async () => {
  // 通话结束后停用Twilio音频会话
  await TwilioVoice.audioSession.stop();
});

3. 同步CallKit与Twilio的通话状态

Twilio通话连接成功后,必须通知CallKeep更新状态为已连接,避免状态不一致触发终止:

// 在connectTwilio方法中,Twilio连接成功后添加状态同步
call.on('connected', async () => {
  await RNCallKeep.reportConnected(this.activeSession.callUUID);
});

4. 修正事件触发顺序

在answerCall事件中,先通知CallKeep标记通话为进行中,再请求Twilio参会信息:

private async handleAcceptCall() {
  // 先告知CallKeep开始通话
  await RNCallKeep.startCall(this.activeSession.callUUID, this.activeSession.callerId, 'My VoIP App');
  // 再请求后端获取Twilio参会信息
  const conferenceInfo = await this.requestConferenceJoinInfo();
  this.handleConferenceJoinInfo(conferenceInfo);
}

5. 优化CallKeep初始化配置

确保CallKeep初始化时开启音频会话共享模式:

await RNCallKeep.setup({
  ios: {
    appName: 'My VoIP App',
    audioSessionMode: 'voiceChat',
    audioSessionActive: true,
    audioSessionPreferredSampleRate: 44100,
    audioSessionPreferredIOBufferDuration: 0.005
  }
});

内容的提问来源于stack exchange,提问作者Zeeshan Ghazanfar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 03:08:12