修改linphone-sdk-android-第四篇

在使用Linphone SDK Android时遇到一个问题,即当一个呼叫正在进行时,收到新的呼叫会导致异常振铃。通过Logcat分析发现ToneManager的相关方法被调用。通过阅读源码,发现在startRingtone方法中缺少对linphone_core_tone_indications_enabled的判断。在源码中添加该判断并重新编译后,只需在Java层设置Config关闭tone_indications,即可避免通话中异常振铃的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

在使用linphone-sdk-android过程中,发现当有一起呼叫在通话中时,又收到一起呼叫,会莫名其妙的播报振铃声音,问题是已经调用linphone-sdk-android提供的接口关闭了振铃声音

// 关闭Ring
mCore.setRing(null);
mCore.setRingback(null);
mCore.setRemoteRingbackTone(null);
mCore.setNativeRingingEnabled(false);
mCore.setRingDuringIncomingEarlyMedia(false);
mCore.setVibrationOnIncomingCallEnabled(false);

// 关闭CallErrorTone
Reason[] reasons = Reason.values();
for (Reason reason : reasons) {
    mCore.setCallErrorTone(reason, null);
}

// 关闭ToneId
ToneID[] toneIds = ToneID.values();
for (ToneID toneId : toneIds) {
    mCore.setTone(toneId, "");
}

分析

查看Logcat输出的日志,分析发现有ToneManagerdoStartRingtone等关键词

13056-13056/com.guodong.android.linphone I/liblinphone: [ToneManager] [0x934e70ac] state changed : [None, LinphoneCallIncomingReceived]
13056-13056/com.guodong.android.linphone I/liblinphone: [ToneManager] add new session [0x934e70ac]
13056-13056/com.guodong.android.linphone I/liblinphone: [ToneManager] doStopToneToPlaySomethingElse
13056-13056/com.guodong.android.linphone I/liblinphone: [ToneManager] doStartRingtone
13056-13056/com.guodong.android.linphone I/liblinphone: [ToneManager] doStartNamedTone [2]

打开IDE去源码中搜索一番,发现tone-manager.cpp,在其中找到doStopToneToPlaySomethingElsedoStartRingtonedoStartNamedTone方法,与Logcat日志输出吻合

void ToneManager::doStopToneToPlaySomethingElse(const std::shared_ptr<CallSession> &session) {
	lInfo() << "[ToneManager] " << __func__;
	if (isAnotherSessionInState(session, State::Tone)) {
		doStopTone();
	}
}

void ToneManager::doStartRingtone(const std::shared_ptr<CallSession> &session) {
	lInfo() << "[ToneManager] " << __func__;
	LinphoneCore *lc = getCore()->getCCore();
    // 如果有一个正在通话的呼叫就调用`doStartNamedTone`
	if (isAnotherSessionInState(session, State::Call)) {
		/* play a tone within the context of the current call */
		doStartNamedTone(session, LinphoneToneCallWaiting);
	} else {
		MSSndCard *ringcard = lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard;
		if (ringcard && !linphone_core_is_native_ringing_enabled(lc)) {
			if (!linphone_core_callkit_enabled(lc)){
				ms_snd_card_set_stream_type(ringcard, MS_SND_CARD_STREAM_RING);
				linphone_ringtoneplayer_start(lc->factory, lc->ringtoneplayer, ringcard, lc->sound_conf.local_ring, 2000);
			}else{
				ms_message("Callkit is enabled, not playing ringtone.");
			}
		}
	}
}

void ToneManager::doStartNamedTone(const std::shared_ptr<CallSession> &session, LinphoneToneID toneId) {
	lInfo() << "[ToneManager] " << __func__ << " [" << Utils::toString(toneId) << "]";
	LinphoneToneDescription *tone = getToneFromId(toneId);

    // 在Java中已将audiofile置为"",所以会走else分支
	if (tone && tone->audiofile) {
		playFile(tone->audiofile);
	} else {
        // 此处生成振铃声音
		MSDtmfGenCustomTone dtmfTone = generateToneFromId(toneId);
		playTone(session, dtmfTone);
	}
}

