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

Android VoIP应用:基于ConnectionService本地播放DTMF音的问题

解决PJSIP VoIP应用中DTMF按键无本地音频反馈的问题

你已经实现了SIP信令发送DTMF(非RTP方式),但本地按键没有音频反馈,之前调用Connection.onPlayDtmfTone(digit.charAt(0))没效果,想要像播放保持音那样通过事件触发的方式实现,这里给你几个可行的方案:

先排查onPlayDtmfTone失效的常见原因

  • 确认当前Connection处于激活状态(比如STATE_ACTIVE),未建立的通话或挂起的连接可能没有可用的音频通道
  • 检查音频权限是否齐全:Android需要RECORD_AUDIO和MODIFY_AUDIO_SETTINGS,iOS需要正确配置AudioSession权限
  • 确认PJSIP的音频子系统已初始化,比如Endpoint的libInit()和audDevManager().init()已调用

方案1:直接调用AudioMedia的DTMF播放方法

保持音是通过事件触发内部音频播放,本质也是调用了PJSIP的音频媒体接口,你可以直接在按键处理逻辑中获取Connection关联的AudioMedia来播放DTMF:

// 按键回调中获取当前活跃Connection
Connection conn = getCurrentActiveConnection();
if (conn != null && conn.getState() == Connection.STATE_ACTIVE) {
    try {
        AudioMedia audioMedia = conn.getAudioMedia();
        if (audioMedia != null) {
            // 参数:DTMF数字、播放时长(毫秒)、音量(0-1,0静音,1最大)
            audioMedia.playDtmf(digit.charAt(0), 200, 0.6f);
        }
    } catch (PjException e) {
        // 处理异常,比如日志输出
        e.printStackTrace();
    }
}

方案2:用ToneGenerator生成并播放DTMF音

如果AudioMedia方式不行,可以直接用PJSIP的ToneGenerator来生成标准DTMF频率的提示音:

try {
    Endpoint endpoint = Endpoint.instance();
    ToneGenerator toneGen = endpoint.createToneGenerator();
    if (toneGen != null) {
        ToneDesc dtmfTone = ToneDesc.getDtmfTone(digit.charAt(0));
        if (dtmfTone != null) {
            // 播放200毫秒的DTMF音
            toneGen.startTone(dtmfTone, 200);
            // 播放完成后释放资源(可根据需求延迟释放)
            toneGen.stopTone();
            toneGen.release();
        }
    }
} catch (PjException e) {
    e.printStackTrace();
}

方案3:沿用sendConnectionEvent的事件触发方式

如果你想保持和播放保持音一致的代码风格,可以自定义事件并扩展Connection的事件处理:

  1. 定义自定义事件常量:
public static final String EVENT_PLAY_DTMF_TONE = "PLAY_DTMF_TONE";
  1. 在按键处理时发送事件:
connection.sendConnectionEvent(EVENT_PLAY_DTMF_TONE, digit);
  1. 在Connection的事件监听中处理播放逻辑:
// 假设你有Connection的事件监听器
connection.addOnConnectionEventListener(new OnConnectionEventListener() {
    @Override
    public void onConnectionEvent(Connection conn, String event, Object data) {
        if (EVENT_PLAY_DTMF_TONE.equals(event)) {
            String digit = (String) data;
            // 这里复用方案1或2的播放逻辑
            try {
                AudioMedia audioMedia = conn.getAudioMedia();
                if (audioMedia != null) {
                    audioMedia.playDtmf(digit.charAt(0), 200, 0.6f);
                }
            } catch (PjException e) {
                e.printStackTrace();
            }
        }
        // 其他事件处理...
    }
});

测试时注意:确保在通话建立后再触发按键,避免在连接初始化阶段调用音频播放接口。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 09:20:10