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

iOS端WebRTC接收视频呼叫时无视频ICE候选生成问题

iOS WebRTC 视频通话接收端无视频ICE候选问题

问题现象

发起视频呼叫流程正常,但接收端在设置本地描述后,didGenerate代理仅返回音频ICE候选(candidate.sdpMid=0),始终不生成视频ICE候选(candidate.sdpMid=1),导致doAcceptCall中的定时器因检测不到视频候选无法退出,呼叫应答流程卡壳。

已知前置条件

  • 服务器返回的Remote SDP已包含完整的视频相关参数
  • 代码中创建媒体发送者时,已尝试添加视频轨道

操作流程回顾

  • 收到视频呼叫邀请后,处理含m=video的Remote SDP,创建Offer类型RTCSessionDescription
  • 初始化媒体资源,向peerConnection添加视频轨道
  • 设置peerConnection远程描述,在回调中创建OfferToReceiveAudio和OfferToReceiveVideo均为true的应答约束
  • 调用setLocalDescription设置本地SDP
  • WebRTC仅生成音频ICE候选,无视频候选输出

问题定位与修复方案

1. 修复startMode赋值逻辑错误

当前代码中defaultPeerConnectionConstraints依赖self.startMode判断是否接收视频,但接收呼叫场景下startMode未被同步为视频模式,导致约束中视频接收参数未生效。

修改acceptCall方法,同步startMode为当前应答的视频模式:

- (void) acceptCall:(ndCallMode)mode{
    RLogInfo(@"tag = %@", self.localTag);
    if ([self isEnded]){
        return;
    }
    if (!self.isInviteReceived) {
        self.isIncomingAcceptedBeforeInvite = YES;
        self.localModeIncomingAcceptedBeforeInvite = mode;
        return;
    }
    
    self.isAnswered = YES;
    self.localMode = mode;
    // 新增:同步startMode为当前应答的呼叫模式
    self.startMode = mode;
    self.state = ndCallStateIncomingAnswer;
    
    [self.callManager showCallInterface:self];
    [self.callViewDelegate didCallStateChanged];
    
    [self prepare];
    // ... 剩余原有代码保持不变 ...
}

2. 调整视频轨道添加的判断条件

createMediaSenders中原本使用self.startMode判断是否添加视频轨道,但接收呼叫时startMode更新不及时,导致视频轨道未被正确添加到peerConnection。改用已在acceptCall中设置的self.localMode作为判断条件:

- (void) createMediaSenders{
    self.stream = [self.factory mediaStreamWithStreamId:kMediaStreamId];

    RTCMediaConstraints *constraints = [self defaultMediaAudioConstraints];
    RTCAudioSource *audioSource = [self.factory audioSourceWithConstraints:constraints];
    RTCAudioTrack *audioTrack = [self.factory audioTrackWithSource:audioSource trackId:kAudioTrackId];
    NSMutableArray *streamIds = [@[kMediaStreamId] mutableCopy];
    [self.stream addAudioTrack:audioTrack];

#if !TARGET_IPHONE_SIMULATOR
    // 修改判断条件为localMode,确保接收视频呼叫时添加视频轨道
    if (self.localMode == ndCallModeVideo){
        RTCVideoSource *videoSource = [self.factory videoSource];
        self.videoCapturer = [[VideoCapturer alloc] init];
        [self.videoCapturer startCaptureLocalVideoWithVideoSource:videoSource
                                                         settings:[LocalVideoCaptureSetting createDefaultSetting]];
        self.localVideoTrack = [self.factory videoTrackWithSource:videoSource
                                                          trackId:kVideoTrackId];
        [self.stream addVideoTrack:self.localVideoTrack];
        [self.localVideoTrack addRenderer:[self.callViewDelegate getCameraPreviewView]];
        
        [self.peerConnection addTrack:self.localVideoTrack streamIds:streamIds];
    }
#endif

    [self.peerConnection addTrack: audioTrack streamIds:streamIds];
}

3. 确保应答约束正确设置视频接收参数

检查defaultAnswerConstraints方法(如果未实现则补充),确保应答时根据当前呼叫模式设置正确的视频接收参数:

- (RTCMediaConstraints *)defaultAnswerConstraints {
    NSDictionary *mandatoryConstraints = @{
        @"OfferToReceiveAudio" : @"true",
        @"OfferToReceiveVideo" : (self.localMode == ndCallModeVideo) ? @"true" : @"false"
    };
    NSDictionary *optionalConstraints = @{ @"DtlsSrtpKeyAgreement" : @"true" };
    return [[RTCMediaConstraints alloc] initWithMandatoryConstraints:mandatoryConstraints
                                                 optionalConstraints:optionalConstraints];
}

4. 排查SDP预处理是否破坏视频参数

prepareRemoteSdp方法中对Remote SDP进行了修改,需确认未移除m=video行或视频相关的关键属性。可临时注释掉SDP预处理代码,测试是否能生成视频ICE候选,逐步定位是否是SDP修改导致的问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 02:01:03