好的,现在先找到调用doStopToneToPlaySomethingElse的方法,在IDE中查找,发现startRingtone方法

void ToneManager::printDebugInfo(const std::shared_ptr<CallSession> &session) {
	auto callState = session->getState();
    auto toneState = getState(session);
	lInfo() << "[ToneManager] [" << session << "] state changed : [" << stateToString(toneState)  << ", " << Utils::toString(callState) << "]";
}

void ToneManager::startRingtone(const std::shared_ptr<CallSession> &session) {
	printDebugInfo(session); // 对应Logcat第一行输出日志
	setState(session, State::Ringtone); // 对应Logcat第二行输出日志
    // 如果另外一个呼叫不在Ringtone且不在Ringback状态
	if (!isAnotherSessionInState(session, State::Ringtone) && !isAnotherSessionInState(session, State::Ringback)) {
		doStopToneToPlaySomethingElse(session);
		doStartRingtone(session);
		mStats->number_of_startRingtone++;
	}
}

查看ToneManager::startRingtone下面的startErrorTone方法,发现此方法是调用linphone_core_tone_indications_enabled判断是否可以播报Tone,猜想可以在startRingtone方法中也增加此判断逻辑

void ToneManager::startErrorTone(const std::shared_ptr<CallSession> &session, LinphoneReason reason) {
	LinphoneCore *lc = getCore()->getCCore();
    // 此处判断是否可以播报Tone
	if (linphone_core_tone_indications_enabled(lc)) {
		printDebugInfo(session);
		doStopToneToPlaySomethingElse(session);
		doStartErrorTone(session, reason);
		mStats->number_of_startErrorTone++;
	}
}

不过需要先了解下linphone_core_tone_indications_enabled方法的实现,此方法位于msic.c中,方法内部从linphone_config中读取soundsection下tone_indicationskey的值转换为bool_t类型,大于0为Ture,小于等于0为Flase,其中linphone_config可以从Java层配置

bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc){
	return !!linphone_config_get_int(lc->config,"sound","tone_indications",1);
}

好的,问题分析完毕,可以在startRingtone方法中也增加此判断逻辑了

void ToneManager::startRingtone(const std::shared_ptr<CallSession> &session) {
	printDebugInfo(session);
	setState(session, State::Ringtone);
	// modified by guodongAndroid on 2022/04/24 修改有正在通话的呼叫时,又收到一起呼叫播报Ringtone问题
	// 增加tone_indications是否开启判断
	LinphoneCore *lc = getCore()->getCCore();
	if (!linphone_core_tone_indications_enabled(lc)) {
		return;
	}
	
	if (!isAnotherSessionInState(session, State::Ringtone) && !isAnotherSessionInState(session, State::Ringback)) {
		doStopToneToPlaySomethingElse(session);
		doStartRingtone(session);
		mStats->number_of_startRingtone++;
	}
}

保存重新编译,等待编译完成拷贝至AS中,现在只需在Java层初始化时配置Config,修改tone_indications的值即可

// modified by guodongAndroid on 2022/04/24 修改有正在通话的呼叫时,又收到一起呼叫播报Ringtone问题
// 关闭ToneIndications
mCore.getConfig().setInt("sound", "tone_indications", 0);

happy~

