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

iOS Swift端WebRTC与Janus Gateway集成时insertDtmf方法无法发送DTMF至对端的问题求助

解决iOS WebRTC + Janus Gateway DTMF发送失败问题

你遇到的这个问题挺典型的——语音通话正常但DTMF发不出去,Android端同逻辑却没问题,大概率是iOS WebRTC的细节处理和Android端有差异。结合你贴的代码,我整理了几个关键排查点和修复方案:

1. 精准获取音频轨道的DTMF Sender

你现在用pc.senders.first?.dtmfSender取DTMF Sender,这里有个隐患:PeerConnection的senders可能包含视频或其他轨道,first不一定指向音频轨道。Android端可能刚好第一个是音频sender,但iOS端可能不是,导致拿到的DTMF Sender无效。

修复方法:遍历senders,明确筛选音频轨道对应的sender:

public func insertDTMF(_ tone:String){
    guard let peerConnection = pc else {
        print("Peer connection未初始化")
        return
    }
    // 精准定位音频轨道的sender
    let audioSender = peerConnection.senders.first { sender in
        sender.track?.kind == RTCRtpMediaType.audio.rawValue
    }
    
    guard let dtmfSender = audioSender?.dtmfSender else {
        print("未找到音频轨道对应的有效DTMF Sender")
        return
    }
    
    // 避免重复发送(如果当前DTMF正在播放)
    if !dtmfSender.isActive {
        let success = dtmfSender.insertDtmf(tone, duration: 200, interToneGap: 70)
        if !success {
            print("DTMF音发送失败: \(tone)")
        }
    } else {
        print("DTMF Sender正忙,请等待当前音播放完成")
    }
}

2. 切换到Unified Plan SDP语义

你的代码里用了rtcConfig.sdpSemantics = .planB,而WebRTC现在更推荐用Unified Plan,部分网关(包括Janus)对Plan B的DTMF协商支持可能有兼容性问题——这很可能是iOS端失效的核心原因(Android端可能默认用了Unified Plan)。

修改SDP语义,并调整轨道添加方式(Unified Plan不支持直接添加MediaStream,需要单独添加Track):

// 在streamsDone方法中修改RTCConfiguration
let rtcConfig = RTCConfiguration.init()
rtcConfig.iceServers = server.iceServers
rtcConfig.bundlePolicy = RTCBundlePolicy.maxBundle
rtcConfig.rtcpMuxPolicy = RTCRtcpMuxPolicy.require
rtcConfig.continualGatheringPolicy = RTCContinualGatheringPolicy.gatherContinually
rtcConfig.sdpSemantics = .unifiedPlan // 替换为Unified Plan

// 替换pc.add(myStream)为逐个添加轨道
if let audioTrack = audioTrack {
    do {
        try pc.addTrack(audioTrack, mediaStreamIds: [LOCAL_MEDIA_ID])
    } catch {
        print("添加音频轨道失败: \(error.localizedDescription)")
    }
}

3. 验证SDP中的DTMF协商信息

DTMF发送需要两端SDP中包含telephone-event的RTP映射。可以分别抓取iOS和Android端的SDP,对比是否iOS端的SDP缺少类似以下的行:

a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16

如果缺失,说明WebRTC没有启用DTMF协商,可以在音频约束中强制开启:

// 初始化audioConstraints时添加DTMF相关约束
let audioConstraints = RTCMediaConstraints(mandatoryConstraints: [
    RTCPair(key: "googDtmf", value: "true")
], optionalConstraints: nil)

4. 补全错误处理,排查隐藏问题

你的代码中setRemoteDescription的completion handler是空的,可能存在隐藏的SDP设置错误,导致DTMF无法正常工作。添加错误日志排查:

pc.setRemoteDescription(sessionDescription) { error in
    if let error = error {
        print("设置远端SDP失败: \(error.localizedDescription)")
    } else {
        print("远端SDP设置成功")
    }
}

5. 调整DTMF参数(可选)

虽然你当前的duration(200ms)和interToneGap(70ms)符合规范,但部分网关对参数有更严格的要求,可以尝试调整为更通用的值:

dtmfSender.insertDtmf(tone, duration: 160, interToneGap: 100)

建议先从第1点和第2点入手排查,这两个是最可能导致iOS端DTMF失效的原因。如果还是不行,可以检查Janus Gateway的日志,看是否收到了iOS端的DTMF包,进一步定位问题。

内容的提问来源于stack exchange,提问作者Bilal Şimşek

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 20:42:43