<think>好的,用户的问题是关于如何在Linphone Desktop 4.5.0-alpha版本中导入RTP地址。我需要先理解用户的具体需求。RTP通常用于实时音视频传输,用户可能希望将某个RTP流地址导入到Linphone中,以便接收或发送媒体流。 首先,我需要回忆一下Linphone的功能。Linphone支持SIP协议,但直接导入RTP地址可能需要使用命令行或者高级配置。因为RTP通常是SIP通话建立后自动处理的,直接操作RTP可能不在常规的GUI功能中。查看用户提供的引用内容,特别是引用[3]提到了CoreImpl.java中的inviteAddress方法,这属于Android SDK的部分,但用户询问的是Desktop版本,可能需要不同的方法。 接下来,考虑Linphone Desktop是否有命令行参数或API可以直接处理RTP流。通常,这类操作可能需要使用Linphone的终端命令或者配置文件。例如,使用linphonec命令行的版本,或者通过配置文件设置媒体流地址。 另外,用户提到的版本是4.5.0-alpha,属于较旧的版本,可能需要查阅该版本的文档或源代码。引用[1]提到了LinPhone-SDK的代码仓库,可能需要检查该版本的源代码是否存在相关功能。但用户的问题是关于Desktop应用,而不是SDK集成,可能需要不同的步骤。 可能的解决方案步骤包括:通过命令行启动Linphone并指定RTP地址,或者使用配置文件设置。例如,使用linphonec命令,启动后输入命令建立通话时指定RTP地址。例如,使用`call rtp://@IP:port`这样的命令,但需要确认Linphone是否支持这种URI格式。 另外,可能需要通过自定义SIP INVITE消息,在消息头中指定RTP地址。这需要了解SIP协议的结构,以及如何在Linphone中发送自定义的INVITE请求。引用[3]中的inviteAddress方法可能用于发起呼叫,但参数是Address对象,可能需要构造包含RTP地址的地址字符串。 此外,用户可能需要配置Linphone的音频和视频设置,手动指定RTP端口或地址。在设置中找到网络或媒体配置部分,手动输入RTP流的IP和端口。但通常这些设置是用于接收流,而非主动导入外部RTP流。 还需要考虑是否需要使用第三方工具将RTP流导入到Linphone,比如通过GStreamer等多媒体框架中转。但这种方法可能超出Linphone本身的配置,需要更复杂的环境搭建。 总结可能的步骤:1. 使用命令行参数或终端命令直接呼叫RTP地址;2. 在配置文件中设置RTP参数;3. 通过自定义SIP消息包含RTP信息;4. 使用高级API或脚本控制Linphone的行为。需要进一步验证这些方法的可行性,并参考Linphone的文档或社区讨论。 最后,由于用户使用的是较旧的alpha版本,可能存在功能限制或不同的配置方式,建议用户升级到稳定版或查阅对应版本的文档。</think>在Linphone Desktop 4.5.0-alpha版本中导入RTP地址主要通过**命令行参数或API调用**实现,因为该功能未直接集成在图形界面中。以下是具体步骤: --- ### 方法一:通过命令行启动时指定RTP流 1. **启动Linphone时添加媒体参数** 使用`linphonec`命令行工具启动程序,并通过`--media`参数指定RTP地址格式: ```bash linphonec -C --media="rtp://目标IP:端口" ``` 例如,接收RTP流到本地端口6000: ```bash linphonec -C --media="rtp://0.0.0.0:6000" ``` 2. **建立呼叫后自动关联RTP** 在命令行界面中,输入以下命令发起呼叫(假设目标SIP地址为`sip:user@example.org`): ```bash call sip:user@example.org ``` Linphone会自动使用配置的RTP参数进行媒体传输[^3]。 --- ### 方法二:通过API动态设置(需开发适配) 若需在代码层面实现,可参考LinPhone-SDK的`Core`接口: 1. **配置媒体参数** 在初始化`Core`时设置RTP地址: ```cpp LinphoneCore *lc = linphone_core_new(NULL, NULL, NULL, NULL); linphone_core_set_media_rtp_port(lc, 6000); // 设置本地RTP端口 ``` 2. **发起呼叫时绑定地址** 使用`linphone_core_invite_address()`发起呼叫,并通过SDP协议协商RTP参数。 --- ### 注意事项 - **版本兼容性**:4.5.0-alpha版本可能存在稳定性问题,建议升级至稳定版(如5.x)[^1][^2]。 - **防火墙配置**:确保目标端口在防火墙中开放。 - **协议支持**:RTP需配合SIP或SDP协议使用,纯RTP流需额外工具解析。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值